Arduino-Modbus-RTU-从站程序

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

//基本参数

#define baudrate 115200 //定义通讯波特率

#define slaveID 1 //定义modbus RTU从站站号

#define modbusDataSize 100 //定义modbus数据库空间大小,可根据实际情况自行修改大小

unsigned int modbusData[modbusDataSize]={}; //建立modbus数据库

//系统参数

#define bufferSize 255 //一帧数据的最大字节数量

unsigned char frame[bufferSize]; //用于保存接收或发送的数据

HardwareSerial* ModbusPort;

//函数声明

unsigned int calculateCRC(unsigned char* _regs,unsigned char arraySize); //声明CRC校验函数

void modbusRTU_slave(); //声明modbus RTU从站函数

void responseError(unsigned char ID,unsigned char function,unsigned char wrongNumber); //声明错误信息返回函数

void modbusRTU_INI(HardwareSerial *SerialPort); //声明modbus RTU端口初始化函数

//初始化函数

void setup()

{

delay(100);

modbusRTU_INI(&Serial); //定义modbus通讯端口端口0:&Serial 端口1:&Serial1 端口2:&Serial2

}

//主循环

void loop()

{

modbusRTU_slave(); //执行modbus函数

}

//modbus RTU端口初始化函数

//参数:端口号

void modbusRTU_INI(HardwareSerial *SerialPort)

{

ModbusPort = SerialPort;

(*ModbusPort).begin(baudrate);

(*ModbusPort).flush();

}

//modbus RTU从站函数

//支持功能码03,06,16

void modbusRTU_slave()

{

unsigned int characterTime; //字符时间

unsigned char errorFlag=0; //错误标志

unsigned int crc16; //校验位

unsigned char address=0;

if (baudrate > 19200) //波特率大于19200时进入条件

{

characterTime = 750;

}

else

{

characterTime = 15000000/baudrate; //1.5字符时间

}

while((*ModbusPort).available()>0) //如果串口缓冲区数据量大于0进入条件

{

if(address

{

frame[address]=(*ModbusPort).read();

address++;

}

else //条件不满足时直接清空缓冲区

{

(*ModbusPort).read();

}

delayMicroseconds(characterTime); //等待1.5个字符时间

if((*ModbusPort).available()==0) //1.5个字符时间后缓冲区仍然没有收到数据,认为一帧数据已经接收完成,进入条件

{

unsigned char function=frame[1]; //读取功能码

if(frame[0]==slaveID||frame[0]==0) //站号匹配或者消息为广播形式,进入条件

{

crc16 = ((frame[address - 2] << 8) | frame[address - 1]);

if(calculateCRC(&frame[0],address - 2)==crc16) //数据校验通过,进入条件

{

if (frame[0]!=0 && (function == 3)) //功能码03不支持广播消息

{

unsigned int startData=((frame[2] << 8) | frame[3]); //读取modbus数据库起始地址

unsigned int dataSize=((frame[4] << 8) | frame[5]); //需要读取的modbus数据库数据长度

unsigned int endData=startData+dataSize; //需要读取的modbus数据库数据的结束地址

unsigned char responseSize=5+dataSize*2; //计算应答的数据长度

unsigned int temp1,temp2,temp3;

if(dataSize>125 || endData>=modbusDataSize) //读取数据的结束地址超过了modbus数据库的范围或单次读取的数据数量大于125

{

errorFlag=0x02; //数据超过范围

responseError(slaveID,function,errorFlag); //返回错误消息

}

else

{

frame[0]=slaveID; //设定站号

frame[1]=function; //设定功能码

frame[2]=dataSize*2; //设定数据长度

temp3=3;

for(temp1=startData;temp1

{

temp2=modbusData[temp1]; //取出modbus数据库中的数据

frame[temp3]=temp2>>8;

temp3++;

frame[temp3]=temp2 & 0xFF;

temp3++;

}

crc16 = calculateCRC(&frame[0],responseSize-2);

frame[responseSize-2] = crc16 >> 8; //填写校验位

frame[responseSize-1] = crc16 & 0xFF;

(*ModbusPort).write(&frame[0],responseSize); //返回功能码03的消息

}

}

else if(function == 6) //功能码为06时进入条件

{

unsigned int startData=((frame[2] << 8) | frame[3]); //写入modbus数据库的地址

unsigned int setData=((frame[4] << 8) | frame[5]); //写入modbus数据库的数值

if(startData>=modbusDataSize)

{

errorFlag=0x02; //数据超过范围

responseError(slaveID,function,errorFlag); //返回错误消息

}

else

{

modbusData[startData]=setData; //写入数据到modbus数据库

frame[0]=slaveID; //设定站号

相关文档
最新文档