上一篇我已经给大家介绍过了,不知道有没有人验证过我在上一篇文章中的程序,因为当时没有搭建硬件环境进行试验,程序在实际的板子上是跑不起来的,这篇文章就是来填坑的。
( P1 `1 }6 ?& {. {( X( C. z, A# g7 R9 G9 q& y
我想明白一个问题:其实具体的代码怎么写是不太重要的,重要的是我实现该功能的思路。只要把思路理顺,代码自然而然就出来了,这可能也是在逛论坛的时候,大家更喜欢分享自己的想法,而不愿意直接贴代码的原因。
4 B" [/ Z) i# H, M+ S& K* i/ W
% E+ b& g7 m! E9 m( J4 \3 E说回我们的主题,自定义协议说白了就是协议的格式不同于其他的一些标准协议,但差别也仅仅体现在协议的内容上。在进行串口通信的时候,数据是一个字节一个字节的进行发送和接收的,理论上只要能实现一个字节的发送和接收,这个问题就已经解决了。但是很多人和我刚开始接触这个问题的时候一样,脑子转不过来,想不明白怎么从接收一个数据怎么扩展到接收一帧数据,下面给大家说一下我的思路:
. L5 H& ?- k8 U$ s7 b3 o! g
. @7 M; T, S" m6 ~1 l- P我们先来说数据的接收,要实现这一功能显然离不了串口中断,既然要用到中断自然少不了对STM32进行配置;大致可以分为以下几个步骤:8 Y! U; Q# i; x
串口时钟使能,GPIO时钟使能;; ?. f9 [" W8 }: t @; B! [8 E
设置引脚复用映射;; _: p, k8 x" r7 z. E
GPIO初始化设置;
; z" Q D J6 L( \ A$ \串口参数初始化;' K" `! q; P$ b: H* Q- v" y) J
开启中断;+ D& ~0 v. I3 V$ t: @
使能串口;3 r1 A- n8 Y) i9 e7 U7 l& }
编写中断处理函数;
3 W( A7 U- m( n. F$ Z l$ B; Q6 `
以上这几个步骤都是些程式化的东西,只需要按照其要求按部就班的配置就可以了。编写中断处理函数是我们的重中之重,因为从这里开始才真正与我们要接受的数据有了联系。
. A% Z& P( b1 ^2 }+ m# p
6 n6 \0 W$ t, }2 y: i
我们要接收AA 01 01 02 BB这么一帧数据,我们可以按照下面这个流程图的方法来编写中断处理函数.0 q+ s! ^& }+ R
+ x w4 m, |& g: ~; P代码实现如下:) H" \* D3 o+ D5 @4 i! c
- void USART1_IRQHandler(void)
1 ?% F5 _ ]4 W3 c7 T - {4 v. h/ K$ `: m8 M; O" F
- u8 Res;//临时变量,存放串口接收的数据9 I( s) t& x$ Y( v! z; e: }
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
1 U8 Y# @# h( D u - {* O) m3 Y# Y) u. z# J
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据' }! p. s' y6 e4 N6 V4 v
- if(rx_stack.head_flag==1)//收到了帧头2 ?. N# [6 @! s2 V5 H, l' j9 F, S
- {3 C _8 ]& u3 w$ S
- if(Res==rx_stack.tail)//判断当前值是不是帧尾
3 t1 a+ ~. R( [2 @8 @: H5 j - {8 k2 t. n$ N" |; v
- rx_stack.finish_flag = 1;+ F8 }: L w4 ~/ m
- rx_stack.tail_flag=1;
2 a3 o9 o8 m- y9 h. I - rx_stack.head_flag=0;. p% S* U( F7 M; H7 F+ j4 c. f5 D
- }0 t% O: B1 G+ n' k) O9 s5 R
- else
$ i: ]6 v: B5 z: n( z - {
' a0 s8 o$ Y, [9 {7 C3 t - rx_stack.recevie_data[rx_stack.data_pt] = Res;8 Q% N8 ^6 x# D
- rx_stack.data_pt++;
7 o# @4 {6 m0 t: x - if(rx_stack.data_pt > 9): m: T5 I( }- F/ a' f' a
- {
5 ~+ s g; ~" p9 n - rx_stack.data_pt = 0;
1 Q; e0 F. G- U- Q' _ - }7 }5 _+ r$ V, M9 L' I
- } ) F+ B! D# H2 J8 I4 P3 c2 p
- }
" S& t# q W* k, Y0 B9 p - else//没有收到帧头. k( Y2 H. V1 w6 S7 f# h
- {
; \% t# V( r( Q0 @$ y* H9 ` - if(Res==rx_stack.head)7 e6 ]) r; I/ R5 A
- rx_stack.head_flag=1;
3 Z4 R3 |/ W0 K4 K3 |8 V - else
0 ?. |, y6 {- }' l& m7 b1 D. J- _ - {
8 X$ @/ [) B$ } - CommClr();
" n& I, H8 J. \6 `6 W; @- X$ ^6 V - return; - I9 q% k# S- k3 |- L
- }
- |5 O0 [/ d6 a2 E; m9 W - }
2 g4 h. s6 p$ P6 p - }1 d! `* X/ [# w" w
- USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志/ N7 l5 {! d" m& r& x3 k4 c6 R6 A
- }
复制代码
- _( b' q+ V/ U8 Q; p通过以上操作我们就可以将AA 01 01 02 7B这一帧数据存放到数组中了。那么我们怎么将控制字解析出来呢?这就要用到解包函数。解包函数怎么写相信大家应该有思路了吧!定义一个解包函数,先判断数据接收完成功能的标志位是不是已经置位,如果已经置位就直接把数组里相应位置的数据取出来就完成了。
5 _# L: s. H8 G; M7 U# N2 Q. L1 Y. i- }' v E
3 [7 u. k7 j' H7 j
当然,这种方法是可以实现我们最初制定的目标的,但是如果数据传输过程中出错该怎么办呢?会不会出现取出来的控制字和预期的不一样呢?这个问题小伙伴们可以自己去摸索。当然大家如果有更好的实现方法,也可以给我留言,一起交流一下。
( ]( @' S6 w! c+ X9 y7 q0 Z3 i& b, m/ N
上一篇传送:https://www.stmcu.org.cn/module/forum/thread-627440-1-1.html; k1 p+ R# k3 S5 N% | v, N! L2 g7 j/ T
, x* L2 D) ^) J. ^
|