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: