G0外部中断框图% }# j8 {; F- R* ]
1 a U# h2 ]3 C" _2 h
: A4 Y3 c- N1 M( q' {- i% l% T1 W: `6 F3 M. D! `3 _0 V- e
扩展中断和事件控制器可以生成中断和事件,并将处理器从停止模式唤醒。 7 l$ `2 r6 r% @
9 b3 N# \# }) W$ E0 w$ `1 r4 c9 l中断来源
% |! p" _, ~3 I! l: B) {+ j可配置事件(Configurable events)来自GPIO,PVD以及比较器COMP1和COMP2的外部中断关联。
" ]5 L$ t d, w: \; x
0 t( [. t! m1 ]直接事件(Direct events)来自RTC,Tamper,I2C1,USARTS 1和2,CEC,LPUART1,LPTIM 1、2,LSE,UCPD 1、2。
! @; h; V! o5 l; ]' O% t6 V; }$ x2 H! z6 E B
GPIO 中断线定义
2 k0 k' t6 i C# Z' N# d# G+ VGPIOA~D有16条,GPIOF有4条。EXTI多路复用器输出可独立于EXTI_IMR和EXTI_EMR寄存器中定义的任何掩码使用。
, V2 f0 d: P/ L- R# p o" h7 ]" n! X
; a2 |0 Z( B5 }! _4 \
; s- J$ A- Q. X% \2 P& S/ q
8 [- O; n$ y, o9 X1 s+ e) ~! g% y EXTI 类型+ W6 A! Q+ I5 D- H4 U
" }% {, ~4 x: ^/ ]9 L6 {1 `* d
o0 d( Y4 H& h' `5 {
: E3 z) H6 C, O2 r1 _7 j( {外部中断实验
( G8 n* \4 A6 y3 `3 P8 C( x+ o新建芯片工程,找到对应的芯片,这里是G071C8T6;0 V0 B& v) _! X. X5 L1 `
SYS设置“Serial Wire”调试接口,RCC设置使用HSE;
( Y1 j( h3 S- _% s( ]+ @" l9 j设置时钟树,使用HSE、PLLCLK、HCLK=64(MHz),保持激活CSS;
3 M2 C5 q, h0 u2 x$ v6 ?& \- A/ e
) @6 a/ v$ Y+ s9 _, Z9 p2 [& Y
! K( |! w# @& r; J4 ~$ ]
设置PC6引脚为GPIO_Output,默认电平为低电平、开漏输出、不上下拉、速率低;
6 Q2 q1 E3 J$ F4 b! n7 a/ n6 ~0 ~) m2 ]) D3 d
' q- ?0 E/ B" r& v, A8 d" ~
! Z8 e( B! w) X* `3 |4 R
) ~& X* W1 m- g+ M( x& l
! w9 e* ?9 p" J9 z& n# r设置 PA0为外部中断GPIO_EXTI0,外部中断模式上升沿响应、下拉;% v- T/ l% V% f" U/ Y, Q
9 ?2 u. { t6 q1 ^% J* w; O
# u* r1 c1 I$ l
. B8 n2 j2 x3 Y, Q! Z8 ~. [ 在NVIC选项卡中,使能EXTI 0&1中断,设置优先级为2;
3 z7 O) a _5 E6 C& M5 U4 ?6 T- p3 N& C6 u* T$ S2 {" z; A
. l& R9 s) o" o1 Y/ u
1 p9 i* M, z( D* c
在project manager中,project里设置好工程名称,IDE软件为MDK-ARM,版本为V5;
/ {8 z( Y( ?4 j3 vcode generator,设置如下(如何设置参考),生成代码,使用mdk软件打开工程;
) |1 f2 P% A) D
2 j* q: y# B5 ~, a5 C- h6 M7 B+ ?. p4 V6 g! y
0 h) F1 R {) G8 \
在MDK软件debug中,勾上Reset and Run;3 g* S |, w1 v
代码讲解
}, x; t V# W+ O* _0 a) P在startup_stm32g071xx.s启动文件中可以看到,中断线0和1(PA0属于中断线0)使用EXTI0_1_IRQHandler函数;
% s! O, ~% n/ |& ^6 i7 ]stm32g0xx_it.c中我们可以找该函数原型void EXTI0_1_IRQHandler(void),编译后,烧录到芯片就能工作。我们可以在原型函数中编写代码,但是这样不利移植;
5 i2 x4 Y# j- A' n5 L# {- void EXTI0_1_IRQHandler(void)
* V: L1 y$ J4 _8 k' _ - {; ~+ t `5 Y* D' p
- /* USER CODE BEGIN EXTI0_1_IRQn 0 */% C: j! S' Z7 Z" }* j+ J: r& A
- HAL_Delay(10);4 A. c7 e! _ B' Y! }4 b, h& O
- if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)
$ I E: b7 B; C& M6 \ - {+ w5 ~* C) Y: K, N: P" W0 j+ t
- HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
# l& t+ K9 Q- H1 U3 B1 s - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6);( z9 d8 T6 ]0 e% O7 w4 n
- }6 l2 b9 j( a9 E7 {) N; M
- /* USER CODE END EXTI0_1_IRQn 0 */
, l2 y+ z- S% U/ l - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);" N6 a/ \* b7 Q) T
- /* USER CODE BEGIN EXTI0_1_IRQn 1 */
' y% N+ D2 J ^ H - /* USER CODE END EXTI0_1_IRQn 1 */
5 |- G0 N, r) E2 J' I - }
复制代码 ! m4 l, b1 H" W5 w7 W0 I5 ?
复原我们刚才写的代码,理清HAL库中函数之间的调用,中断函数原型调用HAL_GPIO_EXTI_IRQHandler(),这个函数用来清除中断标志位和判断是什么电平变化边沿调用对应的回调函数,所以需要我们手动编写回调函数;
) y* V! K h! C/ ~/ i' u$ J* R3 N' p2 T6 }: \
$ D9 P7 Z# ~2 ~- s0 m" d1 N
$ g3 p( r( x& O' a1 m. _/ n+ t* d 在main.c文件中,int main(){ }代码后面写上自己的HAL_GPIO_EXTI_Rising_Callback()回调函数,因为我们是上升沿触发,所以用上升沿回调函数;0 [6 m( z2 |5 ^& l! ^6 ~7 Y
在stm32g0xx_hal_gpio.c文件中找到回调函数,复制到main.c文件中,修改一下
4 W& s+ m, |: L3 z- /*
- r5 T& Y7 {" J+ U4 H5 B$ a4 T - *stm32g0xx_hal_gpio.c文件中的代码) q ^6 D) s% J- s# Q
- */4 s! N1 h. ?3 ^% ~# X6 ^ ?
- __weak void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)$ l6 q. K* k( d5 X
- {
( x7 O. M- t, y* F! _' I - /* Prevent unused argument(s) compilation warning */
: T# |6 h7 i3 ~5 u* K& ? - UNUSED(GPIO_Pin);. `( y J, n2 M6 g" W5 r
- " Z6 O* n5 A0 x) e Q
- /* NOTE: This function should not be modified, when the callback is needed,
- w2 v9 b- g3 ~* k' W - the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file" x' D+ k7 w/ d) e# E/ C, d! y
- */( R( O: b3 Q. `. n' q# \1 q* n
- }
复制代码 ( ^$ Q* e& [$ J! ^1 m
手动写的回调函数如下,最后编译,烧录即可。
) ^& e3 u: ~/ A. N: `. J- /* USER CODE BEGIN 4 */- U) V' z! @# d
- void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
) L- u7 w$ C) K9 [8 r - {. n \/ t# b# N6 o; d; ~( G2 H$ }/ m
- /* Prevent unused argument(s) compilation warning */
9 ]' O# i+ |7 e - UNUSED(GPIO_Pin);, [& u! V2 M; @& D
- HAL_Delay(10); //延时10ms,去抖动 S+ p7 |0 e5 T2 Y' @% e, a& E
- /*判断是不是PA0引脚中断并且PA0引脚处于高电平*/! B3 l, [5 f. }
- if(GPIO_Pin==GPIO_PIN_0&&HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)
0 G8 u( e# m2 L: w4 t - {
1 {/ X2 W, x% B3 y" x( i) K - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6); //翻转PC6引脚电平,达到闪烁效果; D6 b0 ?/ U/ O7 h. v
- }
% @7 r. _9 _% o: c, g7 g' S( s - }8 }+ b# r1 W, V1 {4 ]5 j
- /* USER CODE END 4 */
复制代码
' W; T/ u: Q; s4 z0 z中断初始化代码,被放在MX_GPIO_Init()中
' b1 d" e- I! { Z5 |. h- /*Configure GPIO pin : PA0 */2 r) o) P% i, t
- GPIO_InitStruct.Pin = GPIO_PIN_0;( z# X% K9 s1 ?& p/ @. N2 s% G: v
- GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;8 P. v5 r. H/ [2 K7 v
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
( h4 y& P! _2 T H6 w/ _3 h& I6 d - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);4 z& f. R- }9 _. N( n' f
- 7 r# x# t7 o4 ]7 a4 {% N' Z$ X
- /* EXTI interrupt init*/+ Y0 c9 e: r1 }5 C4 E
- HAL_NVIC_SetPriority(EXTI0_1_IRQn, 2, 0);
: p6 F. b6 o+ X$ u - HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
复制代码
/ C; ], X. C- V0 k. u硬件原理图. Z$ g* t; ]( s6 S% n6 P$ H
. x/ P/ r' E1 r1 N
4 ?$ P4 W0 Y# ]5 {* I0 j; }, a3 [- U3 E# @
|