#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); } } }