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

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

[复制链接]
吐息间丶时光中 发布时间:2017-3-7 22:58
前段时间贴主看了Cortex-M3的NVIC,对其中断嵌套甚是着迷,于是瞎搞了几下下……瞎搞就瞎搞嘛,但却搞出了问题……
1 t- D6 U4 T* I2 J3 Y4 Q* m/ A- A7 C9 ?  z* s" V" L) s
废话不多说,直奔主题!
, s* p6 b2 U, c  p+ @. h
2 h: f; [9 k6 z* T& L* V/ _! ?通过查看
Cortex-M3有关异常和NVIC章节的资料,贴主本来是想实现这么几个工程目标:( U) @  ^' x  T8 z
(贴主板子上的芯片型号是STM32F103C8T6,PA.8接的一个LED的阴极;MDK版本5.17&5.23)
+ D, F( ?* H  w
================================================================
0 C) \; M: i- C+ _# P1 }$ y- f. H【1】不操作优先级寄存器,软件触发EXTI2中断进入其ISR里,再软件触发EXTI1。判断是否会发生中断嵌套?
+ K- Z3 H) C8 ~  
工程预估:不会。- L1 J# C: u8 {2 g  X8 M
         why:①当不操作优先级寄存器时,Cortex-M3内核默认从比特0分组(因为SCB_AIRCR寄存器的优先级分组三位复位值为0),即优先级寄存器高四位均表示抢占优先级;
; X- d% a0 @" Q- y
                  ②优先级寄存器NVIC_IPRx高四位复位值为0,由于没重新赋值,所以抢占优先级均为0;【也就类似于除能了CM3的中断嵌套机制。】
) e; ]- y+ S/ a, L) Q
                  ③优先级寄存器高四位均表示抢占优先级且为0,亚优先级均为0。所以优先级取默认的硬件异常号,虽然EXTI1的默认异常号高于EXTI2,但不会发生中断嵌套。
# ^4 E! r6 |0 P& K2 s9 G& k  ]-------------------------------------------------------------------------------------------------------------------------------/ o. {* }& m( R7 I
【2】优先级寄存器的高三位表示抢占优先级,且EXTI1和EXTI2抢占优先级相同,但EXTI2的亚优先级高于EXTI1。软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?
/ K- d8 \* I7 `# E2 s  工程预估:不会。
- L; Z* m$ [5 `% J6 }
         why:
