哎,长久不玩,基本的ADC、Time模块都不会用了 。。。
大家应该遇到过类似:头、地址、命令、数据长度、数据、校验 这种格式的协议,比如 刷卡器模块、电表模块、串口屏等基本都是采用这种格式的协议——我称之为类ModBus协议,因为它不是严格的ModBus协议
本例程所用开发板:普中PZ6806L
本例程功能:通过UART控制数码管显示 0~9
本例程所用的协议:
协议格式:head address cmd length datas check
bytes : 1 1 1 1 n 1
说明:
1、length = datas 的长度,本历程固定为 1
2、check = address、 cmd、length、datas 的异或值
3、cmd 取值范围:0,1,2,3, ... 10,
对应功能分别为:cmd = 0, 显示字符 0、cmd = 1,显示字符 1、。。。cmd = 9,显示字符 9,cmd = 10,循环显示 字符 0~9,间隔500ms
4、datas 字段未使用,可为任意值
5、一般接收到报文后,应当返回应答信息,本例程为报文原样返回
CubeMx配置过程:
配置过程附件里也有
编写测试代码:
这里主要说两点:
1、HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
我发现,使用HAL库按标准库的方式处理UART通信也是可以的,这里把 Size 设为 1 即可,然后需要在UART回调函数中重复调用此函数;——我没有经过长时间大数据测试,不能保证这样做没有问题。
2、善用 状态机。
个人感觉 C语言 的难点就这4个:结构体、指针、状态机、软件寄存器(位域)
接收状态机:
- switch(uart_rec.state) // 状态机-接收协议处理
- { // 协议格式: head(1byte)/address(1byte)/cmd(1byte)/length(1byte)/datas(length byte)/check(1byte)
- case UART_Idle:
- if (uart_rec_tmp == uart_rec.head) // UART_Idle ==> UART_Head
- uart_rec.state = UART_Head;
- break;
- case UART_Head:
- if (uart_rec_tmp == uart_rec.addr) // UART_Head ==> UART_Addr
- uart_rec.state = UART_Addr;
- else if (uart_rec_tmp != uart_rec.head) // UART_Head ==> UART_Idle
- uart_rec.state = UART_Idle;
- break;
- case UART_Addr:
- if (isValidCMD(uart_rec_tmp)) // UART_Addr ==> UART_CMD
- {
- uart_rec.cmd = uart_rec_tmp;
- uart_rec.state = UART_CMD;
- }
- else if (uart_rec_tmp == uart_rec.head) // UART_Addr ==> UART_Head
- uart_rec.state = UART_Head;
- else // UART_Addr ==> UART_Idle
- uart_rec.state = UART_Idle;
- break;
- case UART_CMD:
- if (isValidLen(uart_rec_tmp))
- {
- uart_rec.len = uart_rec_tmp;
- uart_rec.cnt = 0;
-
- if (uart_rec_tmp == 0) // UART_CMD ==> UART_Datas
- uart_rec.state = UART_Datas;
- else // UART_CMD ==> UART_Len
- uart_rec.state = UART_Len;
- }
- else if (uart_rec_tmp == uart_rec.head) // UART_CMD ==> UART_Head
- uart_rec.state = UART_Head;
- else // UART_CMD ==> UART_Idle
- uart_rec.state = UART_Idle;
- break;
- case UART_Len:
- uart_rec.buf[uart_rec.cnt] = uart_rec_tmp;
- uart_rec.cnt++;
-
- if (uart_rec.cnt == uart_rec.len) // UART_Len ==> UART_Datas
- uart_rec.state = UART_Datas;
- break;
- case UART_Datas:
- if (uart_rec_tmp == checkUartBuf(&uart_rec)) // UART_Datas ==> UART_Complete
- uart_rec.state = UART_Complete;
- else if (uart_rec_tmp == uart_rec.head) // UART_Datas ==> UART_Head
- uart_rec.state = UART_Head;
- else // UART_Datas ==> UART_Idle
- uart_rec.state = UART_Idle;
- break;
- case UART_Complete: // 在 uart_recHandle() 中 UART_Complete ==> UART_Idle
- break;
- default: uart_rec.state = UART_Idle; break;
- }
复制代码
测试:(测试视频请查看附件)
奉上全部工程和文件:
modbus_fake.rar
(18.69 MB, 下载次数: 72)
|