上一篇我已经给大家介绍过了,不知道有没有人验证过我在上一篇文章中的程序,因为当时没有搭建硬件环境进行试验,程序在实际的板子上是跑不起来的,这篇文章就是来填坑的。
G4 M& F& d- [" `
: K% Z- c. N( V我想明白一个问题:其实具体的代码怎么写是不太重要的,重要的是我实现该功能的思路。只要把思路理顺,代码自然而然就出来了,这可能也是在逛论坛的时候,大家更喜欢分享自己的想法,而不愿意直接贴代码的原因。
( V* W6 P+ Q, q: C* ]7 @) k( _4 T0 }; h+ H! R
说回我们的主题,自定义协议说白了就是协议的格式不同于其他的一些标准协议,但差别也仅仅体现在协议的内容上。在进行串口通信的时候,数据是一个字节一个字节的进行发送和接收的,理论上只要能实现一个字节的发送和接收,这个问题就已经解决了。但是很多人和我刚开始接触这个问题的时候一样,脑子转不过来,想不明白怎么从接收一个数据怎么扩展到接收一帧数据,下面给大家说一下我的思路:
1 F: M# L4 ]* v. J8 P: R+ \0 f) P5 A0 ` [- w. Y
我们先来说数据的接收,要实现这一功能显然离不了串口中断,既然要用到中断自然少不了对STM32进行配置;大致可以分为以下几个步骤:- E& s* q4 j7 j4 @* } O
串口时钟使能,GPIO时钟使能;" k9 O5 h/ w- k3 g
设置引脚复用映射;* n1 l+ C, e! q. d
GPIO初始化设置;* B* E% ]+ l* A( _5 |2 B
串口参数初始化;3 w- ^1 v( v+ O. H4 z1 t% b
开启中断;
# y, p' N8 X( q. M0 {$ u使能串口;$ `, z% z4 ~/ ^, v/ b$ U4 y
编写中断处理函数;9 V# B; b" H( p# i: p$ o
7 x q8 e0 T: Q7 F: T以上这几个步骤都是些程式化的东西,只需要按照其要求按部就班的配置就可以了。编写中断处理函数是我们的重中之重,因为从这里开始才真正与我们要接受的数据有了联系。
7 y. h. L" A5 Z4 h# I3 \
8 M* |* B4 n) N" }) o4 x( f
我们要接收AA 01 01 02 BB这么一帧数据,我们可以按照下面这个流程图的方法来编写中断处理函数.5 M+ u4 Z6 p; w
3 A% ?3 _' K7 P6 Y L
代码实现如下:
6 O/ }" M8 J& V- w- void USART1_IRQHandler(void) # d/ M, B6 q4 o0 }# q: _
- {8 j4 u( I9 }. ~" f+ Q0 K8 W
- u8 Res;//临时变量,存放串口接收的数据
! B6 h: M# j; S5 u# Z4 d - if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断( o: ^9 W* w1 W+ y @
- {# p$ n( D, R7 Q& C
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据# k/ F4 q+ ]" r4 S) y
- if(rx_stack.head_flag==1)//收到了帧头
) j7 G: A( J _ - {
" l% T$ D: ]! n4 A - if(Res==rx_stack.tail)//判断当前值是不是帧尾
: W/ z- p9 r/ {! |) f; U - {5 W- @8 T# a0 t6 _/ |
- rx_stack.finish_flag = 1;
- d3 E9 A$ E# a; x4 c - rx_stack.tail_flag=1;
- ]5 X& R7 x3 }5 `/ j5 u2 S - rx_stack.head_flag=0;
( [2 h K7 R& r0 y' t$ ? - }' U5 n: F$ F5 j$ l: b
- else3 h- C4 p- C/ D l U7 X
- {
! p) E2 F6 w8 }6 O* G1 A D - rx_stack.recevie_data[rx_stack.data_pt] = Res;
3 f7 g, [9 m( ]3 s" | f - rx_stack.data_pt++;
" e( J" r/ y U! S: j - if(rx_stack.data_pt > 9)$ m: w! u* P& f. g& T4 P
- {
) l. t3 U3 C3 h2 n/ S5 S - rx_stack.data_pt = 0;
% F5 l' d+ R& n- q* } - }
9 y+ a1 q8 n2 Z" q - }
5 h0 S- a+ f" B' B5 k9 c- U - }
8 W7 W0 ]" \+ }$ Q. F - else//没有收到帧头
3 \! K& y- K5 _8 A' w4 K2 R - { n8 a; @% x4 e" I# |( A$ b
- if(Res==rx_stack.head)# X, W* N% T1 [2 X# Z# K# T
- rx_stack.head_flag=1;9 @+ \1 O) G; H; y3 q
- else
0 a$ y. l, n. I& n ` - {0 d2 Z) g, w' o0 d' I
- CommClr();$ {$ Q4 O& Z0 r4 o \0 M! u+ e4 W) I" S
- return;
' G0 k e0 G3 A, A# U! C - } : i/ p9 v+ G- x6 g) t+ U5 {
- } $ P- V5 W% i# ] i t9 H1 X1 w1 i
- }
# Z7 R: R+ q. l9 P- \# @1 R - USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志7 ^- R& w* k; v
- }
复制代码 8 k& e& Y; z8 N& x, R6 m
通过以上操作我们就可以将AA 01 01 02 7B这一帧数据存放到数组中了。那么我们怎么将控制字解析出来呢?这就要用到解包函数。解包函数怎么写相信大家应该有思路了吧!定义一个解包函数,先判断数据接收完成功能的标志位是不是已经置位,如果已经置位就直接把数组里相应位置的数据取出来就完成了。
0 F x" T4 ?: m# D; y
9 q6 `; h* j+ D& c6 ~% H! Q* U; N; Y" E1 Z5 z1 Q
当然,这种方法是可以实现我们最初制定的目标的,但是如果数据传输过程中出错该怎么办呢?会不会出现取出来的控制字和预期的不一样呢?这个问题小伙伴们可以自己去摸索。当然大家如果有更好的实现方法,也可以给我留言,一起交流一下。
9 v* Z+ J4 [4 G8 \% x" |4 r4 N* n M3 Z
上一篇传送:https://www.stmcu.org.cn/module/forum/thread-627440-1-1.html% q/ G1 Q+ @+ W6 C v7 e
( X. d% i" I" d |