OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7715|回复: 19

求助modbus---51单片机通讯

[复制链接]

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
发表于 2021-6-8 18:01:25 | 显示全部楼层 |阅读模式
1金钱
想请教下大神们,用modbus协议写485通讯,其中的变量可以设置成xdata区吗?目前我写的程序,用串口助手可以正常收发,但是用死活都调不出。unsigned char xdata RecvBuf[32];                 //串口接收32个字节
unsigned char xdata SendBuf[32];                 //串口发送32个字节
unsigned char  RS485RecvCnt = 0;//接收
unsigned char  RS485SendCnt = 0;//发送
signed short xdata Address,Kp,Ki,Kd;//设置变量
signed short xdata*ModbusHoldReg[6];//寄存器映射地址
unsigned short StartRegAddress, RegisterNum;//寄存器首地址,和寄存器数量
unsigned char xdata Registerbuff[22];//
unsigned char xdata *pSendBuf = SendBuf;       //串口发送指针

/* 串口配置函数,baud-通信波特率 */void ConfigUART()
{
  RS485_DIR = 0; //RS485设置为接收方向
//        SCON=0x50; //[bit6:5]SM1 SM2 = 1 0;[bit4]REN=1
//  AUXR=0x11; //[bit4]BRTR=1,允许独立波特率发生器运行;[bit0]SIBRS=1,独立波特率作为串口1的波特率发生器,此时定时器1释放
//  BRT=0XFD;   //独特波特率发生器定时器(产生波特率9600)
//          EA=1;
//    ES=1;
        S2CON = 0x50;   //串口2工作在方式1  10位异步收发 S2REN=1允许接收
        AUXR = 0x10;    //BRTR=1 独立波特率发生器开始计数
        AUXR1 = 0x10;//从P1口切换到P4口
  BRT = 0xFD;           //独立波特率发生器初值     
  IE2 =0x01;        //开串口2中断  ES2=1
  EA =1;        //开总中断

}
/* 软件延时函数,延时时间(t*10)us */
void DelayX10us(unsigned char t)
{
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
}
/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite(unsigned char  *pSendBuf, unsigned char  RS485SendCnt)
{
          RS485_DIR = 1;  //RS485设置为发送
    while (RS485SendCnt--)   //循环发送所有字节//停止位去除
    {
        flagTxd = 0;      //清零发送标志
        S2BUF = *pSendBuf++;    //发送一个字节数据
        while (!flagTxd); //等待该字节发送完成
    }
    DelayX10us(5);  //等待最后的停止位完成,延时时间由波特率决定
    RS485_DIR = 0;  //RS485设置为接收
}
/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */

unsigned char UartRead(unsigned char xdata *buf, unsigned char len)
{
    unsigned char i;
    if (len > RS485RecvCnt)  //指定读取长度大于实际接收到的数据长度时,
    {                  //读取长度设置为实际接收到的数据长度
        len = RS485RecvCnt;
    }
    for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
    {
        *buf++ = RecvBuf;
    }
    RS485RecvCnt = 0;  //RS485RecvCnt = 0;  //接收计数器清零

    return len;  //返回实际读取长度
}
/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
void UartRxMonitor(unsigned char ms)
{
    static unsigned char cntbkp = 0;
    static unsigned char idletmr = 0;
    if (RS485RecvCnt> 0)  //接收计数器大于零时,监控总线空闲时间
    {
        if (cntbkp != RS485RecvCnt)  //接收计数器改变,即刚接收到数据时,清零空闲计时
        {
            cntbkp = RS485RecvCnt;
            idletmr = 0;
        }
        else                   //接收计数器未改变,即总线空闲时,累积空闲时间
        {
            if (idletmr < 30)  //空闲计时小于30ms时,持续累加
            {
                idletmr += ms;
                if (idletmr >= 30)  //空闲时间达到30ms时,即判定为一帧接收完毕
                {
                    flagFrame = 1;  //设置帧接收完成标志
                }
            }
        }
    }
    else
    {
        cntbkp = 0;
    }
}
/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver()
{
    unsigned char len;
    unsigned char xdata buf[40];

    if (flagFrame) //有命令到达时,读取处理该命令
    {
        flagFrame = 0;
        len = UartRead(buf, sizeof(buf)-2); //将接收到的命令读取到缓冲区中
        UartAction();  //传递数据帧,调用动作执行函数
    }
}
/* 串口中断服务函数 */
void InterruptUART2() interrupt 8//interrupt 4
{
         if (S2CON&S2RI)  //接收到新字节
    {
        S2CON&=~S2RI ;  //S2RI = 0;  //清零接收中断标志位
        if (RS485RecvCnt < sizeof(RecvBuf)) //接收缓冲区尚未用完时,
        {                            //保存接收字节,并递增计数器
            RecvBuf[RS485RecvCnt++] = S2BUF;
        }
    }
    if (S2CON&S2TI)  //字节发送完毕
    {
        S2CON&=~S2TI;     //S2TI=0 //S2TI = 0;   //清零发送中断标志位
        flagTxd = 1;  //设置字节发送完成标志
    }
}
这些是我的部分代码能否帮看看是哪里的问题


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-8 18:02:53 | 显示全部楼层
用modbus调试精灵死活通讯不成功
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-9 10:09:57 | 显示全部楼层
没人肯回答吗,我用串口通讯助手进行modbus通讯没误,但用modbus调试精灵就不能通讯成功,查了资料xdata是片外rom,不知道这个会不会有影响,因为data去太小了,所有用的xdata,请求大虾们帮看看啊
回复

