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

谈一谈STM32串口通信时,自定义协议问题

[复制链接]
只取一瓢 发布时间:2020-10-23 09:49
先说一下我想要实现的功能:- @, x# X) c% z4 c3 @1 Z
通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。- _3 `$ V. F* s' R; V; N7 A; b; n
自定义的通信协议如下:
$ H1 d6 j, s1 rAA  01  01  02  BB5 Z, d6 u5 ^6 s
AA —— 帧头0 r9 D3 z# F6 f) S/ M
01  —— 地址
$ q; i- b& W; |+ B01  —— 控制字(是01就点亮LED,是00就熄灭LED)
- m& {1 a2 \. b- x1 Q) f/ r6 ?8 ^02  —— 校验和(地址+控制字)/ _$ T- b, f$ V6 [$ _
BB —— 帧尾8 d" K; r; y0 w' _, T4 W
' F8 y/ H8 g  w3 i1 v3 g
今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。2 F6 H( S( N9 Q
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;  k" U" R) W1 l$ n0 U& N
你准备好了吗?接下来跟着我的节奏开始.......
: F. i5 k, w/ N' k1 C第一步:替换中断服务函数;
' g) P2 ]. B; T& B把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到), y9 m! S5 Z/ n& j' O0 p
  1. void USART1_IRQHandler(void)                  
    3 K0 y8 N% q$ j1 E3 Y8 |6 E
  2. {
      g# b) K$ A& J" ]! m' F" N7 u3 T5 W
  3.   u8 Res;//临时变量,存放串口接收的数据$ f# z7 d0 L4 [. K9 u$ V2 o
  4. ! i0 m6 ^/ c9 `5 p. {  h, o, Q7 }
  5.   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断* ], [9 M- D/ x  T  z3 W
  6.   {. n9 i9 G8 r; k0 t
  7.     Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据
    3 m; w) O7 ]5 \
  8.     if(rx_stack.head_flag==1)//收到了帧头
    # A% \4 _1 n: E; u1 ^# |
  9.     {9 A8 t; }9 L* \& p$ {# B0 l
  10.         if(Res==0xBB)//判断当前值是不是帧尾
    , @" ^* z2 G4 k7 q' l5 Y, E" t
  11.         {" d# [9 y. t& Z: \
  12.           rx_stack.finish_flag = 1;/ \7 A+ X* h' Z1 t
  13.           rx_stack.tail_flag=1;* L5 h" i) C; i: \& p4 x
  14.           rx_stack.head_flag=0;
    : z; f* `* \) Q5 Z
  15.         }/ ^9 P# e! [( K3 B7 p: @0 o3 V
  16.         else! l9 w( P$ f% f' B9 m( w1 ~1 W
  17.         {
    ) I# c0 q% a6 G7 }
  18.           rx_stack.recevie_data[rx_stack.data_pt] = Res;
    ; s. Z% \; ?8 T) ]( ?5 N7 k
  19.           rx_stack.data_pt++;
    ) K' A' ?1 C6 k$ y6 i; J
  20.           if(rx_stack.data_pt > 9)
    % z! c6 M$ f# ~4 x# u
  21.           {) J, h3 y+ x; t& J
  22.             rx_stack.data_pt = 0;# N% S" `; `' W5 }7 r
  23.           }' P& P: z( V3 K# h5 ~8 d- w' ~
  24.         }                  ) E# b; J9 \3 @) ?
  25.     }
    $ i# c0 G( r+ x. q
  26.     else//没有收到帧头
    % D5 p! I& t8 v& N' U6 d9 M
  27.     {
      w+ o5 r+ a& q# d
  28.       if(Res==rx_stack.head)* l6 u0 y  `& S! k# a: B5 M3 v3 u
  29.         rx_stack.head_flag=1;' p0 g: {7 }8 u9 K
  30.       else% ~8 t+ Q+ g; Z' ~1 `
  31.       {
    / ?- s* a9 Y6 A6 T* m
  32.         CommClr();) J1 Y1 Q! @9 t8 C* `" c
  33.         return;  
    ' H2 [; ~" @2 g+ m  L
  34.       }  5 T  r9 A8 g! K4 V: m, t- O+ @
  35.     }    % F: B2 ]; Y: n) ?. a: n, |
  36.   }
    : j0 r. R8 c0 e8 G1 \: e8 W! f; u
  37.   USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
    2 h. i! v2 B, E; t% \
  38. }
复制代码
到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......' k- R4 \3 _3 ^# E
( ~  u/ L; I" Q6 K" b
第二步:添加自定义的函数- o1 p4 n' _/ ]

  1. # P; \4 _' f6 @( y" P% u9 `
  2. void rx_stack_init()" A9 y' t. w1 v
  3. {/ f; ^' T1 a4 H( k( A' E
  4.     rx_stack.head = 0xAA;         //协议栈头,起始位
    & N( }5 C4 ^  N. u
  5.     rx_stack.addr=0x01;           //从机地址9 b( }+ _/ g( _# ?& a
  6.     memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    1 P3 U& @6 ?( I# C2 l" u3 X
  7.     rx_stack.tail = 0xBB;         //协议栈尾,结束位! l5 f/ ]; X& u4 u
  8.     rx_stack.head_flag = 0;: Q2 e9 C* b: c' ]. U8 K. T
  9.     rx_stack.tail_flag = 0;7 |2 r! {* ^) G  w
  10.     rx_stack.finish_flag = 0;
    , @+ x* g# b$ k/ n
  11. //  rx_stack.lock_flag = 0;
      _$ {0 X  }5 G6 Q* P3 ]2 P  c# z, P
  12.     rx_stack.data_pt = 0;* w& |: w! R6 g  r
  13. }: n# V- s5 [5 n7 s2 {; f
  14. struct receive_stack rx_stack;% E9 k' J. w/ P& X
  15. . r: T# A6 }! v; p+ M
  16. void CommClr(void)
    # y6 h+ ?. u4 A4 N
  17. {
    . |$ M9 p; o' W( d, r: d0 t8 q4 \2 @
  18.   rx_stack.head_flag = 0;% h* f7 ]) D! |/ A( p6 J
  19.   rx_stack.tail_flag = 0;
    , v9 [3 w+ o9 T4 V/ s6 H6 d
  20.   rx_stack.finish_flag = 0;
    $ A9 v& P9 l& l6 c
  21.   rx_stack.data_pt = 0;! d: @3 w# q* x& L1 S* \6 t1 ^) N
  22.   ( V% [  x: J, X
  23.   memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
      N7 c3 h  S/ |: m$ Q! N
  24.   rx_stack.commPack_OK_flag=0;* d' b% f2 [& X
  25. }
复制代码

9 K( `6 C7 B6 p& G0 p/ K! @把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......
$ T2 Z! V) C( j( i& p
9 h+ d, s% ]1 c# [  ^3 B- J第三步:自定义函数的声明(可以在usart.h文件中进行声明)
2 a1 }) [7 J7 r5 A! u& x- U& k
声明自定义的结构体变量:! L* o8 ~8 z9 t" x$ \, n

$ p' y" E, J" |: v- [7 R
  1. struct receive_stack
    3 [# s9 H7 V. H* u3 ^: e
  2. {- Z, O) r+ \* L5 M! s- j
  3.     u8 head;//帧头
    ! P2 J3 T9 B% i" e( n8 o
  4.     u8 addr;//从机地址3 x) @3 ?5 y+ l  Z& W
  5.     u8 recevie_data[10];//数据  f1 M7 U& u+ f( S" V
  6.     u8 check;//校验; W% E2 `3 b8 N! `+ L& ]
  7.     u8 tail;//帧尾
    + f, |4 G+ N- R5 d1 J: K" p
  8.     u8 head_flag;//接收到帧头标志位
    7 _9 }; ]3 J& ]4 O% h+ Y* p3 p
  9.     u8 tail_flag;//接收到帧尾标志位
    & ~( ?  @2 L) U$ M  B/ S2 f' Q, j
  10.     u8 finish_flag;//接收完成标志位. w) A0 D( D* I/ s: B
  11.     u8 data_pt;//已接收的字节数
    , J. j5 d$ x3 L1 G( U& H6 n/ b
  12.     u8 commPack_OK_flag;//数据解包完成标志
    0 {+ m/ Z' V; y" m
  13. };
    ; A# d' c8 M: |
  14. extern struct receive_stack rx_stack;
复制代码

! Y/ [; b, X3 E% |& ]4 E( Y6 q2 Z声明上文中自定义的两个函数:5 S/ g) q8 m# z1 a4 M
  1. void rx_stack_init(void);4 U# t) m8 C' T9 h: b2 F9 s
  2. void CommClr(void);
复制代码

& P+ J  T9 H$ c6 S' g现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void  _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?. a. N! I  E2 Y

' Y- J. A9 N- ~5 y第四步:验证是不是能正确返回数据1 U  M* z/ ~* o& m# A* L- N7 R2 a

2 M5 [! k. [8 y8 |" `" O; F2 {仿照第二步在usart.c中添加串口发送函数) `+ H: K- l, @0 ~

$ ~, u- w  i+ b; _! I
  1. void usart_send(u8 byte): q1 S$ o' S- X/ D: v
  2. {: Q# P& y4 K# F1 h  s) N
  3.   USART_SendData(USART1,byte);
    7 \+ I+ i0 I  q( |% ]
  4.   while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位
    4 e1 j& R; z# R+ v' G- w$ L
  5. }
复制代码
/ ^9 v- }5 m6 d' C7 K* w( E. k
别忘记声明这个函数;; A( S6 e8 K# R% m2 }7 E
0 F6 O# L& W9 Y& N/ f0 ]3 }! j
第五步:写主函数/ r4 [# g1 c$ B6 c" i9 Z9 q% n
  1. int main(void); z+ G+ v" ?9 H. Z2 B4 v
  2. { # E. u8 n' t6 p

  3. , [; A: g7 ]' B/ O: Y! U
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组27 g; Z5 ?( \7 |, d, h: G- M: R5 x
  5.   delay_init(168);    //延时初始化 * x! E; K+ p% M' f: Q4 y, s
  6.   uart_init(9600);  //串口初始化波特率为115200. b% i5 U. h; i+ J
  7.   LED_Init();          //初始化与LED连接的硬件接口  
    ! d8 }% f6 r2 b: \
  8.   while(1)1 `* T( w. L2 X; v, m# S# H
  9.   {
    ( [% C! f$ |) x
  10.     u8 i;
    ! a+ c( }$ i$ |
  11.     u8 SendBuf[5];) Z. O. b" S3 d. V
  12.     if(rx_stack.finish_flag ==1)//数据接收完成
    8 a- \/ ^- Q' u- m5 {% k
  13.     {0 n* n9 w# \- G& ^$ O, N" F$ b7 R
  14.       SendBuf[0]=0x7B;
    ) y! e1 ?. u: i1 F
  15.       SendBuf[1]=rx_stack.recevie_data[0];
    7 R) z4 W* P9 l0 T5 V4 ^# c! M
  16.       SendBuf[2]=rx_stack.recevie_data[1];0 t6 I0 L, @1 T% h
  17.       SendBuf[3]=rx_stack.recevie_data[2];
    & t- L+ b* M& Q4 K
  18.       SendBuf[4]=0x7D;
    8 J1 \, G  ^0 B8 d5 {4 b+ @8 ^
  19.       for(i=0;i<5;i++)( Q8 n0 W5 J) b0 R3 I
  20.       {( U, w- d) i! c" C& ?! j7 ^' F
  21.         usart_send(SendBuf[i]);
    3 S  V6 y* T8 ~  f/ t( a8 `
  22.       }3 k, o) E6 {) a
  23.     }
    / V$ @: ~+ T9 n: [& c. I2 F; [, b
  24.   }1 c" u6 U# _/ [2 X; u/ F! z
  25. }
复制代码
" _  U* f  H- A6 L6 }+ p7 a* V/ u
编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA  01  01  02  BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。# n3 b& D4 p2 R: ]/ N2 B
8 c; M$ {0 t, j* Q# E( b) F

4 R* t* ?: w& n
9 e1 w3 W. \( z* Q! i
0 O& x# |: V  N9 D- I; P5 w; B' a& s

评分

参与人数 1 ST金币 +5 收起 理由
子曰好人 + 5 赞一个!

查看全部评分

收藏 评论0 发布时间:2020-10-23 09:49

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版