1 概述% U' }& Z8 I* V$ e% Y: q2 T
1.1 资源概述
2 l4 F. E4 g Q开发板:ST官方NUCLEO-F103RB开发板 b5 t6 R% \/ r# Q3 V( g
CUBEMX版本:1.3.0
- k, J6 M! o8 A# B% X MMDK版本:5.23& A) N, f# N7 Z0 ^
主控芯片型号:STM32F103RBT6
% M z: I( |) K5 X/ L; Y! S
* {; F8 B# Y9 I8 I5 C
' {2 @( D9 K/ G/ S. i% o6 c2 Q% N- J" @, G8 v) M9 A
1.2 引脚资源分配
& L! D, m" t" z/ _* v
( ?* M$ t8 A3 E( i* q2 Q3 \
# v, ]5 k" V8 q% \0 Q' i, C5 W
6 Q4 A5 i% ~6 w; y" [$ G1.3 中断概述5 |! m6 b" B* G8 C) n6 T- ?
外部中断/事件控制器框图' {( P7 o X3 j& l& V
/ m) B( [- e% u. O8 E! \0 Q3 c# D8 y- B" v, U4 Y7 B5 x6 h
优先级分组可以设置为5种方式。分别是1个抢占优先级/16个子优先级到16个抢占优先级/1个子优先级。
& P" g g0 B! Y; i/ [. G- V
5 o" z# w/ F" L
1 J' I/ i# m$ t$ M$ B
, a$ Z$ d9 r* z" f( o
1.4 实现功能
2 B9 N+ Q$ i# Z3 Q实现功能:
+ r% L7 @$ _- [2 G, r1、上电初始化后,LED2灯亮。
5 T: o3 M6 G* s2 Z* R2 z( u2、若按键被按下,触发外部中断,则将LED2灯状态翻转。 f5 G+ g7 C9 R/ p' ]5 I
' z$ ?) c( s& {3 w0 U1 q. I
2 软件开发,使用中断的方式4 X) T: i6 {) f, c* g& }7 `$ p
2.1 CUBEMX配置
/ [' n( n/ ]6 O1 mButton部分原理图如下,PC13为低输入有效。电路中与按键并联的100nF是按键消抖用,使用正点原子的开发板没有此电容,会出现按一次,LED灯亮灭各一次的现象,说明抖动了,执行了两次中断。
- P3 R$ Y4 B2 I/ Y+ o! M# Z9 @7 R6 L, E# J5 o
3 E! I! v4 O# R3 N
, r* Y4 Z6 ]$ W0 U5 v$ H& g, [PC13配置为中断模式,下降沿触发,上拉。
* U+ j$ F2 c5 u! a9 U) a4 c3 W- O% E" F- ^% O
7 M6 I& L- J/ ~) E+ O" L: j" k: ?& ?" i8 Z
中断分组设置,采用默认设置,抢占优先级0,子优先级0。
+ ~9 J n% }" q9 o: x# x" M: J
2 ^% q8 O0 [* \9 z( p1 i- i
" g& Z4 {8 L' J# Q% ?( x" N8 Y) ]3 \' m+ p3 ? E: v
中断优先级说明,线10到线15使用同一个中断优先级,PC13对应的是线13。! X" Q9 y* p" n! u3 w' a
9 v' ]8 ?/ V9 E+ q$ z' D# y$ W
* d" g# A' P) d; G
% w: g- O }( s9 z2.2 程序代码9 ]- ?/ ?* \0 P+ J- f
生成程序代码,系统自动对LED2和Button进行了初始化,并对Button对应的中断进行了分组和使能。$ u3 v! }+ s1 \( R# Q/ e+ B" B
+ ~2 x# x( `7 `6 d" K+ V
- void MX_GPIO_Init(void)2 _$ {) h0 d+ o2 W4 I4 K
- {9 W, o. s5 S+ D3 ]7 y$ B
- 9 u6 t" R R6 s+ j6 ?, z
- GPIO_InitTypeDef GPIO_InitStruct = {0};$ J3 L( ?) @- p( W: G$ R* w
- - }' e1 ~! X1 P: n* p
- /* GPIO Ports Clock Enable */
8 O3 x4 ?+ C% z8 @4 ^3 f - __HAL_RCC_GPIOC_CLK_ENABLE();7 V# @) I8 t7 B8 d) V6 }
- __HAL_RCC_GPIOA_CLK_ENABLE();
; F1 J! Z9 l- d9 f - % T& p$ x' Y( U$ t- |8 j
- /*Configure GPIO pin Output Level */
E" F ^2 ^3 L$ M: g0 s5 ] - HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);2 Q3 a$ F u9 x; E7 N1 i/ c0 j& R
. c% e8 S2 s9 S) X/ g- /*Configure GPIO pin : PtPin */7 S/ n+ N* ]" W: a( ^
- GPIO_InitStruct.Pin = Button_Pin;+ x r h) q2 z/ J
- GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;3 r. Y X6 c9 b
- GPIO_InitStruct.Pull = GPIO_PULLUP;
' i- {6 y0 U" w) H% X8 E - HAL_GPIO_Init(Button_GPIO_Port, &GPIO_InitStruct);# e4 ]3 {, R1 N) z; ^- t, V+ A
- ' D: ]5 {' ?) y; p8 f! h$ ~
- /*Configure GPIO pin : PtPin */
2 p; O) v6 S) Y* n& ~ - GPIO_InitStruct.Pin = LED2_Pin;6 X' S; T$ i5 e. }6 n
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- d% D8 O. {' s4 O( w o n$ @- `: M - GPIO_InitStruct.Pull = GPIO_PULLDOWN;' o! ^; o+ e* l% S8 y% u
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
" w# ]4 p' V4 h3 t/ ] - HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
4 A- h- B2 o8 b6 R& J7 J J- I# | - 0 X$ S: E) g' I2 s4 O+ B
- /* EXTI interrupt init*/% _! \7 R( @: E* R5 H, o. m5 k
- HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
. E' @! o& x$ G0 u - HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);) n3 @9 _7 t! Q/ W* }6 `# y
- 4 H$ P* g% q K
- }
复制代码
U: E( [4 O7 w) n# C% o在main函数中增加初始化LED2,让上电初始化时亮灯。
7 B2 ]( ^+ ~; |+ r4 \. T3 B( L1 h) ~9 P) Q4 U* S+ q* l' {- k
- HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET);//上电初始化将LED2灯点亮
复制代码
6 U* {( r8 {2 `& Y- F3 A6 R增加中断回调函数,当检测到中断时执行中断回调函数,翻转LED2灯的状态。
+ r% O7 {7 |- A* e, x* h
/ a3 L" E/ X1 |0 q4 C% @% f- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//中断回调函数,当有中断发生时,将LED2灯进行翻转- q4 K: `. f# a3 H
- { 0 s) X& X! O. v
- HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
) D; ]* \: g' [3 n - }
复制代码 8 K# _( H/ ^) F, Y2 M9 n8 ^
while(1)函数保留为空,编程到此完成。
7 a9 C* O8 D1 t( s实现过程分析。
& q* w4 F, _$ m# o. f7 z# o1、在stm32f1xx_it.c中定义了EXIT15-10中断服务函数。
9 H, n; d+ W9 p3 S
/ S6 O G4 Y+ Z' z, O- void EXTI15_10_IRQHandler(void)//中断处理函数,当检测到中断,即Button被按下时,检测到下降沿即为有效0 g6 K; I% s& }9 s
- {& L3 [) J: D- r1 c! h
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
. X- M% b" b: [# l/ m - }
复制代码
; k5 l& q% U* u; Q& h9 ^2、在stm32f1xx_hal_gpio.c中定义了HAL_GPIO_EXTI_IRQHandler。
, J! @& y) I {" {) [3 O& d, e/ _1 H% v3 f
- void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
& x! s4 g- ~ G+ D2 Q$ d - {- P" n' d- C @) @
- /* 检测到了中断 */6 x( w6 s c ~, k+ F7 @
- if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
0 v' p6 [+ d! l8 E - {
) A/ O2 ]! X9 f; N" m4 Z - __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);//清除中断状态% s# v+ u$ A4 j5 L$ F" o( r& a
- HAL_GPIO_EXTI_Callback(GPIO_Pin);//调用回调函数 ) O1 A7 q9 ~9 ^2 ~0 O
- }9 O* Y$ K8 k" `0 E w$ z
- }
复制代码 5 Z( O2 @, e! E2 R7 H: s2 ~/ A
3、在main函数中定义了回调函数HAL_GPIO_EXTI_Callback。
2 R# g( y, N8 @6 G1 Q: j4、当Button被按下时,1到3会依次执行。: Z+ d9 _. ~+ M/ T* Z4 S/ M6 R
T$ w) t2 g3 A: L+ O5 {
3 使用两次检测电平的方式- L$ V+ Q; @0 S- N
程序源代码如下,使用了gg=G VIm的自动调整格式功能,这个工具是真香,实现的功能是循环,当第一次按时,1S闪烁一次,再按一次时,500mS闪烁2次,按第三下时250mS闪烁4次。在写程序过程中同样用到了ALT +/的补全提示功能。2 R9 r) }4 k O g* y
& I4 c: D Q- X7 o/ m( n% G" ^
- while (1)8 M5 j/ U6 g `! T$ j6 ]; A
- {! s, v4 V; t& g! G6 i
- /* USER CODE END WHILE */
4 _1 K1 n: i! v# \ - if(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)==0)
. L* _* E6 B7 A# @. M- ^+ ]8 k# a - {6 F. P( q. k; ?( ?3 {$ \- S
- HAL_Delay(10);
0 p( s3 K$ |) K - if(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)==0)
( b S& H7 b5 {; t! w! g - {$ t- R; s' ~/ v5 K, h
- key=1;! |* b, i% H* G$ ?
- }
4 |# o& u( v4 ^! n5 l - else6 }3 u7 f3 [2 Q3 \1 M
- key=0;$ m* [% ], w4 ^% |
- }
: o, _7 W3 q c: }# k- D - while(key==1)
2 V5 u4 F1 y% z& [% I - {! j! O9 H& p' c9 o7 y: V
- switch(time)4 U! R! t9 R; X+ `7 X$ O5 E
- {
. A( l$ R8 ^" T: Z! }% q6 z - case 0:
; y* e3 G* S- i2 Z9 A0 g - for(int i=0;i<2;i++)
$ a. Y4 J& v! E6 v, B. H - {+ U$ a' m" \7 ]$ e; g; f, G( N) U1 [
- HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);//翻转LED灯
. ~: t9 l b8 v8 }, |4 `7 B, B& } - HAL_Delay(1000);//延迟1s3 y% s0 E6 h m( J
- key=0;) R. Z: r* F7 e9 W# q
- }
4 ]/ W& d! O" H; r/ [6 ? - break;
# R$ Y& Y! c6 b. H - case 1:( \: E" x4 G3 k! @* g3 A! C8 R
- for(int i=0;i<4;i++)
) v1 {( k5 y1 Q: s - {
# B& b4 J1 P) E- B - HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);//翻转LED灯3 p8 L7 Z/ `" Q" Y$ W
- HAL_Delay(500);//延迟1s
1 h# }$ e" z7 ~ - key=0;
4 }" F; ?4 @5 v2 e% Z! J2 r - }* J5 u- @: T) ^* ~" }# f! p& j
- break;
1 e' J/ T) X& C3 e - case 2:6 P, P" z! x* }
- for(int i=0;i<8;i++)9 s s$ M8 z1 K8 o" t
- {
; \' m1 {6 E4 @/ W0 t - HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);//翻转LED灯
) O* r) a+ V( {7 u: ?9 f - HAL_Delay(250);//延迟1s
% v5 w( ~3 i2 f/ N6 [ - key=0;, J- k+ K, ^, ]& a, o9 s# b' I
- }4 w# t: t, ~. V
- break;; {6 w$ Z* a- s
- default:break;: u4 @3 G5 m/ X; Z$ E: D
- }
$ Z7 r/ @1 U: C8 z9 f7 {. B' J - time++;
) s! u! M O. G8 a- } - if(time==3)2 q( [5 ^8 B# @2 Y9 i* f
- time=0;
0 L* x8 K9 h* U9 B - }7 n U" o/ Y6 x( ^. C) Q
- /* USER CODE BEGIN 3 */9 t9 [4 i U2 d, Q# u
- }
1 c! U7 q( ]; u+ F& _4 i, u - /* USER CODE END 3 */
+ g. Y9 J8 j1 V b$ N - }* D M1 \" I Y2 y9 K- a5 M
复制代码
% B; s3 ~. l+ a I: u4 实现结果
# K6 L2 |% V& A9 P+ ~上电后LED灯常亮,当有按键按下时,LED翻转状态。黑色按键是复位键Reset,蓝色按键是用户按键(PC13 Button)。
0 ~6 z+ r. F. ?" _+ K$ I3 \
# m$ c# m8 k* d
4 G8 z" t; {( i
+ h8 I# \; I+ K3 W1 Q' W% HTips:在使用中断时请务必配置好gpio的上下拉,若为下降沿触发,则配置为上拉。若为上升沿触发,则配置为下拉。否则有可能导致中断不可用。+ j7 t% [6 ~( V3 Q3 O% E3 J- G$ u# q
& x6 l# V) Q* a1 M
6 l1 d8 A$ e3 T( `- H9 m
8 I9 w; f# v5 v9 o% w0 I% q
|