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

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

[复制链接]
只取一瓢 发布时间:2020-10-23 09:49
先说一下我想要实现的功能:
* J+ d7 m# m! Y3 c1 x( `) x/ v+ u通过PC的串口助手发送一帧数据给STM32设备,STM32设备解析出某一位,若是1就点亮1个LED灯,若是0就把该LED灯熄灭。
7 A5 E2 l! Y5 u  O3 W  e自定义的通信协议如下:
& P. L5 N6 m9 eAA  01  01  02  BB4 ^4 }+ i+ m( ?; t5 k* F1 ^
AA —— 帧头; C0 d% a! ^0 n- C
01  —— 地址
* U1 {9 C% t/ y01  —— 控制字(是01就点亮LED,是00就熄灭LED)3 t8 d- [7 \6 {
02  —— 校验和(地址+控制字)& f; w: c. {1 L: v
BB —— 帧尾2 f" N5 I- `, r, ~7 A
' I' M# q+ G2 Z6 T* x
今天我们主要是讨论一下自定义协议的问题,在这里我就默认你的STM32设备已经可以和电脑的串口助手可以通信上了。如果还没有实现这一功能,建议参考STM32FX开发指南(库函数版),下方我也会提供出源代码供大家参考。+ L- T0 I" }& N7 [
因为我硬件采用的是STM32F407,大家可以根据自己的实际情况进行移植;$ [" V2 E# L2 C8 X* M
你准备好了吗?接下来跟着我的节奏开始.......
5 ~; L/ H/ U0 S& ^* N( ^6 h2 Y5 i第一步:替换中断服务函数;
* _5 e/ e5 M* H把原来的中断服务函数用下面的函数代替(函数可以在usart.c文件中找到)9 A+ ^4 O7 j  R
  1. void USART1_IRQHandler(void)                  
    0 Z8 X9 ]6 s, z" [9 H( @
  2. {
    . K" B0 L2 k# S+ I% Q9 H& I, S$ j
  3.   u8 Res;//临时变量,存放串口接收的数据
    + F5 k0 X; W% u4 i

  4. # F- _. {% F& k; h+ T
  5.   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断) O; k9 Y' c- y2 G# v8 G3 g
  6.   {+ I1 P2 x  O, c# r
  7.     Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据
    ! B9 x3 X% u! y5 p! S/ b1 T
  8.     if(rx_stack.head_flag==1)//收到了帧头
    ) t7 X; h* I+ F
  9.     {
    6 Y1 n3 n1 O. J6 |$ w8 ^9 W3 a
  10.         if(Res==0xBB)//判断当前值是不是帧尾
    0 `: X8 a3 e4 T: w  G
  11.         {0 x9 o8 G4 L. C3 h2 D& B
  12.           rx_stack.finish_flag = 1;
    0 P4 N) Q2 ^+ e4 y
  13.           rx_stack.tail_flag=1;8 z6 z, m: M2 V6 K* n- U) z
  14.           rx_stack.head_flag=0;
    6 X. f) U0 J& r$ F( `
  15.         }
    1 o7 q9 c2 n( ^3 x
  16.         else  N0 G3 w. ?: l  L' |
  17.         {4 E1 j* V% c+ Q0 e! ^, e" v
  18.           rx_stack.recevie_data[rx_stack.data_pt] = Res;
    0 C( K* `: Z0 @" d/ E7 [: i& \; X
  19.           rx_stack.data_pt++;
    8 j! G1 X( D8 Q
  20.           if(rx_stack.data_pt > 9)( K  g+ U% x: \) V4 m
  21.           {; O8 {- e. V( x9 d
  22.             rx_stack.data_pt = 0;
    4 P9 W4 j3 I* |: @* P: s9 E) T& ~
  23.           }
    ' ?6 g3 q" v: \4 P2 j; C' O. l
  24.         }                  
    1 [0 b. h: U- O. K. t
  25.     }% D+ }) D) M8 }! C
  26.     else//没有收到帧头
    , F9 X- L# j0 I7 T0 m) T6 G  V
  27.     {+ r& U$ {6 d5 S7 T6 X  U
  28.       if(Res==rx_stack.head)
    2 A7 ~1 \1 B4 c/ O$ [3 R8 M% |
  29.         rx_stack.head_flag=1;6 S! O4 _. {, j# Q: d9 s
  30.       else
    5 t4 e- C6 R0 Q* E# q6 V
  31.       {
    & K. S1 Z! x' x( C9 b1 ^4 x. j( l4 @/ a
  32.         CommClr();
    # i5 q$ Y& ~# y; ~3 o# m
  33.         return;  ' r2 j# z% A& ]2 E
  34.       }  7 B0 K# I1 s' L7 S2 b$ d" ^
  35.     }   
    & m# z5 o7 Z4 M6 }8 l- Z
  36.   }
    ) u: M- @7 \# y# l3 Y. g& W! |* L
  37.   USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志) Y# t/ Z6 Y- ?. L" J
  38. }
复制代码
到这里你会发现,运行之后会出现很多错误,别慌别慌,问题不大,那是因为我的中断服务函数里面定义了一些原来没有的变量和函数;接着往下看.......( s: W1 m1 p  \' h) n! X1 s' @2 O

$ l: z* z. P# ~. Y第二步:添加自定义的函数
$ K8 D1 P7 _, g
  1. ( K! b  u4 J8 v
  2. void rx_stack_init()
    ; c! M- F: M5 H7 v# r/ Z
  3. {
    7 }& @* A# K9 y5 T2 F
  4.     rx_stack.head = 0xAA;         //协议栈头,起始位
    & `& m/ x$ h5 Y, l. x. \; y
  5.     rx_stack.addr=0x01;           //从机地址
    8 t. N8 f) m. K
  6.     memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零* w& G. z5 {" q! b3 b. [' L6 n: F
  7.     rx_stack.tail = 0xBB;         //协议栈尾,结束位
    1 Q4 o3 ?% ?; `! s- Y, M
  8.     rx_stack.head_flag = 0;
    ; F/ Q% F3 ]1 T0 W
  9.     rx_stack.tail_flag = 0;# G' x5 Z& j$ S9 M. Q/ z" I
  10.     rx_stack.finish_flag = 0;
    8 L) l, n4 A, g+ |- v# R8 ^, l
  11. //  rx_stack.lock_flag = 0;) V' G; H& j- B; q/ Y6 A+ N
  12.     rx_stack.data_pt = 0;* t0 i  q  S# v. Q( R
  13. }1 a( X4 m" P# O
  14. struct receive_stack rx_stack;' n7 h2 v. b+ \% ]

  15. ; L' }! O, n2 _& N( M
  16. void CommClr(void)+ s/ P9 b. w9 f- F8 z/ Z
  17. {$ G$ v6 Z' W# Y# G' `
  18.   rx_stack.head_flag = 0;
    # h- ?4 ?/ \* s
  19.   rx_stack.tail_flag = 0;- [' V! x* w2 k6 t" U6 s( Y
  20.   rx_stack.finish_flag = 0;1 ~! t% ~2 q2 P$ V
  21.   rx_stack.data_pt = 0;
    $ ]; i. W( p: R; a3 S" E3 ~
  22.   ' u- o* ?( Z( p0 n
  23.   memset(rx_stack.recevie_data, 0, sizeof(rx_stack.recevie_data));//把tx_stack.data[]全部初始化为零
    : I* z1 O5 U* o
  24.   rx_stack.commPack_OK_flag=0;
    6 d/ W2 c6 x& T0 E3 @
  25. }
复制代码

$ y/ X  @4 `* W7 h  c5 v' ?把这两个函数放到中断服务函数前面。什么还会报错??当然了,因为我们定义的函数都没有声明,接着来......  x% L% H2 {4 `6 s
; J( b+ }" h# o, M
第三步:自定义函数的声明(可以在usart.h文件中进行声明)) x, Q$ `6 s0 ]6 @
( h( |3 e; _- {! [5 f( K" r3 X
声明自定义的结构体变量:
& A' X0 d8 Z- x: C8 A
8 Y: O0 \& {2 I* W- H* h5 f( Y6 M
  1. struct receive_stack
    ' Q. |4 e# V! Q# h
  2. {
    " w- I5 B( e! f/ |+ ^& b! J
  3.     u8 head;//帧头% ^6 L4 i( |# u8 I3 N
  4.     u8 addr;//从机地址
    - ]) F% S. y% c0 j2 h, r
  5.     u8 recevie_data[10];//数据4 @( i; K+ A8 [9 [( c
  6.     u8 check;//校验" b+ l4 Y; V3 ~
  7.     u8 tail;//帧尾* |! J( N" f; N$ Z- e
  8.     u8 head_flag;//接收到帧头标志位
    : I" e# E% ~: s3 ]" q; Q3 Q
  9.     u8 tail_flag;//接收到帧尾标志位
    # k2 F8 F( y+ O' H8 ?; A
  10.     u8 finish_flag;//接收完成标志位
    , g0 u2 b- P. y/ X# }# [
  11.     u8 data_pt;//已接收的字节数
    3 u3 d7 q$ C, R( O) X
  12.     u8 commPack_OK_flag;//数据解包完成标志
    6 [/ h, ^/ Z& z% I# z& j
  13. };
    0 t  V7 m+ a# i3 C4 h0 Y! F& _$ C, ?
  14. extern struct receive_stack rx_stack;
复制代码
% q( D8 L7 T, N) }* T# f! v; T! w
声明上文中自定义的两个函数:& h2 a) `! w; T
  1. void rx_stack_init(void);
    . F% X1 u0 n! F& ^8 O
  2. void CommClr(void);
复制代码

6 m: D- y, V6 U1 Y现在是不是就没有错误了,但是可能还有几个警告。如果还有错误的话应该是因为_sys_exit(int x) 这个函数,把他改成void  _sys_exit(int x) 再试一试,错误应该就没有了吧。那警告怎么去呢?出现告警可能是因为我们使用了memset()这个函数,我们只需要在usart.c中包含#include <string.h>头文件就可以了。现在理论上应该是没有任何报警了,你的是不是这样的?
+ W. L( l- E: p7 P8 ]- e9 O' E
. W, v( _" g5 R2 y: a3 t' a第四步:验证是不是能正确返回数据- R+ g. H5 s" b- @) G& A
$ e8 |2 F* B0 L: I& l1 x" q: w
仿照第二步在usart.c中添加串口发送函数
, }: F6 p% R. Z, P8 K9 o9 S) \4 j$ B0 `6 Q
  1. void usart_send(u8 byte)1 Y9 t& ~6 `1 ?( N
  2. {* z' z; A2 ^# Z4 N% h7 r, k7 ~, n
  3.   USART_SendData(USART1,byte);
      E0 d0 ?3 [' ~4 A' K/ i$ F
  4.   while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//发送完成标志位
    ! f7 v0 i" _/ R+ i( _
  5. }
复制代码

! S7 r$ Y7 F; h7 u/ ?5 F2 T8 ?# l别忘记声明这个函数;! O% N" I" t* [4 w# r' }
: Q! n9 w$ l% a1 H. _; {+ a# n
第五步:写主函数
. A1 J9 h. ^) L6 n/ E4 Y
  1. int main(void)3 z" {7 [& u1 j! ~, h
  2. { , q' e: M0 @: d) b# H

  3. ( z/ S: J1 k. m, D
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2. u0 h" {$ r( G- I) M6 z; f
  5.   delay_init(168);    //延时初始化
    & d: Y0 \4 r/ e$ o2 X$ f* b* j1 Y
  6.   uart_init(9600);  //串口初始化波特率为1152007 y/ Z0 a. g- H5 i# g2 g" _( ~1 Z
  7.   LED_Init();          //初始化与LED连接的硬件接口  - X# ?; D  t+ Q
  8.   while(1)! V( E$ ^0 [+ s. J5 h$ w& e
  9.   {
    8 ?# s4 V3 |. B
  10.     u8 i;( B2 T- k, q% M+ O( c9 w
  11.     u8 SendBuf[5];
    $ I* r  j8 @- }( z' J
  12.     if(rx_stack.finish_flag ==1)//数据接收完成+ S& _7 g+ w- ~/ f" u
  13.     {# J6 S" f8 V' O) W: Q' f
  14.       SendBuf[0]=0x7B;
    5 n4 l- l8 q! a: y8 M) l
  15.       SendBuf[1]=rx_stack.recevie_data[0];
    - D# a/ Y4 E: N* H; F0 a* ?3 t
  16.       SendBuf[2]=rx_stack.recevie_data[1];
    ( t. `3 X. F2 R) n5 m: b( {
  17.       SendBuf[3]=rx_stack.recevie_data[2];0 X, r: @6 u5 |
  18.       SendBuf[4]=0x7D;$ j2 t& @' i' r: u# d
  19.       for(i=0;i<5;i++)# `- }2 `7 F3 S! c
  20.       {
    ! |1 f% h9 u- [8 v( |, r* b" r
  21.         usart_send(SendBuf[i]);- S4 }8 u7 I5 I& y
  22.       }: w( M" D- c3 z8 D! k1 z6 {* B& X7 A* D& F
  23.     }
    % \9 q. N+ q& G& \! f
  24.   }
    ' w& T) ~/ f, x# D/ u9 w# s2 w. K
  25. }
复制代码
: l% W1 Z3 u  _' H
编译一下,把程序下载到板子里面试一试,当你用电脑的串口助手发送AA  01  01  02  BB 给你的目标板,它能把发的数据原样传回来吗?坛友们一块讨论一下。
; z$ F( I' o7 z3 f7 c! R
% a5 Q2 A- m9 U5 V% e5 o! M2 s+ {, g' w! L: A5 u

4 K( X( ~' b6 [8 Y- I/ t, F
7 I% W2 k. `( B" j# b/ o* `* g+ k8 `8 X

评分

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

查看全部评分

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

举报

0个回答

所属标签

相似分享

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