打印
[AVR单片机]

用MEGA8写的modbus实现了一个功能

[复制链接]
2805|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2007-9-20 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
还没有调试,请大家帮忙看看,第一次写通信程序,avr还不熟悉,不知道中断处理的如何。


主程序:

#include"485.h"
#include"modbus_client.h"

extern UINT16 Get_CRC ( BYTE *, BYTE);
extern void message_storage(BYTE *,BYTE,BYTE);
extern EQUIPMENT_PARAMETER EQUIPMENT_PARAMETER_TABLE[MAX_EQU_NUM];
//extern uchar T_flag;
//extern uchar buf_p;
//extern uchar Receive_now;         //在接收中断中,只要确认应答的设备地址正确就置位
                                   //
//===========================================
BYTE Receive_en;                   //接收使能
//===========================================                                   
BYTE WAIT_Responsion;              //等待应答:发送完一帧请求后置位,作为持续等待标志,
                                   //在接收中断中,如果接到这个设备的应答,只要地址正
                                   //就可以清除从而结束超时等待;
BYTE WAIT_Time;                    //
//===========================================
//  全局变量结构体
//===========================================
MB_INFORMATION      mb_infor;
//MASTER_INFORMATION  mas_infor;
ADU_CONTROL         adu;
//===========================================
//              超时错误
//===========================================
#define MAX_CHAOSHI  3
BYTE CHAOSHI_ErrTime[MAX_EQU_NUM];         //超时错误计数器  超过MAX_CHAOSHI次就要把
                          //EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQUIP_STATE
                          //变为ERR
//===========================================
//        帧错误
//===========================================
BYTE ZHEN_ErrTime[MAX_EQU_NUM];