使用道具 举报

12

主题

3389

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8643
金钱
8643
注册时间
2020-5-11
在线时间
4098 小时
发表于 2021-6-9 10:20:40 | 显示全部楼层
单片机啥型号?
编译结果data有多少?idata有多少?code有多少?
截图看看
专治疑难杂症
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-9 15:56:48 | 显示全部楼层
STC12C5A08S2     Program Size: data=9.2 xdata=700 code=3138
creating hex file from "lesson18_2"...
"lesson18_2" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:01
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-9 15:58:01 | 显示全部楼层
帮我看看呢,xdata区使用需要注意什么吗?
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 10:07:33 | 显示全部楼层
没有大神回答吗
回复

使用道具 举报

12

主题

3389

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8643
金钱
8643
注册时间
2020-5-11
在线时间
4098 小时
发表于 2021-6-10 12:40:55 | 显示全部楼层
本帖最后由 LcwSwust 于 2021-6-10 12:56 编辑
gdqxp 发表于 2021-6-9 15:56
STC12C5A08S2     Program Size: data=9.2 xdata=700 code=3138
creating hex file from "lesson18_2"...
...

点击楼层左下角的“回复”,我才能收到通知。
傲游截图20210610123348.jpg
xdata用法无误,详细说明可参考单片机的PDF手册中3.2.2节。
傲游截图20210610123848.jpg

你所说“死活都调不出”,
不知你做了哪些调试?比如检查接收到的数据是否存入了数组?字节数对不对?
程序中,检查下这一句看有什么问题:   *buf++ = RecvBuf;
可能是网页对代码显示有问题,有些东西未显示出来,以后发代码要点击<>添加代码文字,或把C文件(或工程)作为附件发上来。
傲游截图20210610125509.jpg

modbus调试精灵我不了解,也许它有检查CRC校验,但你的这段代码未能体现出有校验。

我更信任串口调试助手,如sscom5.13.1,直接看原始数据。



专治疑难杂症
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 13:55:35 | 显示全部楼层
首先非常感谢大神的解答,你那个贴中指出的 *buf++ = RecvBuf;是这样写的,复制的过程中可能复制漏了,下面这个是串口助手发送的modbus码,是可以接收到的,但是调试精灵不行,调试精灵不行后就无法和昆仑通态的屏通讯

,还麻烦帮看下啊,
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 14:47:29 | 显示全部楼层
*buf++ = RecvBuf;这个写的是这个,复制的时候复制错了,不知道为什么图片上传不了,好像问题在这里 UartWrite( SendBuf,(SendCnt));//
原函数是/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
  1. void UartWrite(unsigned char  *pSendBuf, unsigned char  RS485SendCnt)
  2. {
  3.           RS485_DIR = 1;  //RS485设置为发送
  4.     while (RS485SendCnt--)   //循环发送所有字节//停止位去除
  5.     {
  6.         flagTxd = 0;      //清零发送标志
  7.         S2BUF = *pSendBuf++;    //发送一个字节数据
  8.         while (!flagTxd); //等待该字节发送完成
  9.     }
  10.     DelayX10us(5);  //等待最后的停止位完成,延时时间由波特率决定
  11.     RS485_DIR = 0;  //RS485设置为接收
  12. }
