STM8S modbus响应的简单处理

43 篇文章 2 订阅
10 篇文章 1 订阅

前言

板子上用了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);
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值