上一篇我已经给大家介绍过了,不知道有没有人验证过我在上一篇文章中的程序,因为当时没有搭建硬件环境进行试验,程序在实际的板子上是跑不起来的,这篇文章就是来填坑的。
$ T6 }0 O; g3 n" L4 ^1 E, v* J# M- [ s0 X+ M
我想明白一个问题:其实具体的代码怎么写是不太重要的,重要的是我实现该功能的思路。只要把思路理顺,代码自然而然就出来了,这可能也是在逛论坛的时候,大家更喜欢分享自己的想法,而不愿意直接贴代码的原因。
5 O/ d' u, ~3 \4 Z+ _. z6 P
9 \: @; {2 O5 V( O3 [说回我们的主题,自定义协议说白了就是协议的格式不同于其他的一些标准协议,但差别也仅仅体现在协议的内容上。在进行串口通信的时候,数据是一个字节一个字节的进行发送和接收的,理论上只要能实现一个字节的发送和接收,这个问题就已经解决了。但是很多人和我刚开始接触这个问题的时候一样,脑子转不过来,想不明白怎么从接收一个数据怎么扩展到接收一帧数据,下面给大家说一下我的思路:
1 P( J' t( V* y9 @' W, E$ P: S K, m- ~) m' ^- W/ \3 U5 {' n
我们先来说数据的接收,要实现这一功能显然离不了串口中断,既然要用到中断自然少不了对STM32进行配置;大致可以分为以下几个步骤:
8 u3 Z6 @% |. I8 a0 d1 J串口时钟使能,GPIO时钟使能;
! r/ K4 b G( K3 s, h设置引脚复用映射;
% @- q% b! q% _3 x; t* sGPIO初始化设置;) Y* G: B k; L) y$ Y
串口参数初始化;
5 y* o& s& }9 h: [" g+ Z开启中断;
* P8 b$ |0 C4 [+ X; u使能串口;
x$ p- i' \9 }( p" n1 G编写中断处理函数;
( D0 l% O P* Y+ y; }4 o) ]2 t9 d9 z9 e* t) x5 `
以上这几个步骤都是些程式化的东西,只需要按照其要求按部就班的配置就可以了。编写中断处理函数是我们的重中之重,因为从这里开始才真正与我们要接受的数据有了联系。
) X! i- g4 R: H3 b/ u1 t/ \6 l$ L
9 E% Z# m; r9 o( G" \( q. A
我们要接收AA 01 01 02 BB这么一帧数据,我们可以按照下面这个流程图的方法来编写中断处理函数.
! ]6 u5 s! B! {4 m$ e/ ~1 z# [ E$ R5 x- g
代码实现如下:
. P" E/ _ `) H. p2 |) ?, s8 G" H- void USART1_IRQHandler(void) $ f1 W$ c0 P$ c) K0 Z) q* M+ i" `
- {) u$ K+ D: m% V5 k3 s5 G5 j& L! X
- u8 Res;//临时变量,存放串口接收的数据$ d- W7 l2 |" v3 R( P$ o& L& L E( ?
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
9 Y$ t% n& l1 ?* } - {3 \8 o1 a- m4 P. q
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据7 K- b# c, g+ _7 v& @5 c' {( d
- if(rx_stack.head_flag==1)//收到了帧头
* h- a: Y n: M: Q. B+ X - {/ }3 ~& H; D9 B% ~4 m+ L, A
- if(Res==rx_stack.tail)//判断当前值是不是帧尾
; r0 F3 v1 t: N/ c* j - {
& H$ E: x7 {5 m) x - rx_stack.finish_flag = 1;4 V( d& c/ ?' t4 Y$ F
- rx_stack.tail_flag=1;+ Q- \0 ~2 E" }/ X1 D
- rx_stack.head_flag=0;
* r' X( T5 L! j" `: I: M9 P - }
2 l4 t; I7 \4 H; W - else" z3 R# m. |2 P( f; `
- {
$ x! a5 c# u; S. c - rx_stack.recevie_data[rx_stack.data_pt] = Res;* q% F8 `, e7 j
- rx_stack.data_pt++;
" s1 F) E3 O& n, e5 { q( b% m - if(rx_stack.data_pt > 9)
) r4 J9 e4 C9 u" M7 t7 E9 _ A - {
9 V5 i+ {# j9 @0 V' \0 T - rx_stack.data_pt = 0;
' w4 s9 f% s2 z - }
" ^# w0 \3 k* o& s6 q* q6 h - }
$ C9 ^9 I) C- Y2 p8 H - }
, ?8 W- @2 U; } - else//没有收到帧头" y( {) f/ i" I3 P
- {3 k3 r f9 d. P S" b1 n6 w( I
- if(Res==rx_stack.head)
9 X i. R4 C0 L5 ?% h5 e W& I8 E - rx_stack.head_flag=1;5 O6 e/ g; e+ q9 w" c- \
- else
6 s7 p M2 i& F# \3 J X* D - { w$ q h; }8 {
- CommClr();
" }0 g5 [8 d5 R4 E. N - return;
7 F7 n6 C: o+ f5 R - }
! P/ J' x; r5 s5 B - } + H2 s2 d H0 E. |
- }
, V. O& C% [8 E. W4 { - USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
9 [% E4 F$ u1 \ - }
复制代码
6 e& E2 ?7 w% t6 F6 @0 n/ y0 t8 P通过以上操作我们就可以将AA 01 01 02 7B这一帧数据存放到数组中了。那么我们怎么将控制字解析出来呢?这就要用到解包函数。解包函数怎么写相信大家应该有思路了吧!定义一个解包函数,先判断数据接收完成功能的标志位是不是已经置位,如果已经置位就直接把数组里相应位置的数据取出来就完成了。9 h) Q l. @; Z+ u7 \" a
1 K% r- `: }! s; v$ C. w* o6 @
: k' \0 R: K; W) t( g
当然,这种方法是可以实现我们最初制定的目标的,但是如果数据传输过程中出错该怎么办呢?会不会出现取出来的控制字和预期的不一样呢?这个问题小伙伴们可以自己去摸索。当然大家如果有更好的实现方法,也可以给我留言,一起交流一下。; x( t' T4 i6 m# E. ^9 Q' p
& R. t2 |6 j3 p, j/ }" j4 i" R上一篇传送:https://www.stmcu.org.cn/module/forum/thread-627440-1-1.html) H2 B" |: z' M( u/ r; y! _3 |' ^' b
6 z+ n8 A1 s" t' ^) D |