51单片机新手入门之Modbus通讯Word文档下载推荐.docx
《51单片机新手入门之Modbus通讯Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《51单片机新手入门之Modbus通讯Word文档下载推荐.docx(26页珍藏版)》请在冰豆网上搜索。
//MAX1241模数芯片引脚设置,此电路板我没焊^_^
//sbitADC_CS=P0^1;
//sbitADC_CLK=P0^0;
//sbitADC_DOUT=P0^2;
sbitADC_CS=P3^6;
sbitADC_CLK=P3^5;
sbitADC_DOUT=P3^7;
//LCD12864LCD屏幕引脚设置
sbitcs=P2^2;
sbitsid=P2^1;
sbitsclk=P2^0;
sbitDQ=P0^1;
//DS18B20温度引脚设置,依然没有…
#defineN11
#defineN220
voiddelayms(unsignedchart)
{
unsignedchari;
unsignedcharj;
for(j=t;
j;
j--)
for(i=192;
i;
i--);
/*1ms延时*/
}
voiddelayus(uintt)
uinti;
for(i=0;
i<
t;
i++)
{
_nop_();
}
voiddelay(floatsec)
unsignedinti;
unsignedintj;
j=sec*100;
while(j--)
{
i=1561;
while(--i);
}
voidUART1_init()//串口1初始化,此串口和电脑通讯
{
TMOD=0x20;
/设置定时器工作方式2
TH1=0xfd;
//波特率9600
TL1=0xfd;
TR1=1;
REN=1;
SM0=0;
SM1=1;
//ES=1;
voidUART2_init()//串口2初始化,和模块通讯Modbus
S2CON=0x50;
//方式1,允许接收
BRT=0xf4;
//波特率2400
AUXR=AUXR|0X10;
//允许独立波特率允许
AUXR1=AUXR1&
0xef;
//将uart2切换到P1口
IE2=IE2|0X01;
//允许串口2中断
voidUART1_Send(unsignedcharUART_data)//
//ES=0;
SBUF=UART_data;
//将接收的数据发送回去
while(TI!
=1);
//检查发送中断标志位
TI=0;
//另发送中断标志位为0
voidUART2_Send(unsignedcharUART_data)//串口2发送
//ES=0;
S2BUF=UART_data;
while((S2CON&
0x02)!
=0x02);
S2CON&
=~0x02;
//ES=1;
voidUART1_Send_String(char*str,charlen)//串口1发送字符串
=len;
i++)
UART1_Send(str[i]);
voidUART2_Send_String(char*str,charlen)//串口2发送字符串
UART2_Send(str[i]);
unsignedcharCreat_Addr(unsignedcharadr,unsignedcharposition)//计算模块地址
unsignedcharhich;
unsignedcharloch;
hich=adr/16;
loch=adr%16;
if(hich>
9)
hich+=7;
if(loch>
loch+=7;
if(position==1)
returnhich+0x30;
elseif(position==0)
returnloch+0x30;
unsignedcharCheckSum(unsignedchar*str,unsignedcharposition,ucharlen)/计算校验码
uchari;
unsignedintsum=0;
ucharhi,lo;
//ucharlen=12;
for(i=1;
i<
=len;
i++)
*str++;
sum+=*str;
sum=256-(sum%256);
hi=sum/16;
lo=sum%16;
if(hi>
9)
hi+=7;
if(lo>
lo+=7;
hi+=0x30;
lo+=0x30;
if(sum==256)
hi=lo=0x30;
if(position==1)
returnhi;
elseif(position==0)
returnlo;
voiddata_init()
sendbuffer[0]=0x5B;
sendbuffer[1]=0x30;
sendbuffer[2]=0x30;
sendbuffer[3]=0x30;
sendbuffer[4]=0x30;
sendbuffer[5]=0x30;
sendbuffer[6]=0x7C;
sendbuffer[7]=0x30;
sendbuffer[8]=0x30;
sendbuffer[9]=0x30;
sendbuffer[10]=0x30;
sendbuffer[11]=0x30;
//TEM
sendbuffer[12]=0x30;
sendbuffer[13]=0x30;
sendbuffer[14]=0x5D;
sendbuffer[15]=0x0D;
sendbuffer[16]=0x0A;
voidcalculate_module(unsignedcharstr[])//lcd屏显示
unsignedintconcen;
ucharwan,qian,bai,shi,ge;
/*uchard4=str[7]-48;
uchard3=str[8]-48;
uchard2=str[9]-48;
uchard1=str[10]-48;
*///浓度只需要后面部分
uchard4=str[24]-48;
uchard3=str[25]-48;
uchard2=str[26]-48;
uchard1=str[27]-48;
if(d4>
d4-=7;
if(d3>
d3-=7;
if(d2>
d2-=7;
if(d1>
d1-=7;
concen=d4*4096+d3*256+d2*16+d1;
gascon=concen;
wan=concen/10000;
qian=concen%10000/1000;
bai=concen%1000/100;
shi=concen%100/10;
ge=concen%10;
//sendbuffer[6]=wan+0x30;
//最终显示XXX.X%
sendbuffer[7]=qian+0x30;
sendbuffer[8]=bai+0x30;
sendbuffer[9]=shi+0x30;
sendbuffer[10]=ge+0x30;
voidmodule_init()//气体模块初始化
Send_Buff[0]='
:
'
;
Send_Buff[3]='
0'
Send_Buff[4]='
3'
Send_Buff[5]='
Send_Buff[6]='
Send_Buff[7]='
Send_Buff[8]='
A'
Send_Buff[9]='
Send_Buff[10]='
Send_Buff[11]='
Send_Buff[12]='
1'
Send_Buff[1]=Creat_Addr(31,1);
Send_Buff[2]=Creat_Addr(31,0);
Send_Buff[13]=CheckSum(Send_Buff,1,12);
Send_Buff[14]=CheckSum(Send_Buff,0,12);
Send_Buff[15]=0x0D;
Send_Buff[16]=0x0A;
//手动添加校验,例如字符‘0’换成ASCII码0X30,添加偶校验后就是0X3A,最终发送给模块的以下数据,地址被写死,这个不像C#做的一目了然O(∩_∩)O
test[0]=0X3A;
test[1]=0XB1;
test[2]=0XC6;
test[3]=0X30;
test[4]=0X33;
test[5]=0X30;
test[6]=0X30;
test[7]=0X30;
test[8]=0X41;
test[9]=0X30;
test[10]=0X30;
test[11]=0X30;
test[12]=0XB1;
test[13]=0X39;
test[14]=0XB4;
test[15]=0X8D;
test[16]=0X0A;
/*uintread_max1241()AD芯片处理
uintADC_Data;
ADC_CLK=0;
ADC_CS=0;
ADC_Data=0;
while(!
ADC_DOUT);
ADC_CLK=1;
12;
{
ADC_Data<
<
=1;
ADC_Data|=ADC_DOUT;
}
ADC_CS=1;
returnADC_Data;
unsignedintad_filter()//滤波
unsignedintcount1,i,j;
unsignedintvalue_buf[N];
unsignedinttemp;
for(count1=0;
count1<
N;
count1++)
value_buf[count1]=read_max1241();
delayms(20);
for(j=0;
j<
(N-1);
j++)
for(i=0;
(N-j);
if(value_buf[i]>
value_buf[i+1])
temp=value_buf[i];
value_buf[i]=value_buf[i+1];
value_buf[i+1]=temp;
for(count1=3;
(N-3);
sum+=value_buf[count1];
return(unsignedint)(sum/(N-6));
voidcalculate_o2()//测试用
uintcon_fin=0;
ad_data=ad_filter();
ad_vol=(ad_data/4096.0)*2500.0;
//Voltage
ad_data=(uint)ad_vol;
//concentration
delayms
(2);
if(average_counter>
0)
sum_o2+=ad_data;
oldtemp[average_counter-1]=ad_data;
average_counter--;
else
sum_o2-=oldtemp[19];
for(i=20;
i>
0;
i--)
oldtemp[i]=oldtemp[i-1];
oldtemp[0]=ad_data;
sum_o2+=oldtemp[0];
con_fin=(uint)(sum_o2/N2);
//O2_con=0.8*con_fin+0.2*pre_contemp;
//pre_contemp=O2_con;
wan=con_fin/10000;
qian=con_fin%10000/1000;
bai=con_fin%1000/100;
shi=con_fin%100/10;
ge=con_fin%10;
sendbuffer[1]=wan+0x30;
sendbuffer[2]=qian+0x30;
sendbuffer[3]=bai+0x30;
sendbuffer[4]=shi+0x30;
sendbuffer[5]=ge+0x30;
delayms(5);
}
//-------------18B20温度显示复位函数---------------
voidow_reset(void)
charpresence=1;
while(presence)
while(presence)
DQ=1;
delayus
(2);
DQ=0;
//
delayus(550);
//550us
//
delayus(66);
//66us
presence=DQ;
delayus(500);
//延时500us
presence=~DQ;
DQ=1;
}
//-----------18B20写命令函数------------
voidwrite_byte(ucharval)
for(i=8;
i>
i--)//
DQ=0;
delayus(5);
//5us
DQ=val&
0x01;
//66us
val=val/2;
DQ=1;
delayus(11);
//--------------18B20读一个字节函数---------
ucharread_byte(void)
ucharvalue=0;
value>
>
delayus(4);
//4us
DQ=1;
//4us
if(DQ)value|=0x80;
return(value);
voidRead_Temperature(void)
unsignedintTemp1,Temp2;
ucharbai,shi,ge;
ow_reset();
//DS18B20
write_byte(0xCC);
write_byte(0x44);
//DS1302复位
write_byte(0xbe);
Temp1=read_byte();
Temp2=read_byte();
temperature=(((Temp2<
8)|Temp1)*0.625);
//0.0625=xx,0.625=xx.x,6.25=xx.xx
bai=temperature/100;
shi=temperature%100/10;
ge=temperature%10;
sendbuffer[11]=bai+0x30;
sendbuffer[12]=shi+0x30;
sendbuffer[13]=ge+0x30;
}*//图中电路板此部分没焊,此部分代码不使用^_^
voidwritecmd_lcd(ucharcmd)//lcd屏写指令
ucharcmd1;
cmd1=cmd;
//----------先写控制,选择写指令,还是写数据11111000
5;
i++)//必须sid先发送,然后sclk,不然不行
sid=1;
sclk=1;
sclk=0;
3;
sid=0;
//delayms(10);
cmd=cmd&
0xf0;
//先高4位
8;
if(cmd&
0x80)
elsesid=0;
cmd=cmd<
1;
cmd1=((cmd1<
4)&
0xf0);
//低4位
if(cmd1&
cmd1=cmd1<
voidwritedata_lcd(uchardat)
uchardat1;
dat1=dat;
//11111010
dat=dat&
if(dat&
dat=dat<
dat1=((dat1<
if(dat1&
dat1=dat1<
voidinit_lcd()//初始化lcd屏
cs=1;
writecmd_lcd(0x30);
//设定为8位控制
writecmd_lcd(0x0c);
//显示打开
writecmd_lcd(0x01);
//清屏
voidgotoxy(uintrow,uintcol)
switch(row)
case1:
writecmd_lcd(0x80+col);
break;
ca