你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

NVIC优先级+软件中断(SWIER)+软件仿真+硬件仿真(JTAG)+中断延迟

[复制链接]
吐息间丶时光中 发布时间:2017-3-7 22:58
前段时间贴主看了Cortex-M3的NVIC,对其中断嵌套甚是着迷,于是瞎搞了几下下……瞎搞就瞎搞嘛,但却搞出了问题……+ ]# z3 M+ D6 t7 z4 k9 J: g
5 p7 Y' ?1 w5 ?* B1 ~; |
废话不多说,直奔主题!, w6 O/ b9 a5 U2 ?, j; G; R/ k, |
1 R' c3 s) Q: S5 ], F$ i5 O
通过查看
Cortex-M3有关异常和NVIC章节的资料,贴主本来是想实现这么几个工程目标:5 H- W( Q* L1 O' W
(贴主板子上的芯片型号是STM32F103C8T6,PA.8接的一个LED的阴极;MDK版本5.17&5.23)
) B6 u# n. m1 s' n: `$ p& K6 K
================================================================
- t+ s* n6 H2 F5 e: B  p【1】不操作优先级寄存器,软件触发EXTI2中断进入其ISR里,再软件触发EXTI1。判断是否会发生中断嵌套?: Y2 K" J6 k# m+ e- X
  
工程预估:不会。. H% O/ u5 X% H* }- ?" ]3 W; A0 ]
         why:①当不操作优先级寄存器时,Cortex-M3内核默认从比特0分组(因为SCB_AIRCR寄存器的优先级分组三位复位值为0),即优先级寄存器高四位均表示抢占优先级;9 A; b( \" \" g# Y" [4 x  ~' t
                  ②优先级寄存器NVIC_IPRx高四位复位值为0,由于没重新赋值,所以抢占优先级均为0;【也就类似于除能了CM3的中断嵌套机制。】; }$ N  }& ~; Q8 t7 R3 r( v3 a0 J
                  ③优先级寄存器高四位均表示抢占优先级且为0,亚优先级均为0。所以优先级取默认的硬件异常号,虽然EXTI1的默认异常号高于EXTI2,但不会发生中断嵌套。' v/ n, Z5 J- N
-------------------------------------------------------------------------------------------------------------------------------
8 Q5 E* W5 n5 ^' s+ ~
【2】优先级寄存器的高三位表示抢占优先级,且EXTI1和EXTI2抢占优先级相同,但EXTI2的亚优先级高于EXTI1。软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?5 Y% m) B% D& B* ]$ T* ?' j
  工程预估:不会。
3 C  o4 m7 M: b* V0 S) x# x
         why:
二者抢占优先级相同,亚优先级的高低不导致中断嵌套。只是当抢占优先级相同的异常有不止一个同时悬起时,就优先响应亚优先级最高的异常。
6 v& d" l6 _+ V8 F6 q-------------------------------------------------------------------------------------------------------------------------------
# E( \/ {1 G& i, S* W1 L- J( Y
【3】优先级寄存器的高二位表示抢占优先级,且EXTI2抢占优先级高于EXTI1,但EXTI2的亚优先级低于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?2 T8 M$ j( G6 P; E+ G# F
  工程预估:会。

* {% `& ?$ c' o+ a) c         why:
EXTI2抢占优先级高于EXTI1,亚优先级的高低不导致中断嵌套。
2 N% `9 P; A- G! l& L" M
-------------------------------------------------------------------------------------------------------------------------------- R; z; @+ n# [2 M- r. n/ j. L
【4】无抢占优先级,优先级寄存器的高四位均表示亚优先级,但EXTI2的亚优先级高于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?: v6 c) i6 U4 Y; E
  工程预估:不会。

4 ^1 g& f, u/ B* h, o         why:
无抢占优先级【相当于除能了CM3中断嵌套机制】,亚优先级的高低不导致中断嵌套。
0 A' ^' O3 P( }6 @, a
================================================================
  Q% P# v5 [- w7 L1 h很明显,每一个程序均非常简单。但将程序下载到硬件上跑的效果会不会如预估一样呢?
4 ^& }' Z) A8 X% i+ ?
* J  n8 M# t# C第一个工程的代码如下:

