avr单片机中使用MODBUS协议的方法 下载本文

内容发布更新时间 : 2024/5/23 0:46:18星期一 下面是文章的全部内容请认真阅读。

Avr单片机中使用modbus协议的方法

有幸做了个项目,其中使用到了单片机和上位机通讯的程序,上位机用组态实现功能,探索了些方法,写出来和大家分享一下,这些知识本不是什么秘密,本人参考了许多资料,自己整合了一下。每种程序都是算法多样,最终功能实现就行。

大家做单片机串口通讯时是不是总想有一种以不变应万变的思想,就是在底层单片机硬件和软件不变的情况下,去适应任何上位机软件系统,当然可以实现,这就需要用到标准的通讯协议了,以下我就和大家分享一下我做的modbus协议(单片机端),如果上位机用组态软件的情况下,你直接使用通讯协议就行它会自动和单片机通讯。

大家在设计单片机程序时首先要定义好数据结构,先构想一下需要哪些采集数据,上位机需要查询什么数据,数据的类型和全局与否,运算的精度等等。然后把上位机需要采集的数据用一个数组管理起来,便于modbus协议的实现。单片机里串口通讯程序尽量用查询发送,中断接收的方式,要定义发送缓冲区和接收缓冲区,以便提高系统效率。以下程序用gcc实现,单片机用avr单片机。

ISR(USART0_RX_vect)//串口0接收中断服务程序

{

volatile unsigned char status,data; cli();//关中断

status = UCSR0A;//ucsr0a赋值状态标志 data = UDR0;//接收的数据放入data变量

usart0_rx_complete=0;//接收完成标志赋值0,还没有完成

if ((status & (FRAMING_ERROR0 | PARITY_ERROR0 | DATA_OVERRUN0))==0)//如果各标志位正确则,执行以下 {

usart0_rx_count++;//接收缓冲区指针加一 switch (usart0_rx_count) {

case 1:

if(data==add//第一个字节是地址,读入内部本机地址进行比较 {

usart0_rx_buf[0]=data;

TIMSK0=0x01;//启动定时器0,进行超时控制 } else

{

usart0_rx_count=0; }

break;

case 2:

if (((data==0x03)||(data==0x01)||(data==0x05)||(data==0x10))==0)//如果第一位不等于读指令0x03,01,05,10功能码,则清接收缓冲区指针 {

usart0_rx_count=0; }

else//等于这几个功能码则进行,则将他放入接收数组,并预计接收数组长度,不是10码时都是8个字节 {

usart0_rx_buf[1]=data; if (data!=0x10) {

rx0_buf_size=8; } }

break;

case 3:

usart0_rx_buf[2]=data; break; case 4:

usart0_rx_buf[3]=data; break; case 5:

usart0_rx_buf[4]=data; break; case 6:

usart0_rx_buf[5]=data; break; case 7:

usart0_rx_buf[6]=data;//10码时接收的字节计数 if (usart0_rx_buf[1]==0x10) {

rx0_buf_size=9+usart0_rx_buf[6]; }

break;

case 8:

usart0_rx_buf[7]=data;//1,用10功能码时有效的数据位,system_reg_data的数据,这里规定最多接收26个字节(不带crc) break; case 9:

usart0_rx_buf[8]=data;//2 break; case 10:

usart0_rx_buf[9]=data;//3 break; case 11:

usart0_rx_buf[10]=data;//4 break; case 12:

usart0_rx_buf[11]=data;//5 break; case 13:

usart0_rx_buf[12]=data;//6 break; case 14:

usart0_rx_buf[13]=data;//7 break; case 15:

usart0_rx_buf[14]=data;//8 break; case 16:

usart0_rx_buf[15]=data;//9 break; case 17:

usart0_rx_buf[16]=data;//10 break; case 18:

usart0_rx_buf[17]=data;//11 break; case 19:

usart0_rx_buf[18]=data;//12 break; case 20:

usart0_rx_buf[19]=data;//13 break; case 21:

usart0_rx_buf[20]=data;//14 break; case 22: