哎,长久不玩,基本的ADC、Time模块都不会用了。。。, S/ q+ L+ y. E; ~' L6 j( \5 \2 Q
大家应该遇到过类似:头、地址、命令、数据长度、数据、校验 这种格式的协议,比如 刷卡器模块、电表模块、串口屏等基本都是采用这种格式的协议——我称之为类ModBus协议,因为它不是严格的ModBus协议
* z( i2 o+ I. B/ N; x# t1 r" L. C& d, f# C# J9 Y
本例程所用开发板:普中PZ6806L
+ }! Z$ X' K" |6 K9 Q7 t' s# p本例程功能:通过UART控制数码管显示 0~9, h+ w- j, P5 J. L0 Q; U
本例程所用的协议:
1 T0 Q) |# D' W* E. ?% h协议格式:head address cmd length datas check
5 g' X7 v1 W2 D" @bytes : 1 1 1 1 n 1
% [9 x3 e" p! p说明:9 n1 j; R- s* I/ v: g
1、length = datas 的长度,本历程固定为 18 {/ Q0 }* t4 t
2、check = address、 cmd、length、datas 的异或值& [1 B6 w1 @& }# a2 y" @6 f
3、cmd 取值范围:0,1,2,3, ... 10,
+ j" V8 {/ [0 l$ ~ 对应功能分别为:cmd = 0, 显示字符 0、cmd = 1,显示字符 1、。。。cmd = 9,显示字符 9,cmd = 10,循环显示 字符 0~9,间隔500ms
. |$ S6 Y- p$ a( M* Q, J4、datas 字段未使用,可为任意值
, O5 S1 F/ r2 E8 I6 K5、一般接收到报文后,应当返回应答信息,本例程为报文原样返回* C0 n" i& r0 g. Z" X
3 N8 M+ U# O+ H" s4 ~0 q* H
CubeMx配置过程:
9 E! U" ]* m7 L# G; @0 ~配置过程附件里也有
; \: u6 s8 L( D% ^/ \' J
z4 Z# i4 V' G# |4 r3 d2 V7 ]; c$ D9 H: j! X7 o
$ t6 T. M7 z8 W& |% `( r; u" D( S( p
w$ T4 i4 o8 i* q
3 J/ I$ g+ B7 H) y/ L4 N
编写测试代码:
6 I! l6 v! |$ F: P这里主要说两点:& ?4 u! ?: J" U% Y1 S
1、HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
/ l9 ?1 h/ Y4 A
. u3 ^' c" |5 R' f
0 l( a4 K5 R. N0 I& K2 Y- s 我发现,使用HAL库按标准库的方式处理UART通信也是可以的,这里把 Size 设为 1 即可,然后需要在UART回调函数中重复调用此函数;——我没有经过长时间大数据测试,不能保证这样做没有问题。
( Z- J' V/ ~( }6 r {9 T$ m* e1 l2、善用 状态机。
5 Z3 g& g5 R2 u( y' F& S 个人感觉 C语言 的难点就这4个:结构体、指针、状态机、软件寄存器(位域)4 R; U: Z4 ]6 G: l5 z
接收状态机:/ p/ t4 ~* Q3 f
* I( ] m/ N& F8 y# t$ l' X
- switch(uart_rec.state) // 状态机-接收协议处理
2 `9 U2 o% Y* R0 c) U* C! ^- k - { // 协议格式: head(1byte)/address(1byte)/cmd(1byte)/length(1byte)/datas(length byte)/check(1byte)
2 j5 y* ~5 k$ N G: y - case UART_Idle:
% Z N- z9 G7 z - if (uart_rec_tmp == uart_rec.head) // UART_Idle ==> UART_Head
: k! Q" E0 \* U - uart_rec.state = UART_Head;
* a5 m9 J2 M2 v) k8 i - break;
5 J, G8 r! R/ F* i& j+ c - case UART_Head:4 J( ]5 P4 M2 v2 p( k$ T; B
- if (uart_rec_tmp == uart_rec.addr) // UART_Head ==> UART_Addr$ q ^% a: S/ P( @
- uart_rec.state = UART_Addr;. v. A2 u) c: R
- else if (uart_rec_tmp != uart_rec.head) // UART_Head ==> UART_Idle
+ } Z& \3 C7 f9 f - uart_rec.state = UART_Idle;5 n! e6 v+ d" B! J3 i
- break;7 |& Z* j- t6 l
- case UART_Addr:
, g8 _% J/ Z8 J0 V: p) Z) E - if (isValidCMD(uart_rec_tmp)) // UART_Addr ==> UART_CMD/ C$ K/ d9 C& @: c" `/ T1 X: U
- {
: a) b2 w' ], [( V( W: C - uart_rec.cmd = uart_rec_tmp;
" G8 |! b$ ?. x9 | - uart_rec.state = UART_CMD;3 w6 B7 o+ V8 e( Z5 q7 J: H, p
- }
/ S7 N. F: g' F$ F; l O6 s - else if (uart_rec_tmp == uart_rec.head) // UART_Addr ==> UART_Head. W( w! m. R6 a7 p9 U
- uart_rec.state = UART_Head;7 B) I9 ]6 ]5 {+ ~$ f/ h" C$ c7 @
- else // UART_Addr ==> UART_Idle. J1 F7 X, @3 x# @" U7 V- [! i1 U
- uart_rec.state = UART_Idle;- H w9 q' d* A' v1 C
- break;1 a/ N$ h2 m) ^& O# K8 y
- case UART_CMD:% G9 J* V- K$ K; X$ U
- if (isValidLen(uart_rec_tmp))
" p6 v/ j$ t* {& \9 R - {
# Z! V2 ?2 y2 G" T* m# h4 Y - uart_rec.len = uart_rec_tmp;
; X& _" @# U( x( I2 A8 c - uart_rec.cnt = 0;
7 Z/ Z2 w- @* j' D- c. e$ i -
, l1 Y) j* S9 o! x. O5 Q, l - if (uart_rec_tmp == 0) // UART_CMD ==> UART_Datas
X! Y! X, ~. b8 ]" y+ k& M - uart_rec.state = UART_Datas;
/ N6 s3 F6 g3 r" m: ^ - else // UART_CMD ==> UART_Len* a$ [: | N. M& r- d9 F
- uart_rec.state = UART_Len;7 {" x g+ C" Z% V. q; l7 |7 E' g# D+ k& d
- }
% g3 | w, J8 B - else if (uart_rec_tmp == uart_rec.head) // UART_CMD ==> UART_Head
. G4 \# G! T. @) P& @0 s - uart_rec.state = UART_Head;4 i2 k* C* Z7 ~9 w
- else // UART_CMD ==> UART_Idle# Q5 M8 b, V. u& |. y
- uart_rec.state = UART_Idle;6 H- j- @5 f# R% I* @* U3 t0 R# O- a
- break;; q3 B l8 Y6 U: P
- case UART_Len:7 x( u, v9 R) T& g ]
- uart_rec.buf[uart_rec.cnt] = uart_rec_tmp;6 D6 ~3 x) M$ M+ v
- uart_rec.cnt++;# H6 [& Q5 { J+ L$ W) J C) J
- " f9 |& z) u& N C2 ?
- if (uart_rec.cnt == uart_rec.len) // UART_Len ==> UART_Datas
3 P7 B! v, \. B k b - uart_rec.state = UART_Datas;
" y4 a6 n. Q" o g7 } - break;
. ~/ d3 k+ m* V0 X* N: A' ` - case UART_Datas:$ b3 O% {% M3 ]+ L
- if (uart_rec_tmp == checkUartBuf(&uart_rec)) // UART_Datas ==> UART_Complete
7 q7 y, V4 \1 {0 _- P Z `% X - uart_rec.state = UART_Complete;. |. W6 v* r7 ^! X# i( r7 Q
- else if (uart_rec_tmp == uart_rec.head) // UART_Datas ==> UART_Head D7 W V/ n6 w) Y u- L0 j8 P
- uart_rec.state = UART_Head;7 t0 x5 R3 q5 w. C* q8 p
- else // UART_Datas ==> UART_Idle; ?0 O, u' s3 H- ?0 I
- uart_rec.state = UART_Idle;
$ { S5 B0 {! \ - break;
/ [) O1 d+ ]& W4 B - case UART_Complete: // 在 uart_recHandle() 中 UART_Complete ==> UART_Idle
! ^0 f9 u# M2 Y4 t3 I3 f: T - break;# S5 B4 @/ S! B: K
- default: uart_rec.state = UART_Idle; break; P; h5 g1 _/ T$ R
- }
`. f8 }7 V8 Y% L: ^: ], A# A8 w
复制代码 ( Y" k2 }* G; X0 j. W- x. H; O
测试:(测试视频请查看附件)* E2 e. n E F k6 [) o! A/ B
6 X. c! q0 D% ?; B0 W+ S2 ~9 f
" j+ G+ }& q/ }& S. n( K0 }* c
3 ^+ h1 r C8 a& Y9 R
奉上全部工程和文件:- U0 q8 Q7 y( ?" L
modbus_fake.rar
(18.69 MB, 下载次数: 72)
|