复制代码

把这个应用到modbus协议里面的;STM32里面是这样写的 USART_SendData(USART_485, *pSendBuf++);可以正常通讯,我把这句改到51里面UartWrite( SendBuf,(SendCnt));用这个替代,不知道有没有影响啊
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 15:34:08 | 显示全部楼层
本帖最后由 gdqxp 于 2021-6-13 12:10 编辑

还麻烦大神帮看看啊!调试精灵里面发送 05 06 0004 0007 88 4D接收到07 88 4D;发送05 03 0002 0001 24 4E 接收89 87 4D,麻烦帮我看下啊,STM32程序是这样的

复制代码

//改成51是这样的
  1. * 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
  2. void UartWrite(unsigned char  *pSendBuf, unsigned char  RS485SendCnt)
  3. {
  4.           RS485_DIR = 1;  //RS485设置为发送
  5.     while (RS485SendCnt--)   //循环发送所有字节//停止位去除
  6.     {
  7.         flagTxd = 0;      //清零发送标志
  8.         S2BUF = *pSendBuf++;    //发送一个字节数据
  9.         while (!flagTxd); //等待该字节发送完成
  10.     }
  11.     DelayX10us(5);  //等待最后的停止位完成,延时时间由波特率决定
  12.     RS485_DIR = 0;  //RS485设置为接收
  13. }
  14. /* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */

  15. unsigned char UartRead(unsigned char xdata *buf, unsigned char len)
  16. {
  17.     unsigned char i;
  18.     if (len > RecvCnt)  //指定读取长度大于实际接收到的数据长度时,
  19.     {                  //读取长度设置为实际接收到的数据长度
  20.         len = RecvCnt;
  21.     }
  22.     for (i=0; i<len; i++)  //拷贝接收到的数据到接收指针上
  23.     {
  24.         *buf++ = RecvBuf[i];
  25.     }
  26.     RecvCnt = 0;  //RS485RecvCnt = 0;  //接收计数器清零
  27.    
  28.     return len;  //返回实际读取长度
  29. }

  30. /* 串口中断服务函数 */
  31. void InterruptUART2() interrupt 8//interrupt 4
  32. {
  33.          if (S2CON&S2RI)  //接收到新字节
  34.     {
  35.         S2CON&=~S2RI ;  //S2RI = 0;  //清零接收中断标志位
  36.         if (RecvCnt < sizeof(RecvBuf)) //接收缓冲区尚未用完时,
  37.         {                            //保存接收字节,并递增计数器
  38.             RecvBuf[RecvCnt++] = S2BUF;
  39.         }
  40.     }
  41.     if (S2CON&S2TI)  //字节发送完毕
  42.     {
  43.         S2CON&=~S2TI;     //S2TI=0 //S2TI = 0;   //清零发送中断标志位
  44.         flagTxd = 1;  //设置字节发送完成标志
  45.     }
  46. }
复制代码


会不会程序的错误在写的51函数的接收函数里啊,还麻烦大神帮看下啊
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 17:32:24 | 显示全部楼层
大神在吗?我的用串助手就可以发送:比如发送050600050003D84E接收到050600050003D84E;比如发送050300030001758E接收到05 03 02 65 A3 22 AD 、、个人感觉没有任何问题,但是用modbus调试精灵调试就像上面发的,连昆仑通态的屏也毫无反应。特别的急,我已经在这个死循环里好多天了
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 17:55:20 | 显示全部楼层
3397372037这个是我qq可以加我,能解决这个问题可以有偿回报的,非常感谢
回复

使用道具 举报

12

主题

3389

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8643
金钱
8643
注册时间
2020-5-11
在线时间
4098 小时
发表于 2021-6-10 19:44:57 | 显示全部楼层
再次提醒,点击我所在楼层的左下方“回复”我才能收到通知,一闪一闪的通知。
你在最底下“发表回复”就如同别人回复了你的帖,我是不知道的,需找到你的帖子点开来看才能看到。
modbus是有CRC校验的,此事你可知晓?你这些代码未能体现CRC。
专治疑难杂症
回复

