前段时间贴主看了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. ^- #include "stm32f10x.h"4 |$ k1 c7 D* O1 J2 r5 `7 U0 `2 K
" L" [2 o z! D6 W; z- #define GPIOA_ODR_Addr (GPIOA_BASE+0x0C) //GPIOA端口寄存器ODR的地址9 e! c% ?; ~1 l4 i! {/ {3 A3 n4 @
* Z1 q4 Y- |" i' W# y4 f- #define BitBand(Addr, BitNum) *(__IO uint32_t *)((Addr&0xF0000000)+0x02000000+ \8 O8 G1 k3 d9 [- E. v6 ^8 ^
- ((Addr&0x000FFFFF)<<5)+(BitNum<<2))
( v' `* m- ^$ ]6 e7 U* s m2 w - #define PAout(n) BitBand(GPIOA_ODR_Addr, n) //偏移地址取的是32位寄存器的第一字节的,所以n的取值为0~31
; [; }; X7 q$ c4 b5 P9 Y( i
! f8 [$ W. m2 \4 j" \2 G- FlagStatus led = SET; //外部调用的全局变量(声明在stm32f10x_it.h头文件)4 {8 f# [+ n) u* i
5 m4 H$ |' g8 M2 g- static void RCC_Configuration(void); //函数原型声明! b2 K1 F9 M3 _0 }$ t, T
- static void GPIO_Configuration(void);, \. o E" W, m
- 2 J0 E, N$ b) A% }5 o) ?# I
- /**********************************************************************
1 c: z# u1 a. H9 A G6 `- N4 ] - * Function Name : MAIN
- F" {7 p+ j0 F0 a9 G, t( p - * Description : main program+ {4 S O) J( Q2 ?6 b, L6 C
- * Input : None( A! ]+ k& @# O
- * Output : None
b! W9 W. f% K& P - * Return : None
# l9 U$ {8 \6 o/ N! }( W/ i - **********************************************************************/- z4 q" f' l |2 f6 u# H. v
- int main(void)8 F C% m; W) m# U9 N* W, C
- {
1 X0 v3 V: C: c1 _% s - RCC_Configuration();8 R0 f) S, T$ u6 f* U, p, l
- GPIO_Configuration();9 F' O: [# T7 F* p7 z- H% n. k
- PAout(11) = led; //上电关闭LED" z3 Z8 e3 J9 C
- ) w& }# r, K1 I' d
- NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;5 u, `0 d5 Z/ e N2 t6 W0 v# C- a
- EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
0 G$ y1 T$ o$ y4 I7 T' f - , ?' q0 H7 t1 `
- EXTI->SWIER = EXTI_Line2;
) N. C/ z) |* V# U' f - ( w! B; B0 J9 t# X8 {
- while(1)
( m- h( X* l9 l6 h - {
1 Q; a8 r) r* J1 i. ]( h' n - PAout(11) = led;& M' P# l6 }$ A4 n+ O' x/ c
- }
1 [- ~& V+ l2 I0 l* J - . v) e( G+ E# q5 q5 M/ V! _
- // return (0);
$ X; t7 z+ c7 C$ g - }
8 F6 ^) M/ D* C# s. [' ? a/ r
3 O& J$ O3 t$ n- k, n) S- /**********************************************************************
5 [& i4 F6 O/ M - * Function Name : RCC_Configuration6 E, r* X1 E+ h1 B
- * Description : 配置时钟参数,使能外设时钟/ t9 ~ P' ^" w; T* ~- Z2 C$ j5 r
- * Input : None7 x( `9 U! P. O( i
- * Output : None
) b( h+ j3 b) Y/ Y' S" U# K - * Return : None9 q2 d. s% V& T- l# o+ u" ?
- **********************************************************************/, O0 L8 c0 e. i! @( M
- static void RCC_Configuration(void)! L) j/ b" j: w S) ~
- {
d, l& Y7 }- z0 I: F, c5 \ - RCC_DeInit(); //将外设RCC寄存器重设为缺省值(选择HSI作为系统时钟,其它保持复位值)
& ~( g" d, N7 j' x - RCC_HSEConfig(RCC_HSE_ON); //HSE晶振ON7 x$ h2 D, d1 R" ~
- if(RCC_WaitForHSEStartUp() == SUCCESS) //等待HSE晶振稳定, X6 Y( k" J- _2 m
- { k$ B$ ^6 ?. {3 V
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟(HCLK)—— HCLK = SYSCLK/1
1 A( H5 i3 J9 a2 J! ~: J& d/ S - RCC_PCLK2Config(RCC_HCLK_Div1); //设置高速AHB时钟(PCLK2)—— PCLK2 = HCLK/1/ w }/ u( {. S) [4 X9 `1 k
- RCC_PCLK1Config(RCC_HCLK_Div2); //设置低速AHB时钟(PCLK1)—— PCLK1 = HCLK/2* w6 A, g1 m; P; s
- FLASH_SetLatency(FLASH_Latency_2); //在SYSCLK周期与闪存访问时间插入2个等待周期
$ u% M' ]' ?* ^ - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //启用闪存预取缓冲区
& k8 d1 a. A3 r - RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //设置PLL时钟源及倍频系数 —— PLLCLK = (HSECLK/1) * 9 = 72MHz
6 Z' h1 E; Q& p2 q - RCC_PLLCmd(ENABLE); //使能PLL
L/ Z+ F) V0 L0 a - while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL就绪
. H# N% z, G! r - RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //设置系统时钟(SYSCLK)—— 选择PLL作为系统时钟
( v- f3 y& u9 ^8 \& K9 k. K - while(RCC_GetSYSCLKSource() != 0x08); //返回用作系统时钟的时钟源 —— 0x08:PLL作为系统时钟! q, m' @# D4 @/ `+ X
- }5 ]( [3 c0 Q+ _) b
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
# [4 N; U5 k9 o - }
- @( z) p( B& [; W$ F+ \9 z
8 {% z! p; d. i7 i/ C& y @- /**********************************************************************; M* T$ S8 }: ?) @
- * Function Name : GPIO_Configuration
) C5 [) T# I( s4 o - * Description : 配置GPIO参数
5 ]0 k; x& L4 X6 B; K4 K/ m) ? - * Input : None( r8 d3 q! l) S$ O) n- G
- * Output : None
, {7 e) z% D) l; z - * Return : None/ U- h# R/ ?3 W x! C1 S4 Y
- **********************************************************************/6 Y1 s, y0 h" J/ M. s) U5 L$ ^
- static void GPIO_Configuration(void)" C( P Z6 f5 y6 s% `' S( o8 X
- {
! ^7 S2 g7 ?( V! p: P/ F' m6 h' z - GPIO_InitTypeDef GPIO_InitStructure;
g& I% I0 G- U4 ~. k1 @* o: J -
( h% D, D4 Z6 M \8 ]7 K - /* 将GPIOA.11引脚设置为通用推挽输出模式,最大速度50MHz */- w3 d6 b b1 f
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;' U% a$ Q4 R% v |
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIOA.9已配置
* R% P9 Y" { g) F1 W6 f& E8 M: ] - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/ [& B6 D6 x& S0 k! P - GPIO_Init(GPIOA, &GPIO_InitStructure);
2 {6 `" l' Y [' I6 R* d - - p# w7 ^# u" N2 `( u# ^% q& r$ A
- /* 将GPIOA.1和GPIOA.2引脚设置为浮空输入模式 */2 a4 F* [. P" `4 I7 d2 d6 l: P. \
- // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
; e0 R2 U0 ^; j1 e+ c8 V - // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;5 k' B) L8 E3 K. e0 B
- // GPIO_Init(GPIOA, &GPIO_InitStructure);
A8 H* F3 H% T/ `0 ?% s2 \& ?/ i9 ? - & Q# B* ?' w7 f) _6 N, g
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);2 C, U3 m; O; L5 A# w- A
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);9 q7 B7 S: \% p
- }
复制代码 “stm32f10x_it.c”源文件里:; |) {5 V2 y" f0 ?) ~5 W6 V4 S# c8 w
- /** G8 |, N8 |( w/ M
- * @brief This function handles External lines 1 interrupt request.1 p7 L; _1 v0 x# M8 e8 r9 L" v
- * @param None
! H! x) N+ x0 d2 ?$ ?7 g - * @retval None# [+ `. Z( d+ M" [+ _) s8 k
- */5 Z a2 J. u% G! `/ A3 Q0 T
- void EXTI1_IRQHandler(void)
8 ? [" n8 W& l! S1 p( p! b - {. i7 q4 m% j1 r' O
- EXTI->PR = EXTI_Line1;: Z# Q# a4 ^. o& F+ R+ t
- led = RESET;3 s0 m, W; ]# |8 ^- @
- } t6 b, B3 ]7 J1 D8 S5 ~
$ M' F- F4 a$ n [, V- /**+ t7 K, W: x* F3 \+ {
- * @brief This function handles External lines 2 interrupt request.( P/ i$ u! L+ E( ]
- * @param None/ ~- r( \0 o% f7 r4 Z6 T' P- O
- * @retval None( O3 u$ n. s9 W7 ]& y
- */
; f- ?) K7 Z8 Z% L8 T8 f' x - void EXTI2_IRQHandler(void)) c" U0 i( T( T7 L: s
- {
7 G4 C7 d5 ^5 V7 e" N5 q# b7 t, O - EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
# P6 k" P, s9 q6 T2 g2 ~ - EXTI->SWIER = EXTI_Line1; //EXTI1触发请求* P* K; C1 @/ E0 d- f) y7 _
- / Q0 [6 w7 f8 K5 _& n6 R2 b% J% C
- EXTI->PR = EXTI_Line1; //清除触发请求$ j$ C; V0 V' C7 @8 e( ?$ @% A4 [
- NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
( u! _: J% C$ T' D5 F& e - }
复制代码 “stm32f10x_it.h”源文件里:
* M" x/ L8 W) i( ]- /****** 用户自定义 ******/
* O9 J7 b5 L) `# }3 h, M - 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- int main(void)7 @5 u0 Z5 p5 V& S. h
- {, o- y! t/ E x7 i( D
- RCC_Configuration();* z6 x9 l) i& y5 m
- GPIO_Configuration();! W6 F: M5 s- M/ j t9 e2 X
- PAout(11) = led; //上电关闭LED
8 f7 S" ?9 n& [8 ~# i7 J -
/ e6 r \) U7 R( Z- {: k - NVIC->ISER[0] = NVIC_ISER_SETENA_7 | NVIC_ISER_SETENA_8;
1 G' l9 m8 q3 ^1 ^+ P* N - EXTI->IMR |= EXTI_Line1 | EXTI_Line2;
% ~4 \8 I6 Y5 G* V* W2 F' a -
9 M/ l# B- C0 B# m% i( A, @5 b1 r - EXTI->SWIER = EXTI_Line2;# B5 T, s8 M7 F; _9 t4 Y
- & G% ?: W7 W/ M
- flag = flag;
+ D; ?$ y" W9 E& e - flag = flag;
: Z# z! L) a) ]' [. X; x9 [0 V - flag = flag;9 D5 j! _6 ~, A: T
-
$ U0 B1 k6 G$ _& | - while(1)& r9 f4 ~ C I2 S B
- {
: `7 g& M) t& v4 Z - PAout(11) = led;
|" n. F4 g6 R2 T" |% n1 E - }0 ]; u) {! H7 q
- 8 p+ f( ~& _) Z% v a
- // return (0);
1 q, ]7 m; i+ x* f/ `. d3 B" S - }
复制代码 在线调试时在该三条语句均设置了断点,第一次全速运停在了第一条赋值语句处,再次全速运行时,程序进入到了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- /**
7 w# u: W d0 }: ~3 J; f - * @brief This function handles External lines 2 interrupt request.4 Z) E- E9 R5 S: N4 z, n+ T" C1 O
- * @param None$ p* c5 M7 P$ \8 m) n
- * @retval None
! [0 B& C) A! f& R+ l - */
( k) c) r2 G4 X5 I, \5 T - void EXTI2_IRQHandler(void)
) |8 z' ~3 j$ Z# v - {
" b, X& E& K0 d- G3 G1 { - EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
! G/ [9 C9 ^& `2 n$ A3 O: N - EXTI->SWIER = EXTI_Line1; //EXTI1触发请求: {6 G a. L" c) t. t! O7 E
- % v ]6 U4 X1 m8 S) Q
- EXTI->PR = EXTI_Line1; //清除触发请求
8 t4 c" i/ P; W. s% {7 b; s% c. r - NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】+ T$ [. \/ }' X! u& S
- }
复制代码 也就是语句“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
, D3 \; \ l0 I( X9 V. O( q1 @1 @/ a! t
在EXTI1的ISR里的第一条语句也设置一个断点,然后继续全速运行,程序果真进入到了EXTI1的ISR,而且是在执行完EXTI2的ISR后再进入的。如下图所示:6 I; V9 b( q+ _ v4 ]
å¾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
- /**
5 |0 w( r6 V4 i5 G - * @brief This function handles External lines 2 interrupt request.
: w8 g- ]7 s+ a: s* x6 m; G - * @param None; f: d& P- j8 P
- * @retval None3 D% J! `2 S( u5 ` K
- */
6 @! l$ H- R3 i4 q - void EXTI2_IRQHandler(void)
/ V. v& K! F) t% l( f/ X0 \% | - {
; T: j6 b, M, o' f- I8 X - EXTI->PR = EXTI_Line2; //同时清除了EXTI_SWIER寄存器对应位
: X# K6 g8 u1 v, ^1 e% U - EXTI->SWIER = EXTI_Line1;
2 U V" p% l& h* @3 ~) N6 ]! | - flag = flag; /****** !!!此句必须有!!!否则程序运行有问题 ******/
. i2 r, {: z1 L - /*** 以下是判断EXTI1是否已经发生中断嵌套(两条清除语句缺一不可) ***/
! A% ?# E, O( E J5 }4 L - EXTI->PR = EXTI_Line1; //清除触发请求【必须先清除触发请求,然后再清除中断悬起标志 —— 软件仿真无区别,但硬件必须如此】
]* U& M) H- q( l1 k - NVIC->ICPR[0] = NVIC_ICPR_CLRPEND_7;//清除中断悬起标志【正常情况下,该寄存器对应的中断悬起标志在进入ISR时会自动清除】
6 G* h2 Y- n6 X3 M - }
复制代码
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脚必须与板子的VCC相连,至于第2脚呢?
经过帖主测试发现:JLink仿真器端口的第2脚连接的是仿真器内AMS1117稳压芯片的输出脚(或许有些JLink没有集成3.3V稳压输出),所以是可以给目标板子提供电源的。若板子没有独立供电,那么必须将JLink仿真器端口的第2脚与目标板的VCC相连。
注意:无论目标板是否独立供电,如若不连接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”的窗口提示! 前一个翻译出来也就是提示连接有问题。
(回复不能从本地上传图片,没图片显示形象,各位大虾将就下
回复时选择“高级模式”就可以添加图片了。
也可以使用ST-LINK/V2-1调试器。
哈哈,多谢大神提示,看到喃。(今后可以愉快的斗图了
目前身边只有JLink仿真器,其它仿真器今后应该用得到。+ T3 ~; p9 n3 ?& a
7 _. E8 w" y. x
借此将图片上传:2 Z$ l! \, e. L l; P6 l* Q- s
一般用FC头2*10P线连接,不会出现这种情况(前提是目标板本身已将对应的JLink输入引脚的第1脚连到VCC上。比如帖主的板子就是的,下图),容易出现这种情况是在用杜邦线去连接,又是1用JLink仿真器给目标板供电,就很容易少连这一根线。
. F$ j0 w$ a G) b5 G
--------------------------------------------------------------
感谢@zero99 的支持。
--------------------------------------------------------------