你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32C0评测】C071:GPIO+定时器+串口

[复制链接]
戈壁滩上的辉煌 发布时间:2025-5-10 23:38
       我们板子第一次上电的时候看到的就是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 |
1.png
  P' H2 G# D5 \) H" I& {: O

* L+ F1 J- R: O" i       按键:
; Q: `3 \" B4 x2 I2 z4 z0 o8 e
2.png
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 ^
3.png
# R1 B' N2 q2 R( i: w. d* R& Q
1 ~2 v0 a7 J" B' @7 V
       我们先看一下基于STM32Cube的模块配置,由于引脚的多样性,我们可以在引脚上直接操作:
& J6 i% ?# }: u4 @
4.png
) V. i2 g) l7 Q
' l0 l1 A9 O! T0 D" p: e, b' H0 M3 z
       接下来配置三个引脚,一个按键,两个LED:
" |* L; Q3 v8 o! t4 @: ~
5.png
/ {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
6.png
9 W" M! R" ?9 y
# D+ t) H! l) J: Z
       接下来配置定时器,我们选用的是定时器14,是一个普通定时器,配置的参数也比较少,定时1ms:0 j/ Z+ J, j6 W2 Y3 O! a
7.png " g: h" n; i7 K4 Q! S# ]7 q

; X* ]' E7 o) s( a       接下来是中断配置,实际上我们在上面的具体模块配置的时候就可以进行中断配置,也可以统一开启:
* o9 U. v' ^: b8 r7 B
8.png
# P2 w  K9 _3 g( K+ w

4 p4 f5 F( E! p0 S1 R       到这里硬件方面的配置已经基本完成,我们开始软件方面的操作,实际上我们实现的功能也是非常基础了,初始化和定时处理部分都已经添加了:+ n" \( ]/ r7 e5 ~3 g; }
9.png
2 J& a% m8 w5 b& @' ^1 b
       我们创建两个变量:! U! T5 B; x8 v) [  a1 ]

0 _7 ~7 P3 n  K- \: u
  1. uint16_t LED_TimeCnt_limit = 0;% F; u3 X4 ~' Y& Q
  2. 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( }# `
  1. void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)% p" T% T" t4 J$ T3 N
  2. {
    6 H. z9 x2 J5 }2 f6 U" K
  3.      if(GPIO_Pin == GPIO_PIN_13)
    1 ^6 {' [1 E0 a# u
  4.      {
    7 u" g" ~6 s" ?" c& ]0 T; `, F
  5.                 LED_TimeCnt_limit += 500;
    . r3 Y& e! a8 J1 \2 `3 ?
  6.                 TimeCnt = 0;: r, A$ T* O2 O8 O- G
  7.                 if(LED_TimeCnt_limit > 1500 )
    7 O% E1 H, l& F$ F# ?
  8.                     LED_TimeCnt_limit = 500;
    : W% R5 N( r4 x
  9.      }
    + m2 T# R6 k) l8 N) e5 z
  10. }' ?1 q, {' z6 p0 e- T
  11. + u! ], x2 K7 }( ]
  12. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)! ~) E- ^$ J  R  ?/ R6 r! \
  13. {
    " W* e/ P  ?9 x
  14.   if (htim->Instance == TIM14) {% ]* i' |( r% I) E- E
  15.     HAL_IncTick();
    3 X+ r* `4 k: g5 d
  16.         TimeCnt++;. q$ h! {5 U0 c  Q
  17.         if(TimeCnt > LED_TimeCnt_limit)
    ' S, p* ^+ r# h
  18.         {# @3 [  k$ E* |
  19.             HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
    8 h! Q/ v; Z" O8 n9 b5 ]
  20.             HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    ) o! \/ o6 d% A% ^8 \, o. A
  21.             TimeCnt = 0;' C: `% H* A( `. ?1 y' T' R  Z
  22.         }
    ' S! y$ s- V6 q& p
  23.   }% G4 f5 Y- y7 ?, Y& g( }: z$ I
  24. }
复制代码
      这样我们就通过定时器实现的了LED的翻转控制,这个时候我们加入串口的控制,实在是串口和这种多模式的控制太搭了,我们可以通过串口实现同样的翻转控制命令,同时也可以通过串口打印当前状态,我们试一下加入模式变量,因为要实现同步控制,必须按键和串口命令控制的对象是同一个。
; W5 b5 H# v7 C* p2 C       配置串口2模块:
: i7 h  V+ N7 P$ f* ?
10.png
+ [0 h+ G; O2 `+ }' w/ H  j2 v- M

. h' T; A/ M) h       实际上在生成工程的的时候这个模块就配置了,估计当成必备选项了,行为这个串口连接的STlink:
( Y, b" A7 E# U4 R( z) P
11.png
% ]* h( r: P  @: M
5 Y+ H4 D1 R4 _! f. r
       我们先实现一下printf打印功能,加入一下代码即可:5 f% L3 s* o$ U; T
  1. #if defined(__ICCARM__)5 M! R& B5 Z! U5 m% j" p
  2. __ATTRIBUTES size_t __write(int, const unsigned char *, size_t);
    " k' ~# m+ z2 b3 N% b
  3. #endif /* __ICCARM__ */
    + C. h6 \0 F+ ]

  4. ' u: B* s& S6 y! z' z7 T1 g; ?1 Z
  5. #if defined(__ICCARM__)7 [6 u" Z% u5 T0 N$ O4 H6 S+ i
  6. /* New definition from EWARM V9, compatible with EWARM8 */, ~$ S( [) I, T7 A9 y$ @
  7. int iar_fputc(int ch);
    ( Z5 ]/ R9 m) y5 [' ~; K
  8. #define PUTCHAR_PROTOTYPE int iar_fputc(int ch)% |6 q- o; X8 p9 [  q& B
  9. #elif defined ( __CC_ARM ) || defined(__ARMCC_VERSION); ?( k" I% S7 |" {" L, N/ P' j1 {% x
  10. /* ARM Compiler 5/6*/
    % w' n8 Z2 }+ S
  11. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    * T) d3 A7 j9 u( Z
  12. #elif defined(__GNUC__)6 y8 B5 Z( g/ l
  13. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)6 {" e3 ]. z% P. _
  14. #endif /* __ICCARM__ */
复制代码
      然后将printf与串口2关联:, z2 E! p# r' `+ i" L  w6 ]
  1. PUTCHAR_PROTOTYPE
    0 K# T. |6 q/ ]0 N' ]- P: x# N
  2. {
    2 k' x4 g; a, a" s
  3.   /* Place your implementation of fputc here */
    % H% `0 h8 h' E. p2 e  Q
  4.   /* e.g. write a character to the USART3 and Loop until the end of transmission */
    % D# }4 F! Y4 h& G" {- p3 ~
  5.   HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);! y* r8 k+ u( t# ]: c
  6. 5 w' w* Y  [' i* H
  7.   return ch;
    0 a$ q5 v; ?7 g
  8. }
复制代码
      这个时候我们就可以用使用printf打印功能了。
8 M* S' k4 t2 J$ i: z       串口的接收依然使用的是回调函数的方式,同时修改按键控制内容:
2 q1 [+ U# {5 _% {8 Q6 D
  1. void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)! N: P* g5 k- B' `; i$ v
  2. {
    * H  A. x/ j6 W. Z! m& i0 G% i
  3.      if(GPIO_Pin == GPIO_PIN_13)) Z" _2 c! A: e1 y' X7 N  A
  4.      {& P3 W, t, g7 P! {( K9 N3 ~
  5.                 LED_Mode++;/ O" a( A6 c6 |" Y# l
  6. " x1 T/ Q6 t) J/ k$ H8 i, Z3 X! g
  7.                 LED_TimeCnt_limit = 500+500*LED_Mode;
    ( J- |" E9 ]6 ]! A, k! {" v4 u
  8.                 TimeCnt = 0;0 O  c9 c9 k+ X8 X& z
  9.                 if(LED_TimeCnt_limit > 1500 ), J( W" n8 \  o' L, R
  10.                 {% l5 h4 B, \' l* q' A4 B6 q4 M0 J
  11.                     LED_Mode = 0;4 Q7 t3 E) A) W$ s9 G
  12.                     LED_TimeCnt_limit = 500;) y" ~0 ^- c# L& j+ j7 q7 s
  13.                 }7 l( ]2 ]+ I* x8 _8 S# L0 V
  14.                 printf("New Mode:    %d\n\r",LED_Mode);
    8 a. ^" F+ e9 M$ K/ M
  15.      }
    $ n, d+ W) _5 @5 I% ?/ A: F
  16. }
    7 o$ [# s; {& ]$ z
  17. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    1 v) S5 Y6 b3 U- ~2 a  x9 C
  18. {# A" C- J& n3 z: E
  19.     if(huart->Instance==USART2)# J  I- T7 J% R3 D
  20.   {
    3 n0 p1 p! I$ d: t& s
  21.             if(UART2_RXData == 0x00||UART2_RXData == 0x01 || UART2_RXData == 0x02)
    " v5 ?4 F" z; [  v
  22.             {
    ) F5 _0 t: J" F; K( C# h& |0 F
  23.                 LED_Mode = UART2_RXData;3 t. b2 i# ~/ g/ b7 o
  24.                 printf("New Mode:    %d\n\r",LED_Mode);
    8 N( l3 ]3 |3 E& i# [
  25.                 LED_TimeCnt_limit = 500+500*LED_Mode;  {5 }4 b3 X' R) R! g. f
  26.                 TimeCnt = 0;
    , P* {9 |' w# w2 Q
  27.             }% x7 L( c7 ^5 M, }1 p4 O0 Q
  28.             HAL_UART_Receive_IT(&huart2, &UART2_RXData, 1);
    $ I, u- O% A7 }1 O
  29.   }
      T: x0 h7 {- T  Q
  30. }
复制代码
      整体的效果如下,我们将操作过程和串口控制过程通过动图的方式进行展示:# @4 n# X8 ?' j4 G2 S  e) c3 n# o
74502b93f6b77b2dc011d0d08f253a74 (1).gif - 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/ ^
12.png   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: ~
赞 收藏 评论0 发布时间:2025-5-10 23:38

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版