#include "modbus.h"
#include "crc16.h"
#include "uart.h"
extern u8 ReceiveBuf[MaxDataLen];
extern u8 RecIndexLen;
u8 SendBuf[MaxDataLen] = {0};
u16 StartRegAddr = 0;
u8 err = 0; //错误代码
u8 HoldReg[16] = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}; //存储8路输出功率值
/*
错误代码说明:
0x01 不是支持的功能码
0x02 起始地址不在规定范围内
0x03 寄存器数量不在规定范围内
0x04 数据校验错误
*/
//处理接收到的数据
// 接收: [地址][功能码][起始地址高][起始地址低][总寄存器数高][总寄存器数低][CRC低][CRC高]
void DisposeReceive( void )
{
u16 CRC16 = 0, CRC16Temp = 0;
if( ReceiveBuf[0] == SlaveID ) //地址等于本机地址 地址范围:1 - 32
{
CRC16 = App_Tab_Get_CRC16( ReceiveBuf, RecIndexLen - 2 ); //CRC校验 低字节在前 高字节在后 高字节为报文最后一个字节
CRC16Temp = ( ( u16 )( ReceiveBuf[RecIndexLen - 1] << 8 ) | ReceiveBuf[RecIndexLen - 2] );
if( CRC16 != CRC16Temp )
{
err = 4; //CRC校验错误
}
StartRegAddr = ( u16 )( ReceiveBuf[2] << 8 ) | ReceiveBuf[3];
if( StartRegAddr > 0x07 )
{
err = 2; //起始地址不在规定范围内 00 - 07 1 - 8号通道
}
if( err == 0 )
{
switch( ReceiveBuf[1] ) //功能码
{
case 3: //读多个寄存器
{
Modbus_03_Slave();
break;
}
case 6: //写单个寄存器
{
Modbus_06_Slave();
break;
}
case 16: //写多个寄存器
{
Modbus_16_Slave();
break;
}
default:
{
err = 1; //不支持该功能码
break;
}
}
}
if( err > 0 )
{
SendBuf[0] = ReceiveBuf[0];
SendBuf[1] = ReceiveBuf[1] | 0x80;
SendBuf[2] = err; //发送错误代码
CRC16Temp = App_Tab_Get_CRC16( SendBuf, 3 ); //计算CRC校验值
SendBuf[3] = CRC16Temp & 0xFF; //CRC低位
SendBuf[4] = ( CRC16Temp >> 8 ); //CRC高位
Uart1_Send( SendBuf, 5 );
err = 0; //发送完数据后清除错误标志
}
}
}
/*
函数功能:读保持寄存器 03
主站请求报文: 0x01 0x03 0x0000 0x0001 0x840A 读从0开始的1个保持寄存器
从站正常响应报文: 0x01 0x03 0x02 0x09C4 0xBF87 读到的2字节数据为 0x09C4
*/
void Modbus_03_Slave( void )
{
u16 RegNum = 0;
u16 CRC16Temp = 0;
u8 i = 0;
RegNum = ( u16 )( ReceiveBuf[4] << 8 ) | ReceiveBuf[5]; //获取寄存器数量
if( ( StartRegAddr + RegNum ) < 9 ) //寄存器地址+寄存器数量 在规定范围内
{
SendBuf[0] = ReceiveBuf[0];
SendBuf[1] = ReceiveBuf[1];
SendBuf[2] = RegNum * 2;
for( i = 0; i < RegNum; i++ ) //读取保持寄存器内的值
{
SendBuf[3 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2];
SendBuf[4 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2 + 1];
}
CRC16Temp = App_Tab_Get_CRC16( SendBuf, RegNum * 2 + 3 ); //获取CRC校验值
SendBuf[RegNum * 2 + 3] = CRC16Temp & 0xFF; //CRC低位
SendBuf[RegNum * 2 + 4] = ( CRC16Temp >> 8 ); //CRC高位
Uart1_Send( SendBuf, RegNum * 2 + 5 );
}
else
{
err = 3; //寄存器数量不在规定范围内
}
}
/*
函数功能:写单个保持寄存器 06
主站请求报文: 0x01 0x06 0x0000 0x1388 0x849C 写0号寄存器的值为0x1388
从站正常响应报文: 0x01 0x06 0x0000 0x1388 0x849C 0号寄存器的值为0x1388
*/
void Modbus_06_Slave( void )
{
u16 RegValue = 0;
u16 CRC16Temp = 0;
RegValue = ( u16 )( ReceiveBuf[4] << 8 ) | ReceiveBuf[5]; //获取寄存器值
if( RegValue < 1001 ) //寄存器值不超过1000
{
HoldReg[StartRegAddr * 2] = ReceiveBuf[4]; //存储寄存器值
HoldReg[StartRegAddr * 2 + 1] = ReceiveBuf[5];
SendBuf[0] = ReceiveBuf[0];
SendBuf[1] = ReceiveBuf[1];
SendBuf[2] = ReceiveBuf[2];
SendBuf[3] = ReceiveBuf[3];
SendBuf[4] = ReceiveBuf[4];
SendBuf[5] = ReceiveBuf[5];
CRC16Temp = App_Tab_Get_CRC16( SendBuf, 6 ); //获取CRC校验值
SendBuf[6] = CRC16Temp & 0xFF; //CRC低位
SendBuf[7] = ( CRC16Temp >> 8 ); //CRC高位
Uart1_Send( SendBuf, 8 );
}
else
{
err = 3; //寄存器数值不在规定范围内
}
}
/*
函数功能:写多个连续保持寄存器值 16
主站请求报文: 0x01 0x10 0x7540 0x0002 0x04 0x0000 0x2710 0xB731 写从0x7540地址开始的2个保持寄存器值 共4字节
从站正常响应报文: 0x01 0x10 0x7540 0x0002 0x5A10 写从0x7540地址开始的2个保持寄存器值
*/
void Modbus_16_Slave( void )
{
u16 RegNum = 0;
u16 CRC16Temp = 0;
u8 i = 0;
RegNum = ( u16 )( ReceiveBuf[4] << 8 ) | ReceiveBuf[5]; //获取寄存器数量
if( ( StartRegAddr + RegNum ) < 9 ) //寄存器地址+寄存器数量 在规定范围内
{
for( i = 0; i < RegNum; i++ ) //存储寄存器设置值
{
HoldReg[StartRegAddr * 2 + i * 2] = ReceiveBuf[i * 2 + 7];
HoldReg[StartRegAddr * 2 + 1 + i * 2] = ReceiveBuf[i * 2 + 8];
}
SendBuf[0] = ReceiveBuf[0];
SendBuf[1] = ReceiveBuf[1];
SendBuf[2] = ReceiveBuf[2];
SendBuf[3] = ReceiveBuf[3];
SendBuf[4] = ReceiveBuf[4];
SendBuf[5] = ReceiveBuf[5];
CRC16Temp = App_Tab_Get_CRC16( SendBuf, 6 ); //获取CRC校验值
SendBuf[6] = CRC16Temp & 0xFF; //CRC低位
SendBuf[7] = ( CRC16Temp >> 8 ); //CRC高位
Uart1_Send( SendBuf, 8 );
}
else
{
err = 3; //寄存器数量不在规定范围内
}
}
嵌入式@hxydj
- 粉丝: 11w+
- 资源: 174
最新资源
- Golang_Puzzlers-新年主题资源
- vscode-vscode
- Algorithm Practice-冒泡排序
- gitmoji-vscode-vscode
- 常见查找算法-折半查找的实现
- StudentManageSystem-学生成绩链表处理
- Truora-Web-nodejs安装及环境配置
- DataStructure-建立学生信息链表
- discussion-vue3-master-通讯录排序
- PanUmlTools-类图
- datastructure-数据结构
- 计算机组成原理-计算机组成原理
- 24.7.8_sort-希尔排序
- renren-ui-nodejs安装及环境配置
- 大数据技术毕业设计源代码全套技术资料.zip
- 智慧农场小程序源代码全套技术资料.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