找回密码
 立即注册
查看: 420|回复: 6

Modbus RTU 从机处理机制 跟风 赚点积分

[复制链接]
  • TA的每日心情
    开心
    前天 08:38
  • 签到天数: 273 天

    [LV.8]以坛为家I

    20

    主题

    218

    回帖

    1677

    积分

    金牌会员

    积分
    1677
    发表于 2024-4-15 09:16:36 | 显示全部楼层 |阅读模式
    本帖最后由 小坤 于 2024-4-15 09:28 编辑

    1. 首先就是基础的串口配置就不说 。
    2. 接收超时机制根据实际的波特兰进行配置,3.5个字节~4个字节都是可以的。串口波特率可以修改的话,接收超时时间可以做成自动计算或者查表类。
    3.接收解析:
    void Modebus_PC_task(void)
    {
        if(UART3.Rx_OK)                 //接收完成
        {
                      //关闭接收
            Modbus.CRC_data = crc16( UART3.Rx_buff, (UART3.Rx_counter - 2));            //计算CRC校验值
            Modbus.CRC_H = Modbus.CRC_data >> 8;
            Modbus.CRC_L = Modbus.CRC_data & 0xFF;                                      //拆分高低位
            if((UART3.Rx_buff[UART3.Rx_counter - 2] == Modbus.CRC_H) && (UART3.Rx_buff[UART3.Rx_counter - 1] == Modbus.CRC_L))  //判断CRC校验是否正确
            {
                Modbus.address = UART3.Rx_buff[0];                                      //地址
                if((Modbus.address == Sys_addr)||(Modbus.address == Broad_addr))        //判断地址
                {
                    Modbus.CMD = UART3.Rx_buff[1];                                      //功能码
                    Modbus.Reg_addr =  UART3.Rx_buff[2]*256+UART3.Rx_buff[3];           //寄存器地址
                    switch(Modbus.CMD )
                    {
                         case 0x03 : PC_ReadReg();              break;                   //读寄存器
                         case 0x06:
                         case 0x10:  PC_WriteReg();             break;                   //写寄存器
                      //default:  Send_Err(Err_CMD);      break;                         //异常功能码
                    }
                }
            }
           // Delay_Ms(1);
            memset(&UART3.Rx_buff, 0, sizeof(UART3.Rx_buff));                             //内存清零
            UART3.Rx_OK = 0;                                                              //状态赋值
            UART3.Rx_counter = 0;                                                         //清零
                  // 打开接收
        }
    }

    4. 读寄存器
    void  PC_ReadReg(void)
    {
        Buff_u16_u8 Buff;
        uint8_t buff_n[255];
        uint16_t i=0;
        uint8_t n=0;

        Modbus.Reg_Len = UART3.Rx_buff[4]*256+UART3.Rx_buff[5];             //寄存器长度
        if((Modbus.Reg_Len<1)||(Modbus.Reg_Len>125))    return;             //寄存器个数范围   1<=寄存器数量<=125
        if(Modbus.Reg_addr+Modbus.Reg_Len >  Reg_len)   return;             //起始地址+寄存器长度<=总寄存器数量

        buff_n[n++] = Sys_addr ;                            //地址
        buff_n[n++] = Modbus.CMD;                           //功能码
        buff_n[n++] = Modbus.Reg_Len*2;                     //数据长度
        for(i=Modbus.Reg_addr; i<(Modbus.Reg_addr+Modbus.Reg_Len); i++ )
        {
            Buff.Dat = Modbus.Reg;
            buff_n[n++] = Buff.Byte[1];
            buff_n[n++] = Buff.Byte[0];                    //数据
        }
        Modbus.CRC_data = crc16( buff_n, n);
        buff_n[n++] = Modbus.CRC_data>>8;
        buff_n[n++] = Modbus.CRC_data&0xFF;                 //校验
        UART3_Send_n(buff_n, n);                            //中断发送
    }


    5.写寄存器
    void PC_WriteReg()
    {
        Buff_u16_u8 Buff;
        uint8_t buff_n[10];
        uint16_t i=0;
        uint8_t n=0;

        if( Modbus.CMD == 0X06 )                         //写单个寄存器
        {
            if( Modbus.Reg_addr <=  Reg_len)            //判断地址是否合规
            {
                Buff.Byte[1] = UART3.Rx_buff[4];
                Buff.Byte[0] = UART3.Rx_buff[5];         //获取数据
                Modbus.Reg[Modbus.Reg_addr] = Buff.Dat;          //寄存器赋值
            }
        }

        if( Modbus.CMD == 0X10 )        //写多个寄存器
        {
            Modbus.Reg_Len = UART3.Rx_buff[4]*256+UART3.Rx_buff[5];
            if((Modbus.Reg_Len<1)||(Modbus.Reg_Len>123))    return;         //寄存器个数范围   1<=寄存器数量<=123
            if(Modbus.Reg_Len*2!=UART3.Rx_buff[6])   return;                //数据字节数据范围  Modbus.Reg_Len*2
            if(Modbus.Reg_addr+Modbus.Reg_Len >  Reg_len)   return;        //起始地址+寄存器长度<=总寄存器数量

            for(i=Modbus.Reg_addr; i<(Modbus.Reg_addr+Modbus.Reg_Len); i++ )
            {
                    Buff.Byte[1] = UART3.Rx_buff[n+7];
                    n++;
                    Buff.Byte[0] = UART3.Rx_buff[n+7];;
                    n++;
                    Modbus.Reg = Buff.Dat;            //寄存器赋值
            }
        }

        for(n=0; n<6; n++)
        {
            buff_n[n] = UART3.Rx_buff[n];       //返回值
        }
        Modbus.CRC_data = crc16(buff_n, n);
        buff_n[n++] = Modbus.CRC_data>>8;
        buff_n[n++] = Modbus.CRC_data&0xFF;     //校验
        UART3_Send_n(buff_n, n);                //发送
    }


    以上就是从机的读写机制;



    结构体声明
    /****************   Modbus定义 **************************************/
    typedef struct
    {
        volatile  uint8_t   address;                //地址
        volatile  uint8_t    CMD;                    //功能码
        volatile  uint16_t   Reg_addr;               //寄存器地址
        volatile  uint16_t   Reg_Len;                //寄存器长度
    //   volatile  uint16_t   Read_Reg[Reg_len];      //读寄存器数组
    //   volatile  uint16_t   Write_Reg[Reg_len];     //写寄存器数组
        volatile  uint16_t   Reg[Reg_len];     //写寄存器数组

        volatile  uint16_t   CRC_data;               //CRC校验
        volatile  uint8_t    CRC_H;                  //CRC H
        volatile  uint8_t    CRC_L;                  //CRC L
        volatile  uint16_t   Err_code;               //异常码
    }Modbus_conf;

    数据 共用体
    /****************   共用体 *****************************/
    typedef union
    {
          unsigned int   Dat;
          unsigned char  Byte[2];
    }Buff_u16_u8;

    寄存器枚举
    enum MODBUS_REG
    {
        Start_Reg = 0,
        Sys_addr_Reg,     //设备地址
    /**************** 1号  ***************************/
        Status_1_Reg,     //状态
        Power_1_Reg,      //功率大小
        Mode_1_Reg,       //模式
        Time_1_Reg,       //时间
        Temp_1_Reg,       //温度
    /**************** 2号  ***************************/
        Status_2_Reg,     //状态
        Power_2_Reg,      //功率大小
        Mode_2_Reg,       //模式
        Time_2_Reg,       //时间
        Temp_2_Reg,       //温度
        Reg_len         //寄存器长度
    };

    可以参考的串口配置
    typedef struct
    {
        uint8_t state;                 //状态
        uint8_t RXDEnable;              //接收使能
        uint8_t TXDEnable;              //接收使能
        uint8_t TX_over_flag;           //发送完成标识
        uint8_t rx_buffer_overflow;     //接收溢出:
        char rx_over_time;              //接收溢出时间
        uint8_t rx_err;                 //校收出错
        uint8_t Rx_OK;                  //校收完成
        //接收
        uint8_t Rx_buff[RX_Len];//接收缓冲区
        uint8_t Rx_wr_index;                      //接收写指针
        uint8_t Rx_rd_index;                      //接收读指针
        uint8_t Rx_counter;                       //接收计数
        //发送
        uint8_t Tx_buff[TX_Len]; //发送缓冲区
        uint8_t Tx_Length;                        //需发送的数据长度
        uint8_t Tx_counter;                       //发送计数
    }Typedef_COMx;

    谢谢,勿喷,挣积分


    回复

    使用道具 举报 送花

  • TA的每日心情
    慵懒
    前天 09:03
  • 签到天数: 293 天

    [LV.8]以坛为家I

    28

    主题

    1804

    回帖

    4663

    积分

    论坛元老

    积分
    4663
    发表于 2024-4-15 09:21:16 | 显示全部楼层
    RTU?
    参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
    技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
    回复

    使用道具 举报 送花

  • TA的每日心情
    开心
    前天 08:38
  • 签到天数: 273 天

    [LV.8]以坛为家I

    20

    主题

    218

    回帖

    1677

    积分

    金牌会员

    积分
    1677
     楼主| 发表于 2024-4-15 09:28:48 | 显示全部楼层

    是的,写错了,修正
    回复 支持 反对

    使用道具 举报 送花

  • TA的每日心情
    开心
    前天 08:38
  • 签到天数: 273 天

    [LV.8]以坛为家I

    20

    主题

    218

    回帖

    1677

    积分

    金牌会员

    积分
    1677
     楼主| 发表于 2024-4-21 13:05:13 | 显示全部楼层
    ୧(๑•̀◡•́๑)૭
    回复 支持 反对

    使用道具 举报 送花

  • TA的每日心情
    慵懒
    昨天 10:15
  • 签到天数: 347 天

    [LV.8]以坛为家I

    31

    主题

    1264

    回帖

    3139

    积分

    论坛元老

    积分
    3139
    发表于 2024-4-21 14:34:10 | 显示全部楼层
    回复

    使用道具 举报 送花

  • TA的每日心情
    慵懒
    2024-10-8 11:44
  • 签到天数: 34 天

    [LV.5]常住居民I

    18

    主题

    24

    回帖

    276

    积分

    中级会员

    积分
    276
    发表于 2024-5-15 17:10:20 | 显示全部楼层
    支持楼主,学习了!谢谢1
    回复 支持 反对

    使用道具 举报 送花

  • TA的每日心情
    开心
    前天 15:45
  • 签到天数: 219 天

    [LV.7]常住居民III

    0

    主题

    18

    回帖

    924

    积分

    高级会员

    积分
    924
    发表于 2024-6-11 11:18:47 | 显示全部楼层
    感谢分享
    回复

    使用道具 举报 送花

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-11-11 04:04 , Processed in 0.070421 second(s), 61 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表