前言
板子上用了STM8S003F3P6,代码空间很紧张。
对串口接收的回包处理,只简单处理了一下。
同事测试时,发现接多块同型号板子,查询时,无响应。接一块是好使的。
看上位机日志,发现查询包长短不一,协议也不一样。
将下位机收包时的modbus查询包,一个一个字节的判断才好使。
回包响应的工程片段
开发环境 : IAR for STM8 3.11.1
/* 串口接收数据中断服务函数 */
#pragma vector = 0x14 //设置串口接收中断向量号 = 0X14
__interrupt void UART1_RX_RXNE(void)
{
// unsigned char ch1;
UART1_SR_RXNE = 1; //清除中断标志
// ch1 = UART1_DR; //读出串口接收到的数据
// Uart_SendData(ch1); //把接收到的数据再通过串口发送出去
if (uart_recv_buf_cb >= (UART1_RECV_BUF_LEN - 1)) {
uart_recv_buf_cb = 0;
}
uart_recv_buf[uart_recv_buf_cb] = UART1_DR;
uart_recv_buf_cb++;
process_uart1_rx();
}
void process_uart1_rx(void)
{
BOOL b_err = FALSE;
BOOL b_need_answer = FALSE;
u8 crc16_H = 0;
u8 crc16_L = 0;
u16 u16_tmp = 0;
do {
// recv 01 03 00 00 00 02 C4 0B
// 接受的modbus指令位 addr 03 00 00 00 02 CRC16_modbus_H CRC16_modbus_L
// uart_recv_buf[0] = this_device_addr
if (uart_recv_buf_cb < 1) {
break;
}
if (P01_485_ADDR != uart_recv_buf[0]) {
b_err = TRUE;
break;
}
if (uart_recv_buf_cb < 2) {
break;
}
// uart_recv_buf[1] = 03 cmd;
if (MODBUS_CMD != uart_recv_buf[1]) {
b_err = TRUE;
break;
}
if (uart_recv_buf_cb < 8) {
break;
}
// 开始计算校验和
// uart_recv_buf[6] = CRC16_modbus_H
// uart_recv_buf[7] = CRC16_modbus_L
CRC16_modbus(uart_recv_buf, 6, &crc16_H, &crc16_L);
if ((crc16_H != uart_recv_buf[6]) || (crc16_L != uart_recv_buf[7])) {
b_err = TRUE; // 校验和错了,不需要回答
break;
}
// uart_recv_buf[2] = reg_addr_H
if (MODBUS_REG_BEGIN_H != uart_recv_buf[2]) {
b_err = TRUE;
b_need_answer = TRUE; // 回答参数错就好
break;
}
// uart_recv_buf[3] = reg_addr_L
if (MODBUS_REG_BEGIN_L != uart_recv_buf[3]) {
b_err = TRUE;
b_need_answer = TRUE; // 回答参数错就好
break;
}
// uart_recv_buf[4] = reg_read_cnt_H
if (MODBUS_REG_READ_CNT_H != uart_recv_buf[4]) {
b_err = TRUE;
b_need_answer = TRUE; // 回答参数错就好
break;
}
// uart_recv_buf[5] = reg_read_cnt_L
if (MODBUS_REG_READ_CNT_L != uart_recv_buf[5]) {
b_err = TRUE;
b_need_answer = TRUE; // 回答参数错就好
break;
}
// 可以回答实时温湿度
uart_recv_buf_cb = 0;
b_need_answer = TRUE;
} while (0);
if (b_need_answer) {
if (b_err) {
// 错误回答 03 非法数据值
uart_send_buf_cb = 5;
uart_send_buf[0] = P01_485_ADDR;
uart_send_buf[1] = MODBUS_CMD | 0x80;
uart_send_buf[2] = 0x03; // 非法数据值
CRC16_modbus(uart_send_buf, 3, &uart_send_buf[3], &uart_send_buf[4]);
}
else {
// 返回实时温湿度
uart_send_buf_cb = 9;
uart_send_buf[0] = P01_485_ADDR;
uart_send_buf[1] = MODBUS_CMD;
uart_send_buf[2] = 0x04; // 回答的字节数
if (temperature_cur > 0) {
u16_tmp = temperature_cur;
} else {
u16_tmp = -temperature_cur;
u16_tmp |= 0x8000;
}
uart_send_buf[3] = (u8)((u16_tmp >> 8) & 0xff); // 温度H
uart_send_buf[4] = (u8)((u16_tmp >> 0) & 0xff); // 温度H
if (humidity_cur > 0) {
u16_tmp = humidity_cur;
} else {
u16_tmp = -humidity_cur;
u16_tmp |= 0x8000;
}
uart_send_buf[5] = (u8)((u16_tmp >> 8) & 0xff); // 温度H
uart_send_buf[6] = (u8)((u16_tmp >> 0) & 0xff); // 温度H
CRC16_modbus(uart_send_buf, uart_send_buf_cb - 2, &uart_send_buf[7], &uart_send_buf[8]);
}
Uart1_SendBuf(uart_send_buf, uart_send_buf_cb);
uart_recv_buf_cb = 0;
}
// 接收超时处理, 不是发给自己的/错包
if (b_err) {
uart_recv_buf_cb = 0;
}
}
// #pragma optimize=none
void CRC16_modbus(u8* buf, u8 len, u8* crc16_H, u8* crc16_L)
{
u16 i = 0;
u16 j = 0;
u16 tmp = 0;
u16 CRC16 = 0xFFFF; // CRC寄存器初始值
for (i = 0; i < len; i++)
{
CRC16 ^= (u16)buf[i];
for (j = 0; j < 8; j++)
{
tmp = (u16)(CRC16 & 0x0001);
CRC16 >>= 1;
if (tmp == 1)
{
CRC16 ^= 0xA001; //异或多项式
}
}
}
*crc16_H = (u8)(CRC16 & 0x00FF);
*crc16_L = (u8)((CRC16 & 0xFF00)>>8);
}