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

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

[复制链接]
只取一瓢 发布时间:2020-10-23 09:49
先说一下我想要实现的功能:5 H( t" J( }: j% r8 t/ T
通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。+ H5 U2 m& V& p* ^% p
自定义的通信协议如下:
# \4 N5 i& o5 x2 w- v0 ], yAA  01  01  02  BB7 T9 C+ n* @! Y
AA —— 帧头: B7 y9 Z+ D3 j4 K% l
01  —— 地址% ~: N6 v# g8 V+ C- X3 b7 l
01  —— 控制字(是01就点亮LED,是00就熄灭LED)! K' y* D. v" Z1 ]( m
02  —— 校验和(地址+控制字)% {& L0 h' `* Q% }* ]/ M# [2 V+ H
BB —— 帧尾/ F: e) q  s3 L2 ]

0 r; o( N! ]' h7 B0 S4 D6 f今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。- H5 g3 n7 F# ~9 j' s6 C& r
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;
6 l, m7 E$ r& H( o1 S你准备好了吗?接下来跟着我的节奏开始.......& |/ A% |' m0 ~4 k
第一步:替换中断服务函数;
. }4 I$ @! F$ [/ Z  A9 _$ }把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到)3 l% A# N+ h0 ]  M. A" G
  1. void USART1_IRQHandler(void)                  3 D) F. g# O0 ~6 }) `& q7 \+ d
  2. {. {! Y6 u# s( |
  3.   u8 Res;//临时变量,存放串口接收的数据
    & z) `; V! U, w6 _+ e& t; N
  4. : [& ^% X; z* K" B# j' H% \7 R
  5.   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断: P) @- ?# k- z0 O4 r/ A
  6.   {
    $ `+ m, J0 v) V, \+ B6 `
  7.     Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据3 y2 l9 F5 ~8 y! K7 R
  8.     if(rx_stack.head_flag==1)//收到了帧头
    ; O% _" t3 _( a0 y6 z
  9.     {8 L4 s' F% N! o' H) j
  10.         if(Res==0xBB)//判断当前值是不是帧尾
    0 C" ?" ~$ l& ?5 M2 b6 {8 ?2 }3 e
  11.         {
    ) A+ b, u4 P) A7 D
  12.           rx_stack.finish_flag = 1;: E, ^# e) v: Z! N, s1 b8 T
  13.           rx_stack.tail_flag=1;
    ) J4 O, `* a& u: X8 |- f2 y' z
  14.           rx_stack.head_flag=0;
    ! P3 [* T. y$ I" r! t
  15.         }
    ( R  ]$ U1 V* M0 g/ B8 @& L0 M
  16.         else- T. ?# `0 ?5 v0 Y
  17.         {) ]% p* n) @, p
  18.           rx_stack.recevie_data[rx_stack.data_pt] = Res;6 M$ ?" W9 _1 V- {. B. {
  19.           rx_stack.data_pt++;1 b4 ^# T, o( W8 A# r5 h% }
  20.           if(rx_stack.data_pt > 9)
    # R6 M, G7 h1 G2 s+ e) k
  21.           {% J. P5 f$ `! J4 A6 U
  22.             rx_stack.data_pt = 0;& e1 ], H; e# s0 H
  23.           }
    $ O2 `) ~& R4 U& _( Z% E
  24.         }                  . K7 l) Y; T; b, l( I
  25.     }0 Z" W% s, a; ?$ I7 f' C
  26.     else//没有收到帧头' c' ]# L) I. Y" ^& n: _5 h0 _2 z
  27.     {
    8 ?: u6 E7 z3 u- h# Q, A1 W
  28.       if(Res==rx_stack.head)
    # S( D/ F9 V. k6 V3 S( E+ b
  29.         rx_stack.head_flag=1;
    # j8 b% K3 `  y" @  d; H- p% p
  30.       else7 K, Y7 `+ ^* C# h% l2 E
  31.       {5 n) R/ R, u! f; v! A, n
  32.         CommClr();- q- G3 }1 b8 i7 Q
  33.         return;  
    4 t& L+ J9 ]$ n$ ~' J2 g
  34.       }  
    4 T" }6 I, j, D$ H; O
  35.     }   
    7 E+ c4 ^$ B% A8 z, @
  36.   }
    2 e) y4 B. ?0 r7 T0 X9 |
  37.   USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
    7 Z! n. t/ V5 `% d
  38. }
