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

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

[复制链接]
只取一瓢 发布时间:2020-10-23 09:49
先说一下我想要实现的功能:
3 F- H9 ]; M) ~5 d- G: N通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。
, a& F5 o% L6 L8 k7 S& a0 y自定义的通信协议如下:
- O& Z- A$ U! T- ?. N; ]9 BAA  01  01  02  BB
7 r# u. W: c- V  L# mAA —— 帧头
' ~- j  X: q' z4 B# w! j01  —— 地址
. _+ M; O" t  W3 M6 o; ~* }0 N* z01  —— 控制字(是01就点亮LED,是00就熄灭LED)7 g3 G6 h2 z6 c/ ?& d
02  —— 校验和(地址+控制字)3 J( P1 M0 P! _4 P2 x3 R% w7 |
BB —— 帧尾
5 p9 w+ r2 E9 d( \
  m* Q9 X3 @1 q# N" f) K7 C今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。! W5 _" d  l/ {: O- {8 y4 }
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;/ M# u& }, x8 ^% Q* d
你准备好了吗?接下来跟着我的节奏开始.......- \' s/ c* J- \! G  h% }
第一步:替换中断服务函数;. s; U1 f; t; @
把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到)$ Q* V% J: J, u+ H% m8 B
  1. void USART1_IRQHandler(void)                  
    * `6 P3 I1 j& R# V  }
  2. {& f6 K# d' r" u" k- e3 P0 ]
  3.   u8 Res;//临时变量,存放串口接收的数据& j7 N) F' p% Y- V+ Z6 r+ m

  4. # G- G) ?# o* _% N" V
  5.   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断0 e6 b. I  G% P. W7 d
  6.   {
    ( C# A! n# n" t
  7.     Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据- l- r9 h4 |4 x; ]! P- k- q
  8.     if(rx_stack.head_flag==1)//收到了帧头' q! x9 U* d6 I
  9.     {. y, i0 C7 x: L/ x
  10.         if(Res==0xBB)//判断当前值是不是帧尾: T# }  C4 x9 c7 P
  11.         {
    ( L" k" i% o' H5 p
  12.           rx_stack.finish_flag = 1;
    4 }$ i) g4 z, M! \
  13.           rx_stack.tail_flag=1;
    ' @/ l) \" j+ o; ?6 v
  14.           rx_stack.head_flag=0;
    7 z" M& d/ Y  g. l; t! Y
  15.         }
    $ U- m, l1 J# I
  16.         else
    ' X  c% E8 z3 Y% r
  17.         {
    6 Q9 ^8 t3 ?6 ]! H! g! {
  18.           rx_stack.recevie_data[rx_stack.data_pt] = Res;
    ' ]9 ?1 M( I# U
  19.           rx_stack.data_pt++;
    : |+ g" w& p7 i6 e0 k( n
  20.           if(rx_stack.data_pt > 9)
    / O# ?0 \' X: ~( ?
  21.           {! S. x! {5 N% U9 j1 P$ [
  22.             rx_stack.data_pt = 0;
    / ]) W2 }  u1 g+ o. E
  23.           }9 \9 }0 j0 L: s9 L% E% f! B' |, {: [
  24.         }                  
    ! [. E1 n! ^4 G% e  B9 P
  25.     }
    $ [$ A( M" G$ X- ^* z, J+ R
  26.     else//没有收到帧头
    ( M& M# j( w% i
  27.     {
    ) u+ p7 d  `1 a. ]
  28.       if(Res==rx_stack.head)
    ) F) J" e# N0 Z& b
  29.         rx_stack.head_flag=1;
    ' _' v) v' V$ p  E) e) V2 N
  30.       else9 p! K2 ^5 f' g" L4 a5 t
  31.       {& V2 E) i7 I) a0 T# X
  32.         CommClr();5 b  j( u: Y- T' E" ]1 y! m' ?
  33.         return;  
    / m  y8 z0 B8 ^9 i5 ?
  34.       }  ; H$ ]8 S, }. L
  35.     }   
    " L, \6 L. |6 s& }3 z
  36.   }/ G% O/ U5 u5 Y5 ]. m7 y  p# q
  37.   USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
    8 q  G( G* |1 [& Z1 A3 |
  38. }
复制代码
到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......8 ~+ T9 z( G+ W7 e& \; G
9 Z% E5 a. K, f
第二步:添加自定义的函数
( t( L$ M: \* p, J/ p

  1. 1 B  V  c# I4 J
  2. void rx_stack_init()
    : @5 }1 h1 Q0 `1 [. O4 ?
  3. {8 Y+ D2 }! i8 E8 ~
  4.     rx_stack.head = 0xAA;         //协议栈头,起始位. J4 p! _, E. c
  5.     rx_stack.addr=0x01;           //从机地址# W4 V5 ^- \% a
  6.     memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零+ `& s, y. w) f2 |2 J4 ^' B) G; {' b
  7.     rx_stack.tail = 0xBB;         //协议栈尾,结束位
      W, h; Y8 w" ^* {- V6 K) {
  8.     rx_stack.head_flag = 0;
    9 G. e; U1 d# p+ U
  9.     rx_stack.tail_flag = 0;
    ' g& c& u- O- M, K- y
  10.     rx_stack.finish_flag = 0;3 p: e! }9 W0 W% i+ ]2 p. T9 S. U
  11. //  rx_stack.lock_flag = 0;
    $ ^- r$ m. K  [, |$ i
  12.     rx_stack.data_pt = 0;' l  A+ R5 h- k2 B+ Z, I
  13. }
    # p. W8 m4 j- J; F8 L
  14. struct receive_stack rx_stack;
    " ~/ X4 K- O- l, j

  15. " d' y/ m" B1 N" Y  C
  16. void CommClr(void)
    ' s8 j; B- q& _0 a* @5 D
  17. {
    # k) W1 _# V$ _8 y
  18.   rx_stack.head_flag = 0;) y( R# u7 J; J3 D
  19.   rx_stack.tail_flag = 0;
    - r9 E' T9 N! m- u. C
  20.   rx_stack.finish_flag = 0;
    0 g8 }: S: e. ]6 Z5 S: w: n4 @
  21.   rx_stack.data_pt = 0;5 b% n# F, t4 u8 V' L% _) I9 ~
  22.   ( B1 b. s, w* u( L+ B* G3 p% y
  23.   memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零5 Q) ~% K+ \' `* X0 m& c: G) @
  24.   rx_stack.commPack_OK_flag=0;- g8 e1 l1 G! x5 s- d
  25. }
