/*************************************************************************************************************
* 文件名: MODBUS_RTU.c
* 功能: MODBUS_RTU通信协议层
* 作者: cp1300@139.com
* 创建时间: 2014-03-24
* 最后修改时间:2015-07-02
* 详细: MODBUS RTU通信协议层
2015-04-27:添加发送延时,防止通信帧结束时产生干扰
2015-05-20:修复当接收字节小于2的时候进行CRC校验出现异常
2016-04-11:增加初始化标记,当没有初始化时,直接退出modbus,增加内存检测,如果内存指针为空,则退出
2017-03-06:增加底层接口支持,并且去掉了溢出检测
2017-03-23:修改名称错误,应为为modbus,增加所有接口回调模式,完全与底层通信解耦,移植性能更强
2018-01-27:增加延时接口
*************************************************************************************************************/
#include "typedef.h"
#include "stdio.h"
#include "modbus_rtu.h"
//调试开关
#define MODBUS_RTU_DBUG 0
#if MODBUS_RTU_DBUG
#include "system.h"
#define modbus_debug(format,...) uart_printf(format,##__VA_ARGS__)
#else
#define modbus_debug(format,...) /\
/
#endif //MODBUS_RTU_DBUG
/*************************************************************************************************************************
* 函数 : bool MODBUS_Init(MODBUS_HANDLE *pHandle,u8 *pTxBuff, u16 TxBuffSize, u16 TxByteTimeUs, u16 RxTimeOutMs,
bool (* pSendData)(u8 *pDataBuff, u16 DataLen),
int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOut, u16 TimeOut, u16 *pReceiveDelay),
void (*pClearRxData)(void),
void (*pDelayMS)(u8 ms))
* 功能 : MODBUS 初始化
* 参数 : pHandle:当前初始化的MODBUS句柄,pTxBuff:发送缓冲区指针;TxBuffSize:发送缓冲区大小;
TxByteTimeUs:发送1个字节的时间(用于RS485收发切换,特别是发送后的切换延时)延时大小为0-65535(us);RxTimeOutMs:接收超时,单位ms,pReceiveDelay:返回接收延时,单位ms
pSendCallBack:发送回调函数(pDataBuff:发送数据缓冲区,DataLen:发送数据长度)
pReadCallBack:接收数据回调函数,会等待直到数据被写入到接收缓冲区(pDataBuff:接收数据缓冲区,ByteTimeOut:等待的字节超时时间,单位ms,TimeOut:数据包超时时间,单位ms)
pClearRxData:清除接收数据缓冲区回调函数
pDelayMS:系统ms延时接口
* 返回 : FALSE:初始化失败;TRUE:初始化成功
* 依赖 : 底层回调接口
* 作者 : cp1300@139.com
* 时间 : 2014-09-25
* 最后修改时间 : 2017-03-23
* 说明 : 发送缓冲区必须大于最大数据包大小,否则会出现内存溢出
2017-03-23:增加回调,抛离底层依赖
2018-01-27:增加延时回调
*************************************************************************************************************************/
bool MODBUS_Init(MODBUS_HANDLE *pHandle,u8 *pTxBuff, u16 TxBuffSize, u16 TxByteTimeUs, u16 RxTimeOutMs,
bool (* pSendData)(u8 *pDataBuff, u16 DataLen),
int (* pReadData)(u8 **pDataBuff, u8 ByteTimeOut, u16 TimeOut, u16 *pReceiveDelay),
void (*pClearRxData)(void),
void (*pDelayMS)(u8 ms))
{
pHandle->ID = 0;
if(pHandle == NULL) return FALSE;
pHandle->WriteRegCnt = 0; //写入寄存器次数
pHandle->ReadRegCnt = 0; //读取寄存器次数
pHandle->ReturnTimeMs = 0; //数据返回时间
pHandle->pTxBuff = pTxBuff; //发送缓冲区
pHandle->TxBuffSize = TxBuffSize; //发送缓冲区大小
pHandle->RxTimeOutMs = RxTimeOutMs; //接收超时时间
if(pHandle->RxTimeOutMs < 20) pHandle->RxTimeOutMs = 20; //限制最小为20ms
pHandle->SlaveAddr = 0; //从机地址无效
pHandle->TxByteTimeUs = TxByteTimeUs; //发送1个字节的时间(用于RS485收发切换,特别是发送后的切换延时)
pHandle->pSendData = pSendData; //发送回调函数
pHandle->pReadData = pReadData; //接收回调函数
pHandle->pClearRxData = pClearRxData; //清除接收回调函数
pHandle->pDelayMS = pDelayMS; //系统毫秒延时接口
pHandle->pSingleRegReadWriteCallBack = NULL; //初始化设置从机单寄存器读写回调函数为空
if((pHandle->pSendData==NULL) || (pHandle->pClearRxData==NULL) || (pHandle->pDelayMS == NULL))
return FALSE; //底层通信接口没有实现,返回初始化失败
pHandle->ID = MODBUS_INIT_ID; //modbus初始化标记
return TRUE;
}
#if(MODBUS_RTU_HOST) //开启主机模式
/*************************************************************************************************************************
* 函数 : MRTU_ERROR MODBUS_HOST_ReadOneReg(MODBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u16 *pRegData)
* 功能 : 主机读取从机一个指定寄存器
* 参数 : pHandle:MODBUS句柄;RegType:读取的寄存器类型;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;pRegData:寄存器的值
* 返回 : MRTU_ERROR:通信状态
* 依赖 : 底层通信驱动
* 作者 : cp1300@139.com
* 时间 : 2014-03-24
* 最后修改时间 : 2017-03-23
* 说明 : MOUEBUS RTU读取数据,读取一个寄存器
输入输出的数据都为小端模式
2017-03-23:增加回调,抛离底层依赖
*************************************************************************************************************************/
MRTU_ERROR MODBUS_HOST_ReadOneReg(MODBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u16 *pRegData)
{
MRTU_READ_FRAME *pFrame; //发送数据帧格式
MRTU_RETURN_FRAME *pReFrame; //返回数据帧格式
MRTU_UNU_FRAME *pUnuFrame; //返回的异常数据帧格式
u16 crc16;
u32 TimeDelay = 0; //用于计算数据接收延时
int len;
u8 *pRxBuff; //接收数据缓冲区指针
if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
if((pHandle->ID != MODBUS_INIT_ID)||(pHandle->pTxBuff==NULL)) return MRTU_HANDLE_ERROR; //2016-04-11增加防止modbus未初始化异常
if(pHandle->TxBuffSize < 8) return MRTU_OVER_ERROR; //检查发送缓冲区
pFrame = (MRTU_READ_FRAME *)pHandle->pTxBuff;
//数据结构填充
pFrame->addr = SlaveAddr; //从机地址
pFrame->fun = (u8)RegType; //功能码,读取
pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
pFrame->RegNum = SWAP16(1); //需要读取的寄存器数量,1
crc16 = MODBUS_CRC16(pHandle->pTxBuff, 6); //计算CRC16
pFrame->CRC16 = crc16; //crc16
#if MODBUS_RTU_DBUG
{
u16 i;
modbus_debug("\r\n<- MODBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,crc16);
for(i = 0;i < 8;i ++)
{
modbus_debug("0x%02X ",pHandle->pTxBuff[i]);
}
modbus_debug("\r\n");
}
#endif //MODBUS_RTU_DBUG
pHandle->pSendData(pHandle->pTxBuff, 6+2); //发送数据
TimeDelay = 8*pHandle->TxByteTimeUs; //计算发送所需时间,进行延时
TimeDelay/=1000; //转换为ms
TimeDelay += 1;
pHandle->pDelayMS(TimeDelay); //等待发送完毕,防止通信帧结束时产生干扰
pHandle->pClearRxData(); //清除接收缓冲区
//等待数据返回
len = pHandle->pReadData(&pRxBuff, 10, pHandle->RxTimeOutMs, &pHandle->ReturnTimeMs); //接收数据
if(len <= 0) //没有接收到数据
{
modbus_debug("接收超时(%dms)!\r\n",pHandle->RxTimeOutMs); //接收数据超时
pHandle->ReturnTimeMs = 0xffff; //接收时间无效
return MRTU_TIME_OUT; //返回超时
}
#if MODBUS_RTU_DBUG
{
u16 i;
modbus_debug("\r\n-> MODBUS RTU RXD(%dB)(ping:%dms):\r\n",len,pHandle->ReturnTimeMs);
for(i = 0;i < len;i ++)
{
modbus_debug("0x%02X ", pRxBuff[i]);
}
modbus_debug("\r\n");
}
#endif //MODBUS_RTU_DBUG
if(len < MODBUS_MIN_RX_BYTE)
{
modbus_debug("返回数据长度错误\r\n");
return MRTU_LEN_ERROR;
}
pReFrame = (MRTU_RETURN_FRAME *)pRxBuff;
//检查地址
if(pReFrame->addr != SlaveAddr)
{
modbus_debug("地址错误,目标地址为:0x%02X,返回地址为:0x%02X\r\n",SlaveAddr, pReFrame->addr);
return MRTU_ADDR_ERROR;
}
//对接受的数据进行CRC校验
crc16 = MODBUS_CRC16(pRxBuff, len-2); //计算CRC16
if((pRxBuff[len-1] != (crc16 >> 8)) || (pRxBuff[len-2] != (crc16 & 0xff)))
{
modbus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pRxBuff[len-2]<<8)|pRxBuff[len-1]);
return MRTU_CRC_ERROR; //返回CRC校验错误
}
//返回的功能码不一致
if(pReFrame->fun != (u8)RegType)
{
pUnuFrame = (MRTU_UNU_FRAME *)pRxBuff; //异常数据帧
if(pUn
没有合适的资源?快使用搜索试试~ 我知道了~
LINUX 串口与SPI操作
共72个文件
h:17个
d:15个
o:13个
需积分: 45 69 下载量 142 浏览量
2018-08-18
08:55:31
上传
评论
收藏 130KB RAR 举报
温馨提示
linux下操作串口使用modbus-rtu协议读取数据,使用SPI接口操作LCD12864液晶。
资源推荐
资源详情
资源评论
收起资源包目录
linux_app.rar (72个子文件)
linux_app
.project 787B
Debug
objects.mk 239B
src
main.d 2KB
main.o 9KB
UserLib
subdir.mk 1KB
SystemLog.o 8KB
SystemLog.d 53B
UserThread
UartThread.o 9KB
subdir.mk 1KB
UartThread.d 583B
subdir.mk 1KB
Program
LCD
LCD12864.o 8KB
subdir.mk 1KB
LCD12864.d 351B
ModBus
MODBUS_RTU.o 17KB
MODBUS_RTU.d 255B
MODBUS_SLAVE.d 337B
subdir.mk 1KB
MODBUS_SLAVE.o 7KB
Hardware
SPI.o 3KB
ASCII_8x16.o 5KB
SPI.d 199B
JLX12864G.d 289B
subdir.mk 1KB
NANO_PI
gpio.o 8KB
common.o 11KB
subdir.mk 1KB
NANO_PI_SPI.d 485B
common.d 323B
NANO_PI_SPI.o 8KB
gpio.d 287B
ASCII_8x16.d 123B
Uart.d 203B
Uart.o 8KB
JLX12864G.o 7KB
A20
subdir.mk 1KB
common.d 195B
A20_SPI.d 191B
linux_app 72KB
sources.mk 579B
makefile 1KB
src
UserLib
SystemLog.h 263B
SystemLog.c 3KB
typedef.h 1KB
UserThread
UserThread.h 239B
UartThread.c 3KB
Program
LCD
LCD12864.c 10KB
LCD12864.h 916B
ModBus
MODBUS_RTU.c 49KB
MODBUS_SLAVE.h 1KB
MODBUS_SLAVE.c 7KB
MODBUS_RTU.h 9KB
Hardware
ASCII_8x16.c 18KB
Uart.c 5KB
Uart.h 2KB
SPI.h 466B
JLX12864G.h 3KB
NANO_PI
libfahw-spi.h 3KB
common.c 5KB
NANO_PI_SPI.h 1KB
common.h 1KB
spi_enum.h 2KB
libfahw-gpio.h 897B
gpio.h 905B
gpio.c 10KB
spidev.h 5KB
NANO_PI_SPI.c 11KB
JLX12864G.c 11KB
SPI.c 1KB
ASCII_8x16.h 198B
main.c 4KB
.cproject 15KB
共 72 条
- 1
资源评论
cp1300
- 粉丝: 1070
- 资源: 62
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功