复制代码
到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......
6 r2 i1 b2 k+ w/ m" |# ^- c4 S$ E4 c) Z$ Q# X6 h& \2 y
第二步:添加自定义的函数: K2 I9 {( l) R4 W9 q& S

  1. + {& Z9 E0 o1 }+ v" D- ^$ g- k
  2. void rx_stack_init()
    ' m) ]$ f, h& @
  3. {" k! e/ L, \0 O6 O, i' U% j
  4.     rx_stack.head = 0xAA;         //协议栈头,起始位" S( D' O! V0 _" m, W0 n" U
  5.     rx_stack.addr=0x01;           //从机地址& x# ~2 f9 f( ~3 i! J' b, z
  6.     memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    . A5 f4 l: T- Z+ g- \, T2 e
  7.     rx_stack.tail = 0xBB;         //协议栈尾,结束位
    " s/ x* U5 C  M' E( u/ s8 d
  8.     rx_stack.head_flag = 0;9 b, H, O  b( H9 ?2 h; G; p$ P7 |
  9.     rx_stack.tail_flag = 0;
    2 {% X# J. E0 N
  10.     rx_stack.finish_flag = 0;
    # d; ]) R1 ^' T/ K, u
  11. //  rx_stack.lock_flag = 0;
    : ?5 ^, k6 z% Z1 U7 c9 f- {. J
  12.     rx_stack.data_pt = 0;
    & @0 Z, e, z3 \# p4 t  X( O/ o
  13. }6 o, |! O% u1 J1 ?; I3 x8 z
  14. struct receive_stack rx_stack;: \9 a% {8 {& X1 Y

  15. " y; {3 b5 ?7 C
  16. void CommClr(void)
    5 I! R# A5 ]2 q' N) `  j
  17. {  P& l  [* @2 }# L* L8 s6 P$ ?  T
  18.   rx_stack.head_flag = 0;' ^1 z) X- a0 ?7 W! H6 G* B+ @& K
  19.   rx_stack.tail_flag = 0;8 X& @5 W7 C& B0 _
  20.   rx_stack.finish_flag = 0;
      T4 a& x# T3 h1 A% X2 W
  21.   rx_stack.data_pt = 0;! u8 v+ q9 M' x! g' {
  22.   
    ) m- o1 ?( L- m0 }. R
  23.   memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    & G. S0 g4 y/ U) }( `, J
  24.   rx_stack.commPack_OK_flag=0;* j0 a% w* @, u! w! l2 V/ J' \
  25. }
复制代码
- g( u  w9 w: Q7 P7 q' m7 {
把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......! q$ B6 m, e) O; E8 T( R
) S: @6 D: M5 w9 }' [  q6 @; t7 D
第三步:自定义函数的声明(可以在usart.h文件中进行声明)
& R/ M. i) W1 L$ T
. T6 U8 V9 x7 w- z4 S% [- Q声明自定义的结构体变量:
! o* O; w8 ?& x) E, f" c
) U5 a/ _8 ^0 a2 a% i# W
  1. struct receive_stack- Z/ O! R# ]7 H/ ]7 W9 r
  2. {
    # N$ i8 Z4 t" L2 r3 i! B) C6 ^2 F0 m
  3.     u8 head;//帧头
    * D' q* ~8 O; b  n; s
  4.     u8 addr;//从机地址* f. i/ e8 |& q2 g) S, J
  5.     u8 recevie_data[10];//数据
    ; S. y: _7 K  i& f5 n
  6.     u8 check;//校验
    ' j% l9 k4 V$ e& D3 y
  7.     u8 tail;//帧尾
    % b+ N$ Y, T. Y2 T
  8.     u8 head_flag;//接收到帧头标志位
    4 U% O& h* T' t$ T. d3 B" |, b
  9.     u8 tail_flag;//接收到帧尾标志位
    " O; E9 c6 a0 t: g) M( Z4 G* T
  10.     u8 finish_flag;//接收完成标志位- p( a  H, v0 B: S% \  ~2 K( |) S
  11.     u8 data_pt;//已接收的字节数8 ]$ Q- V; T( A* L% r
  12.     u8 commPack_OK_flag;//数据解包完成标志
    1 Y3 t/ F& I& t3 T) D, E" P
  13. };
    / L# O8 e4 T+ n
  14. extern struct receive_stack rx_stack;
复制代码

& k3 G2 N1 D1 J3 v声明上文中自定义的两个函数:7 y5 x: X( z& T
  1. void rx_stack_init(void);2 z) h9 L$ J- l5 A+ r  V- M; G
  2. void CommClr(void);
复制代码
8 y  d- E8 D: Z
现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void  _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?! A/ r8 A$ t7 C

2 t& T) V3 [4 U7 V7 e4 K第四步:验证是不是能正确返回数据
5 _( }4 A5 h4 w' U4 q8 n4 k+ ]" d# s$ E9 H
仿照第二步在usart.c中添加串口发送函数
) b4 P7 D  i3 V# |* }. ?$ _" G% \' z: `" U) G: N
  1. void usart_send(u8 byte)/ d! ]  Q; ^* o* h/ p
  2. {; U8 {) b% I4 h4 i7 {
  3.   USART_SendData(USART1,byte);! J5 c9 U2 ?$ i! ]0 N
  4.   while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位6 v" i; D' ~3 }' g& U
  5. }
复制代码

) \0 y9 C* [' B3 ?7 n别忘记声明这个函数;& [, E6 _2 R: A0 n

2 [( m- o+ Q: l1 b第五步:写主函数: F' F% L7 o4 }: e5 u4 |; l  c4 a
  1. int main(void)
    1 e. \( N( c8 @3 Y9 i# W
  2. { - z. H2 ?, @) x. F3 [& h
  3. 1 i; G. P4 g8 i- j" Q
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组26 ]/ Q* |# @3 p, V* J8 K# u
  5.   delay_init(168);    //延时初始化
    3 z. E" F& O' q- y6 \) e+ |
  6.   uart_init(9600);  //串口初始化波特率为115200
    6 K" _3 X. N: F; c6 y! q- c3 |
  7.   LED_Init();          //初始化与LED连接的硬件接口  ' y& R# j4 {, ?# w
  8.   while(1)0 ?- k% w3 ~6 Z- z& W: Y- q
  9.   {2 P% M3 g2 B2 d: L& i
  10.     u8 i;* A1 U1 A; D0 |
  11.     u8 SendBuf[5];
    4 ]0 o6 }1 S( Q- y
  12.     if(rx_stack.finish_flag ==1)//数据接收完成
    & ^+ m$ l& u3 u: g' J8 u
  13.     {
    . B5 k! ~6 t+ m
  14.       SendBuf[0]=0x7B;. H. R' z/ S% x* U  G& P
  15.       SendBuf[1]=rx_stack.recevie_data[0];
    + g& I* _/ l. v. v5 G* `, i  d! u
  16.       SendBuf[2]=rx_stack.recevie_data[1];
    - Q3 e0 i% o# }+ F" j  j* {
  17.       SendBuf[3]=rx_stack.recevie_data[2];' ?2 M5 O' H' z& `5 x! P" W
  18.       SendBuf[4]=0x7D;
    . l! \6 y9 ]5 }8 C% E# y
  19.       for(i=0;i<5;i++)3 _" e. Z: U: b
  20.       {
    9 R  Q7 ^* \$ a! D1 O
  21.         usart_send(SendBuf[i]);
    3 }5 Z- T% Z/ f7 q
  22.       }
    ! ^  S4 M& O7 @
  23.     }
    1 U# P! U3 @: Y" r9 J- h
  24.   }
    0 g4 x+ E# X4 d# o+ ~' Y
  25. }
复制代码
: t+ a) m: v2 \# B5 K* D
编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA  01  01  02  BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。
9 z9 _) H+ V) X" ~% C
2 Y4 }$ U- C1 @; \* P5 T5 r5 f( c& K" v8 x
" f: T4 Z; C6 e* w
4 m' @3 T0 @# ~* W

' d5 z% i6 f: Y! v# X& B% v

评分

参与人数 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 手机版