; G0 \. R- k" ~3 b8 K' M; y% V2 t“main.c”源文件里% n6 l: |7 s) e7 K% |: ~$ C% P
  1. #include "stm32f10x.h"
    + ?! o9 g7 ^5 h6 d2 g% E
  2. 3 h% v8 ?' U2 |4 D1 v# F) [" f
  3. #define GPIOA_ODR_Addr        (GPIOA_BASE+0x0C)                //GPIOA端口寄存器ODR的地址; A+ z* E! ~9 |7 d
  4. 3 _  D9 i! e3 U  T3 p+ y. {
  5. #define BitBand(Addr, BitNum)        *(__IO uint32_t *)((Addr&0xF0000000)+0x02000000+ \
    0 X9 M( `/ b  E, v; B" G
  6.                                                                                                         ((Addr&0x000FFFFF)<<5)+(BitNum<<2))       
    8 I& X  R6 D4 q) p7 A  ^: w" R
  7. #define PAout(n)        BitBand(GPIOA_ODR_Addr, n)        //偏移地址取的是32位寄存器的第一字节的,所以n的取值为0~31
    & C+ s4 l7 u7 A2 ]

  8. 1 T4 U) {# N) a  U
  9. FlagStatus led = SET;                                                        //外部调用的全局变量(声明在stm32f10x_it.h头文件)6 n4 }7 L: \, r3 O  k1 q

  10. 8 g. _5 _3 e) l
  11. static void RCC_Configuration(void);                        //函数原型声明" x8 Y7 R7 u; R
  12. static void GPIO_Configuration(void);
    ; ]! }: B9 y1 \. C

  13. + j( ^) w: {; ?8 ?! r
  14. /**********************************************************************
    5 L4 l8 d0 \' M5 h1 V* b9 o
  15. * Function Name : MAIN
    % A! F; e2 N# g+ S
  16. * Description         : main program/ {1 S% h3 K* J' x3 M. a3 N! V
  17. * Input                 : None4 p& i% {$ ~5 C8 N- Z
  18. * Output                 : None6 ]- v$ Q+ B; Z* K- B2 q" H; P0 @4 w
  19. * Return                 : None
    0 e$ @8 j9 U+ ?. X$ T+ P
  20. **********************************************************************/
    % l7 }* _0 e& Y, E1 Z0 K
  21. int main(void)
    ; y  g+ J$ ]. L& B  O
  22. {
    7 l6 m6 F+ x( V! a; t  j, J
  23.         RCC_Configuration();8 I2 e  X$ F7 t, j2 i+ D) c
  24.         GPIO_Configuration();2 k- S( y' r+ g; w" ^
  25.         PAout(11) = led;                                                        //上电关闭LED
    6 H& b# o4 T1 M# R: h% S! c% y
  26.         % l3 C! Q6 y, ^* [  s' o
  27.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;
    + Q5 a0 g2 X' j! t: o5 \
  28.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;; Q8 l  l6 \( P% x  C0 A
  29.        
    & _' E  |  y, m+ k- g2 k6 s3 H
  30.         EXTI->SWIER = EXTI_Line2;
    , W: W9 o" X3 f0 j
  31.        
    7 k/ j9 D% P* U' P6 z2 w
  32.         while(1)
      ^2 N. v- o4 W$ i& z
  33.         {/ M8 a" {8 ^. n$ ?
  34.                 PAout(11) = led;$ p8 V* f) i: U- \1 i
  35.         }2 ^1 \% V6 U) o3 ?: z" O8 p
  36.         , o. a& V% b* ]
  37. //        return (0);
    ; E- n1 y3 F% [
  38. }
    9 U8 \/ ~+ R% y
  39. $ w0 v" K! o7 w
  40. /**********************************************************************
    " {3 L; s, X& \4 [; u$ A8 H
  41. * Function Name : RCC_Configuration
    ( E  E! R( z* f# g# ~) T0 o
  42. * Description         : 配置时钟参数,使能外设时钟
    . D' D  a; {: t, e2 d
  43. * Input                 : None+ M2 l- p; K- e/ Q
  44. * Output                 : None
    : \; E% T0 P6 y" M, @& A
  45. * Return                 : None& b' Q: ^: ]3 j
  46. **********************************************************************/
    % ]  X* M7 a6 \# H3 Y
  47. static void RCC_Configuration(void)
    9 l/ ]* o: w7 W2 a
  48. {        ! D, d; N) i7 ~, ?2 n$ z
  49.         RCC_DeInit();                                        //将外设RCC寄存器重设为缺省值(选择HSI作为系统时钟,其它保持复位值); i9 C6 ?: Q* M1 Y7 ^
  50.         RCC_HSEConfig(RCC_HSE_ON);                //HSE晶振ON
    : e7 W$ J3 O- X& Y- b, C
  51.         if(RCC_WaitForHSEStartUp() == SUCCESS)        //等待HSE晶振稳定2 K: ?: m1 i1 z. r
  52.         {
    ; \9 j$ p8 J3 G6 U0 j
  53.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);        //设置AHB时钟(HCLK)—— HCLK = SYSCLK/1
    ' J+ G" ^! K) v8 V: A- d
  54.                 RCC_PCLK2Config(RCC_HCLK_Div1);                //设置高速AHB时钟(PCLK2)—— PCLK2 = HCLK/19 v* ^  Z! O, X. h, E3 K% o* |) C/ `
  55.                 RCC_PCLK1Config(RCC_HCLK_Div2);                //设置低速AHB时钟(PCLK1)—— PCLK1 = HCLK/26 t* U5 d5 V$ H( g
  56.                 FLASH_SetLatency(FLASH_Latency_2);        //在SYSCLK周期与闪存访问时间插入2个等待周期
    6 n' B# P4 u/ D
  57.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //启用闪存预取缓冲区6 d3 a# P: a: D  W/ i3 C
  58.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);        //设置PLL时钟源及倍频系数 —— PLLCLK = (HSECLK/1) * 9 = 72MHz
    ( ?8 p! ~* r- q& J) L) R; v6 _
  59.                 RCC_PLLCmd(ENABLE);                                        //使能PLL
    ; F% C4 k/ p% L/ }
  60.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);                //等待PLL就绪& E$ E* v3 t3 `, r0 A/ v% r
  61.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                //设置系统时钟(SYSCLK)—— 选择PLL作为系统时钟
    7 e2 j; |# Z$ w/ G
  62.                 while(RCC_GetSYSCLKSource() != 0x08);                                        //返回用作系统时钟的时钟源 —— 0x08:PLL作为系统时钟
    / n# X3 q# }1 k6 i- A) w
  63.         }
    4 v3 D2 L; z/ Q) T8 S' C" z
  64.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);3 f7 u. f4 C( J* Q( ^! @( W
  65. }
    9 ]7 b9 E& c0 k
  66. , `& h7 o& z3 l0 y9 L) O; V2 ]  J
  67. /**********************************************************************, _4 S$ ]# F" p4 h/ C' z
  68. * Function Name : GPIO_Configuration
    4 \% ~( u+ j) ?  u# g( A
  69. * Description         : 配置GPIO参数! g* o7 C" j2 E6 `
  70. * Input                 : None1 @) ]0 L* g6 R8 c9 ~' o) b
  71. * Output                 : None' ?5 b3 w% G& n3 O3 J
  72. * Return                 : None% m' G; F. n% L. I$ h+ l. ?" w/ i
  73. **********************************************************************/* D' c1 u/ P$ ]0 T' U% i  t! v4 @
  74. static void GPIO_Configuration(void)
    / {3 u- ]1 L1 Q" c
  75. {, [4 u, h; y0 l: r
  76.         GPIO_InitTypeDef GPIO_InitStructure;
    ( ~( X$ E/ k; L4 g! r( u. `
  77.        
      ~6 |: e9 W, U1 t5 o! T
  78.         /* 将GPIOA.11引脚设置为通用推挽输出模式,最大速度50MHz */
    9 R9 Z, a$ _: x! D9 Z
  79.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    ) z! t5 J, q8 T' I7 [
  80.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //GPIOA.9已配置
    9 r7 m/ t# v; t  a: Y$ Y
  81.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;% f! e0 ]/ x) ^6 D- T# y
  82.         GPIO_Init(GPIOA, &GPIO_InitStructure);
    4 C" h( _1 j% z9 ^, y0 g$ u- @
  83.         : g) a8 L% J6 e9 l7 A
  84.         /* 将GPIOA.1和GPIOA.2引脚设置为浮空输入模式 */5 T1 P+ `  F9 h% F
  85. //        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;! \% Y, z4 C( v% n
  86. //        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    7 q% ^3 g7 g) S5 F0 U0 y3 {8 a% j
  87. //        GPIO_Init(GPIOA, &GPIO_InitStructure);  z  j$ @0 p) R8 Y' F+ k8 [, ]
  88.         % E; g7 U( j: x+ o4 W
  89.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
    ; E8 S3 h7 \" ]) G. H4 P
  90.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);1 U) g! N4 ^0 g: |# z, e9 p& @
  91. }
复制代码
“stm32f10x_it.c”源文件里:
; R; B0 V' m/ r" X! z
  1. /**$ ]. r4 G$ h0 i3 S/ p
  2.   * @brief  This function handles External lines 1 interrupt request.& z% u2 R9 F/ H
  3.   * @param  None0 A. a' A, ?+ T0 K6 l
  4.   * @retval None
    $ @1 N0 c. ]3 L; u9 z
  5.   */
    1 w  F9 J/ E# U% |. m
  6. void EXTI1_IRQHandler(void)
    7 T" o; U8 U: {
  7. {: ]8 E5 F! R  M$ [! f+ c; A  t
  8.         EXTI->PR = EXTI_Line1;
    4 i: z% X' ]' B+ [, ~! l" O- X
  9.         led = RESET;8 a& U0 B1 l. j& L; X* a
  10. }
    " g' N2 w  z1 C) j

  11. + A5 d: J- U% H4 M/ P5 D
  12. /**5 E/ X1 q' L$ {7 C, [
  13.   * @brief  This function handles External lines 2 interrupt request.
    + e& m/ Z; G$ d. o/ a6 @2 X
  14.   * @param  None2 @3 y& Y$ n- p% i9 @% z1 i
  15.   * @retval None, C5 ]2 P8 C" Y; f
  16.   */
    + O% L6 K" g7 p4 m/ L, V! K# e  S
  17. void EXTI2_IRQHandler(void)  i3 c6 q) y2 E+ P  v  J- l
  18. {  Y! M8 Q; J5 v4 Z
  19.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    ) O& F6 i: e5 r( g2 J" k0 G) d
  20.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求8 t% ~+ r9 n. c8 P6 k1 Z# U+ H5 c
  21.         / @. h+ P8 k& {0 @. K& `. H
  22.         EXTI->PR = EXTI_Line1;                                //清除触发请求5 d: ~- W2 v/ P1 _5 D- O+ e1 m
  23.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
    ! C5 \! ^; W1 n3 I6 S* C4 j
  24. }
