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

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

[复制链接]
吐息间丶时光中 发布时间:2017-3-7 22:58
前段时间贴主看了Cortex-M3的NVIC,对其中断嵌套甚是着迷,于是瞎搞了几下下……瞎搞就瞎搞嘛,但却搞出了问题……
+ P$ ~% Y: v. t7 Z5 n
4 G9 F: m, D" f+ L2 B8 b: `* P废话不多说,直奔主题!
/ ?; b6 W3 L/ x: }! G
! E/ h4 t- d$ ?, {8 D; [通过查看
Cortex-M3有关异常和NVIC章节的资料,贴主本来是想实现这么几个工程目标:
4 W- @4 u- j4 N& y% P6 r(贴主板子上的芯片型号是STM32F103C8T6,PA.8接的一个LED的阴极;MDK版本5.17&5.23)

( r7 `$ l+ `/ J5 q0 n4 u================================================================/ Q& s# F. }# e, s4 ?; I
【1】不操作优先级寄存器,软件触发EXTI2中断进入其ISR里,再软件触发EXTI1。判断是否会发生中断嵌套?
! u% r& o4 e/ }1 b& v% G  
工程预估:不会。" v% E9 S! h+ @1 j) S
         why:①当不操作优先级寄存器时,Cortex-M3内核默认从比特0分组(因为SCB_AIRCR寄存器的优先级分组三位复位值为0),即优先级寄存器高四位均表示抢占优先级;" I- _- l$ o. k0 _9 {  I
                  ②优先级寄存器NVIC_IPRx高四位复位值为0,由于没重新赋值,所以抢占优先级均为0;【也就类似于除能了CM3的中断嵌套机制。】7 Z& J' Q. t/ l0 Q" \/ |
                  ③优先级寄存器高四位均表示抢占优先级且为0,亚优先级均为0。所以优先级取默认的硬件异常号,虽然EXTI1的默认异常号高于EXTI2,但不会发生中断嵌套。9 s  g, M( S5 x6 x
-------------------------------------------------------------------------------------------------------------------------------0 ?8 N4 X! t  Z1 N
【2】优先级寄存器的高三位表示抢占优先级,且EXTI1和EXTI2抢占优先级相同,但EXTI2的亚优先级高于EXTI1。软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?" j1 O: K+ C0 @6 j8 ~2 |" r
  工程预估:不会。

; e  u# `3 o4 E6 H' u  ^" N, G* u         why:
二者抢占优先级相同,亚优先级的高低不导致中断嵌套。只是当抢占优先级相同的异常有不止一个同时悬起时,就优先响应亚优先级最高的异常。
/ a7 `+ w& |' b; ^( P-------------------------------------------------------------------------------------------------------------------------------) b. N" L  V. M, E8 t* U) d* M0 O+ Z
【3】优先级寄存器的高二位表示抢占优先级,且EXTI2抢占优先级高于EXTI1,但EXTI2的亚优先级低于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?
1 j, L: B, k) D# w# M% }- m2 L  工程预估:会。

& q, c0 G, P) s. v5 A; T         why:
EXTI2抢占优先级高于EXTI1,亚优先级的高低不导致中断嵌套。

7 c: V$ \+ |9 \+ Z-------------------------------------------------------------------------------------------------------------------------------
/ M" ^; ?3 m+ D/ w
【4】无抢占优先级,优先级寄存器的高四位均表示亚优先级,但EXTI2的亚优先级高于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?
( z: e* e, u. C) j1 Z  工程预估:不会。
) h: p) _# K2 ]) _
         why:
无抢占优先级【相当于除能了CM3中断嵌套机制】,亚优先级的高低不导致中断嵌套。

; V) Y7 U# v2 `================================================================- G/ D3 T9 w$ t) u- I
很明显,每一个程序均非常简单。但将程序下载到硬件上跑的效果会不会如预估一样呢?0 ]0 W+ T1 f& x' K( v7 K9 |
2 w7 E+ c1 d# U& a, Z
第一个工程的代码如下:
3 O- S, H# h7 f2 o8 ]
“main.c”源文件里
9 b$ q% q; S6 X4 b% b! J
  1. #include "stm32f10x.h"+ o  h6 l1 J4 r, m5 p- [9 n

  2. / L: o, \/ e9 ?$ ^4 W* V
  3. #define GPIOA_ODR_Addr        (GPIOA_BASE+0x0C)                //GPIOA端口寄存器ODR的地址5 G3 C0 {+ D# x: o$ j5 }4 Y) Q

  4.   T0 _9 |9 q8 r, J' G* t. `4 A1 C( e
  5. #define BitBand(Addr, BitNum)        *(__IO uint32_t *)((Addr&0xF0000000)+0x02000000+ \
    ! `  ~8 n# w" W) Z( L
  6.                                                                                                         ((Addr&0x000FFFFF)<<5)+(BitNum<<2))       
    & m/ |6 f: b  W8 W
  7. #define PAout(n)        BitBand(GPIOA_ODR_Addr, n)        //偏移地址取的是32位寄存器的第一字节的,所以n的取值为0~318 r1 F+ e$ c: _1 e8 _
  8. 9 ^+ x( w0 \4 p
  9. FlagStatus led = SET;                                                        //外部调用的全局变量(声明在stm32f10x_it.h头文件)
    ! n( u" w7 {3 a+ }3 P; @0 b

  10. ( y. C# a- p$ }: n4 A
  11. static void RCC_Configuration(void);                        //函数原型声明. k" m3 ?* q7 a$ P1 C$ ?1 y
  12. static void GPIO_Configuration(void);2 {/ t2 I1 g% `

  13. * v% K2 P& w4 q- J
  14. /**********************************************************************
    8 }" K7 Y& ^; z  u7 n
  15. * Function Name : MAIN
    + O8 Q) o& s1 r) P1 M; s
  16. * Description         : main program) U, w" P& z; [8 d
  17. * Input                 : None
    6 L8 n) n- ~5 T" X: ^  h5 G/ k
  18. * Output                 : None
    : E$ w) e8 E1 L! O$ S
  19. * Return                 : None
    ; s3 y1 T: L$ ~. [$ u1 X
  20. **********************************************************************/+ [+ y" k6 R& X1 i% l
  21. int main(void)' u7 a- S1 P7 K/ h# m; P
  22. {4 \6 M: n& V; b  I6 J! T( w
  23.         RCC_Configuration();- `$ Q/ v! y* @% D: Y& T0 F0 @  O! X
  24.         GPIO_Configuration();
    ; ?. J  ?2 Z4 N" e' m
  25.         PAout(11) = led;                                                        //上电关闭LED
    0 |; f  l$ C% i. T; K2 t2 p
  26.        
    8 ]; K& Y1 p& q( P
  27.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;
    " P- U6 h4 z9 l
  28.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;2 D. X1 u' S( H( [7 U3 V) s( o
  29.         1 Z- u2 W9 |  R1 w
  30.         EXTI->SWIER = EXTI_Line2;
    + M9 Z8 R( W5 G) W
  31.        
    3 @6 G# i2 M& Q$ J' c- b0 e0 J
  32.         while(1)
    ) `) j1 `$ }! K$ c4 j: b
  33.         {
    . `' H9 j3 R! k- a- C2 L8 j; c4 N
  34.                 PAout(11) = led;, Q0 S2 y+ a6 o, H! P
  35.         }2 v! P' A. C1 m6 ?6 Z
  36.        
    - T5 f$ R  N4 i/ ]
  37. //        return (0);8 f# |4 b& z! p3 Q0 F* Y
  38. }. K/ p( n+ N6 T1 e& l, f

  39. , x$ |# P1 y1 n5 k$ W7 P+ Z
  40. /**********************************************************************5 S: |# z# r; c! W5 n, l8 D1 t
  41. * Function Name : RCC_Configuration
    & W( `6 J8 f; M6 z5 o0 a. J
  42. * Description         : 配置时钟参数,使能外设时钟5 T: v- F& N9 @8 s
  43. * Input                 : None1 @0 Y6 k  q: `/ @4 s  ~; S4 F
  44. * Output                 : None* g$ h( {2 u4 ]& h7 r! {
  45. * Return                 : None
    $ B4 b$ i' P5 ~. u5 ^
  46. **********************************************************************/$ U( U+ R% @4 ^( K1 t- n; G
  47. static void RCC_Configuration(void)
    1 r4 n) _/ k4 G& C& L' d' ?2 u
  48. {        * z8 d% F7 Q' W" q% [
  49.         RCC_DeInit();                                        //将外设RCC寄存器重设为缺省值(选择HSI作为系统时钟,其它保持复位值)' N% G" N. l( b8 S. X% Q* A
  50.         RCC_HSEConfig(RCC_HSE_ON);                //HSE晶振ON" q/ ~7 p8 }  o5 X/ y4 Z# Y
  51.         if(RCC_WaitForHSEStartUp() == SUCCESS)        //等待HSE晶振稳定, u7 k5 n' w' _+ K$ {" n0 x7 N1 m
  52.         {. F* x1 {: _1 W+ b9 f( k
  53.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);        //设置AHB时钟(HCLK)—— HCLK = SYSCLK/1
    ) ~6 y' h' p$ G$ y' P. n1 E
  54.                 RCC_PCLK2Config(RCC_HCLK_Div1);                //设置高速AHB时钟(PCLK2)—— PCLK2 = HCLK/1
    0 |+ K# ?; z1 g" w6 E2 I
  55.                 RCC_PCLK1Config(RCC_HCLK_Div2);                //设置低速AHB时钟(PCLK1)—— PCLK1 = HCLK/2. M  x4 Z' i0 M" k" k4 p% f
  56.                 FLASH_SetLatency(FLASH_Latency_2);        //在SYSCLK周期与闪存访问时间插入2个等待周期
    0 Y, j2 `3 Y& v% S2 L$ `4 F7 Z: h- k
  57.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //启用闪存预取缓冲区# T% o8 L- @7 a! t- A
  58.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);        //设置PLL时钟源及倍频系数 —— PLLCLK = (HSECLK/1) * 9 = 72MHz
    3 A+ \  n. N$ k! C6 d8 e+ u/ S
  59.                 RCC_PLLCmd(ENABLE);                                        //使能PLL9 ^3 M. J5 P( ^4 |( Q) x
  60.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);                //等待PLL就绪
    4 l" j1 I3 Z- n
  61.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                //设置系统时钟(SYSCLK)—— 选择PLL作为系统时钟; n; [/ U* z" T# s- i
  62.                 while(RCC_GetSYSCLKSource() != 0x08);                                        //返回用作系统时钟的时钟源 —— 0x08:PLL作为系统时钟: w5 {/ S" l4 Y1 s- @9 h  _
  63.         }# y' B/ r4 N. F- R' y6 h: i
  64.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);! E$ y$ o, \+ V0 V* D
  65. }
    # H0 p8 ?2 P) @" ?7 s

  66. 0 W  T; ?' {$ M/ y9 r$ O
  67. /**********************************************************************" {4 ~7 b: s& x. a5 \3 v; c
  68. * Function Name : GPIO_Configuration
    . h! V/ y) S5 p' H
  69. * Description         : 配置GPIO参数
    6 \- e5 }; F2 p; {0 N5 x6 }
  70. * Input                 : None7 X) y$ c/ a5 B) l. @
  71. * Output                 : None
    4 o( P3 `" x3 A4 R# c0 A- t' n( W9 F
  72. * Return                 : None$ z7 E' K9 @, w! E( c& M
  73. **********************************************************************/
    ) m% [% ?  c  w! d3 }; M
  74. static void GPIO_Configuration(void)$ r$ a% P, C& h1 e- f
  75. {/ R6 U8 A9 X/ g1 Q
  76.         GPIO_InitTypeDef GPIO_InitStructure;' t# E3 }' E' a# b2 S! K- }/ S
  77.         6 r$ X9 |& b) p$ ]
  78.         /* 将GPIOA.11引脚设置为通用推挽输出模式,最大速度50MHz */8 ?1 G2 Q/ p. g& ]0 G- V: P/ ]4 k5 v
  79.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;  U6 P6 r! A, j* w. w5 Q; |9 A
  80.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //GPIOA.9已配置) V  D: t3 c6 W8 c
  81.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;+ @6 O9 _! }! N- w9 H4 o( s4 {3 e
  82.         GPIO_Init(GPIOA, &GPIO_InitStructure);
    ' i0 g( D7 f4 t" V8 z, q" o
  83.        
    4 F( e& h# z& ~! |; H6 p
  84.         /* 将GPIOA.1和GPIOA.2引脚设置为浮空输入模式 */* |8 e6 Z: M. B2 p
  85. //        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;: p3 ]  O! l  _1 J
  86. //        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    2 h6 Y  y; g5 `  m" S
  87. //        GPIO_Init(GPIOA, &GPIO_InitStructure);
    4 x2 v0 W! X4 M7 `) Z. ?
  88.        
    ( ~; B8 P$ r: S$ a: v  h7 L
  89.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);) [* \4 \0 @: _) v
  90.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);
    ( A, P% f" m6 K7 H
  91. }
复制代码
“stm32f10x_it.c”源文件里:: a, @& q: S# m" c/ _
  1. /**7 u/ ^) @6 P) g" P
  2.   * @brief  This function handles External lines 1 interrupt request.
    8 S; e/ v6 ~: _( n+ c
  3.   * @param  None& {! }9 q! D( w7 E' l6 d% A7 y
  4.   * @retval None
    ; N5 B$ p) p" k
  5.   */) c, D; w& J) S6 R0 H& }% ?1 k
  6. void EXTI1_IRQHandler(void)
    % n; ?( H1 w# a- [& Y+ X3 C
  7. {
    2 U) X+ P% i$ d' V- ]1 s/ Y4 D$ T
  8.         EXTI->PR = EXTI_Line1;
    3 l* q9 W2 y3 h
  9.         led = RESET;: g! C! i. h7 Z# {7 {1 y
  10. }
    ! Y! d5 P4 ^. E( l8 L$ U
  11. 4 r8 k, Y2 }7 n
  12. /**. E/ b* F2 A; O
  13.   * @brief  This function handles External lines 2 interrupt request.2 S9 m+ Q, x; H! \3 A8 `  x' Z2 Y4 x  x* ?
  14.   * @param  None* {4 ~0 i1 y8 v# J3 H8 ~3 ^0 d
  15.   * @retval None% `) J' B8 C0 R
  16.   */3 C. C5 j$ ]: N# {+ c- @6 v$ p' c
  17. void EXTI2_IRQHandler(void)
    / }: ~# K1 i" Y
  18. {# _+ ?- ?/ v4 c; k1 ^& V0 Y2 u
  19.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    ! D9 c8 {, N3 g0 V
  20.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求7 Y) }0 u( ?. \- F. B0 R8 f
  21.        
    ( s2 k! l' r0 H7 L
  22.         EXTI->PR = EXTI_Line1;                                //清除触发请求  {, ]- Q3 u7 ?
  23.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】7 m& T1 T8 B. [1 i
  24. }
复制代码
“stm32f10x_it.h”源文件里:' }$ h% O) n; C& k- e8 V
  1. /****** 用户自定义 ******/. K6 ~, a: X0 R/ h( z
  2. extern FlagStatus led;                //声明一个外部调用的全局变量(控制LED亮灭的变量)
复制代码
显然代码很简单,软件仿真时各寄存器也是按照程序的意思显示各项数据指标。但是………………很残酷………………实际与理论发生了偏差 —— 将程序烧进硬件跑,LED亮了(即PA.8被置低了。但初始化时PA.8已被置高,而且EXTI1的ISR里才有将PA.8置低的指令!)。不应该是这样啊:虽然EXTI1的优先级高于EXTI2,但二者的抢占优先级相同,因此并不会发生中断嵌套,而且在EXTI2的ISR里已将EXTI1的触发请求标志和中断悬起标志均清除了。原因何在?
7 S: _/ \7 Q5 P
+ [$ _; ?% _7 E# P) N贴主找啊找,调啊调………………好吧,既然软件仿真解决不了,咋就来瞎搞硬件仿真。# I/ U& b, v1 l" V! J
5 z  s2 t1 ^6 f; C6 h! L8 u+ K
连接好JLink与板子后,在MDK里点击单步调试“Step one line(F11)”,执行触发EXTI2中断的指令“EXTI->SWIER = EXTI_Line2;”后却不进入EXTI2的ISR,而且无论点击多少次单步调试,程序一直停在while里………………问题真是接踵而至啊
………………# E' \' Q8 d  w+ D* j: u; ~9 i0 r

6 d- |' ~( h6 V4 \) U  v. ]' B初入ARM,练习背黑锅。! b0 E5 j/ ?$ u" v2 z8 Z

. {1 m( r! t7 Y+ m, T这时贴主想起了前不久的一次调试经历:单步不行,就全速(贴主本坛第一帖),于是点击全速运行
“Start code execution(F5)”试了下。哈哈,LED亮了!当然,之前的问题并没有得到解决,但是后来的在线调试问题却有了头绪 —— 通过在ISR里设置断点,只要对应的中断被触发且被使能,点击全速运行就可以进入ISR。有了这样一个认知后,贴主又开始瞎搞起来了:软件触发EXTI2后,是何时进入其ISR的?2 t* x2 ~% x) P6 ]

: i. e- Y) j3 }$ A3 h" K+ b为此,贴主就在主函数添加了三条将变量flag的值赋给其本身的赋值语句:
8 k4 g& g, ?" X2 _& }7 I8 v9 |
  1. int main(void)
    ! j2 w# U' ?: g
  2. {2 a: Z6 ^0 Z+ u! t/ D/ P* v2 O
  3.         RCC_Configuration();
    0 i5 b# M$ u+ c- G) I9 E8 P
  4.         GPIO_Configuration();' r. m/ T5 R% E' ^$ k
  5.         PAout(11) = led;                                                        //上电关闭LED% y  ~& j4 X8 W+ v
  6.        
    ) U7 f- K- W8 u
  7.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;6 D! A2 A( j- s6 B, d
  8.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;! ?) \- k: ]3 f% p, s: ~3 `. ~
  9.        
    . r) O. Y& [$ O
  10.         EXTI->SWIER = EXTI_Line2;: i9 T9 P, I' \7 R: G2 O
  11.         ; z1 x% n8 x6 f. Z. L5 z
  12.         flag = flag;: C7 W9 X7 A* {+ ?/ }9 a
  13.         flag = flag;
    & \' i9 @$ ]! y  _
  14.         flag = flag;
    ; s8 ~2 y% s( D- z  `3 Y) r
  15.        
    - e5 O6 k- M3 j3 G7 j
  16.         while(1)
    ( B9 I4 a8 c# G4 ~8 Y6 Q2 B
  17.         {" L  u- ~# O2 r/ K2 M2 }- v8 ~
  18.                 PAout(11) = led;) p$ h) K1 b3 V1 w  \: y
  19.         }
    & |. l, m) U/ B( e+ W
  20.        
    : m4 e  \* ~) s  U* j8 W0 S! \
  21. //        return (0);
    : W4 H  b7 Y1 J6 g$ m; g' x
  22. }
复制代码
在线调试时在该三条语句均设置了断点,第一次全速运停在了第一条赋值语句处,再次全速运行时,程序进入到了EXTI2的ISR。如此说明软件触发一个中断,处理器并不会立即响应,这期间存在一个响应时间。学过8051单片机的童鞋应该知道,8051单片机的中断有一个响应过程:采样→查询→处理(各占1个机器周期)。Cortex-M3内核同样也存在,它将“中断延迟”定义为:从检测到某中断请求,到执行了其服务例程的第一条指令时,已经流逝了的时间。在CM3中,若存储器系统够快,且总线系统允许入栈与取指同时进行,同时该中断可以立即响应,则中断延迟是雷打不动的12周期(满足硬实时所要求的确定性)。在与时间赛跑的这12个周期里,处理器内部一直开足马力,进行了入栈、取向量、更新寄存器以及服务例程取指的一系列操作。但若存储器太慢以至于引入等待周期,或者还有其它因素,则会引入额外的延时。( l: b: X/ t: O$ U8 E
3 R2 q% o* a7 N. m$ I+ U
本帖谈论到这,再来谈在线调试为何进不去ISR,以及最开始的工程为何实现不了预期的目标,原因已很明了。, w2 b1 _0 L: F) V- u/ l2 v

5 _3 q/ w7 R0 g& h1 s* D) G在线调试为何进不去ISR:
中断延迟的存在,以及中断响应机制。: |! b3 @! ?6 r8 D  S0 P
0 F- v4 ^4 S* l
对于最开始的工程为何实现不了预期的目标:1 Q- S" x" k  y( x8 S0 g1 R
在EXTI2的ISR里,软件是这样设置的:% k% c2 s7 [7 v3 h' S- X
  1. /**
    : @. Q8 O. P% ]& P$ c* P
  2.   * @brief  This function handles External lines 2 interrupt request.6 a) ~8 ?  u/ t0 _" Q7 O
  3.   * @param  None2 K7 [/ c( _2 Y# D
  4.   * @retval None
    ' B: [2 g3 k2 y5 }, S8 M1 `
  5.   */( B: I8 \* y3 y0 C
  6. void EXTI2_IRQHandler(void)1 W5 H) ~$ m/ ]% W2 g1 n
  7. {
    # O* Q9 k" D; Z. A7 \
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位2 M+ I) ]. k$ C( x/ \# A
  9.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求: E) i* a( P% D
  10.         - q( K2 z( Y5 P5 i0 N$ I9 m  i% R
  11.         EXTI->PR = EXTI_Line1;                                //清除触发请求( G3 l! m: F- t9 u. m! W
  12.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】% H& r! i+ z$ ?7 b
  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。原因前面已说明)。如下图所示:
  `- O$ M  [4 Z' w; W4 a% B

图1

图1

! u6 G! S2 ]4 e. v9 R  W1 b3 z5 B$ Q在EXTI1的ISR里的第一条语句也设置一个断点,然后继续全速运行,程序果真进入到了EXTI1的ISR,而且是在执行完EXTI2的ISR后再进入的。如下图所示:/ V1 l2 E  y- t3 t0 Q% l. r2 \

图2

图2

0 W: `& ~0 ?5 r: r- r+ ?这里说明了两个问题:$ o6 }9 R0 t. }/ w; c
   一是
前面所探讨的关于
CM3中断响应机制;
/ l+ L  E, o+ g1 N, X   二是只要
没有清除EXTI_PR寄存器中EXTI1的挂起位,即使有清除EXTI_ICPRx寄存器中断悬起标志的指令,该中断悬起标志仍还是会悬起(前提:不是该ISR对应的中断的中断悬起标志。若是该ISR对应的中断的中断悬起标志,在跳出ISR的同时该悬起标志再次被置位。
8 t4 W6 r1 `+ n/ Q   比如:在本例的EXTI2的ISR中,由于指令
“EXTI->PR = EXTI_Line1;”实际无效,所以它下一条清除EXTI1中断悬起标志的语句即使执行了,其对应的中断悬起标志仍是置位状态;而若将EXTI1的ISR里的“EXTI->PR = EXTI_Line1;”注释掉再全速运行,程序会一直停在EXTI1的ISR里。所以有时需要注意二者清除的顺序!)。关于第二点,参考手册里没有指明,但各童鞋需注意!' `) P+ _+ B$ i' U, l( y1 L

1 y; T2 e3 C* A+ X' x; c3 u# N
3 ~- z( g1 b( B6 N2 |经过以上分析,本帖最开始建立的工程的bug已经很明显:在EXTI2的ISR里的“EXTI->SWIER = EXTI_Line1;”语句后同样增加一条给变量flag赋值的语句:$ _/ n. `6 D6 k, u* {
  1. /**% W" V6 ]# E2 @3 ?& s/ i0 \
  2.   * @brief  This function handles External lines 2 interrupt request.
    4 n- I! d* i' f' h
  3.   * @param  None
    ' u0 P; Z: A$ W) M4 U
  4.   * @retval None
    1 l9 _, \" F& S' X  B: |
  5.   */" {/ ]8 N4 D! s- C" k
  6. void EXTI2_IRQHandler(void)
    ( u( _2 ?0 ]3 K' y8 u! K$ c" m
  7. {
    4 x* D% L5 E, i$ x) x  v; ^! |
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位! o* j7 c( D9 Z' J# q6 {' V! \/ w
  9.         EXTI->SWIER = EXTI_Line1;
    7 _8 x( D6 Q5 J. F* s$ w0 z+ G
  10.         flag = flag;                                                /****** !!!此句必须有!!!否则程序运行有问题 ******/  P: O! t5 O' |+ x+ S
  11.         /*** 以下是判断EXTI1是否已经发生中断嵌套(两条清除语句缺一不可) ***/
    + }+ p8 L# m/ j2 d8 X; w4 t
  12.         EXTI->PR = EXTI_Line1;                                //清除触发请求【必须先清除触发请求,然后再清除中断悬起标志 —— 软件仿真无区别,但硬件必须如此】/ U& C9 X* W  c
  13.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】& _9 p9 U" X9 E; y
  14. }
复制代码
0 `8 J8 [0 O' D6 p( G  q" l8 {7 f

- G6 L1 a! e, F/ _7 P2 [6 W' H/ U9 |' C
总结下来,其实就是基本知识没掌握,所以每天都是在瞎搞又瞎搞………………
/ E+ s! K  F( Z2 T
& t- h* V% {. x9 y
/ P- g0 z) m) s: I+ E: \ 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脚被标注为可选择。如以下链接所示9 ?, L& \% ?: D; A% n( M
5 m( O4 I& t- ~$ A3 M% K7 {
也就是第1脚必须与板子的VCC相连,至于第2脚呢?
- o% K1 O: M. U2 h) c+ I经过帖主测试发现:JLink仿真器端口的第2脚连接的是仿真器内AMS1117稳压芯片的输出脚(或许有些JLink没有集成3.3V稳压输出),所以是可以给目标板子提供电源的。若板子没有独立供电,那么必须将JLink仿真器端口的第2脚与目标板的VCC相连。& w" o- |. I/ E  h3 _" x
注意:无论目标板是否独立供电,如若不连接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”的窗口提示! 前一个翻译出来也就是提示连接有问题。( {/ t7 g& c( r$ Q1 w/ a5 o" e8 c
(回复不能从本地上传图片,没图片显示形象,各位大虾将就下)
moyanming2013 回答时间:2017-3-8 13:28:19
吐息间丶时光中 发表于 2017-3-8 09:504 k. t) m  V1 |! \! F, s
关于硬件连接,补充一下:JLink仿真器端口的1、2脚均定义为VCC,但第2脚被标注为可选择。如以下链接所示
( v9 c, |8 C' F/ {5 R7 z1 g6 ]  n/ s3 v1 r1 z
...
2 k, Q5 t/ T4 H- s0 a& _0 {
回复时选择“高级模式”就可以添加图片了。
3 l! P$ O3 @" a5 t也可以使用ST-LINK/V2-1调试器。
吐息间丶时光中 回答时间:2017-3-9 11:53:52
moyanming2013 发表于 2017-3-8 13:283 D, g' j5 O$ n/ c) O
回复时选择“高级模式”就可以添加图片了。, J, F1 p- Q+ B5 P' T# U( B
也可以使用ST-LINK/V2-1调试器。 ...

/ M' h5 g3 u1 n- z4 e  k哈哈,多谢大神提示,看到喃。(今后可以愉快的斗图了)
  ~, w6 U* M& T3 d, \9 e目前身边只有JLink仿真器,其它仿真器今后应该用得到。; S! p( D/ A( D0 n+ f
1 o, z* C3 M+ W
借此将图片上传:
6 J4 P  v: a& m2 a( J 1.PNG
2 H- l1 e+ @% C6 i一般用FC头2*10P线连接,不会出现这种情况(前提是目标板本身已将对应的JLink输入引脚的第1脚连到VCC上。比如帖主的板子就是的,下图),容易出现这种情况是在用杜邦线去连接,又是1用JLink仿真器给目标板供电,就很容易少连这一根线。
" i* z7 e! I4 }; P( B1 K1 \" W 2.PNG
! |( T% [3 `2 F3 D- r1 t. M

3 o: W5 y+ Q, p* [2 a# ?% }, o
吐息间丶时光中 回答时间:2017-3-11 13:32:30
纠正一个文中的描述错误:测试用的LED连接的是GPIOA端口的11脚,文中被错误的描述为第8脚(程序中是PA.11)。
+ T; J! L3 o) O5 i% n6 f+ C4 `--------------------------------------------------------------8 P9 @) }5 |6 u% e; x" M/ W" i
感谢@zero99 的支持。
. S2 i6 T3 j- F5 m, r--------------------------------------------------------------
3 [# m2 ~4 G% K% d

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