前段时间贴主看了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
- #include "stm32f10x.h"
+ ?! o9 g7 ^5 h6 d2 g% E - 3 h% v8 ?' U2 |4 D1 v# F) [" f
- #define GPIOA_ODR_Addr (GPIOA_BASE+0x0C) //GPIOA端口寄存器ODR的地址; A+ z* E! ~9 |7 d
- 3 _ D9 i! e3 U T3 p+ y. {
- #define BitBand(Addr, BitNum) *(__IO uint32_t *)((Addr&0xF0000000)+0x02000000+ \
0 X9 M( `/ b E, v; B" G - ((Addr&0x000FFFFF)<<5)+(BitNum<<2))
8 I& X R6 D4 q) p7 A ^: w" R - #define PAout(n) BitBand(GPIOA_ODR_Addr, n) //偏移地址取的是32位寄存器的第一字节的,所以n的取值为0~31
& C+ s4 l7 u7 A2 ]
1 T4 U) {# N) a U- FlagStatus led = SET; //外部调用的全局变量(声明在stm32f10x_it.h头文件)6 n4 }7 L: \, r3 O k1 q
8 g. _5 _3 e) l- static void RCC_Configuration(void); //函数原型声明" x8 Y7 R7 u; R
- static void GPIO_Configuration(void);
; ]! }: B9 y1 \. C
+ j( ^) w: {; ?8 ?! r- /**********************************************************************
5 L4 l8 d0 \' M5 h1 V* b9 o - * Function Name : MAIN
% A! F; e2 N# g+ S - * Description : main program/ {1 S% h3 K* J' x3 M. a3 N! V
- * Input : None4 p& i% {$ ~5 C8 N- Z
- * Output : None6 ]- v$ Q+ B; Z* K- B2 q" H; P0 @4 w
- * Return : None
0 e$ @8 j9 U+ ?. X$ T+ P - **********************************************************************/
% l7 }* _0 e& Y, E1 Z0 K - int main(void)
; y g+ J$ ]. L& B O - {
7 l6 m6 F+ x( V! a; t j, J - RCC_Configuration();8 I2 e X$ F7 t, j2 i+ D) c
- GPIO_Configuration();2 k- S( y' r+ g; w" ^
- PAout(11) = led; //上电关闭LED
6 H& b# o4 T1 M# R: h% S! c% y - % l3 C! Q6 y, ^* [ s' o
- NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;
+ Q5 a0 g2 X' j! t: o5 \ - EXTI->IMR |= EXTI_Line1 | EXTI_Line2;; Q8 l l6 \( P% x C0 A
-
& _' E | y, m+ k- g2 k6 s3 H - EXTI->SWIER = EXTI_Line2;
, W: W9 o" X3 f0 j -
7 k/ j9 D% P* U' P6 z2 w - while(1)
^2 N. v- o4 W$ i& z - {/ M8 a" {8 ^. n$ ?
- PAout(11) = led;$ p8 V* f) i: U- \1 i
- }2 ^1 \% V6 U) o3 ?: z" O8 p
- , o. a& V% b* ]
- // return (0);
; E- n1 y3 F% [ - }
9 U8 \/ ~+ R% y - $ w0 v" K! o7 w
- /**********************************************************************
" {3 L; s, X& \4 [; u$ A8 H - * Function Name : RCC_Configuration
( E E! R( z* f# g# ~) T0 o - * Description : 配置时钟参数,使能外设时钟
. D' D a; {: t, e2 d - * Input : None+ M2 l- p; K- e/ Q
- * Output : None
: \; E% T0 P6 y" M, @& A - * Return : None& b' Q: ^: ]3 j
- **********************************************************************/
% ] X* M7 a6 \# H3 Y - static void RCC_Configuration(void)
9 l/ ]* o: w7 W2 a - { ! D, d; N) i7 ~, ?2 n$ z
- RCC_DeInit(); //将外设RCC寄存器重设为缺省值(选择HSI作为系统时钟,其它保持复位值); i9 C6 ?: Q* M1 Y7 ^
- RCC_HSEConfig(RCC_HSE_ON); //HSE晶振ON
: e7 W$ J3 O- X& Y- b, C - if(RCC_WaitForHSEStartUp() == SUCCESS) //等待HSE晶振稳定2 K: ?: m1 i1 z. r
- {
; \9 j$ p8 J3 G6 U0 j - RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟(HCLK)—— HCLK = SYSCLK/1
' J+ G" ^! K) v8 V: A- d - RCC_PCLK2Config(RCC_HCLK_Div1); //设置高速AHB时钟(PCLK2)—— PCLK2 = HCLK/19 v* ^ Z! O, X. h, E3 K% o* |) C/ `
- RCC_PCLK1Config(RCC_HCLK_Div2); //设置低速AHB时钟(PCLK1)—— PCLK1 = HCLK/26 t* U5 d5 V$ H( g
- FLASH_SetLatency(FLASH_Latency_2); //在SYSCLK周期与闪存访问时间插入2个等待周期
6 n' B# P4 u/ D - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //启用闪存预取缓冲区6 d3 a# P: a: D W/ i3 C
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //设置PLL时钟源及倍频系数 —— PLLCLK = (HSECLK/1) * 9 = 72MHz
( ?8 p! ~* r- q& J) L) R; v6 _ - RCC_PLLCmd(ENABLE); //使能PLL
; F% C4 k/ p% L/ } - while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL就绪& E$ E* v3 t3 `, r0 A/ v% r
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //设置系统时钟(SYSCLK)—— 选择PLL作为系统时钟
7 e2 j; |# Z$ w/ G - while(RCC_GetSYSCLKSource() != 0x08); //返回用作系统时钟的时钟源 —— 0x08:PLL作为系统时钟
/ n# X3 q# }1 k6 i- A) w - }
4 v3 D2 L; z/ Q) T8 S' C" z - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);3 f7 u. f4 C( J* Q( ^! @( W
- }
9 ]7 b9 E& c0 k - , `& h7 o& z3 l0 y9 L) O; V2 ] J
- /**********************************************************************, _4 S$ ]# F" p4 h/ C' z
- * Function Name : GPIO_Configuration
4 \% ~( u+ j) ? u# g( A - * Description : 配置GPIO参数! g* o7 C" j2 E6 `
- * Input : None1 @) ]0 L* g6 R8 c9 ~' o) b
- * Output : None' ?5 b3 w% G& n3 O3 J
- * Return : None% m' G; F. n% L. I$ h+ l. ?" w/ i
- **********************************************************************/* D' c1 u/ P$ ]0 T' U% i t! v4 @
- static void GPIO_Configuration(void)
/ {3 u- ]1 L1 Q" c - {, [4 u, h; y0 l: r
- GPIO_InitTypeDef GPIO_InitStructure;
( ~( X$ E/ k; L4 g! r( u. ` -
~6 |: e9 W, U1 t5 o! T - /* 将GPIOA.11引脚设置为通用推挽输出模式,最大速度50MHz */
9 R9 Z, a$ _: x! D9 Z - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
) z! t5 J, q8 T' I7 [ - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIOA.9已配置
9 r7 m/ t# v; t a: Y$ Y - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;% f! e0 ]/ x) ^6 D- T# y
- GPIO_Init(GPIOA, &GPIO_InitStructure);
4 C" h( _1 j% z9 ^, y0 g$ u- @ - : g) a8 L% J6 e9 l7 A
- /* 将GPIOA.1和GPIOA.2引脚设置为浮空输入模式 */5 T1 P+ ` F9 h% F
- // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;! \% Y, z4 C( v% n
- // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
7 q% ^3 g7 g) S5 F0 U0 y3 {8 a% j - // GPIO_Init(GPIOA, &GPIO_InitStructure); z j$ @0 p) R8 Y' F+ k8 [, ]
- % E; g7 U( j: x+ o4 W
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
; E8 S3 h7 \" ]) G. H4 P - GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);1 U) g! N4 ^0 g: |# z, e9 p& @
- }
复制代码 “stm32f10x_it.c”源文件里:
; R; B0 V' m/ r" X! z- /**$ ]. r4 G$ h0 i3 S/ p
- * @brief This function handles External lines 1 interrupt request.& z% u2 R9 F/ H
- * @param None0 A. a' A, ?+ T0 K6 l
- * @retval None
$ @1 N0 c. ]3 L; u9 z - */
1 w F9 J/ E# U% |. m - void EXTI1_IRQHandler(void)
7 T" o; U8 U: { - {: ]8 E5 F! R M$ [! f+ c; A t
- EXTI->PR = EXTI_Line1;
4 i: z% X' ]' B+ [, ~! l" O- X - led = RESET;8 a& U0 B1 l. j& L; X* a
- }
" g' N2 w z1 C) j
+ A5 d: J- U% H4 M/ P5 D- /**5 E/ X1 q' L$ {7 C, [
- * @brief This function handles External lines 2 interrupt request.
+ e& m/ Z; G$ d. o/ a6 @2 X - * @param None2 @3 y& Y$ n- p% i9 @% z1 i
- * @retval None, C5 ]2 P8 C" Y; f
- */
+ O% L6 K" g7 p4 m/ L, V! K# e S - void EXTI2_IRQHandler(void) i3 c6 q) y2 E+ P v J- l
- { Y! M8 Q; J5 v4 Z
- EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
) O& F6 i: e5 r( g2 J" k0 G) d - EXTI->SWIER = EXTI_Line1; //EXTI1触发请求8 t% ~+ r9 n. c8 P6 k1 Z# U+ H5 c
- / @. h+ P8 k& {0 @. K& `. H
- EXTI->PR = EXTI_Line1; //清除触发请求5 d: ~- W2 v/ P1 _5 D- O+ e1 m
- NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
! C5 \! ^; W1 n3 I6 S* C4 j - }
复制代码 “stm32f10x_it.h”源文件里:! S; M" q' y9 ~; i9 k1 `+ A
- /****** 用户自定义 ******/* b# T/ Q, Z% u& b
- 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& }
- int main(void)
2 Q3 d# _* h! @. u4 J0 R - {
& H& d! N9 f. X# d) i8 c6 B; U - RCC_Configuration();$ O$ L0 y# ?- C3 i
- GPIO_Configuration();/ m( X. M. V" A- I) i3 y
- PAout(11) = led; //上电关闭LED
. o% r" T4 O$ |0 w - 0 [9 n. E8 S, K7 M: [9 X2 ~$ e
- NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;1 a" k c* \+ B6 k
- EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
I- s2 F. {& W v4 d -
7 C K6 G" V+ ?# M1 Q9 K( `4 J - EXTI->SWIER = EXTI_Line2;
' M" V, s$ x/ v4 K, e- k# X3 A# Z4 ` - # Q5 r& _8 a s5 ^! ~8 i
- flag = flag;
$ j8 O& A' d3 X3 \ - flag = flag;
- ~5 H0 c! n% A+ K" P) X. p - flag = flag;$ e3 o/ o. E+ j+ [0 K" I" a
-
+ |, ?9 ^: {1 Z9 S - while(1)
' O' n1 O1 t( e4 `6 l% ~ - {
" f7 R) I( P4 L# M - PAout(11) = led;
/ | J5 M5 r; L1 B4 Q6 e, p8 ] - }* L$ w; D! t& e/ ]
-
- y- t) M' m+ \; N" F# v# z - // return (0);# |* I6 v8 g' J* F4 ?: S. m
- }
复制代码 在线调试时在该三条语句均设置了断点,第一次全速运停在了第一条赋值语句处,再次全速运行时,程序进入到了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- /**$ C, H9 c; z8 [/ _9 z, W# N/ {
- * @brief This function handles External lines 2 interrupt request.
" p6 _: O- I$ X, b) { - * @param None2 m% v; B$ F# D5 ^1 A
- * @retval None! S! ]7 i% S- h1 @0 `
- */
/ v' x% i/ z# Q% c1 I' k+ Y& s5 I - void EXTI2_IRQHandler(void)
( S4 E& E* o V5 ]% t3 H0 Z, o% B0 L - {; N" ^ J3 q; W4 M7 D' g
- EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
- X! \$ r" H' C6 p - EXTI->SWIER = EXTI_Line1; //EXTI1触发请求
9 I- l* B8 U' u9 s - 4 U1 [ }: B2 |- O0 D* B
- EXTI->PR = EXTI_Line1; //清除触发请求6 M8 H8 w! z5 C0 L& _
- NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
6 x2 W. q! Y) y/ J1 b7 | - }
复制代码 也就是语句“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
. 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
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) |
- /**9 e3 U. j5 N; z! }0 e+ `. A5 A
- * @brief This function handles External lines 2 interrupt request.
) z6 g$ d$ W, K& S. j- S - * @param None
* g3 [1 H2 }5 m( C2 e6 L - * @retval None B/ Y9 N/ x) \6 `) W
- */* {$ x* I5 i6 ~, `3 t
- void EXTI2_IRQHandler(void)
+ S* [0 Y: s7 R: i* e! h - {9 r# x0 {# k$ ~9 \2 l2 |7 A
- EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
* N8 L9 c0 z% _% E2 P - EXTI->SWIER = EXTI_Line1;
5 q1 {+ U2 c+ _9 M: T - flag = flag; /****** !!!此句必须有!!!否则程序运行有问题 ******/) Z- S: `2 q, e
- /*** 以下是判断EXTI1是否已经发生中断嵌套(两条清除语句缺一不可) ***/3 ]* C; S2 {! s0 ~7 G
- EXTI->PR = EXTI_Line1; //清除触发请求【必须先清除触发请求,然后再清除中断悬起标志 —— 软件仿真无区别,但硬件必须如此】! }6 V* w& m( q: M
- NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
0 B1 i' l; r! {) z R - }
复制代码 : \, 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脚必须与板子的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
(回复不能从本地上传图片,没图片显示形象,各位大虾将就下
回复时选择“高级模式”就可以添加图片了。! b( ?7 x; ]+ S2 s( {
也可以使用ST-LINK/V2-1调试器。
哈哈,多谢大神提示,看到喃。(今后可以愉快的斗图了
目前身边只有JLink仿真器,其它仿真器今后应该用得到。
借此将图片上传:; F% h1 Z4 M" @2 f/ F8 X# t
一般用FC头2*10P线连接,不会出现这种情况(前提是目标板本身已将对应的JLink输入引脚的第1脚连到VCC上。比如帖主的板子就是的,下图),容易出现这种情况是在用杜邦线去连接,又是1用JLink仿真器给目标板供电,就很容易少连这一根线。
--------------------------------------------------------------
感谢@zero99 的支持。+ ]0 I+ k0 p! Z C. x" [
--------------------------------------------------------------