NANO130_H2Press/User_RS485Up(PB9冲突)/modbus_slave.c

411 lines
9.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
#define MODBUS_EN PB9
// 任务主体
void Modbus_Task(uint8_t c);
// modbus通讯处理
#pragma pack(push, 1)
typedef struct
{
uint8_t id; // 通信地址
uint8_t cmd; // 功能码
uint16_t reg; // 寄存器地址
union
{
uint16_t cnt; // 读取:寄存器数量
uint16_t data; // 写入:寄存器数据
};
uint16_t crc;
} modbus_request_t;
#pragma pack(pop)
// MODBUS的CRC算法
//uint16_t MODBUS_RTU_CRC16(const uint8_t *puchMsg, uint16_t usDataLen)
//{
// uint16_t crc = 0xFFFF;
// uint8_t i;
// while (usDataLen--) // 传输消息缓冲区
// {
// crc ^= *puchMsg++;
// for(i = 0; i < 8; i++)
// {
// if(crc & 0x0001)
// {
// crc >>= 1;
// crc ^= 0xA001;
// }
// else
// {
// crc >>= 1;
// }
// }
// }
// // 交换高低字节顺序
// return ((crc & 0xFF) << 8) | ((crc >> 8) & 0xFF);
//}
// modbus rtu 数据缓冲区
#define MODBUS_1ST_REG (30001) // 第1个数据地址
#define MODBUS_LAST_REG (30018) // 最后一个数据地址
#define MODBUS_ADR_REG (40001) // 通信地址的数据地址
// modbus rtu错误代码
#define MODBUS_ERR_ILF (0x01) // 无效功能码
#define MODBUS_ERR_ILA (0x02) // 无效通讯地址
#define MODBUS_ERR_ILD (0x03) // 无效数据值
#define MODBUS_ERR_FID (0x04) // 执行失败
#define MODBUS_ERR_ACK (0x05) // ACK命令已接受并在处理中
#define MODBUS_ERR_BUSY (0x06) // 设备忙,拒绝
#define MODBUS_ERR_NAK (0x07) // NAK命令无法执行
// modbus rtu 数据缓冲区
uint8_t MODBUS_RTU_Buf[(MODBUS_LAST_REG - MODBUS_1ST_REG + 1) * 2];
void UART0_IRQHandler(void)
{
uint8_t c;
if(UART_GET_INT_FLAG(UART0, UART_ISR_RDA_IS_Msk) || UART_GET_INT_FLAG(UART0, UART_ISR_RTO_IS_Msk)) /* Rx Ready or Time-out INT*/
{
// do
{
c = UART0->RBR;
// printf("%02X ", c);
/* Handle received data */
Modbus_Task(c);
} //while(UART_IS_RX_READY(UART0));
}
if(UART_GET_INT_FLAG(UART0, UART_ISR_BUF_ERR_IS_Msk)) /* Buffer Error INT */
{
UART_ClearIntFlag(UART0, UART_ISR_BUF_ERR_IS_Msk);
}
if(UART_GET_INT_FLAG(UART0, UART_ISR_RLS_IS_Msk)) /* RLS INT */
{
UART_ClearIntFlag(UART0, UART_ISR_RLS_IS_Msk);
}
}
void Modbus_Init()
{
/* Select IP clock source */
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_UART_CLK_DIVIDER(1));
/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/
/* Set GPA multi-function pins for UART0 RXD and TXD */
SYS->PA_H_MFP &= ~(SYS_PA_H_MFP_PA14_MFP_Msk | SYS_PA_H_MFP_PA15_MFP_Msk);
SYS->PA_H_MFP |= (SYS_PA_H_MFP_PA14_MFP_UART0_RX | SYS_PA_H_MFP_PA15_MFP_UART0_TX);
// 允许外设时钟
CLK_EnableModuleClock(UART0_MODULE);
}
/*---------------------------------------------------------------------------------------------------------*/
/* RS485 Transmit Control (Address Byte: Parity Bit =1 , Data Byte:Parity Bit =0) */
/*---------------------------------------------------------------------------------------------------------*/
static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
MODBUS_EN = 1;
delay_us(1);
/* Send data */
UART_Write(UART0, pu8TxBuf, u32WriteBytes);
delay_ms(6); // 至少5ms保险起见6ms
MODBUS_EN = 0;
}
void Modbus_Open()
{
SYS_ResetModule(UART0_RST);
/* Configure UART and set UART Baudrate */
UART_Open(UART0, 9600ul);
/* Enable RDA\RLS\Time-out Interrupt */
UART_ENABLE_INT(UART0, (UART_IER_RDA_IE_Msk | UART_IER_BUF_ERR_IE_Msk | UART_IER_RLS_IE_Msk)); // | UART_IER_RTO_IE_Msk));
/* Enable UART interrupt */
NVIC_SetPriority(UART0_IRQn, 1);
NVIC_EnableIRQ(UART0_IRQn);
}
void Fill_MODBUS_RTU_Buf()
{
uint8_t len = 0; // 发送数据长度
uint16_t val = 0;
uint32_t val32 = 0;
// 连接状态
if(dcBuff.sampleData.staPress.notConnect)
val |= (1 << 0);
if(dcBuff.sampleData.staExtTempr[0].notConnect)
val |= (1 << 2);
if(dcBuff.sampleData.staDPress.notConnect)
val |= (1 << 4);
// 液位传感器类型
if(dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
val |= (1 << 6);
// 测量值状态
if(dcBuff.sampleData.staPress.underFlow)
val |= (1 << 8);
else if(dcBuff.sampleData.staPress.overFlow)
val |= (2 << 8);
if(dcBuff.sampleData.staExtTempr[0].underFlow)
val |= (1 << 10);
else if(dcBuff.sampleData.staExtTempr[0].overFlow)
val |= (2 << 10);
if(dcBuff.sampleData.staDPress.underFlow)
val |= (1 << 12);
else if(dcBuff.sampleData.staDPress.overFlow)
val |= (2 << 12);
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 差压
val = (uint16_t) dcBuff.sampleData.diff;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 容积百分比
val = (uint16_t) dcBuff.sampleData.volumePct;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 体积
val32 = dcBuff.sampleData.volume;
val32 = htonl(val32);
memmove(MODBUS_RTU_Buf + len, &val32, 4);
len += 4;
// 重量
val32 = dcBuff.sampleData.weight;
val32 = htonl(val32);
memmove(MODBUS_RTU_Buf + len, &val32, 4);
len += 4;
// 高度mmWC 或 mm
if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
val = (uint16_t) KPa2mmH2O(dcBuff.sampleData.diff);
else
val = (uint16_t) dcBuff.sampleData.height;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 压力
val = (uint16_t) dcBuff.sampleData.pressure;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 温度: 有符号数
memmove(&val, &dcBuff.sampleData.extTempr[0], 2);
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 介质
val = (uint16_t) dcBuff.configBottle.source;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 总有效容积
val32 = dcBuff.sampleData.volumeTotal;
val32 = htonl(val32);
memmove(MODBUS_RTU_Buf + len, &val32, 4);
len += 4;
// 真空计状态
val = 0;
if(dcBuff.sampleData.vacuum[0].staVacuum == VACUUM_STATUS_COMM_FAULT)
val |= 1;
else
{
if(dcBuff.sampleData.vacuum[0].staVacuum == VACUUM_STATUS_FAULT)
val |= (3 << 2);
else if(dcBuff.sampleData.vacuum[0].vacuum > 99.99999999)
val |= (2 << 2);
else if(dcBuff.sampleData.vacuum[0].vacuum <= 0.00999999)
val |= (1 << 2);
}
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 真空度
val = dcBuff.sampleData.vacuum[0].vacuum * 100;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 真空计温度
val = (int16_t) dcBuff.sampleData.vacuum[0].tempr;
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 连接状态
val = 0;
if(dcBuff.sampleData.staExtTempr[1].notConnect)
val |= (1 << 0);
// 测量值状态
if(dcBuff.sampleData.staExtTempr[1].underFlow)
val |= (1 << 2);
else if(dcBuff.sampleData.staExtTempr[1].overFlow)
val |= (2 << 2);
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
// 温度2: 有符号数
memmove(&val, &dcBuff.sampleData.extTempr[1], 2);
val = htons(val);
memmove(MODBUS_RTU_Buf + len, &val, 2);
len += 2;
}
// 处理modbus rtu命令已经验证过长度和CRC的包
void MODBUS_RTU_CMD(modbus_request_t *req)
{
static uint8_t BUFF[(MODBUS_LAST_REG - MODBUS_1ST_REG + 1) * 2 + 6]; // 响应包
uint8_t err = 0; // 错误代码
uint8_t len = 0; // 发送数据长度
uint16_t id; // 通信地址
uint16_t reg; // 数据地址
uint16_t cnt; // 数据个数
uint16_t crc;
// 检查通信地址
if(req->id != dcBuff.configBottle.addr && req->id != 0)
return;
// 清空发送帧
memset(BUFF, 0, sizeof(BUFF));
BUFF[len++] = dcBuff.configBottle.addr; // 从机地址
BUFF[len++] = req->cmd; // 命令代码
reg = ntohs(req->reg); // 数据寄存器
if(req->cmd == 0x03 || req->cmd == 0x06)
reg += 40001;
else if(req->cmd == 0x04)
reg += 30001;
else
err = MODBUS_ERR_ILF; // 无效功能码
if(err == 0)
{
if(req->cmd == 0x03) // 读保持数据
{
cnt = ntohs(req->cnt); // 参数个数
if(reg != MODBUS_ADR_REG || cnt != 1)
err = MODBUS_ERR_NAK; // 命令无法执行
else
{
// 用最新的通讯地址刷新缓冲
id = htons(dcBuff.configBottle.addr);
BUFF[len++] = 2; // 数据长度
memmove(BUFF + len, (uint8_t *) &id, 2);
len += 2;
}
}
else if(req->cmd == 0x06) // 设置数据
{
if(reg != MODBUS_ADR_REG)
err = MODBUS_ERR_NAK; // 命令无法执行
else
{
id = ntohs(req->data);
if(id < 1 || id > 247)
err = MODBUS_ERR_ILD; // 无效数据值
else
{
// 设置地址并保存
dcBuff.configBottle.addr = id;
Config_SaveConfig();
BUFF[0] = id; // 新地址
memmove(BUFF + len, &req->reg, 4); // 数据地址和通讯地址
len += 4;
}
}
}
else if(req->cmd == 0x04) // 读输入数据
{
cnt = ntohs(req->cnt); // 参数个数
if(reg < MODBUS_1ST_REG || reg > MODBUS_LAST_REG || cnt < 1 || reg + (cnt - 1) > MODBUS_LAST_REG)
err = MODBUS_ERR_NAK; // 命令无法执行
else
{
// 用最新的采集数据刷新缓冲
Fill_MODBUS_RTU_Buf();
BUFF[len++] = cnt * 2; // 数据长度
memmove(BUFF + len, ((uint8_t *) MODBUS_RTU_Buf) + (reg - MODBUS_1ST_REG) * 2, cnt * 2);
len += cnt * 2;
}
}
}
if(err != 0)
{
BUFF[1] |= 0x80; // 错误指示
BUFF[len++] = err; // 错误代码
}
// 计算CRC
crc = MODBUS_RTU_CRC16(BUFF, len);
crc = htons(crc);
memmove(BUFF+len, &crc, 2);
len += 2;
if(req->id != 0)
{
// 发送应答
RS485_SendDataByte(BUFF, len);
}
}
// 任务主体
void Modbus_Task(uint8_t c)
{
static uint8_t BUFF[sizeof(modbus_request_t)] = {0};
static uint8_t len = 0;
// 取数据
BUFF[len++] = c;
// 验证长度和CRC值
if(len == sizeof(modbus_request_t))
{
if(MODBUS_RTU_CRC16(BUFF, sizeof(modbus_request_t)) == 0)
{
MODBUS_RTU_CMD((modbus_request_t *) BUFF);
len = 0;
}
else
{
// 丢掉第一个字节
memmove(BUFF, BUFF + 1, --len);
}
}
}