2019-10-16 00:35发布
yklstudent 发表于 2016-7-19 13:19 你要做的就是做个MODBUS协议主机,周期读取MODBUS协议从机的内容;
song15032 发表于 2016-7-19 13:32 是啊,可是主机的Modbus协议怎么读取呢。 这是我从机部分 Modbus内容: [mw_shl_code=c,true]/********* ...
最多设置5个标签!
是啊,可是主机的Modbus协议怎么读取呢。 这是我从机部分 Modbus内容:
[mw_shl_code=c,true]/*******************************串口发送函数 ********************************/
void Begin_send(void)
{
DE_OUT; //处于发送
uartsends(sendBuf,sendCount);
DE_IN; //发送完后将485置于接收状态
receCount = 0; //清接收地址偏移寄存器
}
//fuction:01 读单个或多个线圈状态
void readCoils(void)
{
uint addr;
uint tempAddr;
uint byteCount;
uint bitCount;
uint crcData;
uint position;
uint i,k;
uint tempData;
uchar exit = 0;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr;
bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数
byteCount = bitCount / 8; //字节个数
if(bitCount%8 != 0)
byteCount++;
for(k=0;k<byteCount;k++)//字节位置
{
position = k + 3;
sendBuf[position] = 0;
for(i=0;i<8;i++)
{
getCoilVal(tempAddr,&tempData);
sendBuf[position] |= tempData << i;
tempAddr++;
if(tempAddr >= addr+bitCount)//读完
{
exit = 1;
break;
}
}
if(exit == 1)
break;
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 0x01;
sendBuf[2] = byteCount;
byteCount += 3;
crcData = crc16(sendBuf,byteCount);
sendBuf[byteCount] = crcData & 0xff;
byteCount++;
sendBuf[byteCount] = crcData >> 8;
sendCount = byteCount + 1;
Begin_send();
}
//fuction:02 读取线圈输入(只读寄存器)状态
void readInPutCoils(void)
{
uint addr;
uint tempAddr;
uint byteCount;
uint bitCount;
uint crcData;
uint position;
uint i,k;
uint tempData;
uchar exit = 0;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr +10000; //只读线圈寄存器偏移地址10000
bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数
byteCount = bitCount / 8; //字节个数
if(bitCount%8 != 0)
byteCount++;
for(k=0;k<byteCount;k++)//字节位置
{
position = k + 3;
sendBuf[position] = 0;
for(i=0;i<8;i++)
{
getCoilVal(tempAddr,&tempData);
sendBuf[position] |= tempData << i;
tempAddr++;
if(tempAddr >= addr+10000+bitCount)//读完
{
exit = 1;
break;
}
}
if(exit == 1)
break;
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 0x02;
sendBuf[2] = byteCount;
byteCount += 3;
crcData = crc16(sendBuf,byteCount);
sendBuf[byteCount] = crcData & 0xff;
byteCount++;
sendBuf[byteCount] = crcData >> 8;
sendCount = byteCount + 1;
Begin_send();
}
/********function code : 03,读取多个寄存器值 ********/
void readRegisters(void)
{
uint addr;
uint tempAddr;
uint crcData;
uint readCount;
uint byteCount;
uint i;
uint tempData = 0;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr+40000; //+40000,保持寄存器偏移地址
readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数 ,整型
byteCount = readCount * 2; //每个寄存器内容占高,低两个字节
for(i=0;i<byteCount;i+=2,tempAddr++)
{
getRegisterVal(tempAddr,&tempData);
sendBuf[i+3] = tempData >> 8;
sendBuf[i+4] = tempData & 0xff;
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 3; //function code : 03
sendBuf[2] = byteCount;
byteCount += 3; //加上前面的地址,功能码,地址 共3+byteCount个字节
crcData = crc16(sendBuf,byteCount);
sendBuf[byteCount] = crcData & 0xff; // CRC代码低位在前
byteCount++;
sendBuf[byteCount] = crcData >> 8 ; //高位在后
sendCount = byteCount + 1; //例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发
Begin_send();
}
//fuction 04:读取输入寄存器
void readInPutRegisters(void)
{
uint addr;
uint tempAddr;
uint crcData;
uint readCount;
uint byteCount;
uint i;
uint tempData = 0;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr+30000; //+输入寄存器偏移地址:30000
readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数 ,整型
byteCount = readCount * 2; //每个寄存器内容占高,低两个字节
for(i=0;i<byteCount;i+=2,tempAddr++)
{
getRegisterVal(tempAddr,&tempData);
sendBuf[i+3] = tempData >> 8;
sendBuf[i+4] = tempData & 0xff;
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 4; //function code : 04
sendBuf[2] = byteCount;
byteCount += 3; //加上前面的地址,功能码,地址 共3+byteCount个字节
crcData = crc16(sendBuf,byteCount);
sendBuf[byteCount] = crcData & 0xff; // CRC代码低位在前
byteCount++;
sendBuf[byteCount] = crcData >> 8 ; //高位在后
sendCount = byteCount + 1; //例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发
Begin_send();
}
//fuction:05 ,强制单个线圈
void forceSingleCoil(void)
{
uint addr;
uint tempAddr;
uint tempData;
uint onOff;
uchar i;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr;
onOff = (receBuf[4]<<8) + receBuf[5];
if(onOff == 0xff00)
{
tempData = 1;//设为ON
}
else if(onOff == 0x0000)//设为OFF
{
tempData = 0;
}
setCoilVal(tempAddr,tempData);
for(i=0;i<receCount;i++)
{
sendBuf = receBuf;
}
sendCount = receCount;
Begin_send();
}
/****************fuction:06设置单个寄存器ok**********************************************************/
//主机器发送 地址,功能码,寄存器高位,寄存器低位,数据数高位, 数数低位,CRC低位,CRC高位
//例如设置D0 发送, 01 06 00 3F 00 01 */
/*********************************************************************************/
void presetSingleRegister(void)
{
uint addr;
uint tempAddr;
uint tempData;
uint crcData;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = (addr+40000);
tempData = (receBuf[4]<<8) + receBuf[5];
setRegisterVal(tempAddr,tempData);
sendBuf[0] = LocalAddr;
sendBuf[1] = 6; //function code : 16
sendBuf[2] = addr >> 8; //寄存器地址高位
sendBuf[3] = addr & 0xff;//寄存器地址低位
sendBuf[4] =receBuf[4];
sendBuf[5] =receBuf[5];
crcData = crc16(sendBuf,6);//生成CRC校验码
sendBuf[6] = crcData & 0xff; //CRC代码低位在前
sendBuf[7] = crcData >> 8; //高位在后
sendCount = 8;
Begin_send();
}
/********从机响应主机问询函数,function code : 15,强置多线圈值 *********/
//////////////询问数据包格式:
///////////////////////// receBuf[0] receBuf[1] receBuf[2] receBuf[3] receBuf[4] receBuf[5] receBuf[6] receBuf[7] receBuf[8] ... receBuf[9] receBuf[10]
//询问数据格式:receBuf[]={从站地址, 功能码, 起始地址高位,起始地址低位,寄存器数高位,寄存器数低位, 字节计数, 数据高位, 数据低位,... 校验码低位, 校验码高位}
/****************************************************************************/
void forceMultipleCoils(void)
{
uint addr;
uint tempAddr;
uint byteCount;
uint bitCount;
uint crcData;
uint tempData;
uint i,k;
uchar exit = 0;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr;
bitCount = (receBuf[4]<<8) + receBuf[5];
byteCount = bitCount / 8; //字节个数
if(bitCount%8 != 0)
byteCount++;
for(k=0;k<byteCount;k++)//字节位置
{
for(i=0;i<8;i++)
{
tempData = (receBuf[k+3] >>i)&0x01;
setCoilVal(tempAddr,tempData);
tempAddr++;
if(tempAddr >= addr+bitCount)//读完
{
exit = 1;
break;
}
}
if(exit == 1)
break;
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 15; //function code : 16
sendBuf[2] = addr >> 8; //寄存器地址高位
sendBuf[3] = addr & 0xff;//寄存器地址低位
sendBuf[4] = bitCount >> 8;//待设置寄存器数量高位
sendBuf[5] = bitCount & 0xff;//待设置寄存器数量低位
crcData = crc16(sendBuf,6);//生成CRC校验码
sendBuf[6] = crcData & 0xff; //CRC代码低位在前
sendBuf[7] = crcData >> 8; //高位在后
sendCount = 8;
Begin_send();
}
/********从机响应主机问询函数,function code : 16,设置多个寄存器值 *********/
//////////////询问数据包格式:
///////////////////////// receBuf[0] receBuf[1] receBuf[2] receBuf[3] receBuf[4] receBuf[5] receBuf[6] receBuf[7] receBuf[8] ... receBuf[9] receBuf[10]
//询问数据格式:receBuf[]={从站地址, 功能码, 起始地址高位,起始地址低位,寄存器数高位,寄存器数低位, 字节计数, 数据高位, 数据低位,... 校验码低位, 校验码高位}
/****************************************************************************/
void presetMultipleRegisters(void)
{
uint addr;
uint tempAddr;
uint setCount;
uint crcData;
uint tempData;
uchar i;
addr = (receBuf[2]<<8) + receBuf[3];
tempAddr = addr+40000;
setCount = (receBuf[4]<<8) + receBuf[5];
for(i=0;i<setCount;i++,tempAddr++)
{
tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];//待设置寄存器值
setRegisterVal(tempAddr,tempData);
}
sendBuf[0] = LocalAddr;
sendBuf[1] = 16; //function code : 16
sendBuf[2] = addr >> 8; //寄存器地址高位
sendBuf[3] = addr & 0xff;//寄存器地址低位
sendBuf[4] = setCount >> 8;//待设置寄存器数量高位
sendBuf[5] = setCount & 0xff;//待设置寄存器数量低位
crcData = crc16(sendBuf,6);//生成CRC校验码
sendBuf[6] = crcData & 0xff; //CRC代码低位在前
sendBuf[7] = crcData >> 8; //高位在后
sendCount = 8;
Begin_send();
}
/*************************查询uart接收的数据包内容函数 **************************/
////函数功能:丛机根据串口接收到的数据包receBuf[1]里面的内容,即function code执行相应的命令
/********************************************************************************/
void checkComm0Modbus(void) //10ms内必须响应接收数据
{
uint crcData;
uint tempData;
uint temp;
if(receCount > 4) //如果接收到数据
{
switch(receBuf[1])
{
case 1: //读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 1)
{
readCoils(); //读取线圈输出状态(一个或多个)
}
receCount = 0;
}
}
break;
}
case 2: //读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 2)
{
readInPutCoils(); //读取线圈输入状态(一个或多个)
}
receCount = 0;
}
}
break;
}
case 3: //读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 3)
{
readRegisters(); //读取保持寄存器(一个或多个)
}
receCount = 0;
}
}
break;
}
case 4: //读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 4)
{
readInPutRegisters(); //读取输入寄存器(一个或多个)
}
receCount = 0;
}
}
break;
}
case 5: //读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 5)
{
forceSingleCoil(); //强置单个线圈 状态
}
receCount = 0;
}
}
break;
}
case 6: if(receCount >= 8)
{
if(receBuf[0]==LocalAddr)
{
crcData = crc16(receBuf,6);
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 6)
{
presetSingleRegister(); //预置单个保持寄存器
}
receCount = 0;
}
}
break;
case 15://设置多个线圈
tempData = receBuf[6];
tempData += 9; //数据个数
if(receCount >= tempData)
{
if(receBuf[0]==LocalAddr )
{
crcData = crc16(receBuf,tempData-2);
if(crcData == (receBuf[tempData-1]<<8)+ receBuf[tempData-2])//更改了??
{
forceMultipleCoils();
}
}
receCount = 0;
}
break;
case 16: //设置多个寄存器
{
tempData = (receBuf[4]<<8) + receBuf[5]; //设置寄存器个数
tempData = tempData * 2; //数据个数= 寄存器*2
tempData += 9; //从询问数据包格式可知,receCount应该等于9+byteCount
if(receCount >= tempData)
{
if(receBuf[0]==LocalAddr ) //核对地址
{
crcData = crc16(receBuf,tempData-2);
temp=receBuf[tempData-1];
temp=(temp<<8)+receBuf[tempData-2];
if(crcData == temp)
{
presetMultipleRegisters();
}
}
receCount = 0;
}
break;
}
default: break;
}
}
}
/********************以下为移植的数据修改区**************************************************/
//取线圈状态 返回0表示成功
uint getCoilVal(uint addr,uint *tempData)
{
uint tempAddr;
tempAddr = addr;//只取低8位地址
switch(tempAddr)
{
// case RWSTATUES0: *tempData = RWstatus0; break;
default: break;
}
return 0;
}
uint setCoilVal(uint addr,uint tempData)//设定线圈状态 返回0表示成功
{
uint tempAddr;
tempAddr = addr;
switch(tempAddr)
{
// case RWSTATUES0: RWstatus0= tempData; break;
default: break;
}
return 0;
}
/*******************************读取寄存器内容函数 返回0表示成功**************************/
uint getRegisterVal(uint addr,uint *tempData)
{
switch(addr)
{
case WEIDU: { *tempData =Temperature ; break; }
case SHIDU: { *tempData =Humidity ; break; }
case CO2: { *tempData =Co2 ; break; }
case RIZHAO: { *tempData =Rizhao ; break; }
default: break;
}
return 0;
}
/*******************************设置寄存器内容函数 *返回0表示成功*************************/
uint setRegisterVal(uint addr,uint tempData)
{
switch(addr)
{
case WEIDU: {Temperature=tempData ;break; }
case SHIDU: { Humidity=tempData ;break; }
case CO2: { Co2=tempData ;break; }
case RIZHAO: { Rizhao=tempData ; break; }
}
return 0;
}[/mw_shl_code]
我给你一块钱,你给我一根冰棍,我不给你钱,你就不给我冰棍,这就是协议
或者不用modbus协议
你要是想做主机,从机你都会了,主机有什么不会的
一周热门 更多>