我们板子第一次上电的时候看到的就是LED的闪烁实验,而且还可以通过按键来调整闪烁的频率,这个板载demo的效果,两个LED交替闪烁,一般板载的demo都是通过延时的方式实现的。这次我们将通过定时的方式实现两个LED的同频闪烁,通过外部中断的方式采集按键,调整同频闪烁的频率。1 G: r1 N5 S# Z* A5 u, s$ t
我们先看一下需要使用的硬件资源:4 f( O6 \, m- }" g7 Z
LED:
2 D8 Y5 B. |) |/ E" A& {* r
0 R9 K9 C! j" a6 c " V {) N1 F* H( k: _: E5 A
按键:
% c+ c9 m8 j7 T: `4 A
5 ~5 p0 J F) T/ P8 g 4 V0 \9 }: l+ p" ]6 v
GPIO的功能专注于具体引脚的实现,涵盖输入与输出两大核心方面。输入功能主要用于采集外部器件的状态信息(例如按键状态),而输出功能则实现对外部器件的有效控制(LED的控制)。本开发板装备了两个LED灯作为可操控的外部器件实例,同时配备一个用户按键,用于输入信号的检测。简单分析一下原理图,LD1事业绿灯,想要点亮需要PA5输出高电平,LD2为蓝灯,要点亮需要PC9输出低电平。按键按下的时候另一端是地,也就是低电平,所以对应PC13引脚的初始状态要为高电平,不过硬件中R34并没有连接,我们需要通过引脚配置内部上拉。
% F( Y6 q, ]+ O& B" ^ 定时器是MCU的内部模块,通过精准计数进行计时,这就涉及到时钟的配置来计算定时器参数。2 n6 E) s* T' \1 u) |: E4 O& N
接下来我们基于板卡创建工程:4 y; z& b0 c; t
) [/ o& M6 `9 y9 u- q3 R % v4 R7 M/ j* j) _! o2 Y
我们先看一下基于STM32Cube的模块配置,由于引脚的多样性,我们可以在引脚上直接操作:2 t% E/ _ K1 N" k. W- ` Y
2 |+ d ~/ ?+ U( n% }7 t$ E
) `; e; f) y" D5 k/ `+ M
接下来配置三个引脚,一个按键,两个LED:
- o1 T; Z$ |1 C: X$ f+ V
# i4 r: l7 R7 w5 i 1 P. C( ?) C- S0 Z9 E+ E
配置定时器模块前先看一下时钟配置,并修改为24M,最大支持48M:
: o) B& o9 D1 S% _% m5 [7 O
4 {6 h9 f5 C! z+ f; m( |1 M; l# a 4 X0 J& h: E0 }% P
接下来配置定时器,我们选用的是定时器14,是一个普通定时器,配置的参数也比较少,定时1ms:
8 u- r9 I1 e, j# \0 R! D( i6 o5 w5 Q
. Z/ R& {& V0 \$ T& R* Y/ Z
) c. `- l+ I) r* L# {# @ z0 G 接下来是中断配置,实际上我们在上面的具体模块配置的时候就可以进行中断配置,也可以统一开启:
) c& C- a3 o) h
* S6 N E) k. N& O; M% P
: P' p$ i: \( U& U5 _
到这里硬件方面的配置已经基本完成,我们开始软件方面的操作,实际上我们实现的功能也是非常基础了,初始化和定时处理部分都已经添加了:
+ X: d, E$ P s! v: i! T. `. u# Y5 S+ ~0 w6 \& f, a* _+ l
我们创建两个变量:
& o% H( x5 z% `/ Q0 r0 U
2 n8 F. |( r* `& k- uint16_t LED_TimeCnt_limit = 0;
% f, u/ t9 M/ [) G - uint16_t TimeCnt = 0;
复制代码 LED的闪烁就是通过判断TimeCnt是否等于或者大于LED_TimeCnt_limit进行LED的状态翻转。
7 z8 D! i9 A% i) J- l$ g7 {9 Q# R 我们需要做的就是编写对应的回调函数:
8 T$ e( y+ s9 B$ w5 \+ P" _& N5 J- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
6 w4 N1 i' Q% g4 X) n+ ^: |7 J - {
( l' @4 _9 g0 B2 d! \( D - if(GPIO_Pin == GPIO_PIN_13): G" E5 v5 C4 n; A" V4 Q) `
- {" q/ E' X% [: R+ M& F8 ?/ ~; P
- LED_TimeCnt_limit += 500;, w. \4 ?' s2 G4 L0 I" U
- TimeCnt = 0;$ G m8 Q8 i: g
- if(LED_TimeCnt_limit > 1500 )
( M' i8 d5 g* V: W0 s - LED_TimeCnt_limit = 500;
/ @1 C! V# k- t9 J. x2 `( X - }
" N! R" T& J8 _: | - }
7 g Q, C2 [! {. S( f; r( Z% a; H3 J
; ]8 K: o9 J# w( `- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)( |! Q! `4 r S+ a+ q8 g4 r
- {
' D7 v' V& S; n* j2 P - if (htim->Instance == TIM14) {
; v6 l4 {3 [1 p: I - HAL_IncTick();
1 |( \- j+ |3 J4 k3 c+ J, i% W6 o - TimeCnt++;
H; I) R. X [# T8 B( k9 U - if(TimeCnt > LED_TimeCnt_limit)
+ ~8 r7 Q$ h& E6 D- O3 |1 r - {; ^, F1 n& Q3 I% z8 H3 p1 H' ^
- HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
) s& ~, t$ B a/ u - HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
2 C6 S1 B2 Q4 Z - TimeCnt = 0;, g$ W/ G1 d5 _$ w! ~
- }
6 A* `3 K, l' a - }/ o7 e, p+ j. v: Y, ]4 K5 w5 ?) U4 T& K
- }
复制代码 这样我们就通过定时器实现的了LED的翻转控制,这个时候我们加入串口的控制,实在是串口和这种多模式的控制太搭了,我们可以通过串口实现同样的翻转控制命令,同时也可以通过串口打印当前状态,我们试一下加入模式变量,因为要实现同步控制,必须按键和串口命令控制的对象是同一个。 R" e, y* }& w# T0 k5 X* O8 O
配置串口2模块:
5 W" H/ e1 v' W0 R/ B( ^
. {0 K' s2 `# n! }% i7 H+ w * G& ~7 |! S) }% v0 T; V/ @
实际上在生成工程的的时候这个模块就配置了,估计当成必备选项了,行为这个串口连接的STlink:
9 G3 @2 W# Q4 B6 w; ?- j) a: S4 t2 Y
( H+ x, @; Z1 F$ E3 H
' }7 v- ]6 b, K% _2 _3 r6 P3 V
我们先实现一下printf打印功能,加入一下代码即可:! f4 j$ ~* V( Z* i
- #if defined(__ICCARM__)! \# { x2 x4 i7 b' X3 T
- __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);* ^! B5 k1 y2 }5 b2 w. L' ?
- #endif /* __ICCARM__ */
/ {2 y6 c+ W: {0 F; a$ N - & u- O* F1 ` V/ y
- #if defined(__ICCARM__)
5 ?7 @7 ?- }3 k+ N4 K" z0 ` - /* New definition from EWARM V9, compatible with EWARM8 */
. K/ D& l3 ~$ S( |) V - int iar_fputc(int ch);$ n) w3 E: n6 B& H5 x
- #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)
$ b3 D( Q h6 V$ k - #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)0 _7 P6 {: E; K+ {# C
- /* ARM Compiler 5/6*/
/ M+ @3 \/ m# |; h - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)- U' W: i+ z" B" P- R2 \. p% O( x
- #elif defined(__GNUC__)5 R% L9 |0 q5 b0 L1 X9 N$ i E u+ C
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch). Y3 I w, {: k' u2 a! C
- #endif /* __ICCARM__ */
复制代码 然后将printf与串口2关联:: V& V- [7 Y- x- N# m% O5 m4 V
- PUTCHAR_PROTOTYPE
r1 E! X+ j7 K3 v& v$ L - {% ]# I! d- T; D8 j& A' w6 Z
- /* Place your implementation of fputc here */, ~& T" ?- f* O1 I3 H
- /* e.g. write a character to the USART3 and Loop until the end of transmission */& l2 k+ @3 a4 p3 Z
- HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
: c7 s6 L% P5 i9 _* K/ F+ d - ' X( E5 m7 J$ e7 [
- return ch;
5 Z( F2 J; h- `, B7 ]- x5 G0 Z - }
复制代码 这个时候我们就可以用使用printf打印功能了。/ t( A+ k% k* v# |+ V6 s* D
串口的接收依然使用的是回调函数的方式,同时修改按键控制内容:
5 o& b: w; n. P" F- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
, G$ g; C+ K: ]4 e - {
9 @% a1 H, U7 a, L [, L- g - if(GPIO_Pin == GPIO_PIN_13)
0 ^ H3 A7 c8 ?% b& E2 ^4 P9 A - {% \8 f% k6 }8 e- @
- LED_Mode++;, M- }# y2 ~! d# U
" y" W. x) {; v- LED_TimeCnt_limit = 500+500*LED_Mode;
! |, F9 G0 [: L4 N0 D1 \5 n; t2 p. n' \$ H - TimeCnt = 0;# P- f$ [( _. r0 ~
- if(LED_TimeCnt_limit > 1500 )$ u/ {: [: O( i7 j
- {; y- W* t3 t6 t$ s- s3 _- y! n
- LED_Mode = 0;7 D4 i8 f5 _- b5 k' M+ r
- LED_TimeCnt_limit = 500;" E0 n/ N' H9 _. \$ Q. o# N7 z
- }
) ^( P* \0 G0 ~0 y9 W: A; x - printf("New Mode: %d\n\r",LED_Mode);8 ]5 \. ]* b f+ q" a) L
- } l3 g5 e5 a" R$ T
- }
% T( @( o2 w7 _8 [ - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)5 z4 R/ U, i5 L9 ]! x% J
- {0 @/ h% |, O- ~. N H8 F/ j" j
- if(huart->Instance==USART2)
1 A( C( S5 t9 I - {4 d1 b! |0 M U) m' q% c. q
- if(UART2_RXData == 0x00||UART2_RXData == 0x01 || UART2_RXData == 0x02)
1 `/ m/ V# F( Y. h! J - {
! \. e, F5 ]8 `5 \ - LED_Mode = UART2_RXData;
# k! E& _, B+ |* O% Q G - printf("New Mode: %d\n\r",LED_Mode);9 J4 _8 M [0 G) g# _( i
- LED_TimeCnt_limit = 500+500*LED_Mode;! E W8 D+ J: O' L2 ?9 E
- TimeCnt = 0;* e3 S& K) n0 M: X9 |! m# X# D
- }
: Z2 ~: `- A r2 m+ T1 `% |+ t+ X - HAL_UART_Receive_IT(&huart2, &UART2_RXData, 1);
( B/ @( w ]5 ?" m' m' v8 ?1 i - }5 O6 _) p( I: G8 R3 B4 F0 q
- }
复制代码 整体的效果如下,我们将操作过程和串口控制过程通过动图的方式进行展示:
1 [9 |" _( p& t( F
) S, n* h: d3 v# r
8 v6 F3 n: i9 C+ A, G
整个对应的串口反应:; I5 Z- f1 D0 `4 T6 D/ b" ~
( B6 a. a/ o% m4 N+ @9 r ^) l7 w
8 r! F2 ]1 r6 k6 O$ a U4 |% n. c- A" l; d
$ S1 c2 w9 H: Z* B2 m2 K* t' F, o G$ T
3 [" {5 e: }* }/ V
$ K) f2 o# L8 c( X/ K$ `4 H$ i0 f' C- [4 L: t
8 K0 Q$ X( \. o6 D! J0 z. A
" G/ V( D+ P o* L4 W# a! F% M' k7 j: y5 e. i" Y8 S
% D$ P( o* @( x' }, I+ u7 w7 ]2 s1 J2 {# g2 [: H: X
% n7 G2 Q/ e% d3 q- d" ~, @8 ~: F: q; ^7 f. o4 f$ k
' g/ b) s, d: w5 M1 [3 b$ d
) ~- f" G! w% Y8 U G$ E- ?) K& h+ c. i7 l2 \: h9 W
|