我们板子第一次上电的时候看到的就是LED的闪烁实验,而且还可以通过按键来调整闪烁的频率,这个板载demo的效果,两个LED交替闪烁,一般板载的demo都是通过延时的方式实现的。这次我们将通过定时的方式实现两个LED的同频闪烁,通过外部中断的方式采集按键,调整同频闪烁的频率。* U( P# j* o9 w# a% t
我们先看一下需要使用的硬件资源:
# L& W& J2 _8 K5 f LED:2 t5 i/ b4 l! P6 |
P' H2 G# D5 \) H" I& {: O
* L+ F1 J- R: O" i 按键:
; Q: `3 \" B4 x2 I2 z4 z0 o8 e
4 G8 v- B+ w0 ]( {8 k. d, L J+ x/ g4 s- ]# O5 n* ^
GPIO的功能专注于具体引脚的实现,涵盖输入与输出两大核心方面。输入功能主要用于采集外部器件的状态信息(例如按键状态),而输出功能则实现对外部器件的有效控制(LED的控制)。本开发板装备了两个LED灯作为可操控的外部器件实例,同时配备一个用户按键,用于输入信号的检测。简单分析一下原理图,LD1事业绿灯,想要点亮需要PA5输出高电平,LD2为蓝灯,要点亮需要PC9输出低电平。按键按下的时候另一端是地,也就是低电平,所以对应PC13引脚的初始状态要为高电平,不过硬件中R34并没有连接,我们需要通过引脚配置内部上拉。% r! k) I7 A& ]7 J: l
定时器是MCU的内部模块,通过精准计数进行计时,这就涉及到时钟的配置来计算定时器参数。' B3 i6 c0 R0 L5 y _- x! J
接下来我们基于板卡创建工程:$ A3 k* _1 Z; _- p4 {9 t5 ^
# R1 B' N2 q2 R( i: w. d* R& Q 1 ~2 v0 a7 J" B' @7 V
我们先看一下基于STM32Cube的模块配置,由于引脚的多样性,我们可以在引脚上直接操作:
& J6 i% ?# }: u4 @
) V. i2 g) l7 Q ' l0 l1 A9 O! T0 D" p: e, b' H0 M3 z
接下来配置三个引脚,一个按键,两个LED:
" |* L; Q3 v8 o! t4 @: ~
/ {8 I+ h5 x9 F; A5 U ' K7 e N% e6 x9 N `$ ?8 b3 }
配置定时器模块前先看一下时钟配置,并修改为24M,最大支持48M:
3 J6 h8 ~/ F8 V2 D: v2 l
9 W" M! R" ?9 y # D+ t) H! l) J: Z
接下来配置定时器,我们选用的是定时器14,是一个普通定时器,配置的参数也比较少,定时1ms:0 j/ Z+ J, j6 W2 Y3 O! a
" g: h" n; i7 K4 Q! S# ]7 q
; X* ]' E7 o) s( a 接下来是中断配置,实际上我们在上面的具体模块配置的时候就可以进行中断配置,也可以统一开启:
* o9 U. v' ^: b8 r7 B
# P2 w K9 _3 g( K+ w
4 p4 f5 F( E! p0 S1 R 到这里硬件方面的配置已经基本完成,我们开始软件方面的操作,实际上我们实现的功能也是非常基础了,初始化和定时处理部分都已经添加了:+ n" \( ]/ r7 e5 ~3 g; }
2 J& a% m8 w5 b& @' ^1 b
我们创建两个变量:! U! T5 B; x8 v) [ a1 ]
0 _7 ~7 P3 n K- \: u- uint16_t LED_TimeCnt_limit = 0;% F; u3 X4 ~' Y& Q
- uint16_t TimeCnt = 0;
复制代码 LED的闪烁就是通过判断TimeCnt是否等于或者大于LED_TimeCnt_limit进行LED的状态翻转。
: g9 o S. y. {! g) K 我们需要做的就是编写对应的回调函数:$ N% h$ S3 E c& M' R0 F& f( }# `
- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)% p" T% T" t4 J$ T3 N
- {
6 H. z9 x2 J5 }2 f6 U" K - if(GPIO_Pin == GPIO_PIN_13)
1 ^6 {' [1 E0 a# u - {
7 u" g" ~6 s" ?" c& ]0 T; `, F - LED_TimeCnt_limit += 500;
. r3 Y& e! a8 J1 \2 `3 ? - TimeCnt = 0;: r, A$ T* O2 O8 O- G
- if(LED_TimeCnt_limit > 1500 )
7 O% E1 H, l& F$ F# ? - LED_TimeCnt_limit = 500;
: W% R5 N( r4 x - }
+ m2 T# R6 k) l8 N) e5 z - }' ?1 q, {' z6 p0 e- T
- + u! ], x2 K7 }( ]
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)! ~) E- ^$ J R ?/ R6 r! \
- {
" W* e/ P ?9 x - if (htim->Instance == TIM14) {% ]* i' |( r% I) E- E
- HAL_IncTick();
3 X+ r* `4 k: g5 d - TimeCnt++;. q$ h! {5 U0 c Q
- if(TimeCnt > LED_TimeCnt_limit)
' S, p* ^+ r# h - {# @3 [ k$ E* |
- HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
8 h! Q/ v; Z" O8 n9 b5 ] - HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
) o! \/ o6 d% A% ^8 \, o. A - TimeCnt = 0;' C: `% H* A( `. ?1 y' T' R Z
- }
' S! y$ s- V6 q& p - }% G4 f5 Y- y7 ?, Y& g( }: z$ I
- }
复制代码 这样我们就通过定时器实现的了LED的翻转控制,这个时候我们加入串口的控制,实在是串口和这种多模式的控制太搭了,我们可以通过串口实现同样的翻转控制命令,同时也可以通过串口打印当前状态,我们试一下加入模式变量,因为要实现同步控制,必须按键和串口命令控制的对象是同一个。
; W5 b5 H# v7 C* p2 C 配置串口2模块:
: i7 h V+ N7 P$ f* ?
+ [0 h+ G; O2 `+ }' w/ H j2 v- M
. h' T; A/ M) h 实际上在生成工程的的时候这个模块就配置了,估计当成必备选项了,行为这个串口连接的STlink:
( Y, b" A7 E# U4 R( z) P
% ]* h( r: P @: M 5 Y+ H4 D1 R4 _! f. r
我们先实现一下printf打印功能,加入一下代码即可:5 f% L3 s* o$ U; T
- #if defined(__ICCARM__)5 M! R& B5 Z! U5 m% j" p
- __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);
" k' ~# m+ z2 b3 N% b - #endif /* __ICCARM__ */
+ C. h6 \0 F+ ]
' u: B* s& S6 y! z' z7 T1 g; ?1 Z- #if defined(__ICCARM__)7 [6 u" Z% u5 T0 N$ O4 H6 S+ i
- /* New definition from EWARM V9, compatible with EWARM8 */, ~$ S( [) I, T7 A9 y$ @
- int iar_fputc(int ch);
( Z5 ]/ R9 m) y5 [' ~; K - #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)% |6 q- o; X8 p9 [ q& B
- #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION); ?( k" I% S7 |" {" L, N/ P' j1 {% x
- /* ARM Compiler 5/6*/
% w' n8 Z2 }+ S - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
* T) d3 A7 j9 u( Z - #elif defined(__GNUC__)6 y8 B5 Z( g/ l
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)6 {" e3 ]. z% P. _
- #endif /* __ICCARM__ */
复制代码 然后将printf与串口2关联:, z2 E! p# r' `+ i" L w6 ]
- PUTCHAR_PROTOTYPE
0 K# T. |6 q/ ]0 N' ]- P: x# N - {
2 k' x4 g; a, a" s - /* Place your implementation of fputc here */
% H% `0 h8 h' E. p2 e Q - /* e.g. write a character to the USART3 and Loop until the end of transmission */
% D# }4 F! Y4 h& G" {- p3 ~ - HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);! y* r8 k+ u( t# ]: c
- 5 w' w* Y [' i* H
- return ch;
0 a$ q5 v; ?7 g - }
复制代码 这个时候我们就可以用使用printf打印功能了。
8 M* S' k4 t2 J$ i: z 串口的接收依然使用的是回调函数的方式,同时修改按键控制内容:
2 q1 [+ U# {5 _% {8 Q6 D- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)! N: P* g5 k- B' `; i$ v
- {
* H A. x/ j6 W. Z! m& i0 G% i - if(GPIO_Pin == GPIO_PIN_13)) Z" _2 c! A: e1 y' X7 N A
- {& P3 W, t, g7 P! {( K9 N3 ~
- LED_Mode++;/ O" a( A6 c6 |" Y# l
- " x1 T/ Q6 t) J/ k$ H8 i, Z3 X! g
- LED_TimeCnt_limit = 500+500*LED_Mode;
( J- |" E9 ]6 ]! A, k! {" v4 u - TimeCnt = 0;0 O c9 c9 k+ X8 X& z
- if(LED_TimeCnt_limit > 1500 ), J( W" n8 \ o' L, R
- {% l5 h4 B, \' l* q' A4 B6 q4 M0 J
- LED_Mode = 0;4 Q7 t3 E) A) W$ s9 G
- LED_TimeCnt_limit = 500;) y" ~0 ^- c# L& j+ j7 q7 s
- }7 l( ]2 ]+ I* x8 _8 S# L0 V
- printf("New Mode: %d\n\r",LED_Mode);
8 a. ^" F+ e9 M$ K/ M - }
$ n, d+ W) _5 @5 I% ?/ A: F - }
7 o$ [# s; {& ]$ z - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
1 v) S5 Y6 b3 U- ~2 a x9 C - {# A" C- J& n3 z: E
- if(huart->Instance==USART2)# J I- T7 J% R3 D
- {
3 n0 p1 p! I$ d: t& s - if(UART2_RXData == 0x00||UART2_RXData == 0x01 || UART2_RXData == 0x02)
" v5 ?4 F" z; [ v - {
) F5 _0 t: J" F; K( C# h& |0 F - LED_Mode = UART2_RXData;3 t. b2 i# ~/ g/ b7 o
- printf("New Mode: %d\n\r",LED_Mode);
8 N( l3 ]3 |3 E& i# [ - LED_TimeCnt_limit = 500+500*LED_Mode; {5 }4 b3 X' R) R! g. f
- TimeCnt = 0;
, P* {9 |' w# w2 Q - }% x7 L( c7 ^5 M, }1 p4 O0 Q
- HAL_UART_Receive_IT(&huart2, &UART2_RXData, 1);
$ I, u- O% A7 }1 O - }
T: x0 h7 {- T Q - }
复制代码 整体的效果如下,我们将操作过程和串口控制过程通过动图的方式进行展示:# @4 n# X8 ?' j4 G2 S e) c3 n# o
- o' W. @5 e2 c8 x$ h
) u9 E5 h7 V* Z8 m: a5 F; U
整个对应的串口反应:$ q; j7 e: V, f# _4 u1 X) y/ ^
e8 P; S0 b2 w5 d& t: k) b8 p1 K
0 ]* K4 f E, E: K2 |( O
4 M+ P5 s4 l+ @4 V8 ~6 Y* H: w7 [+ x3 K* \) Z7 u4 ^
7 ~& t0 O8 K* D' l0 z- z" d
$ v, v$ X+ B0 [- Z: [1 p' J; i' f2 r$ x% \2 W: [. g- \% W: @( ]
5 v- o [/ e q" X
) @% ~3 z& E' h: x( g' F& s/ a# d
9 ?% E& X: s0 g# a+ o' T2 A
* J) s0 S. {1 A B6 F* L7 N
4 {; W9 C4 c% L/ P( ^$ m, z7 t. P0 ^- t6 ~
9 }' F; z# X) j0 I4 ?0 ?
& ?5 J6 ^4 t: ~3 {3 B
* |( }: E8 v5 A4 l& R K; M$ ^: o: ~
|