哎,长久不玩,基本的ADC、Time模块都不会用了 。。。% }: a- x0 v2 K! o" d) c
大家应该遇到过类似:头、地址、命令、数据长度、数据、校验 这种格式的协议,比如 刷卡器模块、电表模块、串口屏等基本都是采用这种格式的协议——我称之为类ModBus协议,因为它不是严格的ModBus协议4 d1 f/ ?7 J+ Y
- R' Q4 L: _0 L! ] w: M9 D8 ^
本例程所用开发板:普中PZ6806L
9 b- W/ v" t; k8 g* w- @8 z6 s本例程功能:通过UART控制数码管显示 0~9$ b2 `1 _. d1 t3 C, u
本例程所用的协议:
' x/ o6 y$ m- G" A+ y& G协议格式:head address cmd length datas check d" Y& T* W6 B& o3 s: N F: K# A8 k9 l
bytes : 1 1 1 1 n 1: P! k# z, [9 J$ a6 q6 U
说明:
. I$ P: ]$ y6 N1、length = datas 的长度,本历程固定为 18 E+ y) t; e: K* p/ P$ I
2、check = address、 cmd、length、datas 的异或值
; U" o3 _* {: i1 U3、cmd 取值范围:0,1,2,3, ... 10,
. `8 Q. G+ P8 H) V; } 对应功能分别为:cmd = 0, 显示字符 0、cmd = 1,显示字符 1、。。。cmd = 9,显示字符 9,cmd = 10,循环显示 字符 0~9,间隔500ms
" d" @# P$ p+ w4、datas 字段未使用,可为任意值! ?: f. A$ [- `7 C0 u# ~
5、一般接收到报文后,应当返回应答信息,本例程为报文原样返回& X& _" q( C: x) B
- T- e; h. @0 A* r& E( t' W9 XCubeMx配置过程:; z$ U* m# A' Z
配置过程附件里也有
9 S3 p. c2 X3 o4 R1 i" l' l
! s/ U8 r9 h( J( A" c: E! o% I* c8 d1 S6 H0 G
, U, S7 I6 v. O9 z
1 j% ?: H# U- Z, e7 b- C; j% I- x& ]6 D% p. u% M
编写测试代码:
* a* `* I4 }9 ?9 j" ~. ?4 l这里主要说两点:
7 g+ n7 e& K) w* m% [1 i1、HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); 2 D# a2 O) A4 _
0 j: P& L% L/ K! W. U3 _/ w% M- {9 D6 |/ l% l' j9 m, C7 d
我发现,使用HAL库按标准库的方式处理UART通信也是可以的,这里把 Size 设为 1 即可,然后需要在UART回调函数中重复调用此函数;——我没有经过长时间大数据测试,不能保证这样做没有问题。# n7 A# _% I8 [9 }- R2 H5 I: u
2、善用 状态机。
' `. _$ _, D7 z+ e, o. ?: f# V 个人感觉 C语言 的难点就这4个:结构体、指针、状态机、软件寄存器(位域)- y) U& {" \1 C5 I! y
接收状态机:8 t: Z# p# H" p! }" G& f# d7 b
% A: V7 d8 A. X# Y
- switch(uart_rec.state) // 状态机-接收协议处理
# y- E1 m5 m2 _9 t4 [# B - { // 协议格式: head(1byte)/address(1byte)/cmd(1byte)/length(1byte)/datas(length byte)/check(1byte)
2 N& ~) M, ?1 y7 _+ u( h9 C - case UART_Idle:
: `5 Z1 T6 u6 R! r$ [+ ^ - if (uart_rec_tmp == uart_rec.head) // UART_Idle ==> UART_Head+ E8 W# V9 T. F- |; G4 [& X6 ]5 n4 l
- uart_rec.state = UART_Head;
1 {+ c. _1 q% n3 p- v - break;) p" q4 S" \/ `8 c- l& y' U6 ]3 `
- case UART_Head:
2 [- N# |' h9 E2 ^. o) D& T# ~9 k - if (uart_rec_tmp == uart_rec.addr) // UART_Head ==> UART_Addr
/ M8 h% f# x6 w2 w! H3 O - uart_rec.state = UART_Addr;
2 ~( W9 @; N* V - else if (uart_rec_tmp != uart_rec.head) // UART_Head ==> UART_Idle/ T$ k( r/ A" V/ g
- uart_rec.state = UART_Idle;
7 T0 y1 l( B" S+ n - break;
4 {, m" m6 P7 {. k( B j - case UART_Addr:& a4 v9 T7 o0 `( A: T' C
- if (isValidCMD(uart_rec_tmp)) // UART_Addr ==> UART_CMD
- E. @; v6 E& v/ w - {
8 z( b0 t; n& L# n" V - uart_rec.cmd = uart_rec_tmp;
. y6 u+ |& G. G2 } _ - uart_rec.state = UART_CMD;/ G, x* T+ P8 U+ w
- }
2 w4 _6 A' y5 @ M' M - else if (uart_rec_tmp == uart_rec.head) // UART_Addr ==> UART_Head
( n# L* }' G4 x - uart_rec.state = UART_Head;
3 g+ i% d. h9 M2 Q - else // UART_Addr ==> UART_Idle
I( i0 ~* R. o - uart_rec.state = UART_Idle;2 {- x) t7 f! {! R9 L
- break;
4 ~' w; N. c4 d7 _. J - case UART_CMD:
- T4 q! g7 a$ O, y' T - if (isValidLen(uart_rec_tmp))
! g( V4 K' h. q6 b2 k - {, y' _& N2 g+ h0 ?6 a& N9 E
- uart_rec.len = uart_rec_tmp;8 X w* I1 N l% v
- uart_rec.cnt = 0;/ C+ w' Z" u$ G; x* \/ }
-
% k9 l' u# |7 @ - if (uart_rec_tmp == 0) // UART_CMD ==> UART_Datas" A: I* k4 y& H" Z
- uart_rec.state = UART_Datas;
; [5 D" H2 x/ `: O% K3 h$ E$ ` - else // UART_CMD ==> UART_Len
" A9 v9 {! Q+ `- h - uart_rec.state = UART_Len;* F1 K' H# y* z0 U. {/ u
- }5 j" [) a! f! w3 @4 f' x' t
- else if (uart_rec_tmp == uart_rec.head) // UART_CMD ==> UART_Head
: {* F& Q" \% @4 V) L: { - uart_rec.state = UART_Head;
. L& y% A7 P' ]; p+ m2 A - else // UART_CMD ==> UART_Idle
1 b( x- u y V3 o; s+ \9 B9 | - uart_rec.state = UART_Idle;
3 h7 f/ `, k2 _/ j- Y: B - break;, q S# \9 e/ {+ I% X$ U
- case UART_Len:! a/ `5 L0 i& M: i$ J0 f
- uart_rec.buf[uart_rec.cnt] = uart_rec_tmp;
$ D: G, N+ n* v - uart_rec.cnt++;
* J% @6 X2 A! |, @1 F( e1 M4 Y- P -
9 P( U: M" }4 {3 I2 ~- D; v# W- g - if (uart_rec.cnt == uart_rec.len) // UART_Len ==> UART_Datas
2 W- h) D$ _3 M. \5 `! h/ K - uart_rec.state = UART_Datas;
) \1 \5 ?- l5 u( |4 A - break;* t, d9 @. s& W m! w c
- case UART_Datas:
8 [3 A' x. c4 Z5 w+ @; W - if (uart_rec_tmp == checkUartBuf(&uart_rec)) // UART_Datas ==> UART_Complete
, W+ ?. g6 w1 A1 X( X - uart_rec.state = UART_Complete;
' y8 b" @% b& l* _1 K9 e - else if (uart_rec_tmp == uart_rec.head) // UART_Datas ==> UART_Head
, ?" Y s: ?! Y3 |1 M - uart_rec.state = UART_Head;
1 O" y' d3 w b' [0 {/ h - else // UART_Datas ==> UART_Idle
4 ]; h, v+ e+ @/ N - uart_rec.state = UART_Idle;5 r: _( s4 F4 |' O7 V% C
- break;, ^; T: N$ u, D9 _5 I& X
- case UART_Complete: // 在 uart_recHandle() 中 UART_Complete ==> UART_Idle
( t, y m A+ m) Z7 C! A - break;
) N5 s7 B3 D: P" H5 l1 V8 c - default: uart_rec.state = UART_Idle; break;" J& o; h0 e* C6 V2 j# R
- }. M5 W' c i. P! r- G$ H
复制代码
4 F- q2 V3 u& ?; }# g; ]测试:(测试视频请查看附件)
: x$ \4 Z: J: C3 F @, S' e* a
) a/ u! ]4 I2 Z1 P. W, F
/ m7 I$ g# v0 w, i
& l; f* z0 C8 i6 I2 p奉上全部工程和文件:% f7 p8 v5 T- F- f- a- ]1 g
modbus_fake.rar
(18.69 MB, 下载次数: 72)
|