最近研究了一下MODBUS通信,在STC12C5A60S2单片机上实现了MODBUS协议的部分功能,方便上位机从单片机系统上获取数据,比如由单片机获取的温度、湿度、或者控制信号的状态等。有了MODBUS协议后,上位机的开发就很方便了,可以使用C#等高级语言通过串口通信,或者使用组态王直接通过串口通信而不需要写代码,这些都归功于MODBUS协议的开放性,很多的组态软件都能提供对他的支持。甚至通过PLC直接可以和单片机通信,比如在PLC系统上没有AD时,可以使用单片也来进行AD,然后通过MODBUS返回给PLC进行相应的控制。 通过MODBUS协议可以实现主机和多个从机进行通谢,而每个从机有唯一的地址,主机就靠这个地址和从机进行通信。每一帧数据都要通过CRC进行校验,保证通信的正确性。 在进行多机通信时只需要把每个从机的串口并到一起即可,见后面的图。 单片机中3号功能的核心代码如下: unsigned
char createRespond_M(unsigned
char *respondMessage,unsigned
char* _messageReceived ,unsigned
int*
_registerData)
{
unsigned char i,j;
unsigned char numberOfPoints =
0;
unsigned char _slaveAddress =
0 ;
unsigned char bytesToSend =
0;
unsigned char startAddress=
0;
unsigned char crcCalculation[]={
0,
0,
0};
unsigned int CntHi = _messageReceived[
4];
//将其转换为int型,然后放到高8位。
CntHi = CntHi<<
8;
numberOfPoints = CntHi| _messageReceived[
5];
if(numberOfPoints >
MaxnumberOfPoints)
{
return 0;
}
bytesToSend =
2 * numberOfPoints +
5;
_slaveAddress = _messageReceived[
0];
respondMessage[0] =
_slaveAddress;
respondMessage[1] =
3;
respondMessage[2] =
2 *
numberOfPoints;
startAddress = (((unsigned
int)(_messageReceived[
2])) <<
8) | _messageReceived[
3];
j=
0;
for (i =
0; i < numberOfPoints; i++
)
{
respondMessage[i + j +
3] = ((_registerData[startAddress + i] >>
8) &
0xff);
respondMessage[i + j +
4] =(_registerData[startAddress + i] &
0xff);
j++
;
}
calculateCRC(respondMessage, bytesToSend -
2,crcCalculation);
respondMessage[bytesToSend -
2] = crcCalculation[
0];
respondMessage[bytesToSend -
1] = crcCalculation[
1];
return bytesToSend;
}
//对接收的数据进行CRC检验,同时判断是否为Address所指定的从机地址和是否为function3功能。
bit CheckRecData(unsigned
char * RecData,unsigned
char Address)
{
if(RecData[
0] == Address && RecData[
1] ==
3)
//地址为自己的地址,同时功能码为3(function 3)
{
if(checkCRC(RecData,
8))
{
return 1;
}
}
return 0;
} 本例中每个从机返回80个字节的数据,1号机返回i+1, 2号机返回2*i+1 ,当然在实际运用中只要自己定义所返回的数据的含义即可。比如1,2字节代表温度,3,4字节代表湿度,接下来的4个字节代表P0,P1,P2,P3端口的状态等。可以自由定义,很方便。
具体效果见下图:
把两块板的串口通过杜绑线连在一起。
在TEXTBOX中输入从机的地址,返回相应的数据
如果输入的地址从机不存在,那么通信将会超时,就会提示通信故障。这个是根据通信超时来判断的。