⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbus_rtu.c

📁 ucos下的modbus-rtu处理程序,支持1,2,3,4,5,16,15,16 号功能码
💻 C
📖 第 1 页 / 共 2 页
字号:
//****************************************************************************
//Copyright (c) 2007-2008 ABX CO,.LTD
//----------All rights reserved----------
//文件名称: modbusrtu.c
//模块功能: MODBUSRTU通讯协议
//创建日期: 2008.01.2
//创 建 人: 罗德良
//参考文档: LPC2104开发板
//说    明: 参照原modbusrtu.c修改成平台无关性	
//修改历史:
//****************************************************************************
#define IN_MODBUS_RTU
#include "config.h"

//寄存器在此定义
//内部寄存器定义
#define AICOUNT     35                      //AI路数
#define AOCOUNT     146                     //AO路数
#define DOCOUNT     8                      	//DO路数
#define DICOUNT     8                      	//DI路数

/******************************************
ui16AiReg[0]-[15]	AI量化值
ui16AiReg[16]		内部温度值
ui16AiReg[17]-[32]	AI采样值

设备信息
ui16AiReg[33]		设备类型
ui16AiReg[34]		设备版本号

ui16AoReg[0]-[1]	AO

ui16AoReg[2]-[17]	DI计数值(两寄存器为一路)

以下为配置参数
ui16AoReg[18]		存盘请求寄存器
ui16AoReg[19]		站号
ui16AoReg[20]		Uart0波特率
ui16AoReg[21]		Uart0数据位(Bit7), 校验位(Bit6,5), 停止位(Bit4)
ui16AoReg[22]		Uart0帧间隔时间
ui16AoReg[23]		Uart1波特率
ui16AoReg[24]		Uart1数据位(Bit7), 校验位(Bit6,5), 停止位(Bit4)
ui16AoReg[25]		Uart1帧间隔时间
ui16AoReg[26]-[27]	AO零位
ui16AoReg[28]-[29]	AO满度
ui16AoReg[30]-[37]	AI零位(I)
ui16AoReg[38]-[45]	AI满度(I)
ui16AoReg[46]-[53]	AI零位(V)
ui16AoReg[54]-[61]	AI满度(V)
ui16AoReg[62]-[69]  AI显示量程下限
ui16AoReg[70]-[77]	AI显示量程上限
ui16AoReg[78]-[85]	AI显示小数位数
ui16AoReg[86]-[93]	AI报警上限
ui16AoReg[94]-[101] AI报警下限
ui16AoReg[102]		内部温度报警上限
ui16AoReg[103]		内部温度报警下限
ui16AoReg[104]-[111]AI信号类型
ui16AoReg[112]-[119]DI工作模式
ui16AoReg[120]-[127]DO工作模式
ui16AoReg[128]-[135]DO控制源
ui16AoReg[136]-[143]DO点动延时寄存器
ui16AoReg[144]-[145]AO输出寄存器
******************************************/
volatile UINT16 ui16AiReg[AICOUNT];         //AI寄存器
volatile UINT16 ui16AoReg[AOCOUNT];         //AO寄存器
volatile UCHAR ucDoReg[DOCOUNT / 8];        //DO寄存器
volatile UCHAR ucDiReg[DICOUNT / 8];        //DI寄存器

//协议结构
typedef struct
{
    UCHAR   ucSta;          				//站号
    UCHAR   ucFun;          				//功能码
    UCHAR   ucMess[256];        			//内容 
}tagMODBUSREV;                              //MODBUS接收数据结构

typedef struct
{
    UCHAR   ucSta;          				//站号
    UCHAR   ucFun;          				//功能码
    UCHAR   ucStarAdrHi;                    //起始寄存器地址高字节
    UCHAR   ucStarAdrLo;                    //起始寄存器地址低字节
    UCHAR   ucCntHi;                		//数量高字节
    UCHAR   ucCntLo;                		//数量低字节
    UCHAR   ucCrcHi;            			//CRC高字节
    UCHAR   ucCrcLo;            			//CRC低字节
}tagMODREAD;                                //MODBUS读数据结构及多写应答结构

typedef struct
{
    UCHAR   ucSta;          				//站号
    UCHAR   ucFun;          				//功能码
    UCHAR   ucByteCnt;          			//字节数
    UCHAR   ucMess[256];        			//内容
}tagMODREADRESP;                            //MODBUS读应答数据结构

typedef struct
{
    UCHAR   ucSta;          				//站号
    UCHAR   ucFun;          				//功能码
    UCHAR   ucAdrHi;                    	//寄存器地址高字节
    UCHAR   ucAdrLo;                    	//寄存器地址低字节
    UCHAR   ucDatHi;                		//数据高字节
    UCHAR   ucDatLo;                		//数据低字节
    UCHAR   ucCrcHi;            			//CRC高字节
    UCHAR   ucCrcLo;            			//CRC低字节
}tagWRSINGAL;                               //MODBUS写单个寄存器及应答结构

typedef struct
{
    UCHAR   ucSta;          				//站号
    UCHAR   ucFun;          				//功能码
    UCHAR   ucStarAdrHi;                    //起始寄存器地址高字节
    UCHAR   ucStarAdrLo;                    //超始寄存器地址低字节
    UCHAR   ucCntHi;                		//数量高字节
    UCHAR   ucCntLo;                		//数量低字节
    UCHAR   ucByteCnt;          			//字节数
    UCHAR   ucMess[64];         			//内容
}tagWRMULTE;                                //MODBUS写多个寄存器数据结构