int main(void)
{
    UINT16 CRC_BUF;
    BYTE CRC_CHAR;
    MESSAGE_ERR MESSAGE_err;
    //=================================================
    //                 变量初始化
    //=================================================
    WAIT_Time = 0;
    Receive_en =0;
    memset(TxAdu_buf,0,BUFSIZE);
    memset(RxAdu_buf,0,BUFSIZE);
    memset(CHAOSHI_ErrTime,0,MAX_EQU_NUM);
    memset(ZHEN_ErrTime,0,MAX_EQU_NUM);
//    Receive_now = 0;
//===========================================
    MB_INFORMATION_Init(&mb_infor);
//    MASTER_INFORMATION_Init( &mas_infor);
    ADU_CONTROL_Init(&adu);
    PORTd_INIT();
//===========================================
    cli();
    comInit();
    sei();
//    t_485("ni hao ma?\n");
//    t_485("Hello! da jia hao,wo shi tiao zao tuan zhang;\n");
    while(1)
    {
        begin:
        //&&&&&&&&&&&&&&&&&&&&&&&
        // 拼装帧 发送帧
        //&&&&&&&&&&&&&&&&&&&&&&&
        if(!EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_ADDR/*0代表没有设备*/ && EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_STATE/*设备无故障*/) 
        {
            adu.ADULength = 0;
            *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_ADDR;
                                                                          //地址
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = 0x03;                    //功能号
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = 0x00;                    
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW]. REG_ORIGINATION;
                                                                          //起始寄存器
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = 0x00;
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].REG_NUM;
                                                                          //寄存器数量
            adu.ADULength ++;
            CRC_BUF = Get_CRC ( adu.TxADUBuffptr, adu.ADULength  ) ;
            CRC_CHAR = (BYTE)CRC_BUF;                                    
            *(adu.TxADUBuffptr + adu.ADULength) = (BYTE)(CRC_BUF >> 4);   //CRC校验高四位
            adu.ADULength ++;                                         
            *(adu.TxADUBuffptr + adu.ADULength) = CRC_BUF;                 //CRC校验低四位
            adu.ADULength ++;
            *(adu.TxADUBuffptr + adu.ADULength) = '\n';                    //在帧的结尾加上‘\n’做为发送结束标志
            t_485(adu.TxADUBuffptr);                                       //发送帧
            adu.ADULength = 0;
            WAIT_Responsion = 1;                                         //使能等待标志
            OPEN_WaitResponsionClk();                                    //打开超时计数器T0中断
            OPEN_USART1_ReINTERRUPT();                                   //打开接收中断
        }
        else     //如果设备不存在或设备故障转到下一台设备
        {
            if(++mb_infor.EQUIPMENT_NOW  > MAX_EQU_NUM)        //查询完一遍?
            mb_infor.EQUIPMENT_NOW = 0;                         //设备编号从0开始
            goto begin;
        }
        while(WAIT_Responsion)                                  //在接收中断中如果收到当前地址选中设备的应答则清除标志,跳出循环
        {
            if(WAIT_Time >= MAX_WAIT_TIME)                       //超时
            {
                //CLOSE_WaitResponsionClk();                      //关闭T0;
                WAIT_Time = 0;                                  //复位WAIT_Time
                CHAOSHI_ErrTime[mb_infor.EQUIPMENT_NOW] ++;     //超时错误计数器++
                if(CHAOSHI_ErrTime[mb_infor.EQUIPMENT_NOW] >= MAX_CHAOSHI)             //超过最大超时错误
                {
                    EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备
                    CHAOSHI_ErrTime[mb_infor.EQUIPMENT_NOW] = 0;                       //超时错误计数器清0
                }    
                if(++mb_infor.EQUIPMENT_NOW  > MAX_EQU_NUM)                            //设备查询过来一遍?
                mb_infor.EQUIPMENT_NOW = 0;                                             //设备编号从0开始
                WAIT_Responsion = 0;                                                    //重新初始化等待回应标志
                goto begin;
            }
        }
        //&&&&&&&&&&&&&&&&&&&&&&
        //接收除地址外的其他字节
        //&&&&&&&&&&&&&&&&&&&&&&
        for(;;)
        {
            while(!(UCSRA & (1<<RXC)))
            {
                if(mb_infor.T35_OUT)
                {
                    mb_infor.T35_OUT = FALSE;
                    WAIT_Time = 0;             //WAIT_Time复位
                    goto ZHEN_OVER;
                }
            }
            TCNT0 = 0x00;   //重新计数
            WAIT_Time = 0;  //中断次数清零
            delay_us(50);
            *(adu.RxADUBuffPtr + adu.ADULength) = UDR;
            adu.ADULength ++;
        }
        ZHEN_OVER:
        CLOSE_TIMER1(); //关定时器1
//================================================================
/*                   以下内容是帧处理:                            */
//================================================================
        MESSAGE_err = message_process(adu.RxADUBuffPtr,adu.ADULength);
        switch(MESSAGE_err)
        {
            case  CRC_ERR:  ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] ++;     //错误计数器++
                            if(ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] >= MAX_ZHENERR)                //超过最大超时错误
                            {
                                EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备
                                ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] = 0;                          //超时错误计数器清0
                            }
                            goto begin;
                            break;
            case  FUNC_ERR://&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
                            //   这里要分析错误代码 找到原因
                            //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
                            ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] ++;     //错误计数器++
                            if(ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] >= MAX_ZHENERR)                //超过最大超时错误
                            {
                                EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备
                                ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] = 0;                          //超时错误计数器清0
                            }
                            break;
            case  LEN_ERR: ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] ++;     //错误计数器++
                            if(ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] >= MAX_ZHENERR)                //超过最大超时错误
                            {
                                EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备
                                ZHEN_ErrTime[mb_infor.EQUIPMENT_NOW] = 0;                          //超时错误计数器清0
                            }
                            goto begin;
                            break;
            case  NO_ERR:   message_storage(adu.RxADUBuffPtr,mb_infor.EQUIPMENT_NOW,adu.ADULength);    //                   //存储帧
                            if(++mb_infor.EQUIPMENT_NOW  > MAX_EQU_NUM)                            //设备查询过来一遍?
                            mb_infor.EQUIPMENT_NOW = 0;                                             //设备编号从0开始
                            goto begin;
                            break;
        }
    }
}

