我写了个实现一种功能的modbus的主机
还请CHUN版主和各位给个意见。稍后付上流程图!<br /><br />主程序:<br /><br />#include"485.h"<br />#include"modbus_client.h"<br /><br />extern UINT16 Get_CRC ( BYTE *, BYTE);<br />extern void message_storage(BYTE *,BYTE,BYTE);<br />extern EQUIPMENT_PARAMETER EQUIPMENT_PARAMETER_TABLE;<br />//extern uchar T_flag;<br />//extern uchar buf_p;<br />//extern uchar Receive_now; //在接收中断中,只要确认应答的设备地址正确就置位<br /> //<br />//===========================================<br />BYTE Receive_en; //接收使能<br />//=========================================== <br />BYTE WAIT_Responsion; //等待应答:发送完一帧请求后置位,作为持续等待标志,<br /> //在接收中断中,如果接到这个设备的应答,只要地址正<br /> //就可以清除从而结束超时等待;<br />BYTE WAIT_Time; //<br />//===========================================<br />// 全局变量结构体<br />//===========================================<br />MB_INFORMATION mb_infor;<br />//MASTER_INFORMATION mas_infor;<br />ADU_CONTROL adu;<br />//===========================================<br />// 超时错误<br />//===========================================<br />#define MAX_CHAOSHI 3<br />BYTE CHAOSHI_ErrTime; //超时错误计数器 超过MAX_CHAOSHI次就要把<br /> //EQUIPMENT_PARAMETER_TABLE.EQUIP_STATE<br /> //变为ERR<br />//===========================================<br />// 帧错误<br />//===========================================<br />BYTE ZHEN_ErrTime;<br /><br />int main(void)<br />{<br /> UINT16 CRC_BUF;<br /> BYTE CRC_CHAR;<br /> MESSAGE_ERR MESSAGE_err;<br /> //=================================================<br /> // 变量初始化<br /> //=================================================<br /> WAIT_Time = 0;<br /> Receive_en =0;<br /> memset(TxAdu_buf,0,BUFSIZE);<br /> memset(RxAdu_buf,0,BUFSIZE);<br /> memset(CHAOSHI_ErrTime,0,MAX_EQU_NUM);<br /> memset(ZHEN_ErrTime,0,MAX_EQU_NUM);<br />// Receive_now = 0;<br />//===========================================<br /> MB_INFORMATION_Init(&mb_infor);<br />// MASTER_INFORMATION_Init( &mas_infor);<br /> ADU_CONTROL_Init(&adu);<br /> PORTd_INIT();<br />//===========================================<br /> cli();<br /> comInit();<br /> sei();<br />// t_485("ni hao ma?\n");<br />// t_485("Hello! da jia hao,wo shi tiao zao tuan zhang;\n");<br /> while(1)<br /> {<br /> begin:<br /> //&&&&&&&&&&&&&&&&&&&&&&&<br /> // 拼装帧 发送帧<br /> //&&&&&&&&&&&&&&&&&&&&&&&<br /> if(!EQUIPMENT_PARAMETER_TABLE.EQU_ADDR/*0代表没有设备*/ && EQUIPMENT_PARAMETER_TABLE.EQU_STATE/*设备无故障*/) <br /> {<br /> adu.ADULength = 0;<br /> *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE.EQU_ADDR;<br /> //地址<br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = 0x03; //功能号<br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = 0x00; <br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE. REG_ORIGINATION;<br /> //起始寄存器<br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = 0x00;<br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = EQUIPMENT_PARAMETER_TABLE.REG_NUM;<br /> //寄存器数量<br /> adu.ADULength ++;<br /> CRC_BUF = Get_CRC ( adu.TxADUBuffptr, adu.ADULength ) ;<br /> CRC_CHAR = (BYTE)CRC_BUF; <br /> *(adu.TxADUBuffptr + adu.ADULength) = (BYTE)(CRC_BUF >> 4); //CRC校验高四位<br /> adu.ADULength ++; <br /> *(adu.TxADUBuffptr + adu.ADULength) = CRC_BUF; //CRC校验低四位<br /> adu.ADULength ++;<br /> *(adu.TxADUBuffptr + adu.ADULength) = '\n'; //在帧的结尾加上‘\n’做为发送结束标志<br /> t_485(adu.TxADUBuffptr); //发送帧<br /> adu.ADULength = 0;<br /> WAIT_Responsion = 1; //使能等待标志<br /> OPEN_WaitResponsionClk(); //打开超时计数器T0中断<br /> OPEN_USART1_ReINTERRUPT(); //打开接收中断<br /> }<br /> else //如果设备不存在或设备故障转到下一台设备<br /> {<br /> if(++mb_infor.EQUIPMENT_NOW > MAX_EQU_NUM) //查询完一遍?<br /> mb_infor.EQUIPMENT_NOW = 0; //设备编号从0开始<br /> goto begin;<br /> }<br /> while(WAIT_Responsion) //在接收中断中如果收到当前地址选中设备的应答则清除标志,跳出循环<br /> {<br /> if(WAIT_Time >= MAX_WAIT_TIME) //超时<br /> {<br /> //CLOSE_WaitResponsionClk(); //关闭T0;<br /> WAIT_Time = 0; //复位WAIT_Time<br /> CHAOSHI_ErrTime ++; //超时错误计数器++<br /> if(CHAOSHI_ErrTime >= MAX_CHAOSHI) //超过最大超时错误<br /> {<br /> EQUIPMENT_PARAMETER_TABLE.EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备<br /> CHAOSHI_ErrTime = 0; //超时错误计数器清0<br /> } <br /> if(++mb_infor.EQUIPMENT_NOW > MAX_EQU_NUM) //设备查询过来一遍?<br /> mb_infor.EQUIPMENT_NOW = 0; //设备编号从0开始<br /> WAIT_Responsion = 0; //重新初始化等待回应标志<br /> goto begin;<br /> }<br /> }<br /> //&&&&&&&&&&&&&&&&&&&&&&<br /> //接收除地址外的其他字节<br /> //&&&&&&&&&&&&&&&&&&&&&&<br /> for(;;)<br /> {<br /> while(!(UCSRA & (1<<RXC)))<br /> {<br /> if(mb_infor.T35_OUT)<br /> {<br /> mb_infor.T35_OUT = FALSE;<br /> WAIT_Time = 0; //WAIT_Time复位<br /> goto ZHEN_OVER;<br /> }<br /> }<br /> TCNT0 = 0x00; //重新计数<br /> WAIT_Time = 0; //中断次数清零<br /> delay_us(50);<br /> *(adu.RxADUBuffPtr + adu.ADULength) = UDR;<br /> adu.ADULength ++;<br /> }<br /> ZHEN_OVER:<br /> CLOSE_TIMER1(); //关定时器1<br />//================================================================<br />/* 以下内容是帧处理: */<br />//================================================================<br /> MESSAGE_err = message_process(adu.RxADUBuffPtr,adu.ADULength);<br /> switch(MESSAGE_err)<br /> {<br /> case CRC_ERR: ZHEN_ErrTime ++; //错误计数器++<br /> if(ZHEN_ErrTime >= MAX_ZHENERR) //超过最大超时错误<br /> {<br /> EQUIPMENT_PARAMETER_TABLE.EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备<br /> ZHEN_ErrTime = 0; //超时错误计数器清0<br /> }<br /> goto begin;<br /> break;<br /> case FUNC_ERR://&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&<br /> // 这里要分析错误代码 找到原因<br /> //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&<br /> ZHEN_ErrTime ++; //错误计数器++<br /> if(ZHEN_ErrTime >= MAX_ZHENERR) //超过最大超时错误<br /> {<br /> EQUIPMENT_PARAMETER_TABLE.EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备<br /> ZHEN_ErrTime = 0; //超时错误计数器清0<br /> }<br /> break;<br /> case LEN_ERR: ZHEN_ErrTime ++; //错误计数器++<br /> if(ZHEN_ErrTime >= MAX_ZHENERR) //超过最大超时错误<br /> {<br /> EQUIPMENT_PARAMETER_TABLE.EQU_STATE = ERR; //修改设备参数表中的状态,以后不再查询该设备<br /> ZHEN_ErrTime = 0; //超时错误计数器清0<br /> }<br /> goto begin;<br /> break;<br /> case NO_ERR: message_storage(adu.RxADUBuffPtr,mb_infor.EQUIPMENT_NOW,adu.ADULength); // //存储帧<br /> if(++mb_infor.EQUIPMENT_NOW > MAX_EQU_NUM) //设备查询过来一遍?<br /> mb_infor.EQUIPMENT_NOW = 0; //设备编号从0开始<br /> goto begin;<br /> break;<br /> }<br /> }<br />}<br /><br /><br />相关的结构体
#ifndef _MB_CLIENT<br />#define _MB_CLIENT<br />#include <avr/io.h><br />#include <avr/interrupt.h><br />#include <string.h><br /><br />#include "485.h"<br />#define TRUE 1<br />#define FALSE 0<br />#define UINT16 unsigned int<br />#define BYTE unsigned char<br />#define MAX_EQU_NUM 3 //现在使用3个设备<br />#define OK 1<br />#define ERR 0<br />//===================================================================<br />// 错误常量<br />//===================================================================<br />#define CHAOSHI 0XFF<br /><br />//===================================================================<br />//设备数据结构 用于构建设备参数表<br />typedef struct _EQUIPMENT_PARAMETER<br />{<br /> BYTE EQU_ADDR; //设备地址 <br /> BYTE EQU_TYPE; //设备类型<br /> BYTE EQU_STATE; //设备状态<br /> BYTE REG_ORIGINATION; //起始寄存器地址<br /> BYTE REG_NUM; //寄存器数量<br />}EQUIPMENT_PARAMETER;<br /><br />//ADU处理信息结构<br />typedef struct _ADU_CONTROL<br />{<br /> BYTE Address; //地址域<br /> BYTE *RxADUBuffPtr; //指向ADU发送缓冲区的指针<br /> BYTE *TxADUBuffptr; //指向ADU接收缓冲区的指针<br /> BYTE ADULength; //ADU数据长度<br /> BYTE FrameOK; //如果该ADU报文有效(地址有效,奇偶、CRC校验通过)则TRUE<br />}ADU_CONTROL;<br />//通信状态<br />typedef struct _MB_INFORMATION<br />{<br /> BYTE EQUIPMENT_NOW; //当前正在处理设备编号<br />// enum _MODBUS_STATE MODBUS_STATE; //描述modbus状态的变量<br /> BYTE T15_OUT; //1.5ms延时到<br /> BYTE T35_OUT; //3.5ms延时到<br /> BYTE TO_times; //时钟中断次数计数器<br />}MB_INFORMATION;<br />// 帧错误类型<br />typedef enum _MESSAGE_ERR<br />{<br /> CRC_ERR, //CRC校验错<br /> FUNC_ERR, //功能号错 -应该处理错误类型<br /> LEN_ERR, //长度错<br /> NO_ERR //没有错误<br />}MESSAGE_ERR;<br /><br />//=====================================================================================<br />void MB_INFORMATION_Init(MB_INFORMATION *);<br />//void MASTER_INFORMATION_Init(MASTER_INFORMATION *);<br />void ADU_CONTROL_Init(ADU_CONTROL *);<br />MESSAGE_ERR message_process(BYTE *,BYTE);<br />#endif<br />接收中断,时钟中断等操作(winavr(avr——gcc))
接收中断,时钟中断等操作(winavr(avr——gcc))
#include "modbus_client.h"<br />#ifndef _PGM<br />#define _PGM<br />#include <avr/pgmspace.h><br />#endif<br />//=========================================<br />// 返回CRC校验结果<br />//=========================================<br />extern unsigned int Get_CRC(BYTE *,BYTE);<br />//=========================================<br />// 缓冲区<br />//=========================================<br />extern ADU_CONTROL adu;<br />extern MB_INFORMATION mb_infor;<br />extern BYTE WAIT_Time,Receive_en,WAIT_Responsion;<br /><br />//========================================================================<br />// 设备参数表<br />//========================================================================<br />EQUIPMENT_PARAMETER EQUIPMENT_PARAMETER_TABLE=<br />{<br /> {0X09,0,OK,0,0x15}, //1、地址 2、类型 3、状态 4、起始寄存器 5、寄存器数量(十六位,两个字节)<br /> {0x02,1,OK,0,0x0f},<br /> {0x11,0,OK,0,0x15}/*,<br /> {0x00,0,OK,0,0},<br /> {0x00,0,OK,0,0}*/<br />};<br /><br />//==========================================================================<br />// 定时计数器1溢出中断函数<br />//==========================================================================<br />ISR(SIG_OVERFLOW1)<br />{<br /> TCNT1 = 0xf70c; //4M时0.5个字符-0.000573s产生一个中断<br /> mb_infor.TO_times ++;<br /> if(mb_infor.TO_times == 3)mb_infor.T15_OUT = TRUE; //1.5ms延时到<br /> if(mb_infor.TO_times == 7)<br /> {<br /> mb_infor.T35_OUT = TRUE; //3.5ms延时到<br /> CLOSE_TIMER1(); //关定时器<br /> }<br />}<br />//==========================================================================<br />// 定时计数器0溢出中断函数<br />//==========================================================================<br />ISR(SIG_OVERFLOW0)<br />{<br /> WAIT_Time ++;<br /> if(WAIT_Time >= MAX_WAIT_TIME) <br /> {<br /> //WAIT_Time = MAX_WAIT_TIME;<br /> CLOSE_WaitResponsionClk(); //关T0中断<br /> OPEN_USART1_ReINTERRUPT(); //关接收中断<br /> }<br /> else<br /> TCNT0 = 0x00; //重新装入计数器初值<br />}<br />//==========================================================================<br />// USART接收中断函数<br />//==========================================================================<br />ISR(SIG_UART_RECV) //串口接受中断<br />{<br /> BYTE Rdata;<br /> Rdata = UDR;<br /> if(Rdata == EQUIPMENT_PARAMETER_TABLE.EQU_ADDR) //是当前等待帧<br /> {<br /> WAIT_Responsion = 0; //结束超时判断<br /> Receive_en = 1; //使能接收<br /> adu.ADULength = 0;<br /> *(adu.RxADUBuffPtr + adu.ADULength) = Rdata; //为了CRC计算方便,还是要在缓冲区存储整个PDU帧<br /> adu.ADULength ++;<br /> CLOSE_USART1_ReINTERRUPT(); //关接收中断<br /> OPEN_TIMER1(); //开定时器T1<br /> }<br />// delay_us(40); //退出时启动定时器<br />}<br />//===========================================================================<br />// 初始化函数<br />//===========================================================================<br />//modbus状态<br />void MB_INFORMATION_Init(MB_INFORMATION *MBi)<br />{<br /> MBi -> EQUIPMENT_NOW = 0; //初始化时,从第0台设备开始<br />// MBi -> MODBUS_STATE = (enum _MODBUS_STATE)0; <br /> MBi -> T15_OUT = FALSE;<br /> MBi -> T35_OUT = FALSE;<br /> MBi -> TO_times = 0;<br />}<br /><br />void ADU_CONTROL_Init(ADU_CONTROL *adu) <br />{<br /> adu -> Address = 0;<br /> adu -> TxADUBuffptr = TxAdu_buf;<br /> adu -> RxADUBuffPtr = RxAdu_buf;<br /> adu -> ADULength = 0;<br /> adu -> FrameOK = FALSE;<br />}<br />//================================================================================<br />// 接收帧的处理;<br />// 参数: 1.要处理帧的指针 2.要处理帧的长度<br />//================================================================================<br />MESSAGE_ERR message_process(BYTE *Message,BYTE len)<br />{<br /> unsigned int CRC_data,RX_crc;<br /> RX_crc = *(adu.RxADUBuffPtr + adu.ADULength - 2)/*CRC高位*/*256 + *(adu.RxADUBuffPtr + adu.ADULength - 1)/*CRC低位*/;<br /> CRC_data = Get_CRC (adu.RxADUBuffPtr,adu.ADULength - 2); //计算CRC校验<br /> if(CRC_data == RX_crc) //CRC校验正确<br /> {<br /> if(bit_is_clear(*(adu.RxADUBuffPtr + 1),7)) //功能码返回正确?<br /> {<br /> if(*(adu.RxADUBuffPtr + 2) == adu.ADULength - 5) //<br /> {<br /> return NO_ERR;<br /> }<br /> else<br /> return LEN_ERR;<br /> }<br /> else<br /> return FUNC_ERR;<br /> }<br /> else<br /> return CRC_ERR;<br />}<br /><br />顶一下
辛苦了,下去仔细看看。 MARK modbus主机 楼主辛苦了~ 这么久了还有人看? mark mark mark mark 好东西,流程图传上来啊 赞 不错,很好,要实现全功能还有很多 主机必须要看的。 版主,把你的modbus工程放上来被,最近搞这个主机搞死了 我们也有用到,但是自己写的都比较简单而已
页:
[1]