复制代码
“stm32f10x_it.h”源文件里:! S; M" q' y9 ~; i9 k1 `+ A
  1. /****** 用户自定义 ******/* b# T/ Q, Z% u& b
  2. extern FlagStatus led;                //声明一个外部调用的全局变量(控制LED亮灭的变量)
复制代码
显然代码很简单,软件仿真时各寄存器也是按照程序的意思显示各项数据指标。但是………………很残酷………………实际与理论发生了偏差 —— 将程序烧进硬件跑,LED亮了(即PA.8被置低了。但初始化时PA.8已被置高,而且EXTI1的ISR里才有将PA.8置低的指令!)。不应该是这样啊:虽然EXTI1的优先级高于EXTI2,但二者的抢占优先级相同,因此并不会发生中断嵌套,而且在EXTI2的ISR里已将EXTI1的触发请求标志和中断悬起标志均清除了。原因何在?" N  _6 E- @) a7 k) J5 z

( }- V% C) K0 \. m! B贴主找啊找,调啊调………………好吧,既然软件仿真解决不了,咋就来瞎搞硬件仿真。
4 X% @: V/ T) b6 L. b
) \" t, K; e+ w6 l; |% z连接好JLink与板子后,在MDK里点击单步调试“Step one line(F11)”,执行触发EXTI2中断的指令“EXTI->SWIER = EXTI_Line2;”后却不进入EXTI2的ISR,而且无论点击多少次单步调试,程序一直停在while里………………问题真是接踵而至啊
………………
( c/ s+ |! U9 u7 X# f3 j/ y" ?
2 G# d+ P: s, `! H, {9 u
初入ARM,练习背黑锅。( R7 d, a1 r- C3 o: n8 F
4 c4 k/ S% Z4 L# ^
这时贴主想起了前不久的一次调试经历:单步不行,就全速(贴主本坛第一帖),于是点击全速运行
“Start code execution(F5)”试了下。哈哈,LED亮了!当然,之前的问题并没有得到解决,但是后来的在线调试问题却有了头绪 —— 通过在ISR里设置断点,只要对应的中断被触发且被使能,点击全速运行就可以进入ISR。有了这样一个认知后,贴主又开始瞎搞起来了:软件触发EXTI2后,是何时进入其ISR的?
: E. I% x6 H7 R1 @
/ E; I: O  X! _" S为此,贴主就在主函数添加了三条将变量flag的值赋给其本身的赋值语句:) t' m. D9 F% P1 F# [$ Y7 q& p& h& }
  1. int main(void)
    2 Q3 d# _* h! @. u4 J0 R
  2. {
    & H& d! N9 f. X# d) i8 c6 B; U
  3.         RCC_Configuration();$ O$ L0 y# ?- C3 i
  4.         GPIO_Configuration();/ m( X. M. V" A- I) i3 y
  5.         PAout(11) = led;                                                        //上电关闭LED
    . o% r" T4 O$ |0 w
  6.         0 [9 n. E8 S, K7 M: [9 X2 ~$ e
  7.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;1 a" k  c* \+ B6 k
  8.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
      I- s2 F. {& W  v4 d
  9.        
    7 C  K6 G" V+ ?# M1 Q9 K( `4 J
  10.         EXTI->SWIER = EXTI_Line2;
    ' M" V, s$ x/ v4 K, e- k# X3 A# Z4 `
  11.         # Q5 r& _8 a  s5 ^! ~8 i
  12.         flag = flag;
    $ j8 O& A' d3 X3 \
  13.         flag = flag;
    - ~5 H0 c! n% A+ K" P) X. p
  14.         flag = flag;$ e3 o/ o. E+ j+ [0 K" I" a
  15.        
    + |, ?9 ^: {1 Z9 S
  16.         while(1)
    ' O' n1 O1 t( e4 `6 l% ~
  17.         {
    " f7 R) I( P4 L# M
  18.                 PAout(11) = led;
    / |  J5 M5 r; L1 B4 Q6 e, p8 ]
  19.         }* L$ w; D! t& e/ ]
  20.        
    - y- t) M' m+ \; N" F# v# z
  21. //        return (0);# |* I6 v8 g' J* F4 ?: S. m
  22. }
复制代码
在线调试时在该三条语句均设置了断点,第一次全速运停在了第一条赋值语句处,再次全速运行时,程序进入到了EXTI2的ISR。如此说明软件触发一个中断,处理器并不会立即响应,这期间存在一个响应时间。学过8051单片机的童鞋应该知道,8051单片机的中断有一个响应过程:采样→查询→处理(各占1个机器周期)。Cortex-M3内核同样也存在,它将“中断延迟”定义为:从检测到某中断请求,到执行了其服务例程的第一条指令时,已经流逝了的时间。在CM3中,若存储器系统够快,且总线系统允许入栈与取指同时进行,同时该中断可以立即响应,则中断延迟是雷打不动的12周期(满足硬实时所要求的确定性)。在与时间赛跑的这12个周期里,处理器内部一直开足马力,进行了入栈、取向量、更新寄存器以及服务例程取指的一系列操作。但若存储器太慢以至于引入等待周期,或者还有其它因素,则会引入额外的延时。' R5 T4 R$ `3 [$ k8 c7 b  c1 z

2 o3 D, a; q0 m. _本帖谈论到这,再来谈在线调试为何进不去ISR,以及最开始的工程为何实现不了预期的目标,原因已很明了。
$ S8 t" _9 T; H! P# {4 j7 _

. \  z7 U/ a+ X3 s% I: }7 F% G/ k在线调试为何进不去ISR:
中断延迟的存在,以及中断响应机制。
9 x2 T  m( U: ?5 F* J4 ~4 X0 m7 R9 g' e
对于最开始的工程为何实现不了预期的目标:6 t0 r: i2 g; N  p% w
在EXTI2的ISR里,软件是这样设置的:
& ~& p% Y6 D/ E
  1. /**$ C, H9 c; z8 [/ _9 z, W# N/ {
  2.   * @brief  This function handles External lines 2 interrupt request.
    " p6 _: O- I$ X, b) {
  3.   * @param  None2 m% v; B$ F# D5 ^1 A
  4.   * @retval None! S! ]7 i% S- h1 @0 `
  5.   */
    / v' x% i/ z# Q% c1 I' k+ Y& s5 I
  6. void EXTI2_IRQHandler(void)
    ( S4 E& E* o  V5 ]% t3 H0 Z, o% B0 L
  7. {; N" ^  J3 q; W4 M7 D' g
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    - X! \$ r" H' C6 p
  9.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求
    9 I- l* B8 U' u9 s
  10.         4 U1 [  }: B2 |- O0 D* B
  11.         EXTI->PR = EXTI_Line1;                                //清除触发请求6 M8 H8 w! z5 C0 L& _
  12.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
    6 x2 W. q! Y) y/ J1 b7 |
  13. }
复制代码
也就是语句“EXTI->SWIER = EXTI_Line1;”触发EXTI1的中断请求,紧跟着就有清除EXTI1触发中断请求的指令“EXTI->PR = EXTI_Line1;”,显然由于CM3中断响应机制的约束,后面清除EXTI1触发中断请求的指令“EXTI->PR = EXTI_Line1;”实际无效。比如贴主在EXTI2的ISR里的第一条语句和最后一条语句各设置了一个断点,点击全速运行到最后一条指令,实际并没有清除EXTI_PR寄存器中EXTI1的挂起位(但若是在EXTI2的ISR里点击单步调试,就会清除该位,后面全速运行也不会进入EXTI1的ISR。原因前面已说明)。如下图所示:
- K& {( ?% f4 i" N. m8 ^# ^; S

图1

图1
. R7 N9 V  C/ N/ m5 s6 s
在EXTI1的ISR里的第一条语句也设置一个断点,然后继续全速运行,程序果真进入到了EXTI1的ISR,而且是在执行完EXTI2的ISR后再进入的。如下图所示:
6 D4 u2 }5 e. S5 n" O( m1 X5 a6 n

图2

图2
3 j- h# _, A3 L/ M7 P6 U
这里说明了两个问题:
4 y( W' \4 P2 g- |* u5 J! N/ L
   一是
前面所探讨的关于
CM3中断响应机制;- g+ I# ?7 ^4 N/ s' l8 O5 \
   二是只要
没有清除EXTI_PR寄存器中EXTI1的挂起位,即使有清除EXTI_ICPRx寄存器中断悬起标志的指令,该中断悬起标志仍还是会悬起(前提:不是该ISR对应的中断的中断悬起标志。若是该ISR对应的中断的中断悬起标志,在跳出ISR的同时该悬起标志再次被置位。" {( p& {2 ~" ^! T" `$ ]7 }7 C
   比如:在本例的EXTI2的ISR中,由于指令
“EXTI->PR = EXTI_Line1;”实际无效,所以它下一条清除EXTI1中断悬起标志的语句即使执行了,其对应的中断悬起标志仍是置位状态;而若将EXTI1的ISR里的“EXTI->PR = EXTI_Line1;”注释掉再全速运行,程序会一直停在EXTI1的ISR里。所以有时需要注意二者清除的顺序!)。关于第二点,参考手册里没有指明,但各童鞋需注意!# m& I. r/ {2 k; X

# w" A. m: q# r% r; [2 N/ u& p8 Z9 ~# N% t( @. G
经过以上分析,本帖最开始建立的工程的bug已经很明显:在EXTI2的ISR里的“EXTI->SWIER = EXTI_Line1;”语句后同样增加一条给变量flag赋值的语句:1 [0 u, |6 P; K) Q) |
  1. /**9 e3 U. j5 N; z! }0 e+ `. A5 A
  2.   * @brief  This function handles External lines 2 interrupt request.
    ) z6 g$ d$ W, K& S. j- S
  3.   * @param  None
    * g3 [1 H2 }5 m( C2 e6 L
  4.   * @retval None  B/ Y9 N/ x) \6 `) W
  5.   */* {$ x* I5 i6 ~, `3 t
  6. void EXTI2_IRQHandler(void)
    + S* [0 Y: s7 R: i* e! h
  7. {9 r# x0 {# k$ ~9 \2 l2 |7 A
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    * N8 L9 c0 z% _% E2 P
  9.         EXTI->SWIER = EXTI_Line1;
    5 q1 {+ U2 c+ _9 M: T
  10.         flag = flag;                                                /****** !!!此句必须有!!!否则程序运行有问题 ******/) Z- S: `2 q, e
  11.         /*** 以下是判断EXTI1是否已经发生中断嵌套(两条清除语句缺一不可) ***/3 ]* C; S2 {! s0 ~7 G
  12.         EXTI->PR = EXTI_Line1;                                //清除触发请求【必须先清除触发请求,然后再清除中断悬起标志 —— 软件仿真无区别,但硬件必须如此】! }6 V* w& m( q: M
  13.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
    0 B1 i' l; r! {) z  R
  14. }
复制代码
: \, I, |$ I. }/ z) V8 K' E' }
7 w- L2 ]% `& D! U

8 O7 V1 @* m% S' @" d7 [. A总结下来,其实就是基本知识没掌握,所以每天都是在瞎搞又瞎搞………………
& w, v4 t. y% [! M- z# X1 W, v; B4 |+ I( l% j2 D0 O

5 m4 L4 |1 M! B4 T3 q1 R Cortex-M3中文资料.rar (5.19 MB, 下载次数: 24)

评分

参与人数 1 ST金币 +10 收起 理由
zero99 + 10

查看全部评分

赞 收藏 1 评论4 发布时间:2017-3-7 22:58

举报

4个回答
吐息间丶时光中 回答时间:2017-3-8 09:50:39
关于硬件连接,补充一下:JLink仿真器端口的1、2脚均定义为VCC,但第2脚被标注为可选择。如以下链接所示; S6 A, c+ M. e- {

( P1 ^2 y5 Z' N. {, x- N/ p8 R也就是第1脚必须与板子的VCC相连,至于第2脚呢?% F7 x9 `$ k  W- w
经过帖主测试发现:JLink仿真器端口的第2脚连接的是仿真器内AMS1117稳压芯片的输出脚(或许有些JLink没有集成3.3V稳压输出),所以是可以给目标板子提供电源的。若板子没有独立供电,那么必须将JLink仿真器端口的第2脚与目标板的VCC相连。: ?: q( M6 m6 t
注意:无论目标板是否独立供电,如若不连接JLink仿真器端口的第1脚与目标板的VCC,下载程序时会依次弹出内容为“No Cortex-M Device found in JTAG chain. Please check the JTAG cable and the connected devices.”和“Error: Flash Download failed - Target DLL has been cancelled”的窗口提示! 前一个翻译出来也就是提示连接有问题。2 ?9 ~6 z- M1 B% V9 V. b
(回复不能从本地上传图片,没图片显示形象,各位大虾将就下)
moyanming2013 回答时间:2017-3-8 13:28:19
吐息间丶时光中 发表于 2017-3-8 09:50
0 a1 t3 b( S/ z2 l, }+ |关于硬件连接,补充一下:JLink仿真器端口的1、2脚均定义为VCC,但第2脚被标注为可选择。如以下链接所示
- K3 N8 S4 H# q$ T' J( O
( P3 F$ [  U* ~# a' H ...
6 ^  D+ e: W0 R1 f, a" `
回复时选择“高级模式”就可以添加图片了。! b( ?7 x; ]+ S2 s( {
也可以使用ST-LINK/V2-1调试器。
吐息间丶时光中 回答时间:2017-3-9 11:53:52
moyanming2013 发表于 2017-3-8 13:28
, D! ?$ g# S& X$ q) D2 }回复时选择“高级模式”就可以添加图片了。
- p7 z/ d/ X. ?5 s5 D. y9 c也可以使用ST-LINK/V2-1调试器。 ...
7 s1 @0 F( r* J: H* e
哈哈,多谢大神提示,看到喃。(今后可以愉快的斗图了)" p5 B) u8 N1 u: V7 s
目前身边只有JLink仿真器,其它仿真器今后应该用得到。
, u) M6 T* b; g7 f- x
7 {3 x% K3 W% k4 N, u+ g借此将图片上传:; F% h1 Z4 M" @2 f/ F8 X# t
1.PNG
/ I$ X+ E3 ~9 N2 M2 f$ f, J一般用FC头2*10P线连接,不会出现这种情况(前提是目标板本身已将对应的JLink输入引脚的第1脚连到VCC上。比如帖主的板子就是的,下图),容易出现这种情况是在用杜邦线去连接,又是1用JLink仿真器给目标板供电,就很容易少连这一根线。
8 v! F6 z2 n2 q, N" y9 Q 2.PNG 0 i( _% y& F1 o8 i

' E. F5 O; X7 v7 l
吐息间丶时光中 回答时间:2017-3-11 13:32:30
纠正一个文中的描述错误:测试用的LED连接的是GPIOA端口的11脚,文中被错误的描述为第8脚(程序中是PA.11)。1 X3 a0 \1 k! V0 o' }& E' K% c
--------------------------------------------------------------
2 C& f3 I: |) J- ^' {7 p! x感谢@zero99 的支持。+ ]0 I+ k0 p! Z  C. x" [
--------------------------------------------------------------
5 q5 I$ p8 l4 c: Q

$ t- Y* u# n+ h& u
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版