相关帖子

沙发
keer_zu|  楼主 | 2007-9-20 17:22 | 只看该作者

相关的结构体

#ifndef _MB_CLIENT
#define _MB_CLIENT
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>

#include "485.h"
#define TRUE 1
#define FALSE 0
#define UINT16 unsigned int
#define BYTE unsigned char
#define MAX_EQU_NUM  3                        //现在使用3个设备
#define OK 1
#define ERR 0
//===================================================================
//               错误常量
//===================================================================
#define CHAOSHI 0XFF

//===================================================================
//设备数据结构 用于构建设备参数表
typedef struct _EQUIPMENT_PARAMETER
{
    BYTE  EQU_ADDR;                //设备地址 
    BYTE  EQU_TYPE;                //设备类型
    BYTE  EQU_STATE;               //设备状态
    BYTE  REG_ORIGINATION;         //起始寄存器地址
    BYTE  REG_NUM;                 //寄存器数量
}EQUIPMENT_PARAMETER;

//ADU处理信息结构
typedef struct _ADU_CONTROL
{
    BYTE Address;           //地址域
    BYTE *RxADUBuffPtr;     //指向ADU发送缓冲区的指针
    BYTE *TxADUBuffptr;     //指向ADU接收缓冲区的指针
    BYTE ADULength;         //ADU数据长度
    BYTE FrameOK;           //如果该ADU报文有效(地址有效,奇偶、CRC校验通过)则TRUE
}ADU_CONTROL;
//通信状态
typedef struct _MB_INFORMATION
{
    BYTE EQUIPMENT_NOW;                  //当前正在处理设备编号
//  enum _MODBUS_STATE MODBUS_STATE;    //描述modbus状态的变量
    BYTE T15_OUT;                       //1.5ms延时到
    BYTE T35_OUT;                       //3.5ms延时到
    BYTE TO_times;                      //时钟中断次数计数器
}MB_INFORMATION;
// 帧错误类型
typedef enum _MESSAGE_ERR
{
    CRC_ERR,                            //CRC校验错
    FUNC_ERR,                           //功能号错     -应该处理错误类型
    LEN_ERR,                            //长度错
    NO_ERR                              //没有错误
}MESSAGE_ERR;

//=====================================================================================
void MB_INFORMATION_Init(MB_INFORMATION *);
//void MASTER_INFORMATION_Init(MASTER_INFORMATION *);
void ADU_CONTROL_Init(ADU_CONTROL *);
MESSAGE_ERR  message_process(BYTE *,BYTE);
#endif

使用特权

评论回复
板凳
keer_zu|  楼主 | 2007-9-20 17:23 | 只看该作者

串口,时钟中断

#include "modbus_client.h"
#ifndef _PGM
#define _PGM
#include <avr/pgmspace.h>
#endif
//=========================================
//          返回CRC校验结果
//=========================================
extern unsigned int Get_CRC(BYTE *,BYTE);
//=========================================
//                 缓冲区
//=========================================
extern ADU_CONTROL adu;
extern MB_INFORMATION      mb_infor;
extern BYTE WAIT_Time,Receive_en,WAIT_Responsion;

//========================================================================
//   设备参数表
//========================================================================
EQUIPMENT_PARAMETER EQUIPMENT_PARAMETER_TABLE[MAX_EQU_NUM]=
{
  {0X09,0,OK,0,0x15},             //1、地址 2、类型 3、状态 4、起始寄存器 5、寄存器数量(十六位,两个字节)
  {0x02,1,OK,0,0x0f},
  {0x11,0,OK,0,0x15}/*,
  {0x00,0,OK,0,0},
  {0x00,0,OK,0,0}*/
};