复制代码
' E* s$ r3 n  v
把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......3 s) t0 g( g9 n. x
- v0 n+ E' @7 G# ^# h
第三步:自定义函数的声明(可以在usart.h文件中进行声明)
- F5 w+ n* X3 V0 g# S( l* F9 X$ \' z/ A) C! k+ s
声明自定义的结构体变量:% T: A+ A4 n! P, n7 ^! v

  @2 V* s# }* J; g' L. a
  1. struct receive_stack) @4 J4 X- h/ T9 z7 |5 `& M/ E
  2. {
    2 D# P* @! K: {# J5 |9 O
  3.     u8 head;//帧头
    5 T, n& {3 o$ ?. L1 E! @4 }
  4.     u8 addr;//从机地址
    8 C8 T; L5 r" p2 c  L2 h
  5.     u8 recevie_data[10];//数据
    2 z$ A* U, p" }/ u) O: \
  6.     u8 check;//校验
      {5 L6 y& k- C+ B
  7.     u8 tail;//帧尾9 W) R- l7 L9 `- ^1 C" {+ G
  8.     u8 head_flag;//接收到帧头标志位
    0 D9 b2 v! i. v4 W2 ~% K" b
  9.     u8 tail_flag;//接收到帧尾标志位
    9 a+ L( w' }* `, F9 ^% f' F, @
  10.     u8 finish_flag;//接收完成标志位
    2 O/ [5 D7 }7 k! {8 ?0 v/ O
  11.     u8 data_pt;//已接收的字节数# E, b* p$ k, ~- k0 u" G9 ?
  12.     u8 commPack_OK_flag;//数据解包完成标志, q0 n3 W# T# u6 m+ c, R1 Z
  13. };" x& |7 q9 R' v$ {
  14. extern struct receive_stack rx_stack;
复制代码
' V8 ^" O2 @) I1 i
声明上文中自定义的两个函数:
$ r. d; o4 b0 E$ w' @* B
  1. void rx_stack_init(void);
    ( p5 L" L) {3 u  t% f
  2. void CommClr(void);
复制代码

. w" J, V4 q8 X4 {7 b& S0 L, m( W现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void  _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?
' }. A0 O# z/ h: ]' O, i# l: ^8 {6 g- @7 ]% `
第四步:验证是不是能正确返回数据
2 y6 O1 A: u# _% P8 I+ X. j
6 c, p- a2 I1 I4 ]& C仿照第二步在usart.c中添加串口发送函数1 Y* b; O( z5 }$ Z/ a7 }5 i
: ?+ p3 n- y1 h
  1. void usart_send(u8 byte)
    ( d1 i( Q' G0 c5 o  x
  2. {
    - E4 c: _8 D9 t5 n* w
  3.   USART_SendData(USART1,byte);( h8 O4 N9 A! W/ Z8 C
  4.   while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位# j6 H6 M) L+ r- ?0 j, w3 z! G
  5. }
复制代码

7 W6 F" }# q2 b7 A& v$ x别忘记声明这个函数;% U( S: S" u% N

+ T* R4 \: b# v第五步:写主函数
7 ]5 K! G6 c7 |7 }5 x
  1. int main(void)2 V5 o. V. q; J0 H  ^
  2. { 2 k( H/ A5 }& u+ M! O
  3. ; K) Q  R( r. F0 ]/ h& [
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2  N& O0 x: L) a% T2 ]$ p. x
  5.   delay_init(168);    //延时初始化 ( ^1 I8 S/ w- }) s# ?
  6.   uart_init(9600);  //串口初始化波特率为1152000 E; x1 {) S4 ?! K
  7.   LED_Init();          //初始化与LED连接的硬件接口  
    1 J! g( m2 p" W- ?2 w
  8.   while(1)" n% g  U4 }$ k4 S, q( |- X" ^
  9.   {3 x) c$ |- F$ B/ b: }
  10.     u8 i;
    ( \5 c/ h( t# n  X
  11.     u8 SendBuf[5];0 f) T1 ~/ E8 V) w; ]2 ]/ I( q
  12.     if(rx_stack.finish_flag ==1)//数据接收完成
    # N: ]$ N$ Z8 X" |* A
  13.     {' H, |1 ^4 A. U
  14.       SendBuf[0]=0x7B;
    5 a, ?4 u* _5 p0 X6 M
  15.       SendBuf[1]=rx_stack.recevie_data[0];
    # p/ Z6 a% |  J3 R
  16.       SendBuf[2]=rx_stack.recevie_data[1];6 Z* p9 _: l8 i  }% u. _  z
  17.       SendBuf[3]=rx_stack.recevie_data[2];7 v; N+ J7 o' ]0 |1 E! O
  18.       SendBuf[4]=0x7D;0 g+ k( B: S' e4 m$ A9 l) c$ Y
  19.       for(i=0;i<5;i++)0 D- V  E6 F, g, \) D. s% @
  20.       {. [) m8 F( F# s) f
  21.         usart_send(SendBuf[i]);
    9 Z3 I& e) X& s* ^
  22.       }3 c7 l% z+ I6 O& a  M
  23.     }
    . X# @) u+ p+ `. p7 S9 E( b1 Q
  24.   }" E, Z! k* C& d; o. N
  25. }
复制代码

3 E/ q. b1 k  ^. J0 r" x) z编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA  01  01  02  BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。
9 l: w; G% q* ?/ A1 @! f/ Y
5 X* h0 k- _; a8 k( v1 k; k2 ]/ |
6 q3 R: [! n/ Y1 W3 p) h0 S3 Y
, c% T  l. X1 T7 I
  j. C- C& {" D& a
( Q* ?- d" }3 {( C

评分

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

查看全部评分

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

举报

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