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

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

[复制链接]
只取一瓢 发布时间:2020-10-23 09:49
先说一下我想要实现的功能:
9 v- v9 \$ F7 r( J通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。5 d4 ]3 D. `2 g( o0 Q/ Q+ D  Q0 ~
自定义的通信协议如下:
; h# H* C1 x$ d  n2 vAA  01  01  02  BB: ^9 ^$ m7 T5 Y
AA —— 帧头
' V5 H- B0 K! R0 Z/ \9 j) _01  —— 地址
% e  B* s4 D, Z" [0 r% [% `- l01  —— 控制字(是01就点亮LED,是00就熄灭LED)
9 [$ a& U+ G2 S6 k0 w- o02  —— 校验和(地址+控制字)
$ P* C$ B- J: Y" b  Y' rBB —— 帧尾
6 g, B6 b) E" G% n' F2 g  }* {
6 v5 s* N: M# }1 y今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。& o+ T2 k% `5 t! s! ~
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;
. Z( R" n$ y" [4 Y7 ?* ?+ p你准备好了吗?接下来跟着我的节奏开始.......
; p6 C4 A; G+ U4 d, l6 ?6 m第一步:替换中断服务函数;
/ M4 e( U* V8 P2 ~9 B# I把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到)8 W' n- k  g0 g* @
  1. void USART1_IRQHandler(void)                  
    & g5 ~$ k- \4 M
  2. {
    - n% F2 I/ F  k: o8 T1 B
  3.   u8 Res;//临时变量,存放串口接收的数据2 K0 v+ v' q/ ]) d( y/ m3 V

  4. 5 O8 a" d1 K" k' \# c
  5.   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断! ?* @( m; G" E" C; e/ L* B
  6.   {; }9 B. z, \4 W$ Q( [$ w5 t
  7.     Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据
    6 w2 M+ Y! Q9 i3 Q4 F7 \, l3 _; q5 G
  8.     if(rx_stack.head_flag==1)//收到了帧头2 @0 t, k  }7 y1 O2 o4 ?
  9.     {- ?: X! j/ i% j, H# k$ `
  10.         if(Res==0xBB)//判断当前值是不是帧尾
    " [* h8 Q( z5 c( Z
  11.         {. @, {+ T( z0 `9 W! z
  12.           rx_stack.finish_flag = 1;& S" x% m" {; X. K: Q
  13.           rx_stack.tail_flag=1;
      \/ Q8 G: P2 Q8 |# a
  14.           rx_stack.head_flag=0;
    $ {+ |0 C8 l, \% o; @
  15.         }
    % v# F4 T5 ^# |
  16.         else
    % Q5 `( i8 O+ X: u# [6 Z" M
  17.         {( z/ x, f& h* s: `& I+ z$ g8 |
  18.           rx_stack.recevie_data[rx_stack.data_pt] = Res;0 S. q8 s* k1 W0 I/ [$ l, V0 T
  19.           rx_stack.data_pt++;
    9 d1 N1 m9 D, G# S6 `, b
  20.           if(rx_stack.data_pt > 9)6 j- f* [( i$ i4 z  m
  21.           {5 N  m: Z, a# k( r  |+ ^5 h8 x
  22.             rx_stack.data_pt = 0;& e3 f$ i0 Q. i' y2 V8 c: S
  23.           }' y+ ?' z+ J; ?
  24.         }                  
    * i% f) J; D) }
  25.     }
    ' `2 b/ F' c3 W* A: ?! e1 j
  26.     else//没有收到帧头
    ' q* }: q  ^" R2 c( P- b
  27.     {- h4 V" p+ E4 v8 z
  28.       if(Res==rx_stack.head)2 d. j. b, q+ c$ K- c
  29.         rx_stack.head_flag=1;
    2 m7 _9 R) T+ z/ W. X6 Z
  30.       else
    ' O( N7 X( Y  z3 n
  31.       {. G5 \: q; z9 u+ w
  32.         CommClr();
    & ?# l$ A2 `! Y! J- q5 l
  33.         return;  
    0 W8 l. `; \2 s4 ?
  34.       }  ; h! }; r3 u8 C( F
  35.     }   
    5 z% s( f! x: Z" \
  36.   }
    % L$ O! I! x  x0 a: C- D3 k
  37.   USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志, T% m( ]% t9 h1 n: V! |7 q; r* V! |
  38. }
复制代码
到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......
/ I5 @0 H! d1 O0 Z/ b" _
- s, z  E# D7 P7 d* `( l( j第二步:添加自定义的函数
0 T& U" q2 I: h5 e

  1. $ ^; k3 t9 b# Q
  2. void rx_stack_init()
    5 ^2 v: T; Y9 @- w
  3. {, B9 p5 B% H  |( j: o) \# T7 ]' E5 P
  4.     rx_stack.head = 0xAA;         //协议栈头,起始位
    : e' T* W" n5 O2 V) t, C
  5.     rx_stack.addr=0x01;           //从机地址& x) \7 q8 f1 V7 i" C7 @* o, h3 d
  6.     memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    ) C' ]6 S, X! o. ^$ ?. q
  7.     rx_stack.tail = 0xBB;         //协议栈尾,结束位
    ) _: u& _; c- V& J
  8.     rx_stack.head_flag = 0;
    ' [4 Y+ q; j8 B# C$ i7 c
  9.     rx_stack.tail_flag = 0;* g5 B( z  _  F; f* k
  10.     rx_stack.finish_flag = 0;
    3 D2 g5 V( f9 }' `9 i3 Y
  11. //  rx_stack.lock_flag = 0;
    " X6 A8 T4 d% M! Z2 ~
  12.     rx_stack.data_pt = 0;
    ) s) L# [; o2 A8 Z, w+ T7 h0 h; P
  13. }' {4 V3 H& I' M1 _. ]; n8 ^
  14. struct receive_stack rx_stack;
    5 n$ u' {; ^! Z( s

  15. , y5 a: b8 s3 h. U3 X
  16. void CommClr(void), _9 [: W% X% m6 n' d
  17. {# C9 }1 i" h. a( s; k) n" K
  18.   rx_stack.head_flag = 0;
      d! O3 d0 X! v0 D% Y
  19.   rx_stack.tail_flag = 0;
    7 [0 |( A/ r6 h5 g# w3 G. g9 U
  20.   rx_stack.finish_flag = 0;* f1 `7 A) j: E4 c0 O$ [7 X& s' P" |
  21.   rx_stack.data_pt = 0;
    $ v1 ^; f. D( x- E7 Y7 k6 e  i, c; B
  22.   
    % ]0 e+ b3 u' _8 a3 m' S; U: n, D& g
  23.   memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    2 w) {& j0 _  X- X$ d$ m
  24.   rx_stack.commPack_OK_flag=0;% }! X6 b9 _9 D1 ]/ a7 n
  25. }
复制代码
% B2 z4 s1 B& Q4 h( L5 F& L% R, F" _
把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......3 u" n) @* o; w/ a$ q6 b5 E

& B2 P2 ]- q! J; o; Q* ~第三步:自定义函数的声明(可以在usart.h文件中进行声明)
5 U* T: u3 m& T9 P; i0 D! r9 E; N+ L. ?) B" _! I3 d" a8 F8 u2 n, t
声明自定义的结构体变量:4 I0 W# o, i  w5 y' W

8 p$ w/ h" _' u, r  q5 R
  1. struct receive_stack3 Q* D+ d8 }7 a6 Q
  2. {! N% z! ^$ ]6 j5 E; b
  3.     u8 head;//帧头4 M7 j$ `% b' l% S7 \4 W
  4.     u8 addr;//从机地址6 f1 v' Z' A) D7 R; i( B8 q5 J- h
  5.     u8 recevie_data[10];//数据( b4 r) ~( O1 f
  6.     u8 check;//校验/ H& {! G: j- d# G7 G4 z
  7.     u8 tail;//帧尾4 @2 F- ^: p0 _
  8.     u8 head_flag;//接收到帧头标志位/ }- v: t( t+ r! ~
  9.     u8 tail_flag;//接收到帧尾标志位
      `5 s$ `8 ^& A* O0 L% Y
  10.     u8 finish_flag;//接收完成标志位; t4 j9 B2 L: c) r1 n
  11.     u8 data_pt;//已接收的字节数
    ( W/ {) G, M6 z3 V' W
  12.     u8 commPack_OK_flag;//数据解包完成标志
    , O+ t9 I% y, `5 t7 ?
  13. };% O# X6 K" f- U, v' ]% k( n
  14. extern struct receive_stack rx_stack;
复制代码

) [* G( J1 u7 W' O声明上文中自定义的两个函数:) p. @- @+ x: e
  1. void rx_stack_init(void);* |& y1 s9 A- Z# t4 V: u9 ]
  2. void CommClr(void);
复制代码

( ]) ^& a7 {  X* x" M6 C现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void  _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?
' u' D- l! c" P4 b& N
3 |6 U7 Y3 ]0 o0 F5 _1 G% H; x第四步:验证是不是能正确返回数据' z8 `3 P: o+ Z: L# Q/ w: ]
$ Z' Y4 n1 x/ j$ V8 B! u% m
仿照第二步在usart.c中添加串口发送函数
1 z* }1 S1 q1 l2 N) {& Y
7 O; j/ Z/ X$ ^: H9 F, {$ U
  1. void usart_send(u8 byte)8 X! u: ~1 W) k' _# C! h# s
  2. {
    4 M9 q! Z9 D. Q* j9 Z/ v- b/ E
  3.   USART_SendData(USART1,byte);$ |5 n7 M& P; j5 ]7 H. U
  4.   while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位
    ( }* m! p! I5 r  r$ p
  5. }
复制代码
. q) T& k3 a- y. ~, X% [6 \3 l6 u+ w
别忘记声明这个函数;0 R7 K7 }. T5 R. ?6 [

3 y! |, t- ~# w第五步:写主函数
5 ^" Y) d3 a$ w" M: ]" ]5 x7 Q* m8 T
  1. int main(void)
    ) G/ T) Y9 O( A9 I, T! H# l
  2. {
      t" B% \3 G1 p) {$ G: T* V) r
  3. * \3 p# E/ W( g9 V' R6 _1 ?5 ^
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2" b& q: R2 A4 p' o' i  ~0 a
  5.   delay_init(168);    //延时初始化 6 _1 {! K+ N8 u
  6.   uart_init(9600);  //串口初始化波特率为115200" f, C; f( b9 v) Q! [7 F" m
  7.   LED_Init();          //初始化与LED连接的硬件接口  $ j+ R0 J' F" F* b
  8.   while(1)
    % C1 L6 F& p( e! N8 }& z$ O
  9.   {! D. p- e2 F6 X4 B+ d
  10.     u8 i;# c9 y' M; s: a1 f
  11.     u8 SendBuf[5];
    * D/ Y- F* @  ~; a0 B
  12.     if(rx_stack.finish_flag ==1)//数据接收完成
    2 F. L" ]. g3 N3 b( h
  13.     {0 @, x' ]5 B# b
  14.       SendBuf[0]=0x7B;1 M' f6 }: B7 C; ^/ {
  15.       SendBuf[1]=rx_stack.recevie_data[0];
    + h3 m' I0 Q6 s9 I. u6 O$ T
  16.       SendBuf[2]=rx_stack.recevie_data[1];
    ! E1 t6 v2 x' ~0 F8 f) q9 t% c
  17.       SendBuf[3]=rx_stack.recevie_data[2];
    ' x2 r0 v$ P  M" a
  18.       SendBuf[4]=0x7D;: J: I+ r' l  x" }
  19.       for(i=0;i<5;i++)
    " f* k1 d, t6 N# x2 m/ r
  20.       {: X3 y. P5 n7 k1 ~* ^- K% ^/ ~
  21.         usart_send(SendBuf[i]);2 o* C5 F- a9 ~( [& \
  22.       }
    ' G* d5 v% O0 m
  23.     }, P7 s; P5 b, p# H
  24.   }
    2 r' V. h' r+ e( B" Q: a8 Z! g
  25. }
复制代码

7 M# E) K% \% P0 h6 H$ s编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA  01  01  02  BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。
/ Q3 P7 e# D0 h& V7 }- ?. y( V2 ~8 m- b, |: ^1 _
( @# O9 k, g+ p+ g( C8 k+ _2 d0 W+ L
6 x$ x; |  [) v! j! b- e
, {" u  L( o6 j# U

3 U' }8 W2 B4 h0 W

评分

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

查看全部评分

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

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版