//==========================================================================
// 定时计数器1溢出中断函数
//==========================================================================
ISR(SIG_OVERFLOW1)
{
    TCNT1 = 0xf70c;          //4M时0.5个字符-0.000573s产生一个中断
    mb_infor.TO_times ++;
    if(mb_infor.TO_times == 3)mb_infor.T15_OUT = TRUE;    //1.5ms延时到
    if(mb_infor.TO_times == 7)
    {
        mb_infor.T35_OUT = TRUE;    //3.5ms延时到
        CLOSE_TIMER1();                                        //关定时器
    }
}
//==========================================================================
// 定时计数器0溢出中断函数
//==========================================================================
ISR(SIG_OVERFLOW0)
{
    WAIT_Time ++;
    if(WAIT_Time >= MAX_WAIT_TIME)              
    {
        //WAIT_Time = MAX_WAIT_TIME;
        CLOSE_WaitResponsionClk();  //关T0中断
        OPEN_USART1_ReINTERRUPT();  //关接收中断
    }
    else
    TCNT0 = 0x00;                   //重新装入计数器初值
}
//==========================================================================
// USART接收中断函数
//==========================================================================
ISR(SIG_UART_RECV)    //串口接受中断
{
    BYTE Rdata;
    Rdata = UDR;
    if(Rdata == EQUIPMENT_PARAMETER_TABLE[mb_infor.EQUIPMENT_NOW].EQU_ADDR)    //是当前等待帧
    {
        WAIT_Responsion = 0;                                                    //结束超时判断
        Receive_en = 1;                                                         //使能接收
        adu.ADULength = 0;
        *(adu.RxADUBuffPtr + adu.ADULength) = Rdata;                           //为了CRC计算方便,还是要在缓冲区存储整个PDU帧
        adu.ADULength ++;
        CLOSE_USART1_ReINTERRUPT();                                             //关接收中断
        OPEN_TIMER1();                                                          //开定时器T1
    }
//    delay_us(40);                   //退出时启动定时器
}
//===========================================================================
//       初始化函数
//===========================================================================
//modbus状态
void MB_INFORMATION_Init(MB_INFORMATION *MBi)
{
    MBi -> EQUIPMENT_NOW = 0;                         //初始化时,从第0台设备开始
//    MBi -> MODBUS_STATE = (enum _MODBUS_STATE)0;     
    MBi -> T15_OUT = FALSE;
    MBi -> T35_OUT = FALSE;
    MBi -> TO_times = 0;
}

void ADU_CONTROL_Init(ADU_CONTROL *adu)   
{
    adu -> Address = 0;
    adu -> TxADUBuffptr = TxAdu_buf;
    adu -> RxADUBuffPtr = RxAdu_buf;
    adu -> ADULength = 0;
    adu -> FrameOK = FALSE;
}
//================================================================================
// 接收帧的处理;
// 参数:  1.要处理帧的指针  2.要处理帧的长度
//================================================================================
MESSAGE_ERR  message_process(BYTE *Message,BYTE len)
{
    unsigned int CRC_data,RX_crc;
    RX_crc = *(adu.RxADUBuffPtr + adu.ADULength - 2)/*CRC高位*/*256 + *(adu.RxADUBuffPtr + adu.ADULength - 1)/*CRC低位*/;
    CRC_data = Get_CRC (adu.RxADUBuffPtr,adu.ADULength - 2);      //计算CRC校验
    if(CRC_data == RX_crc)                                        //CRC校验正确
    {
        if(bit_is_clear(*(adu.RxADUBuffPtr + 1),7))              //功能码返回正确?
        {
            if(*(adu.RxADUBuffPtr + 2) == adu.ADULength - 5)     //
            {
                return NO_ERR;
            }
            else
            return LEN_ERR;
        }
        else
        return FUNC_ERR;
    }
    else
    return CRC_ERR;
}

使用特权

评论回复
地板
yewuyi| | 2007-9-20 21:52 | 只看该作者

板凳……

使用特权

评论回复
5
keer_zu|  楼主 | 2007-9-21 08:57 | 只看该作者

还望高手指点一二

使用特权

评论回复
6
keer_zu|  楼主 | 2007-9-21 19:38 | 只看该作者

stuk,i;likjh

,gf lh

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1349

主题

12426

帖子

53

粉丝