我们板子第一次上电的时候看到的就是LED的闪烁实验,而且还可以通过按键来调整闪烁的频率,这个板载demo的效果,两个LED交替闪烁,一般板载的demo都是通过延时的方式实现的。这次我们将通过定时的方式实现两个LED的同频闪烁,通过外部中断的方式采集按键,调整同频闪烁的频率。2 D& P, B# A2 u/ ?5 H% a, F+ u s# s
我们先看一下需要使用的硬件资源:1 ]" N% r0 _; K( t
LED:
- a& N4 ~2 n# J* [/ c; l( Q
6 o% R8 f4 n, Y+ @3 \
+ L7 P2 `$ W( s0 @# l+ J* e( h 按键:
- f( U: h+ m1 m* l
g9 y; N# Y5 }( s: v( |0 z
3 `; O* p8 ~0 M$ t) ]
GPIO的功能专注于具体引脚的实现,涵盖输入与输出两大核心方面。输入功能主要用于采集外部器件的状态信息(例如按键状态),而输出功能则实现对外部器件的有效控制(LED的控制)。本开发板装备了两个LED灯作为可操控的外部器件实例,同时配备一个用户按键,用于输入信号的检测。简单分析一下原理图,LD1事业绿灯,想要点亮需要PA5输出高电平,LD2为蓝灯,要点亮需要PC9输出低电平。按键按下的时候另一端是地,也就是低电平,所以对应PC13引脚的初始状态要为高电平,不过硬件中R34并没有连接,我们需要通过引脚配置内部上拉。
3 {' K# j: M. D" A1 H 定时器是MCU的内部模块,通过精准计数进行计时,这就涉及到时钟的配置来计算定时器参数。
) D0 w" L2 ?; u$ F3 ~ 接下来我们基于板卡创建工程:% B' Z$ q) s: R; v1 X
8 J# ?5 {$ ~4 N T* y, k
; w2 w7 |- z {4 c6 P 我们先看一下基于STM32Cube的模块配置,由于引脚的多样性,我们可以在引脚上直接操作: E8 Q( ?8 E. O: ^9 @1 ?/ ]
t$ L9 }! y0 V; i
9 W4 j8 R/ S$ ] F7 S 接下来配置三个引脚,一个按键,两个LED:4 I+ a8 R: M8 h1 g @+ y) A
$ Q* M, z |" v2 `2 {
% H4 D5 P% }9 [/ C- n2 B$ X' k 配置定时器模块前先看一下时钟配置,并修改为24M,最大支持48M:) }0 V8 H3 l- b2 f% T- X+ {) r
; p. n& Q0 m/ A- _
: D1 ?2 a/ |- R8 P! v" ] 接下来配置定时器,我们选用的是定时器14,是一个普通定时器,配置的参数也比较少,定时1ms:
9 N( U& n0 y& |- w
& B+ z2 F% w$ _7 y
( d- X) s6 I9 v' O/ g" E$ J. @ 接下来是中断配置,实际上我们在上面的具体模块配置的时候就可以进行中断配置,也可以统一开启:
% p5 ~) ^1 z/ z% `+ n/ j% i* b! G
9 U- [1 [/ b0 T% N0 f6 w( U 3 i/ J) u- X* {/ T: t
到这里硬件方面的配置已经基本完成,我们开始软件方面的操作,实际上我们实现的功能也是非常基础了,初始化和定时处理部分都已经添加了:6 ?( U- _9 z- \4 O. n
# }5 O0 f, O9 i e/ L
我们创建两个变量:( o. j- v" d; C! W$ f1 n, m
9 O; w4 L; U9 R- v) r- r* L
- uint16_t LED_TimeCnt_limit = 0;
) |% ?# w1 L ]: e! H' V( \. i8 e - uint16_t TimeCnt = 0;
复制代码 LED的闪烁就是通过判断TimeCnt是否等于或者大于LED_TimeCnt_limit进行LED的状态翻转。
3 ^) n7 ]: Q( m! A+ m w L5 E4 ~ 我们需要做的就是编写对应的回调函数:
0 ~1 B! D6 N* _: z4 ^# M- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
! E7 ?2 v& z& K0 _ - {
7 N" d, O( ^3 i& H - if(GPIO_Pin == GPIO_PIN_13)
. `0 B4 ]7 b& G - {
9 f- [, r6 @9 p' F4 h - LED_TimeCnt_limit += 500;; f. Z9 w$ m3 V) v' c7 b
- TimeCnt = 0;) _' a7 Y, Z0 ?- u" z9 H. {( M
- if(LED_TimeCnt_limit > 1500 )- q- ]1 D( i* v$ t5 ^6 t# G
- LED_TimeCnt_limit = 500;
5 K( L! }5 O7 \+ F - }
# ~8 D( @# A7 W7 A3 \$ A& h0 [ - }
8 ^& i7 R# x _4 V9 C7 ~3 w2 ^( }
2 H3 R! O8 Z3 i4 X% T- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- p! N/ Q" B9 `0 U% N9 V - {+ |+ J+ r) f& ^! K9 p4 o. r V
- if (htim->Instance == TIM14) {
; }" u. N( h- Z" M7 B% D3 D; d+ C - HAL_IncTick();: n+ o/ W, ~# b6 j5 K
- TimeCnt++;" N) H, {" |9 X" h1 w
- if(TimeCnt > LED_TimeCnt_limit)
, j9 F( d4 e+ u; S0 x - {/ ` n0 U7 S4 P
- HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);2 k9 s' \6 V8 V; B; e2 t
- HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); w U9 u5 O- w# j P
- TimeCnt = 0;
3 M& x$ d; [, |, p9 i& S - }
$ r- a6 X/ q: q5 r: j+ [: @9 N - }
& o! j" j' h6 n% \ - }
复制代码 这样我们就通过定时器实现的了LED的翻转控制,这个时候我们加入串口的控制,实在是串口和这种多模式的控制太搭了,我们可以通过串口实现同样的翻转控制命令,同时也可以通过串口打印当前状态,我们试一下加入模式变量,因为要实现同步控制,必须按键和串口命令控制的对象是同一个。
4 k* G9 l }9 Q, K. b+ k 配置串口2模块:: Z- y0 }& z3 n6 K
" Z% B+ B A8 c. ]8 [
0 f9 i" `/ v) {" [) z
实际上在生成工程的的时候这个模块就配置了,估计当成必备选项了,行为这个串口连接的STlink:5 o6 Y' G W; p- k- m" D
. f6 [% n" o& O e7 [1 m6 a + l( Z5 r1 O6 g" P
我们先实现一下printf打印功能,加入一下代码即可:' o$ ?" F `3 L8 N. D- L% M
- #if defined(__ICCARM__)
7 l! n6 V6 [0 Z/ V$ J& b - __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);+ G& L! v: [1 E2 R; R+ M5 A# d# ~
- #endif /* __ICCARM__ */
# t7 V# q, X: ?
, g# j$ I" m1 r8 f+ u: \- g- #if defined(__ICCARM__)
( U& f. k) i' F D! P/ C - /* New definition from EWARM V9, compatible with EWARM8 */
/ _8 g' A9 q- e) k7 g) b' x9 S - int iar_fputc(int ch);
2 @ G" j7 c5 W; w m - #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)
7 _2 h, L2 L+ e: }9 B - #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)
+ L8 ~5 @4 J7 b/ u - /* ARM Compiler 5/6*/
2 t- V! L7 ^: p2 d5 e- N# ~5 U2 n- Z - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)2 S5 ?2 e( ~& N$ I% t9 A: Q
- #elif defined(__GNUC__)
0 c0 G- ~/ P0 ]$ V6 ` ^1 S2 k - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
G& w0 x) z2 h2 X @4 O - #endif /* __ICCARM__ */
复制代码 然后将printf与串口2关联:, E! Z0 B y; c |& |
- PUTCHAR_PROTOTYPE5 q9 J* k. N1 s6 W M
- {
" C* L9 t# T+ l+ Y9 [5 ]" o. t - /* Place your implementation of fputc here */
k6 r) l5 L; H - /* e.g. write a character to the USART3 and Loop until the end of transmission */
* Z4 P% ~8 @6 ?% R7 B* R - HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);. z; L; X/ J! S: p
# O- p9 N# Z5 y1 d- return ch;
/ ~5 [! A/ N% A5 |# M& ?7 q4 {1 q6 u - }
复制代码 这个时候我们就可以用使用printf打印功能了。
1 D' }) ~; _( B" p2 _8 W4 B 串口的接收依然使用的是回调函数的方式,同时修改按键控制内容:7 |, ]4 F$ ~; k3 {. e1 W+ m
- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
4 h2 S) G8 l4 R6 \' e - {
0 K6 K Y; O* e: P - if(GPIO_Pin == GPIO_PIN_13)
% u* G& U( W9 |. a - {
9 B" h' a2 S- s1 Y! t7 A$ ` - LED_Mode++;4 A" d+ m) z: J( X; D. W0 ?
- ) S$ q+ Y( F9 m2 T5 _- c
- LED_TimeCnt_limit = 500+500*LED_Mode;) O$ N7 C2 j% j8 x
- TimeCnt = 0;
w, H ~9 K/ x, H" H+ L, | - if(LED_TimeCnt_limit > 1500 )5 { H- U9 T9 v F
- {9 ? c% g+ ~, Z" O2 ?: y; `' ^: u
- LED_Mode = 0;: g6 q0 q: H$ U& [+ o$ E. p: L
- LED_TimeCnt_limit = 500;
+ y. S6 @( C3 U - }. a+ C: ~2 q1 j& O& P
- printf("New Mode: %d\n\r",LED_Mode);: o0 `% h ~3 g4 G0 O9 |& h: H
- }0 r' I% x3 g( C4 E3 I- Y7 V
- }3 {% Y# Y$ w9 E; M8 d5 `
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)2 T, P6 p' Z" ?6 g/ y
- {# ^, r+ b( Q+ k/ Y; v2 C7 u
- if(huart->Instance==USART2)
/ H% x6 Q! A. P x; s# r - {
) Q0 ^2 q, r8 }: z2 @ - if(UART2_RXData == 0x00||UART2_RXData == 0x01 || UART2_RXData == 0x02)+ z/ k/ `, g* `- j1 X# d! s
- {4 {# L( s8 W1 c9 N6 M8 B
- LED_Mode = UART2_RXData;
- _ J# n: B) |" ~; _7 C - printf("New Mode: %d\n\r",LED_Mode);
: a* O; d1 N+ @* O% g - LED_TimeCnt_limit = 500+500*LED_Mode;- G( `% R* k+ `9 o6 L
- TimeCnt = 0;
4 Y1 W' c/ q, H0 A. R& I - }- C& h( G7 A; n2 Y/ w n& B
- HAL_UART_Receive_IT(&huart2, &UART2_RXData, 1);& i( s0 u$ [" Y" h3 j6 f3 _
- }) L5 ?. ]& p0 W- F; h9 _
- }
复制代码 整体的效果如下,我们将操作过程和串口控制过程通过动图的方式进行展示:2 V- {* G2 }- h7 I& |' c7 V, f
: h% ^ Y# s- ]% Z
& g) A4 K1 y M8 {$ \ 整个对应的串口反应:
$ f# d; d- `, b7 x
* a- }9 o3 b1 F5 ^# W: t
6 v% `" @3 N; u* [2 N+ c$ D" ^& Z5 S
$ m* m* p5 n" c6 ~3 b5 m5 L1 i: S( ]6 O/ h1 n: K* d6 c8 S
- X) G, L2 \! p! L+ z8 X! u1 [+ p5 u+ h# O- [4 M4 |
% j) H' v `! |& w/ ?; b# [( i; \
6 p- }" s/ d- z C/ H. k$ B
+ S8 X4 @) ` E8 w
( G, I* ?3 G/ I4 @3 ?- v( R
# d0 b$ X) L7 C; W% m
2 C \; s) [. B8 t$ b. U' t: B* |# c5 ~: B1 ]% e" u( C8 T. R6 u. q \3 r
4 G! b5 C# {3 Q* f0 w
' {$ E$ Y0 H$ p( X/ ?
I: R: z2 i$ c" F. P# h; F2 O! L+ y
|