使用道具 举报

12

主题

3389

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8643
金钱
8643
注册时间
2020-5-11
在线时间
4098 小时
发表于 2021-6-10 19:58:04 | 显示全部楼层
我的一段代码,添加了CRC,仅供参考:
  1. //--------------------------------------------------
  2. //CRC16计算
  3. //nbyte为字节数
  4. //多项式=X16+X15+X2+1

  5. //--------------------------------------------------
  6. U16 crc16(U8 *p,U8 nbyte)   
  7. {  
  8.         U16 crc=0xffff;
  9.         U8 i,d;
  10.         while(nbyte--)   
  11.         {  
  12.                 d=*(p++);
  13.                 for(i=0x01;i;i<<=1)               
  14.                 {      
  15.                         if(crc&0x1){crc>>=1;crc^=0xA001;}
  16.                         else crc>>=1;                        //数据同CRC最低位相异或
  17.                         if(d&i)crc^=0xA001;                //数据都是低位在前
  18.                 }               
  19.         }
  20.         return(crc);
  21. }
  22. //--------------------------------------------------
  23. //串口4发送一串数据
  24. //--------------------------------------------------
  25. void uart4sendframe(U8 s[],U8 size)//发送一帧
  26. {
  27.         U16 i,crc;
  28.         U8        chk=0;
  29.         crc=crc16(s,size);
  30.         for(i=0;i<size;i++)                //数据区
  31.         {
  32.                 uart4_sendbyte(s[i]);
  33.         }
  34.         uart4_sendbyte(crc);        //校验
  35.         uart4_sendbyte(crc>>8);
  36. }
  37. //读取寄存器
  38. void mod_GetReg(U16 add)
  39. {
  40.         uart4buf_tx[0] =0x01;//ADD
  41.         uart4buf_tx[1] =0x03;//CMD
  42.         uart4buf_tx[2] =add>>8;//reg addr_h
  43.         uart4buf_tx[3] =add;//reg addr_l
  44.         uart4buf_tx[4] =0x00;//reg cnt_h
  45.         uart4buf_tx[5] =0x01;//reg cnt_l
  46.         uart4sendframe(uart4buf_tx,6);
  47. }
复制代码
专治疑难杂症
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 21:10:59 | 显示全部楼层
本帖最后由 gdqxp 于 2021-6-11 17:49 编辑
我的一段代码,添加了CRC,仅供参考:

//变量寄存器地址映射,从0开始
void Modbus_RegMap()
{
  ModbusHoldReg[0] = (signed short*)&Address;                       //设备地址
  ModbusHoldReg[1] = (signed short*)&frequency;                     //频率
  ModbusHoldReg[2] = (signed short*)&duty_3;                        //占空比
  ModbusHoldReg[3] = (signed short*)&Kp;                           
  ModbusHoldReg[4] = (signed short*)&Ki;               
  ModbusHoldReg[5] = (signed short*)&Kd;                    
}
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 21:16:18 | 显示全部楼层
本帖最后由 gdqxp 于 2021-6-11 17:40 编辑
LcwSwust 发表于 2021-6-10 19:58
我的一段代码,添加了CRC,仅供参考:

大神我的modbus协议//变量寄存器地址映射,从0开始

回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 21:27:30 | 显示全部楼层
本帖最后由 gdqxp 于 2021-6-11 17:49 编辑
我的一段代码,添加了CRC,仅供参考:

//变量寄存器地址映射,从0开始
void Modbus_RegMap()
{
  ModbusHoldReg[0] = (signed short*)&Address;                       //设备地址
  ModbusHoldReg[1] = (signed short*)&frequency;                     //频率
  ModbusHoldReg[2] = (signed short*)&duty_3;                        //占空比
  ModbusHoldReg[3] = (signed short*)&Kp;                           
  ModbusHoldReg[4] = (signed short*)&Ki;               
  ModbusHoldReg[5] = (signed short*)&Kd;                    
}
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 21:41:46 | 显示全部楼层
LcwSwust 发表于 2021-6-10 19:58
我的一段代码,添加了CRC,仅供参考:

能看到我的回复吗
回复

使用道具 举报

2

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2018-11-7
在线时间
11 小时
 楼主| 发表于 2021-6-10 22:09:19 | 显示全部楼层
本帖最后由 gdqxp 于 2021-6-13 12:08 编辑

现在我把程序贴上啊:

  1. void Modbus_RegMap()
  2. {
  3.   ModbusHoldReg[0] = (signed short*)&Address;                       //设备地址
  4.   ModbusHoldReg[1] = (signed short*)&frequency;                     //频率
  5.   ModbusHoldReg[2] = (signed short*)&duty_3;                        //占空比
  6.   ModbusHoldReg[3] = (signed short*)&Kp;                           
  7.   ModbusHoldReg[4] = (signed short*)&Ki;               
  8.   ModbusHoldReg[5] = (signed short*)&Kd;                    
  9. }
  10. void Modbus_Backup_RegMap(void)
  11. {
  12.         //备份寄存器
  13.   Backup_ModbusHoldReg[0] = (signed short*)&Backup_Address;         
  14.   Backup_ModbusHoldReg[1] = (signed short*)&Backup_frequency;      
  15.   Backup_ModbusHoldReg[2] = (signed short*)&Backup_duty_3;   
  16.   Backup_ModbusHoldReg[3] = (signed short*)&Backup_Kp;        
  17.   Backup_ModbusHoldReg[4] = (signed short*)&Backup_Ki;  
  18.   Backup_ModbusHoldReg[5] = (signed short*)&Backup_Kd;      
  19. }//CRC效验
  20. unsigned short CRCData(unsigned char xdata *ptr,unsigned char len)
  21. {
  22.   unsigned char CRCDataH = 0xFF;
  23.         unsigned char CRCDataL = 0xFF;
  24.         unsigned char Index=0;
  25.         unsigned short         CRCResult=0;
  26.         while(len--)
  27.         {
  28.                 Index = CRCDataH ^ *ptr++;
  29.                 CRCDataH = CRCDataL ^ RevCRC16H[Index];
  30.                 CRCDataL = RevCRC16L[Index];
  31.         }
  32.         CRCResult = (((unsigned short)CRCDataL)<<8)|CRCDataH;
  33.         return(CRCResult);
  34. } /* 串口动作函数,根据接收到的命令帧执行响应的动作
  35.    buf-接收到的命令帧指针,len-命令帧长度 */
  36. void UartAction()
  37. {
  38.   unsigned short RegCRC;
  39.         unsigned short CalCRC;
  40. //        if(flagFrame == 1)
  41. //        {
  42. //                flagFrame=0;
  43.         if((RecvBuf[0] == Address)||(RecvBuf[0] == 0))
  44.   {
  45.                 if((RecvBuf[1] == 03)||(RecvBuf[1] == 06)||(RecvBuf[1] == 16))//功能码
  46.                 {
  47.                         StartRegAddress = ((((unsigned short)RecvBuf[2])<<8)|RecvBuf[3]);//寄存器起始地址
  48.                   if(StartRegAddress < 100)
  49.                         {
  50.                                 CalCRC = CRCData(RecvBuf,(RecvCnt-2));                                      /???CRCD£?é??           
  51.                                 RegCRC = (((unsigned short)RecvBuf[RecvCnt-1])<<8)|RecvBuf[RecvCnt-2]; /????óê?μ?μ?CRCD£?é??
  52.                                 RegCRC = CalCRC; //*****2aê?íê±?oó′?ì???á?é?3y*****
  53.                                 if(CalCRC == RegCRC)      
  54.                                 {
  55.                                                 switch(RecvBuf[1])
  56.                                           {
  57.                                                   case 03: //读多个寄存器
  58.                                                                ReadManyRegister(RecvBuf,SendBuf);
  59.                                                          break;
  60.                                                   case 06: //写单个寄存器
  61.                                                                WriteOneRegister(RecvBuf,SendBuf);
  62.                                                          break;
  63.                                                   case 16: //写多个寄存器
  64.                                                                WriteManyRegister(RecvBuf,SendBuf);
  65.                                                                break;
  66.                                           }
  67.                                         }
  68.                                   else                                       //CRCD£?é′í?ó
  69.                                   {
  70.                               SendBuf[0] = RecvBuf[0];
  71.                               SendBuf[1] = RecvBuf[1]|0x80;
  72.                               SendBuf[2] = 0x04;                       //′í?ó′ú??0x04:CRCD£?é??òì3£
  73.                                           CalCRC = CRCData(SendBuf,3);        
  74.                         SendBuf[3] = CalCRC&0xFF;
  75.                         SendBuf[4] = (CalCRC>>8)&0xFF;               
  76.                         SendCnt = 6;                //               
  77.                                   }
  78.                         }
  79.                         else//超出范围
  80.                         {
  81.                             SendBuf[0] = RecvBuf[0];
  82.                             SendBuf[1] = RecvBuf[1]|0x80;
  83.                             SendBuf[2] = 0x02;                           //0x02:寄存器地址超出范围
  84.                             CalCRC = CRCData(SendBuf,3);               
  85.                       SendBuf[3] = CalCRC&0xFF;
  86.                       SendBuf[4] = (CalCRC>>8)&0xFF;               
  87.                       SendCnt = 6;
  88.                         }
  89.          }
  90.          else  //功能码错误
  91.          {
  92.                           SendBuf[0] = RecvBuf[0];
  93.                           SendBuf[1] = RecvBuf[1]|0x80;
  94.                           SendBuf[2] = 0x01;                           //0x01:功能码错误
  95.         CalCRC = CRCData(SendBuf,3);                                
  96.                     SendBuf[3] = CalCRC&0xFF;
  97.                     SendBuf[4] = (CalCRC>>8)&0xFF;               
  98.                     SendCnt = 6;        
  99.          }
  100.     RecvCnt = 0;
  101.                 pSendBuf = SendBuf;
  102.                 RS485_DIR = 1;//准备发送
  103.                 UartWrite( SendBuf, (SendCnt-1));
  104.   }
  105. //}

  106. //读多个寄存器地址
  107. void ReadManyRegister(unsigned char xdata*RecvBuf,unsigned char xdata*SendBuf)            
  108. {
  109.         unsigned char  i=0;
  110.   unsigned short CalCRC;   
  111.         RegisterNum = (((unsigned short)RecvBuf[4])<<8)|RecvBuf[5];        //获取寄存器数量
  112.   if((StartRegAddress+RegisterNum)<100)//地址小于100
  113.         {
  114.                 SendBuf[0] = RecvBuf[0];
  115.                 SendBuf[1] = RecvBuf[1];
  116.                 SendBuf[2] = RegisterNum<<1;//字节数为寄存器的两倍
  117.                 for(i=0;i<RegisterNum;i++)//把接收到的数据写进去
  118.                 {
  119.       SendBuf[3+i*2] = (*ModbusHoldReg[StartRegAddress+i]>>8)&0xFF;  //先发送高字节再发送低字节
  120.       SendBuf[4+i*2] = (*ModbusHoldReg[StartRegAddress+i])&0xFF;   
  121.                 }
  122.                 CalCRC = CRCData(SendBuf,((RegisterNum<<1)+3));
  123.                 SendBuf[(RegisterNum<<1)+3] = CalCRC&0xFF;
  124.                 SendBuf[(RegisterNum<<1)+4] = (CalCRC>>8)&0xFF;
  125.                 SendCnt = SendBuf[2]+6;
  126.         }
  127.         else                                                               //寄存器地址+数量超出范围
  128.         {
  129.                 SendBuf[0] = RecvBuf[0];
  130.                 SendBuf[1] = RecvBuf[1]|0x80;
  131.                 SendBuf[2] = 0x02;                                               //错误代码
  132.     CalCRC = CRCData(SendBuf,3);        
  133.                 SendBuf[3] = CalCRC&0xFF;
  134.                 SendBuf[4] = (CalCRC>>8)&0xFF;               
  135.                 SendCnt = 6;//
  136.         }        
  137.          RecvCnt = 0;
  138.          pSendBuf = SendBuf;
  139.          RS485_DIR = 1;//准备发送
  140.          UartWrite( SendBuf,(SendCnt-1));
  141. }




复制代码
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-22 19:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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