找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2783|回复: 0
打印 上一主题 下一主题
收起左侧

我现在正在研究基于avr,mega128的modbus 源码

[复制链接]
跳转到指定楼层
楼主
ID:167315 发表于 2017-3-1 09:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我现在正在研究基于avr,mega128的modbus 做了个modbus   也是基于网友的代码调试的  上传

Avr单片机中使用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:
        usart0_rx_buf[21]=data;//15
        break;
        case 23:
        usart0_rx_buf[22]=data;//16
        break;
        case 24:
        usart0_rx_buf[23]=data;//17
        break;
        case 25:
        usart0_rx_buf[24]=data;//18
        break;
        case 26:
        usart0_rx_buf[25]=data;//19
        break;
        case 27:
        usart0_rx_buf[26]=data;//20
        break;
        case 28:
        usart0_rx_buf[27]=data;//21
        break;
        case 29:
        usart0_rx_buf[28]=data;//22
        break;
        case 30:
        usart0_rx_buf[29]=data;//23
        break;
        case 31:
        usart0_rx_buf[30]=data;//24
        break;
        case 32:
        usart0_rx_buf[31]=data;//25
        break;
        case 33:
        usart0_rx_buf[32]=data;//26
        break;
        case 34:
        usart0_rx_buf[33]=data;//27
        break;
        case 35:
        usart0_rx_buf[34]=data;//28
        break;
   }

            if(usart0_rx_count>=rx0_buf_size)//串口0接收到了指定个数的数组则
            {
                usart0_rx_count=0;//接收缓冲区指针清零
                usart0_rx_complete=1;//串口0接收完标志
                time0_num=0;//串口0的中断次数清零。它是超时控制的依据
                TIMSK0=0x00;//收到数据后则停止定时器0不进行超时控制
            }

    }
else
{
          usart0_rx_count=0;
}

  sei(); //开中断
}
以上中断接收程序可以实现上位机发来的0x03,01,05,10功能码指令,并且可以自动判断上位机发来10功能码的包长。大家首先要深入了解modbus通讯协议的内涵,仔细体会各行程序的含义。其中本人加入了对通讯的超时控制,实际应用中很有必要。
前面已经将上位机发来的命令,用中断接收的方式存入了单片机的接收缓冲区,中断服务程序不能执行太长时间,所以要将对指令的解读放入了主程序里。
把对modbus指令的解读程序列出,如下,只给出框架,因为每种应用是不一样的,需自己加入。
void run_modbus(void)
{

switch (usart0_rx_buf[1])
   {
    //判断主机发来的modbus 功能码是什么
    case 0x01://读继电器输出的当前状
        要加入回传数据
    break;

    case 0x03://功能码03

    要加入回传数据

    break;

    case 0x05://05功能码
    要加入回传数据

    break;

    case 0x10://10功能码
    要加入回传数据

    break;
   }

}
以上程序完全依赖一个提供给上位机数据的数组,自己要仔细排列好数据顺序,定义好长度。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表