我们板子第一次上电的时候看到的就是LED的闪烁实验,而且还可以通过按键来调整闪烁的频率,这个板载demo的效果,两个LED交替闪烁,一般板载的demo都是通过延时的方式实现的。这次我们将通过定时的方式实现两个LED的同频闪烁,通过外部中断的方式采集按键,调整同频闪烁的频率。2 K' z5 s4 K# C
我们先看一下需要使用的硬件资源:$ G, o( L! E( h7 \
LED:1 K, M* e/ G) ]/ N7 ]
4 r. _# Y7 f. b* s4 i$ b
# I3 Z* V+ d$ S6 |6 o4 V 按键:% b5 k) e% T3 p) ?( w' f' _6 D7 Y
0 @3 `' U3 r9 B) n" C, d h1 X' o9 Q
3 ?$ K: E& _ V( }, V
GPIO的功能专注于具体引脚的实现,涵盖输入与输出两大核心方面。输入功能主要用于采集外部器件的状态信息(例如按键状态),而输出功能则实现对外部器件的有效控制(LED的控制)。本开发板装备了两个LED灯作为可操控的外部器件实例,同时配备一个用户按键,用于输入信号的检测。简单分析一下原理图,LD1事业绿灯,想要点亮需要PA5输出高电平,LD2为蓝灯,要点亮需要PC9输出低电平。按键按下的时候另一端是地,也就是低电平,所以对应PC13引脚的初始状态要为高电平,不过硬件中R34并没有连接,我们需要通过引脚配置内部上拉。
5 C; t( o" ^5 I 定时器是MCU的内部模块,通过精准计数进行计时,这就涉及到时钟的配置来计算定时器参数。8 M1 S( |9 X* M# O% ?$ \
接下来我们基于板卡创建工程:4 \! f! X4 p# \8 a
$ o* h# R v+ M! U" o
( K' D- P; G- {, ~3 q! |$ x 我们先看一下基于STM32Cube的模块配置,由于引脚的多样性,我们可以在引脚上直接操作:5 Y M- o( b2 \/ |* _2 J# @
3 ], r; ^' m1 [- O* K) E) n! e7 d
1 V4 r0 l6 C3 H: Y( a 接下来配置三个引脚,一个按键,两个LED:# H& g2 p* s6 E
$ y8 v* y; y2 w1 Q
) }9 z+ K8 U( @9 t, X 配置定时器模块前先看一下时钟配置,并修改为24M,最大支持48M:
1 M0 N2 m" s) l6 L, F$ `
: o1 A) W- R0 V. G4 ]$ p - {2 L1 k/ `5 h' x
接下来配置定时器,我们选用的是定时器14,是一个普通定时器,配置的参数也比较少,定时1ms:- t& Q, v4 u3 J' \
" \ y5 G% V8 o& S6 d, z" f
( u4 E7 z5 l$ f7 X8 s. q8 p 接下来是中断配置,实际上我们在上面的具体模块配置的时候就可以进行中断配置,也可以统一开启:7 \5 {: p9 o' H4 B9 h4 f8 m+ J
7 X& e4 `& i$ [1 b, z/ v6 A
0 n3 y" |2 f% ~; {- o$ v" O, | 到这里硬件方面的配置已经基本完成,我们开始软件方面的操作,实际上我们实现的功能也是非常基础了,初始化和定时处理部分都已经添加了:
' ^& V$ I4 |) K+ ]8 K' V# L a6 n
, {. k9 |8 I: }3 v% O; c 我们创建两个变量:$ |% j- |) F5 l0 f5 E3 L6 ~* R
/ \; A7 b1 L0 @2 \ _* z
- uint16_t LED_TimeCnt_limit = 0;% @3 Y, c% p% M- P
- uint16_t TimeCnt = 0;
复制代码 LED的闪烁就是通过判断TimeCnt是否等于或者大于LED_TimeCnt_limit进行LED的状态翻转。# L3 C0 m9 X5 r* z% o Z
我们需要做的就是编写对应的回调函数:
T; X% N1 N. @0 g- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)3 S5 z R* R/ X
- {
1 ?* w) N D- @4 x - if(GPIO_Pin == GPIO_PIN_13)
! C T4 H e) K4 l$ o3 \7 L - {
3 q: p" t0 f* ?$ O5 P! d9 [ - LED_TimeCnt_limit += 500;3 x' g4 `0 Y; ]/ x
- TimeCnt = 0;7 {% J6 T& x+ W
- if(LED_TimeCnt_limit > 1500 )
- [, N4 x+ M2 g" [) D$ f8 V* z - LED_TimeCnt_limit = 500;* j+ I3 v" O- g% v: n; c$ b
- }
9 g% M7 |6 j2 a - }
' O5 @. s' f* f- g. w
' c }8 ?& \* ^: N. f+ ^0 c- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
5 ^! a& W% P8 ^: p4 y' ]+ X - {* H/ I8 E- S5 K' ` |- z
- if (htim->Instance == TIM14) {
( M( m# M9 s8 [ ?& r - HAL_IncTick();
. V+ ~ j; k% q( }) ? - TimeCnt++;
! @2 l; K* a# @2 Y8 i% X5 ]+ R - if(TimeCnt > LED_TimeCnt_limit)
1 Q" Z m r& I3 i - {+ ]2 g9 v" S6 G: D, B. e
- HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);! [. F% h" k: W0 s" E* L
- HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
1 h$ E4 ^( o4 Q8 z# Y8 r J* } - TimeCnt = 0;
$ F# G$ Y! B9 W7 j; q1 T) w- @: u8 ^6 | - }
, Y' G8 k2 H' [ - }9 h% e; ]+ R) z$ o1 `' F( b
- }
复制代码 这样我们就通过定时器实现的了LED的翻转控制,这个时候我们加入串口的控制,实在是串口和这种多模式的控制太搭了,我们可以通过串口实现同样的翻转控制命令,同时也可以通过串口打印当前状态,我们试一下加入模式变量,因为要实现同步控制,必须按键和串口命令控制的对象是同一个。6 q- l: G7 h8 I/ _0 e
配置串口2模块:
% o5 l6 i" S( @5 s5 \
# f* K& i. z3 G
& Z$ j3 \# L2 X8 t* t/ Z( G' ~' S 实际上在生成工程的的时候这个模块就配置了,估计当成必备选项了,行为这个串口连接的STlink:
9 p7 J6 v/ v9 M# _/ @/ r
. K, O5 q6 |3 q
+ {1 W& a9 i! N) t2 O" ]1 q4 Q 我们先实现一下printf打印功能,加入一下代码即可:
2 g, l+ j( a, K" ^- O l. O* [( k- #if defined(__ICCARM__)
% u" ?) c: \) e - __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);
) w3 m/ S7 j8 y* V: @$ y" ~- B - #endif /* __ICCARM__ */
( x% T+ [5 s3 j2 `2 o
' x+ m+ ]4 K" D* R* X l2 b- #if defined(__ICCARM__)/ i; p4 z8 d# s3 p) K6 m8 i; w/ w
- /* New definition from EWARM V9, compatible with EWARM8 */
+ @3 D4 A$ }: X* p+ s - int iar_fputc(int ch);) g/ I: Z, E0 U; T+ G7 z+ B, A
- #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)/ j1 }3 R- \5 D, x3 a
- #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION)
0 }# s7 L* X, d, T - /* ARM Compiler 5/6*/: \2 L7 T, |. @& O5 k, e- J9 K
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
! h9 K9 U4 \9 U! B9 r - #elif defined(__GNUC__)
! `1 O8 i. D" N# E. ]! b - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)) }$ k9 C+ e5 T* i9 }' F* I# S
- #endif /* __ICCARM__ */
复制代码 然后将printf与串口2关联:
6 d" S" }5 D6 @ z: X, B- PUTCHAR_PROTOTYPE1 ~8 T d: w' ?, t% u. M
- {
) s6 e: C( U4 y$ R. L/ A - /* Place your implementation of fputc here */
7 C+ w$ W# r% {: Z6 _4 m - /* e.g. write a character to the USART3 and Loop until the end of transmission */; ]2 v0 ~) _7 Z" A! Z
- HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);9 Z5 P. O9 R) M$ r) B+ c- z
- / M6 e' s( M% g$ ~! Q
- return ch;* a# V& i; T) U7 V& w/ w* a, Q
- }
复制代码 这个时候我们就可以用使用printf打印功能了。* D7 M& G# T* T" N
串口的接收依然使用的是回调函数的方式,同时修改按键控制内容:
: X# r% u/ W( G9 m- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)& c+ c" n! M7 \
- {
- ~4 o! W1 }! i% O/ n - if(GPIO_Pin == GPIO_PIN_13)! v! r1 Y; {* I A' x
- {$ N8 i- t' |3 ]
- LED_Mode++; C" c* \* t: e) w! e; v5 ~2 V: a* p
1 [' R8 D+ A9 h" n6 ]* l- LED_TimeCnt_limit = 500+500*LED_Mode;
9 |/ z0 l& v) G& p6 l" v' F8 T - TimeCnt = 0;
. m% h# O+ u' D - if(LED_TimeCnt_limit > 1500 )+ R* b; r. ^- Q n2 a# M2 r5 X& Z
- {
+ K$ \. }7 Z9 {& x { - LED_Mode = 0;9 Z! x8 {+ u" G& \6 H/ N& {
- LED_TimeCnt_limit = 500;
9 [ p- ]! \2 @ - }* B' ?) v3 z) S
- printf("New Mode: %d\n\r",LED_Mode);
. A& a& X2 W; h& b, ~# J - }8 A+ ?2 R7 f: r7 h% q7 W5 B9 i+ ^
- }
4 Z5 o# O$ Y: E0 \ - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)# ] |6 a9 \$ R7 p" r
- {2 T0 t3 l% I1 J) V
- if(huart->Instance==USART2)# v/ ]4 [& d9 R
- {
2 @ t Q3 |$ S! k9 y5 J Z7 b - if(UART2_RXData == 0x00||UART2_RXData == 0x01 || UART2_RXData == 0x02), y" C$ A; |9 v0 P# i/ C
- {
8 a+ x% ^. T/ x - LED_Mode = UART2_RXData;
0 m2 M1 A; H2 c s+ {& b: A - printf("New Mode: %d\n\r",LED_Mode);# H4 d8 |8 ~; g# Y0 r/ }* t
- LED_TimeCnt_limit = 500+500*LED_Mode;" q ]( ]$ x B) M# ^ g/ _, q
- TimeCnt = 0;
% i: X5 L# F _- O: L9 Q4 Q - }/ B* U+ E: Y3 ^
- HAL_UART_Receive_IT(&huart2, &UART2_RXData, 1);: E9 [& b/ h0 D5 @! h8 Q- L3 n) b2 E
- }
5 x& f$ X6 g- ^7 i9 e3 U - }
复制代码 整体的效果如下,我们将操作过程和串口控制过程通过动图的方式进行展示:5 h3 a" {$ a6 n: o, l9 G( n5 }8 D
3 e1 P7 }0 M- R0 } P & b- b2 p) Z; i% z9 X8 a+ W
整个对应的串口反应:6 ` C3 h2 A' Q8 f; t m
* I& c, K1 H+ G" h0 a2 w3 r' ^ K3 E! n
) a2 ?3 a" ~: H; A2 T. t. P# g4 R' [9 o. P l& }# V! O) U
9 Z; o* p) w* |0 J/ a: G* e) s
1 N+ h! \/ o" w: E3 \9 |
7 j/ E4 Z5 Q# B: V1 u
2 t$ |* A# a! j! ]
0 }, d5 @5 m/ d5 y
0 f0 o5 {9 W. }6 Q5 K: g5 j5 d' h0 X" d$ ~8 L- H5 M5 J8 {" b
. z0 V. c5 G8 p3 w6 i- D- X( P; t
" b2 M9 }! Y# E( F* K. l( t6 `9 _" p6 V; {6 X1 f* }
3 X/ s" D. w+ t3 H3 W" B
7 Z% c( S# `! i. W2 l' e% f7 ]
) k1 A7 {; A% A' o6 p/ D
. W) P" Q# |1 l
|