typedef struct
{
    UCHAR   ucSta;                          //站号
    UCHAR   ucFun;                          //功能码
    UCHAR   ucLen;                          //长度
    UCHAR   ucFunNo;                        //代号
    UCHAR   ucMess[128];                    //内容
}tagWRCONFIG;                               //配置结构

//MODBUS异常码
#define NO_ERR      0x00                    //无异常
#define FUN_ERR     0x01                    //不支持的功能码
#define ADR_ERR     0x02                    //地址超出范围
#define VAL_ERR     0x03                    //数据超出范围
#define FAIL_ERR    0x04                    //执行失败
#define CALL_ERR    0x05                    //调用参数错误

//****************************************************************************
//函数名称: Read_MultAI
//函数功能: 读输入寄存器(AI)
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 4号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultAI(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, i, ui16Len;
    UCHAR m;
    tagMODREAD *tagpModRead;
    tagMODREADRESP *tagpModReadResp;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpModRead = (tagMODREAD *)ucpRevcBuff;            //接收缓冲区
    tagpModReadResp = (tagMODREADRESP *)ucpSendBuff;    //应答缓冲区
    
    tagpModReadResp -> ucSta = tagpModRead -> ucSta;    //站号
    tagpModReadResp -> ucFun = tagpModRead -> ucFun;    //功能码
    
    //寄存器起始地址
    ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
    if (ui16Temp >= AICOUNT) return (ADR_ERR);              //寄存器超出范围

    //寄存器数量	
    ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
    if ((ui16Len + ui16Temp) > AICOUNT) return(ADR_ERR);    //寄存器超出范围
    
    //返回数据字节数
    tagpModReadResp -> ucByteCnt = ui16Len * 2;
    
    //内容处理
    m = 0;
    for (i = ui16Temp; i < ui16Len + ui16Temp; i++)
    {
        tagpModReadResp -> ucMess[m++] = ui16AiReg[i] / 256ul;
        tagpModReadResp -> ucMess[m++] = ui16AiReg[i];
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
    
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;

    //发送缓冲长度
    *ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Read_MultAO
//函数功能: 读保持寄存器(AO)
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 3号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultAO(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, i, ui16Len;
    UCHAR m;
    tagMODREAD *tagpModRead;
    tagMODREADRESP *tagpModReadResp;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpModRead = (tagMODREAD *)ucpRevcBuff;            //接收缓冲区
    tagpModReadResp = (tagMODREADRESP *)ucpSendBuff;    //应答缓冲区
    
    tagpModReadResp -> ucSta = tagpModRead -> ucSta;    //站号
    tagpModReadResp -> ucFun = tagpModRead -> ucFun;    //功能码
    
    //寄存器起始地址
    ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
    if (ui16Temp >= AOCOUNT) return (ADR_ERR);              //寄存器超出范围

    //寄存器数量	
    ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
    if ((ui16Len + ui16Temp) > AOCOUNT) return(ADR_ERR);    //寄存器超出范围
    
    //返回数据字节数
    tagpModReadResp -> ucByteCnt = ui16Len * 2;
    
    //内容处理
    m = 0;
    for (i = ui16Temp; i < ui16Len + ui16Temp; i++)
    {
        tagpModReadResp -> ucMess[m++] = ui16AoReg[i] / 256ul;
        tagpModReadResp -> ucMess[m++] = ui16AoReg[i];
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
    
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
    
    //发送缓冲长度
    *ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Read_MultCoil
//函数功能: 读取线圈状态
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 1号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultCoil(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, i, ui16Len;
    UCHAR ucTemp, ucByteNo, ucBitNo;
    tagMODREAD *tagpModRead;
    tagMODREADRESP *tagpModReadResp;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpModRead = (tagMODREAD *)ucpRevcBuff;            //接收缓冲区
    tagpModReadResp = (tagMODREADRESP *)ucpSendBuff;    //应答缓冲区
    
    tagpModReadResp -> ucSta = tagpModRead -> ucSta;    //站号
    tagpModReadResp -> ucFun = tagpModRead -> ucFun;    //功能码
    
    //寄存器起始地址
    ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
    if (ui16Temp >= DOCOUNT) return (ADR_ERR);                  //寄存器超出范围

    //寄存器数量	
    ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
    if ((ui16Len + ui16Temp) > DOCOUNT) return(ADR_ERR);        //寄存器超出范围
    
    //返回数据字节数
    tagpModReadResp -> ucByteCnt = ui16Len / 8;
    if ((ui16Len % 8) != 0)
    {
        tagpModReadResp -> ucByteCnt += 1;
    }
    
    //内容处理
    i = 0;
    while (i < ui16Len)
    {
        //取寄存器位值
        ucByteNo = ui16Temp / 8;
        ucBitNo = ui16Temp % 8;
        ucTemp = ((ucDoReg[ucByteNo] >> ucBitNo) & 0x01);
        
        if ((i % 8) == 0)
        {
            tagpModReadResp -> ucMess[i / 8] = 0x00;
        }
        
        //填充到发送缓冲
        tagpModReadResp -> ucMess[i / 8] |= (ucTemp << (i % 8));

        i++;
        ui16Temp++;
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
    
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
    
    //发送缓冲长度
    *ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Read_MultDI
//函数功能: 读取离输入状态

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -