微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 手把手教你学51单片机之十八 RS485通信与Modbus协议

手把手教你学51单片机之十八 RS485通信与Modbus协议

时间:11-19 来源:互联网 点击:

2-无效地址

len=3;

break;

}

case0x06://写入单个寄存器

if((buf[2]==0x00)&&(buf[3]<=0x05))//只支持0x0000~0x0005

{

if(buf[3]<=0x04)

{

i=buf[3];//提取寄存器地址

regGroup[i]=buf[5];//保存寄存器数据

cnt=regGroup[i]>>4;//显示到液晶上

if(cnt>=0xA)

str[0]=cnt-0xA+A;

else

str[0]=cnt+0;

cnt=regGroup[i]&0x0F;

if(cnt>=0xA)

str[1]=cnt-0xA+A;

else

str[1]=cnt+0;

str[2]=;

LcdShowStr(i*3,0,str);

}

else//地址0x05为蜂鸣器状态

{

flagBuzzOn=(bit)buf[5];//寄存器值转为蜂鸣器的开关

}

len-=2;//长度-2以重新计算CRC并返回原帧

&nb

break;

}

else//寄存器地址不被支持时,返回错误码

{

buf[1]=0x86;//功能码最高位置1

buf[2]=0x02;//设置异常码为02-无效地址

len=3;

break;

}

default://其它不支持的功能码

buf[1]|=0x80;//功能码最高位置1

buf[2]=0x01;//设置异常码为01-无效功能

len=3;

break;

}

crc=GetCRC16(buf,len);//计算返回帧的CRC校验值

buf[len++]=crc>>8;//CRC高字节

buf[len++]=crc&0xFF;//CRC低字节

UartWrite(buf,len);//发送返回帧

}

/*配置并启动T0,ms-T0定时时间*/

voidConfigTimer0(unsignedintms)

{

unsignedlongtmp;//临时变量

tmp=11059200/12;//定时器计数频率

tmp=(tmp*ms)/1000;//计算所需的计数值

tmp=65536-tmp;//计算定时器重载值

tmp=tmp+33;//补偿中断响应延时造成的误差

T0RH=(unsignedchar)(tmp>>8);//定时器重载值拆分为高低字节

T0RL=(unsignedchar)tmp;

TMOD&=0xF0;//清零T0的控制位

TMOD|=0x01;//配置T0为模式1

TH0=T0RH;//加载T0重载值

TL0=T0RL;

ET0=1;//使能T0中断

TR0=1;//启动T0

}

/*T0中断服务函数,执行串口接收监控和蜂鸣器驱动*/

voidInterruptTimer0()interrupt1

{

TH0=T0RH;//重新加载重载值

TL0=T0RL;

if(flagBuzzOn)//执行蜂鸣器鸣叫或关闭

BUZZ=~BUZZ;

else

BUZZ=1;

UartRxMonitor(1);//串口接收监控

}

大家可以看到负责解析协议的UartAction函数很长,因为协议解析本来就是一件很繁琐的事情。我们的例程仅解析执行了两个功能命令,就已经有近百行程序了,如果你需要解析更多的功能命令的话,那么建议把每个功能都做一个函数,然后在相应的case分支里调用即可,这样就不会使单个函数过于庞大而难以维护。

1.1练习题

1、了解RS485通信以及和RS232的不同用法。

2、了解Modbus协议以及RTU数据帧的规则。

3、写一个电子钟程序,并且可以通过485调试器校时。


Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top