
C#的行吗可以的话我再给你大概的代码
先组成命令的byte数组
byte[] Dp = new byte[8];
byte[] DpC = new byte[6];
Dp[0] = 0x01;//这是表的地址,假定是01
Dp[1] = 0x03;//这是功能码,03是读寄存器数据
Dp[2] = 0x00;
Dp[3] = 0x03;//表的相应寄存器地址
Dp[4] = 0x00;
Dp[5] = 0x0C;//表的相应寄存器参数,根据功能码和表的不同,这几个编码有变化
for (int i = 0; i < 6; i++)
{
DpC[i] = Dp[i];
}
uint ValCRC;
ValCRC = CRC(DpC);//CRC为自己写的CRC-16校验码的函数,具体的实现这里不给要的话可以发给你
Dp[6] = (byte)(ValCRC % 256);
Dp[7] = (byte)(ValCRC / 256);
然后把这个数组发给串口,编程语言不同发送方式不同
还在程序可以设置波特率,校验什么的,编程语言不同设置方式也不同
然后接受数据,也是一个byte数组
然后自己解析数组,把需要的转化成10进制或者你需要的格式 望采纳
<p>这是我自己用单片机写过的ModBus通信程序,你可以参照一下。其实比较简单,就是按步骤一步步的来就行了。</p>
<p></p>
这个是MODBUS控制电磁阀的一个程序。其中还有AD采集的部分。对CRC校验用查表的方法。至于怎样把校验的结果拆分成高低位字节,再发送,看程序吧。
#include"reg51h"
#include"intrinsh"
#define uchar unsigned char
#define uint unsigned int
#define Pressure P0
////////////////
/////////////////////
uchar addr;
uchar Pressure_updata;
uchar Pressure_lowdata;
/////////////////
sbit Dcf_open=P1^0;//电磁阀开启
sbit Dcf_close=P1^1;//电磁阀关闭
bit dr;
bit Dcf_state=1 ;
bit Halfsecond=0;
bit Onesecond=0;
//////////////////////////////
sbit Mydress_set=P2^5 ;
sbit P_uplimite =P2^6 ;
sbit P_lowlimite=P2^7;
sbit Stor=P3^2;
sbit myint=P3^3;
sbit ADC_wr =P3^6;
sbit ADC_rd =P3^7;
sbit xuantong =P1^7;
sbit addrset=P1^2;
sbit upset=P1^3;
sbit lowset=P1^4;
/////////////////////////
uchar code Myreturnstateopen[3] ={0x01,0x01,0x00};
uchar code Myreturnstateclose[3]={0x01,0x01,0x01};
uchar code Myreturnopen[3] ={0x01,0x01,0x10};
uchar code Myreturnclose[3]={0x01,0x01,0x20};
uchar receive_count=0;
uchar mysend[6],aq[8];
uchar Adc_value;
unsigned long Mycount=0;
uchar jishi=0; //定时一秒计数
uint crc=0,myaw=0;
uint crc16(unsigned char puchMsg, unsigned int usDataLen);
bit yifasong=0;
void Beginsend( uchar Me );
bit check_modbus() ;
void Open_dcf() ;
void Close_dcf();
void timer0() ;
void uart_init(void) ;
void delay(uint z) ;
void Read_adc();
void Tosend();
/////////
/延时/
void delay(uint z)
{
uchar y;
while(z--)
for(y=113;y>0;y--);
}
/串口初始化/
void uart_init(void) interrupt 4 using 1
{
if(RI)
{
aq[receive_count]=SBUF;
RI=0;
receive_count++;
if(0==receive_count%8)
{
yifasong=0;
receive_count=0;
};
RI=0;
}
}
/定时器0初始化/
void timer0() interrupt 1 using 1
{
TH0=0x4b;
TL0=0x63;
jishi++;
if (0==jishi%10) {
Halfsecond=1;
aq[0]=0;aq[1]=0;aq[2]=0;aq[3]=0;aq[4]=0;aq[5]=0;aq[6]=0;aq[7]=0;receive_count=0;
}
}
void Read_adc()
{
ADC_rd=1;
ADC_wr=1;
_nop_();
_nop_();
_nop_();
_nop_();
myint=1;
P0=0xff;
ADC_wr=0;
_nop_();
_nop_();
_nop_();
_nop_();
ADC_wr=1;
while( myint==1);
ADC_rd=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
Adc_value=P0; //读出的数据赋与addate
ADC_rd=1;
}
void Open_dcf()
{
Dcf_open=0; delay(1200); Dcf_open=1; Dcf_state=1;
}
void Close_dcf()
{
Dcf_close=0; delay(1200);Dcf_close=1; Dcf_state=0;
}
void Read_Pressure()
{
Read_adc() ;
if (Dcf_state)
{
if((Adc_value<Pressure_lowdata)|| (Adc_value>Pressure_updata))
{
delay(1200);
if((Adc_value<Pressure_lowdata)|| (Adc_value>Pressure_updata)) { Close_dcf(); }
}
else
{ ; }
}
else
{
if((Adc_value>Pressure_lowdata)&&(Adc_value<Pressure_updata))
{ delay(1200);
if((Adc_value>Pressure_lowdata)&&(Adc_value<Pressure_updata)) { Open_dcf(); }
}
else ;
}
}
void initialize()
{
TMOD=0x20;
SCON=0x50;//串口通讯方式1
TH1=0xfd;//波特率9600
TL1=0xfd;
TH0=0x4b;
TL0=0x63;
TI=0;//发送中断标志位清零
RI=0;//接收中断标志位清零
Mydress_set=1;P_lowlimite=1; P_uplimite=1; xuantong=1;
Mydress_set=0;delay(20);addrset=1;delay(20);addr=P0;
delay(20);
addrset=0;Mydress_set=1;delay(200);P0=0xff;
P_lowlimite=0;delay(20);lowset=1;delay(20);Pressure_lowdata=P0;
delay(20);
lowset=0;P_lowlimite=1;P0=0xff;
P_uplimite=0; delay(20);upset=1;Pressure_updata=P0;delay(20);upset=0;P_uplimite=1;P0=0xff;
xuantong=0;
}
void main(void)
{
IE=0x92;
TR0=1;TR1=1;
// WDTRST=0x1E;
// WDTRST=0xE1;//初始化看门狗
initialize();
Stor=0;
for(;;) { // WDTRST=0x1E;
//WDTRST=0xE1;//喂狗指令
if (Halfsecond==1) {
Halfsecond=0;
Read_Pressure();
}
//够一秒开始转换
if(receive_count==0&&(yifasong==0))
{ Stor=0;
dr= check_modbus();
if (dr&&addr==aq[0])
{ if(aq[1]==0x05)
switch ( aq[3])
{
case 0x00 :
if(!Dcf_state) Open_dcf();
Beginsend(0) ; break;
case 0x01 :
if(Dcf_state) Close_dcf();
Beginsend(1);
break;
default : ;
}
else if(aq[1]==0x01)
{
if(Dcf_state)
{ Beginsend(2);
}
else
{ Beginsend(3);
}
}
else;
}
else
;
}
}
}
void Beginsend(uchar Me )
{
uchar i;
ES=0; Stor=1;
TI=0;
mysend[0]=addr;
switch(Me)
{
case 0:
{ for(i=1;i<4;i++)
{
mysend[i] = Myreturnopen[i-1];
}
i=0;
}break;
case 1:
{for(i=1;i<4;i++)
{
mysend[i] = Myreturnclose[i-1];
} i=0;}break;
case 2:
{ for(i=1;i<4;i++)
{
mysend[i] = Myreturnstateopen[i-1];
} i=0;}break;
case 3:
{for(i=1;i<4;i++)
{
mysend[i] = Myreturnstateclose[i-1];
}i=0;}break;
default : ;}
myaw=crc16(mysend,4);
mysend[4] =myaw&0x00ff;
mysend[5] =(myaw>>8)&0x00ff;
for(i=0;i<6;i++)
{
SBUF=mysend[i];
while(TI!=1);
TI=0;
}
Stor=0;
ES=1;
yifasong=1;
}
bit check_modbus()
{
uchar m,n ;
crc=crc16(aq,6);
m=crc;n=crc>>8&0x00ff;
if(aq[6]==m&&aq[7]==n)
return 1 ;
else
return 0;
}
uint crc16(uchar puchMsg, uint usDataLen)
{
uchar uchCRCHi = 0xFF ; // 高CRC字节初始化
uchar uchCRCLo = 0xFF ; // 低CRC 字节初始化
unsigned long uIndex ; // CRC循环中的索引
while (usDataLen--) // 传输消息缓冲区
{
uIndex = uchCRCHi ^ puchMsg++ ; // 计算CRC
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
uchCRCLo = auchCRCLo[uIndex] ;
}
return (uchCRCHi | uchCRCLo<<8);
}
/CRC校验/
// CRC 高位字节值表
modbus程序应包含通讯模块,modbus读写指令生成模块,人机交互等主要组成部分。通过人机交互,设定前端设备id,以及通讯参数,寄存器地址等,通过modbus指令生成模块生成指令,并将指令通过通讯模块送出,并接收返回数据 ,数据解析后通过人机交互窗口显示。
无需关心数据是否接收完毕,只要有数据发过来,都收到自己的缓冲区当中。
在应用层,打开一个任务以定期扫描缓冲区中的新数据。 如果有新数据,确定其是否为必需的协议帧。 通过帧头帧尾标识符还有校验等判断接收帧的正确性,如果正确再处理,不正确丢弃。
Modbus没有固定的帧头标记,长度也没有固定。 判断时,首先查找具有正确地址的字符,然后找出后续功能代码是否正确。 根据功能代码,确定后续数据有多长并进行校验。 如果验证正确,则说明帧是正确的。
扩展资料:
举例说明如下:
从站地址03,从0开始读取10个寄存器,则接收到的帧为03 03 00 00 00 0a xx xx,查找从站地址03的字节,找到后,以下功能码为03,符合功能码范围。
该功能码的数据包括固定为8个字节的校验和,然后在其后没有8个字节时,表示其已被没收,然后在关闭后进行判断。 如果正确,则可以在应用层中正确处理该帧。
以上就是关于关于C#编写modbus通讯协议的求助全部的内容,包括:关于C#编写modbus通讯协议的求助、单片机串口modbus协议通信程序,或者讲一下详细过程怎么写也行!谢谢了!、单片机modbus下位机程序怎么编写等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)