微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Modbus协议完全资料与程序解析

Modbus协议完全资料与程序解析

时间:12-01 来源:互联网 点击:

for(i=8; i>

ACC = ACC >>

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->timestr[0] = ds1302->

ds1302->timestr[1] = ds1302->

ds1302->

ds1302->

ds1302->

ds1302->timestr[3] = ds1302->

ds1302->timestr[4] = ds1302->

ds1302->

ds1302->

ds1302->

ds1302->timestr[6] = ds1302->

ds1302->timestr[7] = ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->datestr[2] = ds1302->

ds1302->datestr[3] = ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->

ds1302->datestr[5] = ds1302->

ds1302->datestr[6] = ds1302-> 5、程序,以下位机为程序对象,主要使用c语言编写,首先,先从变量入手,既然modbus接受以帧为单位,所以就要设置两个缓冲区,用来接收数据,我们这里使用数组来存储接收来的数据Modbus_send_buf[Modbus_max_send_buf];//数据发送缓冲 和 Modbus_recevie_buf[Modbus_max_recevie_buf];//数据接收缓冲 ,其中Modbus_max_send_buf,和Modbus_max_recevie_buf ,为宏定义,这样可以方便的修改一帧最大的存储数据。有了发送接收缓冲,就可以写中断函数了,进入中断后,首先做一些必要的工作,清ES ,判断IR,清IR,做完后,就可以开始接收数据了,但有个问题?如果设备处于空闲状态,那么接收数据后按命令执行,但如果当设备正在执行指令的时候,则不应该再继续的接收指令,那样的话,会让程序进入混乱状态。所以要在基础工作做完后,增加一个判断,来确定设备的忙闲。if((Modbus_cmd_flag == 0) && (Modbus_exe_flag == 0)),判断完以后就可以继续下面的工作了。如果通讯中包含奇偶校验的话,那么则判断奇偶校验。下面就是接收数据。Modbus_recevie_buf[Modbus_recevie_count] = SBUF; ,将接收来的数据存入数组并记录存入的数据个数Modbus_recevie_count,由于modbus是通过时间来判断一帧的结束的,所以在程序中,必须要有一个定时器函数,这个定时器用来判断程序是正在接受,还是已经接受完成了。所以中断的最后所做的是计数器自加Modbus_recevie_count++;,定时器清0 Modbus_timeout_cnt = 0; ,将设备状态转入接收状态Modbus_recevie_flag = 1;。此时,串口中断的工作就完成了。

下面开始分析定时器,定时器的目的其实就1个,判断一帧是否接收完毕,如果完毕,则进入下一步。在定时器中断函数中,首先要对定时器值进行初始化,这个就不多说了,然后是判断程序是否处于接受状态if(Modbus_recevie_flag == 1),这个状态只有在串口中断函数中才会被置位,其他的情况不会被置位。若程序不是接收状态,则直接跳出定时器中断,若程序处于接收状态,则定时计数自加Modbus_timeout_cnt++;,自加后进入判断if(Modbus_timeout_cnt >= Modbus_max_timeout_cnt),判断的值即为modbus接收一帧传输完成所需要的时间间隔。至于是多少时间,可以通过修改Modbus_max_timeout_cnt来确定。可以将定时器终端设置为1ms1次,在9600的情况下将超时时间设为4,#define Modbus_max_timeout_cnt 4,这样如果串口中断不在接收数据时,定时计数将不会清0,当到达设定的超时时间后即判断接收结束,转向命令解析状态。

接收来的数据可以经过一个函数来执行,同时也可以经过两个函数,解析与执行两步来分别执行。我喜欢后者,因为这样可以把解析的过程和执行的过程分开来写。程序显得更加清晰与明朗。

在主函数中就执行1个函数,

while(1)

{

Modbus_proc();

}

这个函数是经过打包的两个函数,进入这个函数

void Modbus_proc()

{

Modbus_cmd();

Modbus_exe();

}

可以看到,程序分为cmd解析,exe执行。

Cmd 命令解析函数

有这么几个问题是需要判断的,命令解析状态,接收来的数据个数,crc,地址,这几个问题是命令解析时需要注意的,顺序可以稍做变化。但最好是这个顺序。

首先判断程序是否处于命令解析状态if(Modbus_cmd_flag == 1)。命令解析状态标志只有在超时后置位,其他情况下不置位。之后是判断接收数据是否大于4字节,if(Modbus_recevie_count > 4)。当程序接收数据小于4字节则说明接收发生错误,抛弃它。下一步则是判断crc校验,由于crc在一帧的最后两位,所以crc应该取缓冲的最后两位

modbus_crc_h=Modbus_recevie_buf[Modbus_recevie_count-2];

modbus_crc_l = Modbus_recevie_buf[Modbus_recevie_count-1];

然后将取来的数据合并成一个16位数据,得到接收的crc

modbus_crc = ((unsigned int)(modbus_crc_h) < 8) | modbus_crc_l;

重新计算1帧的crc,得到自己的crc

modbus_crc_b = crc16(Modbus_recevie_buf,Modbus_recevie_count - 2);

最后进行对比,将自己算的crc和接收的crc进行比较,来判断接收的数据是否正确。

if( modbus_crc_b == modbus_crc )

在crc判断正确后,就可以判断地址了

if(Modbus_recevie_buf[0] == Modbus_addr) // Modbus_addr为一个宏定义的本机地址,若多机可以在此处修改。

当地址,crc,等全判断正确以后,就可以判断最重要的功能码了。由于功能码很多,所以1可以用宏定义来定义功能码增加程序的可读性,2可以利用switch来命令的模式

#define

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

网站地图

Top