modbus主机程序,单片机modbus下位机程序怎么编写

阅读(76)发布于 2023-08-22

如何测试modbus主机程序,只有一台电脑,且电脑没有硬件的串口 简单实用的方案: 1、买2个USB-RS232转换器,使电脑具备2个串口。单片机modbus下位机程序怎么编写 这个是MODBUS控制电磁阀的一个程序。

配图

简单实用的方案:

1、买2个USB-RS232转换器(大概100来元搞定),使电脑具备2个串口。两个串口之间用串行交叉电缆连接,即2-3、3-2、5-5。

2、从网上下载modbus从机模拟软件——modbusslave软件,运行时指定一个串口,仿真modbus从机。

3、运行用户开发的modbus主机程序,并指定另一个串口,这样组成了测试平台。

剩下的工作就是程序测试了。

下载VSPM虚拟串口软件,免费的

然后设置一下,

比如你要虚拟2个已经互联的串口COM7

COM8,在vspm.ini的最后一行增加下面的内容

COM7=127.0.0.1:7102;127.0.0.1:7101;Active;UDP_BC

COM8=127.0.0.1:7101;127.0.0.1:7102;Active;UDP_BC

然后运行就可以了

modbus程序应包含通讯模块,modbus读写指令生成模块,人机交互等主要组成部分。通过人机交互,设定前端设备id,以及通讯参数,寄存器地址等,通过modbus指令生成模块生成指令,并将指令通过通讯模块送出,并接收返回数据,数据解析后通过人机交互窗口显示。

这个是MODBUS控制电磁阀的一个程序。其中还有AD采集的部分。对CRC校验用查表的方法。至于怎样把校验的结果拆分成高低位字节,再发送,看程序吧。

#include"reg51.h"

#include"intrins.h"

#defineucharunsignedchar

#defineuintunsignedint

#definePressureP0

////////////////

/////////////////////

ucharaddr;

ucharPressure_updata;

ucharPressure_lowdata;

/////////////////

sbitDcf_open=P1^0;//电磁阀开启

sbitDcf_close=P1^1;//电磁阀关闭

bitdr;

bitDcf_state=1;

bitHalfsecond=0;

bitOnesecond=0;

//////////////////////////////

sbitMydress_set=P2^5;

sbitP_uplimite=P2^6;

sbitP_lowlimite=P2^7;

sbitStor=P3^2;

sbitmyint=P3^3;

sbitADC_wr=P3^6;

sbitADC_rd=P3^7;

sbitxuantong=P1^7;

sbitaddrset=P1^2;

sbitupset=P1^3;

sbitlowset=P1^4;

/////////////////////////

ucharcodeMyreturnstateopen[3]={0x01,0x01,0x00};

ucharcodeMyreturnstateclose[3]={0x01,0x01,0x01};

ucharcodeMyreturnopen[3]={0x01,0x01,0x10};

ucharcodeMyreturnclose[3]={0x01,0x01,0x20};

ucharreceive_count=0;

ucharmysend[6],aq[8];

ucharAdc_value;

unsignedlongMycount=0;

ucharjishi=0;//定时一秒计数

uintcrc=0,myaw=0;

uintcrc16(unsignedchar*puchMsg,unsignedintusDataLen);

bityifasong=0;

voidBeginsend(ucharMe);

bitcheck_modbus();

voidOpen_dcf();

voidClose_dcf();

voidtimer0();

voiduart_init(void);

voiddelay(uintz);

voidRead_adc();

voidTosend();

/////////

/*************延时*****************/

voiddelay(uintz)

{

uchary;

while(z--)

for(y=113;y>0;y--);

}

/************串口初始化*****************/

voiduart_init(void)interrupt4using1

{

if(RI)

{

aq[receive_count]=SBUF;

RI=0;

receive_count++;

if(0==receive_count%8)

{

yifasong=0;

receive_count=0;

};

RI=0;

}

}

/**************定时器0初始化**************/

voidtimer0()interrupt1using1

{

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;

}

}

voidRead_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;

}

voidOpen_dcf()

{

Dcf_open=0;delay(1200);Dcf_open=1;Dcf_state=1;

}

voidClose_dcf()

{

Dcf_close=0;delay(1200);Dcf_close=1;Dcf_state=0;

}

voidRead_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;

}

}

voidinitialize()

{

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;

}

voidmain(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])

{

case0x00:

if(!Dcf_state)Open_dcf();

Beginsend(0);break;

case0x01:

if(Dcf_state)Close_dcf();

Beginsend(1);

break;

default:;

}

elseif(aq[1]==0x01)

{

if(Dcf_state)

{Beginsend(2);

}

else

{Beginsend(3);

}

}

else;

}

else

;

}

}

}

voidBeginsend(ucharMe)

{

uchari;

ES=0;Stor=1;

TI=0;

mysend[0]=addr;

switch(Me)

{

case0:

{for(i=1;i<4;i++)

{

mysend[i]=Myreturnopen[i-1];

}

i=0;

}break;

case1:

{for(i=1;i<4;i++)

{

mysend[i]=Myreturnclose[i-1];

}i=0;}break;

case2:

{for(i=1;i<4;i++)

{

mysend[i]=Myreturnstateopen[i-1];

}i=0;}break;

case3:

{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;

}

bitcheck_modbus()

{

ucharm,n;

crc=crc16(aq,6);

m=crc;n=crc>>8&0x00ff;

if(aq[6]==m&&aq[7]==n)

return1;

else

return0;

}

uintcrc16(uchar*puchMsg,uintusDataLen)

{

ucharuchCRCHi=0xFF;//*高CRC字节初始化

ucharuchCRCLo=0xFF;//*低CRC字节初始化

unsignedlonguIndex;//CRC循环中的索引

while(usDataLen--)//传输消息缓冲区

{

uIndex=uchCRCHi^*puchMsg++;//计算CRC

uchCRCHi=uchCRCLo^auchCRCHi[uIndex];

uchCRCLo=auchCRCLo[uIndex];

}

return(uchCRCHi|uchCRCLo<<8);

}

/***********************CRC校验*************************/

//CRC高位字节值表

以上就是关于modbus主机程序的解答,如果对你有帮助,不妨关注本站,本站将为你整理更多内容。