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

STM32G0借助串口非空中断实现空闲中断的功能

[复制链接]
STMCU小助手 发布时间:2022-10-25 23:13
1 实现原理$ v+ I; Z# n& n
使用串口通信可实现数据帧的收发,完成机器人控制、采集数据的传输等任务。制定串口通信协议并定时发送一帧数据,常见的处理方法是利用空闲中断,但STM32 HAL库好像没有专用的空闲中断,自己实现起来比较麻烦,这里利用非空中断可以实现同样的功能,缺点是效率比较低,稳定性经过测试也还可以,如果有更好的思路欢迎提出。/ m; |& l. }; x  o
# t* [; m2 @; }2 B  t
1.1 制定串口通信协议+ w! r3 d4 O' [8 E: U/ [; U$ U5 K
制定串口通信协议时一帧数据的长度和内容可以自己定义,STM32的串口传输的数据类型为uint8_t,注意取值不要超过0-255,下面给出一个电机控制的串口通信协议表做示例0 T8 a! J, y! f8 d
1GE6C88([5_S2A7[2K0`AAP.png ! Q) u3 T: r& p% {- N+ P
1 i2 w5 Y5 ]* i7 Z. i
1.2 分析中间变量
1 Z, C  b! W/ m创建接收数组g_fUART1_Buf,其长度等于串口通信协议一帧的长度
8 A& n- E4 E( a- q) @+ Y) L创建接收一个字节的暂存变量g_fUART1_Byte,配置一个字节中断一次
, R3 Z; `; Q9 @3 r% [8 i1 _( e. F# P创建g_fNew_Pack用于主程序中判断是否接收到完整的一帧数据
& L, i6 z" |% y+ x7 Q3 Q* R创建g_fNew_Pack_Cnt记录成功接收一帧数据的次数,方便调试+ j8 N9 o- I6 o  n( \) ~9 c
  1. uint8_t g_fUART1_Byte = 0;- w+ m/ ^5 S- N/ v$ v5 E
  2. uint8_t g_fUART1_Buf[10] = {0};
    & X) C2 F3 o( ~' A. C- N+ j( w! {

  3. ) k8 ^& H: p% [7 ~+ a& F5 D
  4. uint8_t g_fNew_Pack = 0;
    ; n( {, `" m4 G4 x9 J% A3 \
  5. uint8_t g_fNew_Pack_Cnt = 0;
复制代码

/ @  b" [) l# z, X4 l& I1.3 接收数据的处理  e# i3 P/ e% z. `" t
新接收到的字节g_fUART1_Byte写入接收数组g_fUART1_Buf的末尾,每接收一个字节,就将前一个字节左移,保证新接收到的字节一直往数组里填充,当接收的字节超过接收数组的长度后,继续左移,去掉旧数据,填入新数据6 A& P- E! G5 \: U7 I; V. X" Q
8 e  R2 M7 S3 [9 S  v
20210317153926655.png
% i$ R: y$ V5 @4 C" y5 |- Y; ?- J5 Z
2 STM32CubeMX配置
9 {% Q% H) ]. \; c2.1 SWD调试接口配置

* Q( C6 P5 v: @% lSWD接口用于程序的下载、在线调试  z8 x% @4 m+ l, M6 |

/ u, L" a! p+ K1 z& n 20210317153912428.png
" A  [" P* ^: D
% F1 N$ W5 A5 G2.2 时钟树配置
, S. o" [8 ]" v# r5 |STM32G0系列内嵌高精度(±1%)RC振荡时钟,无需外部时钟,所以这里并未使能外部高速时钟,开发板上也没有焊接,直接在时钟树配置选项的HCLK输入64,配置最大的64MHz时钟频率即可。
% E* a! X4 w. O2 G
! I: L+ f# H7 r! Z# G 20210317154247720.png & E& ?1 L: k1 H, e
; Q8 F7 ]' R" z/ `- s3 ?0 @4 B1 \
2.3 UART1串口配置5 X( i/ d' U- N
UART1用于接收上文制定的串口通信协议,并开启非空中断& t% F5 E4 E- O7 u  @
$ {2 X, r9 M# p9 L- f2 p
20210317154445383.png $ Z4 V/ _9 R0 v7 }

/ ~: \7 Z! G7 I6 a5 W1 T
; {; i: l# M( @9 |% w4 {
. r* G; m+ X) K4 X4 H" @$ w9 P. x3 w2.4 生成工程

8 ~3 k, v% @1 }  T输入工程名,选择存放路径(不要有中文),选择IDE为MDK-ARM;只生成用到的文件(目的是提高工程编译速度,减少工程占用空间),并生成单独的.c/.h文件,点击生成代码
- K, Z: l: r+ u. R# z4 D  K7 y: n
20210317154512883.png
$ m' N, t' x4 X9 Q9 O4 p! v 20210317154512880.png % {4 f2 v0 S" q  t7 m5 A* B
" E" C& d# n6 w; u. t- j1 }8 C, w" \6 J. ^
3 添加用户代码5 w2 Q7 ~& J( N9 u( J! l* k
3.1 定义全局变量

; r8 R' m' S! f5 D7 C( P/ y# w2 W3 d
  1. /* USER CODE BEGIN PV */
    % ]2 V% a  q9 G
  2. uint8_t g_fUART1_Byte = 0;/ }$ W* T6 [& F1 s& p# ?  \; J
  3. uint8_t g_fUART1_Buf[10] = {0};
    8 w' t* R# E7 \) G5 U

  4. + {$ c0 E& k1 X* o* V, j, v
  5. uint8_t g_fNew_Pack = 0;
    ; l' j- |6 y( {. m0 t
  6. uint8_t g_fNew_Pack_Cnt = 0;& Z, B4 I# X' G6 p" _' _; N
  7. /* USER CODE END PV */
复制代码

7 s& R9 z3 n8 H  f9 u0 K3.2 UART1中断初始化$ n4 C& z2 J# ]6 p
  1.   /* USER CODE BEGIN 2 */
    & `5 n- q  u1 J- u; b6 V
  2.         HAL_UART_Receive_IT(&huart1, (uint8_t*)&g_fUART1_Byte, 1);  // 启动串口非空中断,第3个参数代表1一个字节中断一次
复制代码
6 y/ p7 J' b. T4 {/ z( l
3.3 UART1的printf重定向, a3 A5 A6 Q! M5 ]0 b7 Q# ]
  1. /* USER CODE BEGIN 0 */
    ( j# i8 d4 l# ^% j; M
  2. /* printf重定向 */
    7 t# m% Q% F2 {( o
  3. #include "stdio.h"
    2 d  K6 F, L( N" D/ F) P( k% M
  4. int fputc(int ch, FILE *f)' z6 ]- o- l3 S$ \" r
  5. {) }) b8 \7 N- E. |
  6.         uint8_t temp[1] = {ch};
    * c3 g2 m: j( o6 b
  7.         HAL_UART_Transmit(&huart1, temp, 1, 5); // huart1根据需要修改" Y, E+ V* J" X$ Q: L; k
  8.         return ch;" b% p) s& V- A
  9. }
复制代码
0 R2 P1 i6 j6 ~2 M
3.4 UART1回调函数

2 W  _1 F' g' [: A2 O
  1. /* USER CODE BEGIN 4 */* Y  Q! v# W0 Q# _4 y
  2. // 串口接收数据回调函数; L* z% X1 a& P4 H
  3. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 0 g' g) v. g3 @
  4. {
    ! t% R. V: B. }$ f$ v# T
  5.         if(huart -> Instance == huart1.Instance )
    3 @3 V, x7 j4 |2 R3 [- Q
  6.         {( d- V: h5 Y" U6 q
  7.             // 往接收数组里填新数据,即实现原理的1.3
    ) c& ?1 ^" I$ @( T
  8.                 for(int i=0;i<9;i++)
    ( ~9 t% Q0 _! D, N  X
  9.                 {
    8 X% s8 B6 _% Q  r9 R* r
  10.                         g_fUART1_Buf<i> = g_fUART1_Buf[i+1];# f% _& d9 N4 }' K6 A
  11.                 }
    3 D0 n; {) T+ n8 \* b- K0 o- ?* W- X- T
  12.                 g_fUART1_Buf[9] = g_fUART1_Byte;
    + o+ f% n: U* \8 Y# q, p
  13.                 if(g_fUART1_Buf[0]==0x5a && g_fUART1_Buf[9]==0xa5) {
    / G; W: Q" J3 v% v, U' q
  14.                         g_fNew_Pack = 1;// 成功接收一帧数据,刷新标志位
    4 f  P0 f* X" a9 k
  15.                 }
    7 w/ X) s: i4 Y8 v
  16.                 HAL_UART_Receive_IT(&huart1, (uint8_t*)&g_fUART1_Byte, 1);  ' N6 n8 |( X3 n+ P: h% k9 W9 n
  17.         }5 a2 n: S) a3 t/ d
  18. }% [* `  u  ^* o8 t3 X& T
  19. </i>
复制代码

; M8 K7 O" `6 c! W) r( ^( b; A3.5 接收数据的处理5 r* K* i9 u: j3 w' p7 p0 T! ~) q
  1. /* USER CODE BEGIN WHILE */
    " w; g" f& V2 {$ |5 G* z
  2.   while (1)" c; o4 {7 h- t2 g0 G2 w( X
  3.   {
    # Q9 d* U; e! J- @, D
  4.                 if(g_fNew_Pack) // 主程序中判断是否成功接收一帧数据, }& a7 l/ l  a7 u! j% Y1 S. P8 {
  5.          {: d5 c5 B! a' V- a
  6.                         g_fNew_Pack = 0; // 清除标志位
    $ C- g; B7 @  U  ^0 S9 U
  7.                         g_fNew_Pack_Cnt++;8 W/ _/ C$ y7 w- [; Q' W6 R
  8.                         printf("g_fNew_Pack_Cnt=%d\r\n",g_fNew_Pack_Cnt);// 输出成功接收一帧数据的次数
    9 t6 z9 o2 n$ N2 N; |
  9.                         for(int i=0;i<10;i++){
    , r; p) T4 E5 L* H
  10.                                 printf("%x ",g_fUART1_Buf);// 16进制输出接收到的一帧数据
    ! Y8 u: b% n1 J) T6 t! U- S
  11.                         }
    * r8 E# M/ ~# v& S, h5 D* V3 [
  12.                         printf("\r\n");
      c' {  \( x3 E/ F: M! I
  13.                         // uart1_handle(); // 串口1接收数据的处理函数,根据需求自己添加
    / ^4 j( v- E; E. d# p  S* d7 O

  14. 8 ?& j# y9 ^7 C% s: d3 D: R
  15.                 }
    6 i5 W4 h2 u! @$ q; N

  16. ) R6 P5 C5 f9 ?) x* H, Y/ R2 I
  17.     /* USER CODE END WHILE */
    3 z+ `- S! G4 Y$ r
  18. 1 w  p- d0 _' x. |
  19.     /* USER CODE BEGIN 3 */2 _6 S4 D" ?" x* ?; k! v
  20.   }
    # v$ `/ Y7 r3 Q7 r
复制代码

% ?/ |8 L# n, R! a4 效果演示' {" {" X3 h0 q) ~+ k/ @
gif中为方便演示,除了帧头帧尾,没有使用上文串口协议定义的内容,用11 22等数据(16进制)代替
+ J) L1 k& d+ J
7 y7 C- z# f6 O% \' Q% ` 20210317155825530.jpg 7 k% j& j; a3 I  {5 |
" L% P9 B4 Q$ s& d+ [; o
20210317155810731.gif 3 G' J- Q& v2 w

& E- c4 `5 P, U" E, ^1 T5 `————————————————: I( i8 H( h- r$ k
版权声明:周云川, b9 w( r  S6 P$ d/ M$ d

: R: y5 [5 X1 X/ e9 o0 Q' U8 K& m/ o7 O$ f, b0 V

" d2 l0 m( ~5 E/ b; z  y, F
20210317154445195.png
赞 收藏 评论0 发布时间:2022-10-25 23:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

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