二者抢占优先级相同,亚优先级的高低不导致中断嵌套。只是当抢占优先级相同的异常有不止一个同时悬起时,就优先响应亚优先级最高的异常。
+ a  m' w/ Q  V- d3 c8 k-------------------------------------------------------------------------------------------------------------------------------
! `$ y8 J) q1 N- F& G1 C
【3】优先级寄存器的高二位表示抢占优先级,且EXTI2抢占优先级高于EXTI1,但EXTI2的亚优先级低于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?
+ e5 v7 o: y9 }( S4 g  工程预估:会。

# z0 x" T: c) t- a         why:
EXTI2抢占优先级高于EXTI1,亚优先级的高低不导致中断嵌套。
: S4 ~1 t( X6 y" `1 b% d5 l
-------------------------------------------------------------------------------------------------------------------------------
. h% I8 w' e0 i# U$ h
【4】无抢占优先级,优先级寄存器的高四位均表示亚优先级,但EXTI2的亚优先级高于EXTI1,在软件触发EXTI1中断进入其ISR里,再软件触发EXTI2。判断是否会发生中断嵌套?
4 Y6 n% z( q( v+ |! D* m- G' x  工程预估:不会。

  a( G& e- k# a! ^9 I  i         why:
无抢占优先级【相当于除能了CM3中断嵌套机制】,亚优先级的高低不导致中断嵌套。

0 Z0 |# R( h" \0 H7 n' v& x! @- t================================================================
& A- }. ]3 Z" P7 }很明显,每一个程序均非常简单。但将程序下载到硬件上跑的效果会不会如预估一样呢?
0 M  g' r2 K) a1 `1 X& B0 v4 m' e, ~7 }" x$ }+ r7 a6 i
第一个工程的代码如下:
9 ~/ V' t5 w4 u$ n! e2 S$ K! [+ @
“main.c”源文件里
9 c3 d7 U" m. ^
  1. #include "stm32f10x.h"4 |$ k1 c7 D* O1 J2 r5 `7 U0 `2 K

  2. " L" [2 o  z! D6 W; z
  3. #define GPIOA_ODR_Addr        (GPIOA_BASE+0x0C)                //GPIOA端口寄存器ODR的地址9 e! c% ?; ~1 l4 i! {/ {3 A3 n4 @

  4. * Z1 q4 Y- |" i' W# y4 f
  5. #define BitBand(Addr, BitNum)        *(__IO uint32_t *)((Addr&0xF0000000)+0x02000000+ \8 O8 G1 k3 d9 [- E. v6 ^8 ^
  6.                                                                                                         ((Addr&0x000FFFFF)<<5)+(BitNum<<2))       
    ( v' `* m- ^$ ]6 e7 U* s  m2 w
  7. #define PAout(n)        BitBand(GPIOA_ODR_Addr, n)        //偏移地址取的是32位寄存器的第一字节的,所以n的取值为0~31
    ; [; }; X7 q$ c4 b5 P9 Y( i

  8. ! f8 [$ W. m2 \4 j" \2 G
  9. FlagStatus led = SET;                                                        //外部调用的全局变量(声明在stm32f10x_it.h头文件)4 {8 f# [+ n) u* i

  10. 5 m4 H$ |' g8 M2 g
  11. static void RCC_Configuration(void);                        //函数原型声明! b2 K1 F9 M3 _0 }$ t, T
  12. static void GPIO_Configuration(void);, \. o  E" W, m
  13. 2 J0 E, N$ b) A% }5 o) ?# I
  14. /**********************************************************************
    1 c: z# u1 a. H9 A  G6 `- N4 ]
  15. * Function Name : MAIN
    - F" {7 p+ j0 F0 a9 G, t( p
  16. * Description         : main program+ {4 S  O) J( Q2 ?6 b, L6 C
  17. * Input                 : None( A! ]+ k& @# O
  18. * Output                 : None
      b! W9 W. f% K& P
  19. * Return                 : None
    # l9 U$ {8 \6 o/ N! }( W/ i
  20. **********************************************************************/- z4 q" f' l  |2 f6 u# H. v
  21. int main(void)8 F  C% m; W) m# U9 N* W, C
  22. {
    1 X0 v3 V: C: c1 _% s
  23.         RCC_Configuration();8 R0 f) S, T$ u6 f* U, p, l
  24.         GPIO_Configuration();9 F' O: [# T7 F* p7 z- H% n. k
  25.         PAout(11) = led;                                                        //上电关闭LED" z3 Z8 e3 J9 C
  26.         ) w& }# r, K1 I' d
  27.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;5 u, `0 d5 Z/ e  N2 t6 W0 v# C- a
  28.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
    0 G$ y1 T$ o$ y4 I7 T' f
  29.         , ?' q0 H7 t1 `
  30.         EXTI->SWIER = EXTI_Line2;
    ) N. C/ z) |* V# U' f
  31.         ( w! B; B0 J9 t# X8 {
  32.         while(1)
    ( m- h( X* l9 l6 h
  33.         {
    1 Q; a8 r) r* J1 i. ]( h' n
  34.                 PAout(11) = led;& M' P# l6 }$ A4 n+ O' x/ c
  35.         }
    1 [- ~& V+ l2 I0 l* J
  36.         . v) e( G+ E# q5 q5 M/ V! _
  37. //        return (0);
    $ X; t7 z+ c7 C$ g
  38. }
    8 F6 ^) M/ D* C# s. [' ?  a/ r

  39. 3 O& J$ O3 t$ n- k, n) S
  40. /**********************************************************************
    5 [& i4 F6 O/ M
  41. * Function Name : RCC_Configuration6 E, r* X1 E+ h1 B
  42. * Description         : 配置时钟参数,使能外设时钟/ t9 ~  P' ^" w; T* ~- Z2 C$ j5 r
  43. * Input                 : None7 x( `9 U! P. O( i
  44. * Output                 : None
    ) b( h+ j3 b) Y/ Y' S" U# K
  45. * Return                 : None9 q2 d. s% V& T- l# o+ u" ?
  46. **********************************************************************/, O0 L8 c0 e. i! @( M
  47. static void RCC_Configuration(void)! L) j/ b" j: w  S) ~
  48. {       
      d, l& Y7 }- z0 I: F, c5 \
  49.         RCC_DeInit();                                        //将外设RCC寄存器重设为缺省值(选择HSI作为系统时钟,其它保持复位值)
    & ~( g" d, N7 j' x
  50.         RCC_HSEConfig(RCC_HSE_ON);                //HSE晶振ON7 x$ h2 D, d1 R" ~
  51.         if(RCC_WaitForHSEStartUp() == SUCCESS)        //等待HSE晶振稳定, X6 Y( k" J- _2 m
  52.         {  k$ B$ ^6 ?. {3 V
  53.                 RCC_HCLKConfig(RCC_SYSCLK_Div1);        //设置AHB时钟(HCLK)—— HCLK = SYSCLK/1
    1 A( H5 i3 J9 a2 J! ~: J& d/ S
  54.                 RCC_PCLK2Config(RCC_HCLK_Div1);                //设置高速AHB时钟(PCLK2)—— PCLK2 = HCLK/1/ w  }/ u( {. S) [4 X9 `1 k
  55.                 RCC_PCLK1Config(RCC_HCLK_Div2);                //设置低速AHB时钟(PCLK1)—— PCLK1 = HCLK/2* w6 A, g1 m; P; s
  56.                 FLASH_SetLatency(FLASH_Latency_2);        //在SYSCLK周期与闪存访问时间插入2个等待周期
    $ u% M' ]' ?* ^
  57.                 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);        //启用闪存预取缓冲区
    & k8 d1 a. A3 r
  58.                 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);        //设置PLL时钟源及倍频系数 —— PLLCLK = (HSECLK/1) * 9 = 72MHz
    6 Z' h1 E; Q& p2 q
  59.                 RCC_PLLCmd(ENABLE);                                        //使能PLL
      L/ Z+ F) V0 L0 a
  60.                 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);                //等待PLL就绪
    . H# N% z, G! r
  61.                 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                //设置系统时钟(SYSCLK)—— 选择PLL作为系统时钟
    ( v- f3 y& u9 ^8 \& K9 k. K
  62.                 while(RCC_GetSYSCLKSource() != 0x08);                                        //返回用作系统时钟的时钟源 —— 0x08:PLL作为系统时钟! q, m' @# D4 @/ `+ X
  63.         }5 ]( [3 c0 Q+ _) b
  64.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    # [4 N; U5 k9 o
  65. }
    - @( z) p( B& [; W$ F+ \9 z

  66. 8 {% z! p; d. i7 i/ C& y  @
  67. /**********************************************************************; M* T$ S8 }: ?) @
  68. * Function Name : GPIO_Configuration
    ) C5 [) T# I( s4 o
  69. * Description         : 配置GPIO参数
    5 ]0 k; x& L4 X6 B; K4 K/ m) ?
  70. * Input                 : None( r8 d3 q! l) S$ O) n- G
  71. * Output                 : None
    , {7 e) z% D) l; z
  72. * Return                 : None/ U- h# R/ ?3 W  x! C1 S4 Y
  73. **********************************************************************/6 Y1 s, y0 h" J/ M. s) U5 L$ ^
  74. static void GPIO_Configuration(void)" C( P  Z6 f5 y6 s% `' S( o8 X
  75. {
    ! ^7 S2 g7 ?( V! p: P/ F' m6 h' z
  76.         GPIO_InitTypeDef GPIO_InitStructure;
      g& I% I0 G- U4 ~. k1 @* o: J
  77.        
    ( h% D, D4 Z6 M  \8 ]7 K
  78.         /* 将GPIOA.11引脚设置为通用推挽输出模式,最大速度50MHz */- w3 d6 b  b1 f
  79.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;' U% a$ Q4 R% v  |
  80.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //GPIOA.9已配置
    * R% P9 Y" {  g) F1 W6 f& E8 M: ]
  81.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    / [& B6 D6 x& S0 k! P
  82.         GPIO_Init(GPIOA, &GPIO_InitStructure);
    2 {6 `" l' Y  [' I6 R* d
  83.         - p# w7 ^# u" N2 `( u# ^% q& r$ A
  84.         /* 将GPIOA.1和GPIOA.2引脚设置为浮空输入模式 */2 a4 F* [. P" `4 I7 d2 d6 l: P. \
  85. //        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    ; e0 R2 U0 ^; j1 e+ c8 V
  86. //        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;5 k' B) L8 E3 K. e0 B
  87. //        GPIO_Init(GPIOA, &GPIO_InitStructure);
      A8 H* F3 H% T/ `0 ?% s2 \& ?/ i9 ?
  88.         & Q# B* ?' w7 f) _6 N, g
  89.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);2 C, U3 m; O; L5 A# w- A
  90.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);9 q7 B7 S: \% p
  91. }
复制代码
“stm32f10x_it.c”源文件里:; |) {5 V2 y" f0 ?) ~5 W6 V4 S# c8 w
  1. /**  G8 |, N8 |( w/ M
  2.   * @brief  This function handles External lines 1 interrupt request.1 p7 L; _1 v0 x# M8 e8 r9 L" v
  3.   * @param  None
    ! H! x) N+ x0 d2 ?$ ?7 g
  4.   * @retval None# [+ `. Z( d+ M" [+ _) s8 k
  5.   */5 Z  a2 J. u% G! `/ A3 Q0 T
  6. void EXTI1_IRQHandler(void)
    8 ?  [" n8 W& l! S1 p( p! b
  7. {. i7 q4 m% j1 r' O
  8.         EXTI->PR = EXTI_Line1;: Z# Q# a4 ^. o& F+ R+ t
  9.         led = RESET;3 s0 m, W; ]# |8 ^- @
  10. }  t6 b, B3 ]7 J1 D8 S5 ~

  11. $ M' F- F4 a$ n  [, V
  12. /**+ t7 K, W: x* F3 \+ {
  13.   * @brief  This function handles External lines 2 interrupt request.( P/ i$ u! L+ E( ]
  14.   * @param  None/ ~- r( \0 o% f7 r4 Z6 T' P- O
  15.   * @retval None( O3 u$ n. s9 W7 ]& y
  16.   */
    ; f- ?) K7 Z8 Z% L8 T8 f' x
  17. void EXTI2_IRQHandler(void)) c" U0 i( T( T7 L: s
  18. {
    7 G4 C7 d5 ^5 V7 e" N5 q# b7 t, O
  19.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    # P6 k" P, s9 q6 T2 g2 ~
  20.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求* P* K; C1 @/ E0 d- f) y7 _
  21.         / Q0 [6 w7 f8 K5 _& n6 R2 b% J% C
  22.         EXTI->PR = EXTI_Line1;                                //清除触发请求$ j$ C; V0 V' C7 @8 e( ?$ @% A4 [
  23.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
    ( u! _: J% C$ T' D5 F& e
  24. }
复制代码
“stm32f10x_it.h”源文件里:
* M" x/ L8 W) i( ]
  1. /****** 用户自定义 ******/
    * O9 J7 b5 L) `# }3 h, M
  2. extern FlagStatus led;                //声明一个外部调用的全局变量(控制LED亮灭的变量)
复制代码
显然代码很简单,软件仿真时各寄存器也是按照程序的意思显示各项数据指标。但是………………很残酷………………实际与理论发生了偏差 —— 将程序烧进硬件跑,LED亮了(即PA.8被置低了。但初始化时PA.8已被置高,而且EXTI1的ISR里才有将PA.8置低的指令!)。不应该是这样啊:虽然EXTI1的优先级高于EXTI2,但二者的抢占优先级相同,因此并不会发生中断嵌套,而且在EXTI2的ISR里已将EXTI1的触发请求标志和中断悬起标志均清除了。原因何在?, V! M/ i: p/ i! n, [4 g* g
0 ]3 U: N1 R3 K/ _# ?9 Z0 v  r
贴主找啊找,调啊调………………好吧,既然软件仿真解决不了,咋就来瞎搞硬件仿真。& N+ F9 t% Z+ |" u, A( f
4 ?" _8 f. @. u  q
连接好JLink与板子后,在MDK里点击单步调试“Step one line(F11)”,执行触发EXTI2中断的指令“EXTI->SWIER = EXTI_Line2;”后却不进入EXTI2的ISR,而且无论点击多少次单步调试,程序一直停在while里………………问题真是接踵而至啊
………………5 m7 _9 [, q5 Z; N/ B1 b; J

, _. |# @' ^' T5 Q  q初入ARM,练习背黑锅。8 [0 u% ?( S) N, v' E. W
  w3 x9 n  g  m9 [1 N+ ?3 `
这时贴主想起了前不久的一次调试经历:单步不行,就全速(贴主本坛第一帖),于是点击全速运行
“Start code execution(F5)”试了下。哈哈,LED亮了!当然,之前的问题并没有得到解决,但是后来的在线调试问题却有了头绪 —— 通过在ISR里设置断点,只要对应的中断被触发且被使能,点击全速运行就可以进入ISR。有了这样一个认知后,贴主又开始瞎搞起来了:软件触发EXTI2后,是何时进入其ISR的?1 u4 @; P0 S) N3 R% ?; v  q

5 d+ s& ]; p8 v! i0 v为此,贴主就在主函数添加了三条将变量flag的值赋给其本身的赋值语句:
! N- n6 D1 g4 r
  1. int main(void)7 @5 u0 Z5 p5 V& S. h
  2. {, o- y! t/ E  x7 i( D
  3.         RCC_Configuration();* z6 x9 l) i& y5 m
  4.         GPIO_Configuration();! W6 F: M5 s- M/ j  t9 e2 X
  5.         PAout(11) = led;                                                        //上电关闭LED
    8 f7 S" ?9 n& [8 ~# i7 J
  6.        
    / e6 r  \) U7 R( Z- {: k
  7.         NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;
    1 G' l9 m8 q3 ^1 ^+ P* N
  8.         EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
    % ~4 \8 I6 Y5 G* V* W2 F' a
  9.        
    9 M/ l# B- C0 B# m% i( A, @5 b1 r
  10.         EXTI->SWIER = EXTI_Line2;# B5 T, s8 M7 F; _9 t4 Y
  11.         & G% ?: W7 W/ M
  12.         flag = flag;
    + D; ?$ y" W9 E& e
  13.         flag = flag;
    : Z# z! L) a) ]' [. X; x9 [0 V
  14.         flag = flag;9 D5 j! _6 ~, A: T
  15.        
    $ U0 B1 k6 G$ _& |
  16.         while(1)& r9 f4 ~  C  I2 S  B
  17.         {
    : `7 g& M) t& v4 Z
  18.                 PAout(11) = led;
      |" n. F4 g6 R2 T" |% n1 E
  19.         }0 ]; u) {! H7 q
  20.         8 p+ f( ~& _) Z% v  a
  21. //        return (0);
    1 q, ]7 m; i+ x* f/ `. d3 B" S
  22. }
复制代码
在线调试时在该三条语句均设置了断点,第一次全速运停在了第一条赋值语句处,再次全速运行时,程序进入到了EXTI2的ISR。如此说明软件触发一个中断,处理器并不会立即响应,这期间存在一个响应时间。学过8051单片机的童鞋应该知道,8051单片机的中断有一个响应过程:采样→查询→处理(各占1个机器周期)。Cortex-M3内核同样也存在,它将“中断延迟”定义为:从检测到某中断请求,到执行了其服务例程的第一条指令时,已经流逝了的时间。在CM3中,若存储器系统够快,且总线系统允许入栈与取指同时进行,同时该中断可以立即响应,则中断延迟是雷打不动的12周期(满足硬实时所要求的确定性)。在与时间赛跑的这12个周期里,处理器内部一直开足马力,进行了入栈、取向量、更新寄存器以及服务例程取指的一系列操作。但若存储器太慢以至于引入等待周期,或者还有其它因素,则会引入额外的延时。
2 c! w# z2 W/ ~9 @- ~5 P3 J4 o# F
3 o- B9 I! B) A" \6 i2 c本帖谈论到这,再来谈在线调试为何进不去ISR,以及最开始的工程为何实现不了预期的目标,原因已很明了。1 D; ~8 [+ Z" G1 E& b& ~6 _2 v& ~

: u  J+ v2 c4 ~2 I, P在线调试为何进不去ISR:
中断延迟的存在,以及中断响应机制。9 U2 p# n8 p( q/ m% Z

* Z  p3 E1 z9 j
对于最开始的工程为何实现不了预期的目标:5 D1 Y/ s" G+ G
在EXTI2的ISR里,软件是这样设置的:
8 r5 ~: @! Z9 b% O
  1. /**
    7 w# u: W  d0 }: ~3 J; f
  2.   * @brief  This function handles External lines 2 interrupt request.4 Z) E- E9 R5 S: N4 z, n+ T" C1 O
  3.   * @param  None$ p* c5 M7 P$ \8 m) n
  4.   * @retval None
    ! [0 B& C) A! f& R+ l
  5.   */
    ( k) c) r2 G4 X5 I, \5 T
  6. void EXTI2_IRQHandler(void)
    ) |8 z' ~3 j$ Z# v
  7. {
    " b, X& E& K0 d- G3 G1 {
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    ! G/ [9 C9 ^& `2 n$ A3 O: N
  9.         EXTI->SWIER = EXTI_Line1;                        //EXTI1触发请求: {6 G  a. L" c) t. t! O7 E
  10.         % v  ]6 U4 X1 m8 S) Q
  11.         EXTI->PR = EXTI_Line1;                                //清除触发请求
    8 t4 c" i/ P; W. s% {7 b; s% c. r
  12.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】+ T$ [. \/ }' X! u& S
  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。原因前面已说明)。如下图所示:7 _+ P6 O2 [' u7 l

图1

图1
, D3 \; \  l0 I( X9 V. O( q1 @1 @/ a! t
在EXTI1的ISR里的第一条语句也设置一个断点,然后继续全速运行,程序果真进入到了EXTI1的ISR,而且是在执行完EXTI2的ISR后再进入的。如下图所示:6 I; V9 b( q+ _  v4 ]

图2

图2

1 S. ^' z. D+ `$ J这里说明了两个问题:/ ?! r- `3 \' |: Y; B; E( Z& D
   一是
前面所探讨的关于
CM3中断响应机制;0 i1 S7 u* h, I/ G
   二是只要
没有清除EXTI_PR寄存器中EXTI1的挂起位,即使有清除EXTI_ICPRx寄存器中断悬起标志的指令,该中断悬起标志仍还是会悬起(前提:不是该ISR对应的中断的中断悬起标志。若是该ISR对应的中断的中断悬起标志,在跳出ISR的同时该悬起标志再次被置位。& S1 v3 k: z( }: V" j! L/ `
   比如:在本例的EXTI2的ISR中,由于指令
“EXTI->PR = EXTI_Line1;”实际无效,所以它下一条清除EXTI1中断悬起标志的语句即使执行了,其对应的中断悬起标志仍是置位状态;而若将EXTI1的ISR里的“EXTI->PR = EXTI_Line1;”注释掉再全速运行,程序会一直停在EXTI1的ISR里。所以有时需要注意二者清除的顺序!)。关于第二点,参考手册里没有指明,但各童鞋需注意!
4 t+ ?9 o! k& @  E( N/ D; c0 g
% d, l0 h- P+ Z: O- B- ~& r: k
! X0 ~0 Y) t: p- O/ r  B+ C% S9 h经过以上分析,本帖最开始建立的工程的bug已经很明显:在EXTI2的ISR里的“EXTI->SWIER = EXTI_Line1;”语句后同样增加一条给变量flag赋值的语句:( \5 ~% T  W& S' D8 I
  1. /**
    5 |0 w( r6 V4 i5 G
  2.   * @brief  This function handles External lines 2 interrupt request.
    : w8 g- ]7 s+ a: s* x6 m; G
  3.   * @param  None; f: d& P- j8 P
  4.   * @retval None3 D% J! `2 S( u5 `  K
  5.   */
    6 @! l$ H- R3 i4 q
  6. void EXTI2_IRQHandler(void)
    / V. v& K! F) t% l( f/ X0 \% |
  7. {
    ; T: j6 b, M, o' f- I8 X
  8.         EXTI->PR = EXTI_Line2;                                //同时清除了EXTI_SWIER寄存器对应位
    : X# K6 g8 u1 v, ^1 e% U
  9.         EXTI->SWIER = EXTI_Line1;
    2 U  V" p% l& h* @3 ~) N6 ]! |
  10.         flag = flag;                                                /****** !!!此句必须有!!!否则程序运行有问题 ******/
    . i2 r, {: z1 L
  11.         /*** 以下是判断EXTI1是否已经发生中断嵌套(两条清除语句缺一不可) ***/
    ! A% ?# E, O( E  J5 }4 L
  12.         EXTI->PR = EXTI_Line1;                                //清除触发请求【必须先清除触发请求,然后再清除中断悬起标志 —— 软件仿真无区别,但硬件必须如此】
      ]* U& M) H- q( l1 k
  13.         NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
    6 G* h2 Y- n6 X3 M
  14. }
复制代码

0 W) ]5 a$ H  _( U
* u2 r( S6 y" _# Q) C: v
7 W6 s0 L0 ^; _0 w( M总结下来,其实就是基本知识没掌握,所以每天都是在瞎搞又瞎搞………………+ I) R( y: v8 y) b

0 F8 |8 I1 @9 O6 d* l# P% l, _0 M; v  U  {0 ]$ B/ 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脚被标注为可选择。如以下链接所示
& Q7 S3 g# |( U+ t. X+ q9 L
! Y2 `) |' w" w( y7 g. K0 `也就是第1脚必须与板子的VCC相连,至于第2脚呢?
; l! D) T0 `6 ]8 D' @经过帖主测试发现:JLink仿真器端口的第2脚连接的是仿真器内AMS1117稳压芯片的输出脚(或许有些JLink没有集成3.3V稳压输出),所以是可以给目标板子提供电源的。若板子没有独立供电,那么必须将JLink仿真器端口的第2脚与目标板的VCC相连。
/ m  `( ?8 K/ C) b* M注意:无论目标板是否独立供电,如若不连接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”的窗口提示! 前一个翻译出来也就是提示连接有问题。
: n$ o! j; H3 P9 ?(回复不能从本地上传图片,没图片显示形象,各位大虾将就下)
moyanming2013 回答时间:2017-3-8 13:28:19
吐息间丶时光中 发表于 2017-3-8 09:50: ]' F* c; X2 [& x1 x
关于硬件连接,补充一下:JLink仿真器端口的1、2脚均定义为VCC,但第2脚被标注为可选择。如以下链接所示
! j6 t; M9 e# p  K* ?' }$ H7 @/ {4 F# C3 v0 @. D. [: \& o4 W
...
2 ^$ p  h9 w6 h' ~6 ^& j; R/ j5 g
回复时选择“高级模式”就可以添加图片了。
- w) h/ o( Q" Q) G1 ]: }也可以使用ST-LINK/V2-1调试器。
吐息间丶时光中 回答时间:2017-3-9 11:53:52
moyanming2013 发表于 2017-3-8 13:28
6 G" C- d" h8 O! K回复时选择“高级模式”就可以添加图片了。
7 G7 c% @" P) l0 \& x9 |* z0 F7 ~) F1 Y也可以使用ST-LINK/V2-1调试器。 ...

( c& y/ @! j7 j  h6 Y: y$ A哈哈,多谢大神提示,看到喃。(今后可以愉快的斗图了)7 Y+ U) `7 V) J: B: a! j
目前身边只有JLink仿真器,其它仿真器今后应该用得到。+ T3 ~; p9 n3 ?& a
7 _. E8 w" y. x
借此将图片上传:2 Z$ l! \, e. L  l; P6 l* Q- s
1.PNG . ]# ~) o5 V* G$ j* Y/ w8 Y6 @% t
一般用FC头2*10P线连接,不会出现这种情况(前提是目标板本身已将对应的JLink输入引脚的第1脚连到VCC上。比如帖主的板子就是的,下图),容易出现这种情况是在用杜邦线去连接,又是1用JLink仿真器给目标板供电,就很容易少连这一根线。
" ]8 D* Q5 j7 _ 2.PNG
6 m; r$ j, _* |9 N
. F$ j0 w$ a  G) b5 G
吐息间丶时光中 回答时间:2017-3-11 13:32:30
纠正一个文中的描述错误:测试用的LED连接的是GPIOA端口的11脚,文中被错误的描述为第8脚(程序中是PA.11)。+ O2 Z  q) _9 F& l" Q
--------------------------------------------------------------
( e4 ~4 @: `2 V, F感谢@zero99 的支持。
/ s& `* B" \9 F" f" j--------------------------------------------------------------
# G; \/ m0 a4 U* J

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