#include "includes.h" // Modbus(RS485接口)工作模式:单向发送,向上位机发送数据, 每30秒向上位机发送一个心跳。 // modbus通讯处理 #pragma pack(push, 1) // RF串口发送帧的循环缓冲 #define MODBUS_SENDM_DATA_COUNT 512 loopbuff_t Modbus_SendM; uint8_t Modbus_SendM_Data[sizeof(ext_data_t) * (MODBUS_SENDM_DATA_COUNT + 1)] = {0}; // RF串口接收的消息通知 SemaphoreHandle_t Modbus_SendQ = NULL; // 二值信号量句柄 typedef struct { uint8_t head_L; uint8_t head_S; uint8_t id; // 通信地址 uint8_t cmd; // 功能码 uint8_t len_H; uint8_t len_L; uint8_t index; // 包序号 uint8_t all; // 包数 uint8_t PSN[7]; uint8_t BOX[12]; // union // { // uint16_t cnt; // 读取:寄存器数量 // uint16_t data; // 写入:寄存器数据 // }; uint16_t crc; } modbus_request_t; #pragma pack(pop) // 发送心跳报文缓冲 #define HEART_SENDBUFF_SIZE 64 uint8_t Heart_sendBuff[HEART_SENDBUFF_SIZE]; // 发送数据报文缓冲 uint8_t Modbus_sendBuff[TASK_SENDBUFF_SIZE]; void ReadModbus_Task(uint8_t c); static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes) { /* Send data */ UART_Transmit(&huart4, pu8TxBuf, u32WriteBytes); } void Slave_IRQHandler(USART_Handle *huart) { uint8_t u8DTU = (uint8_t) huart->Instance->DR; /* Handle received data */ ReadModbus_Task(u8DTU); } void Modbus_Open() { // 创建消息队列 LoopBuff_Create(&Modbus_SendM, sizeof(ext_data_t), MODBUS_SENDM_DATA_COUNT, 0, (uint32_t) Modbus_SendM_Data); // 创建信号量 Modbus_SendQ = xSemaphoreCreateBinary(); } uint8_t pack_heart_send_data() { uint8_t i; uint16_t crc; // 打包上报数据(按modbus从机响应的格式) memset(Heart_sendBuff, 0, HEART_SENDBUFF_SIZE); i = 0; // PSN memmove(Heart_sendBuff + i, dcBuff.configBottle.PSN, 6); i += 6; Heart_sendBuff[i++] = 0x02; // 命令码:心跳 // 数据长度:先预设为0,最后再修改,位置为Heart_sendBuff[7] Heart_sendBuff[i++] = 0; // 硬件版本 Heart_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor; // 软件版本 Heart_sendBuff[i++] = dcBuff.powerInfo.softVer.minor; // 软件日期 Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.year; Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.month; Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.day; // 射频自检状态 Heart_sendBuff[i++] = RF_initStatus; // 网口自检状态 Heart_sendBuff[i++] = Ethernet_initStatus; // 网络连接状态 Heart_sendBuff[i++] = Ethernet_IsConnected(); // GPRS入网状态 Heart_sendBuff[i++] = dcBuff.dtuData.networked; // GPRS信号强度 Heart_sendBuff[i++] = dcBuff.dtuData.rssi; // GPRS连接状态 Heart_sendBuff[i++] = dcBuff.dtuData.connected; // 保留备用 i += 41; // 修改数据长度 Heart_sendBuff[7] = i - 8; // 校验码 crc = MODBUS_RTU_CRC16((uint8_t *) Heart_sendBuff, i); *(uint16_t *)(Heart_sendBuff + i) = htons(crc); i += 2; // 结束符 Heart_sendBuff[i++] = 0x0d; Heart_sendBuff[i++] = 0x0a; return i; } // 任务主体 void Modbus_Task(void *p_arg) { uint8_t i; uint32_t heartTick = 0; ext_data_t Gprs; while(TRUE) { // 本任务读取发送队列的记录 // 这条语句用于任务切换(让其它任务有机会得到执行) xSemaphoreTake(Modbus_SendQ, 1000); if(IsTickOut(heartTick)) { heartTick = GetDelayTick(30000); // 30秒以后再发 // TODO: 发送心跳到上位机,不等待返回 // i = pack_heart_send_data(); // RS485_SendDataByte(Heart_sendBuff, i); } // if(LoopBuff_GetCount(&Modbus_SendM)) // { //// // 取数据 // memmove(&Gprs, LoopBuff_GetDataPtr(&Modbus_SendM, Modbus_SendM.info.rdPtr), sizeof(ext_data_t)); // LoopBuff_RemoveItems(&Modbus_SendM, 1); //// i = pack_modbus_tran_data(&Gprs); //// // TODO: 发送数据到上位机,不等待返回 //// RS485_SendDataByte(Modbus_sendBuff, i); // } } } // 处理modbus rtu命令(已经验证过长度和CRC的包) void MODBUS_RTU_CMD(modbus_request_t *req) { static uint8_t BUFF2[100]; // 响应包 uint8_t err = 0; // 错误代码 uint8_t len = 0; // 发送数据长度 ext_bottle_t bottleRec; uint16_t count; // 通信地址 // uint16_t reg; // 数据地址 uint16_t cnt; // 数据个数 uint16_t crc; ext_box_t boxRec; ext_data_t Gprs; uint8_t i; char* psn; // // 检查通信地址 // 添加记录 // boxCnt.count = 5; // for(i = 0; i < boxCnt.count; i++) // { // memset(&boxRec, 0, sizeof(ext_box_t)); // boxRec.PSN[0] = 26; // boxRec.PSN[3] = (0 + i * 1) / 1000; // boxRec.PSN[4] = ((0 + i * 1) % 1000) >> 8; // boxRec.PSN[5] = ((0 + i * 1) % 1000) & 0xFF; // strcpy(boxRec.TGGU, "TGGU2000000"); // boxRec.TGGU[7] = '0' + (0 + i) / 100; // boxRec.TGGU[8] = '0' + (0 + i) % 100 / 10; // boxRec.TGGU[9] = '0' + (0 + i) % 10; // FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * i, (uint8_t *) &boxRec, sizeof(ext_box_t)); // } // FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t)); if(req->cmd == 0x02) // 读保持数据 { cnt = req->index; // 参数个数 memset(&boxRec, 0, sizeof(ext_box_t)); memset(&bottleRec, 0, sizeof(ext_bottle_t)); boxRec.PSN[0] = req->PSN[0]; boxRec.PSN[1] = req->PSN[1]; boxRec.PSN[2] = req->PSN[2]; boxRec.PSN[3] = req->PSN[3]; boxRec.PSN[4] = req->PSN[4]; boxRec.PSN[5] = req->PSN[5]; bottleRec.PSN[0] = req->PSN[0]; bottleRec.PSN[1] = req->PSN[1]; bottleRec.PSN[2] = req->PSN[2]; bottleRec.PSN[3] = req->PSN[3]; bottleRec.PSN[4] = req->PSN[4]; bottleRec.PSN[5] = req->PSN[5]; for(int i=0; i<11; i++) boxRec.TGGU[i]=req->BOX[i]; boxRec.TGGU[11]=0; if(req->index>0)count=req->index-1; FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * count, (uint8_t *) &boxRec, sizeof(ext_box_t)); // // 更新索引信息 bottleRec.lastData = -1; FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * count, (uint8_t *) &bottleRec, sizeof(ext_bottle_t)); memset(BUFF2, 0, sizeof(BUFF2)); BUFF2[len++]='L'; BUFF2[len++]='S'; BUFF2[len++] = dcBuff.configBottle.addr; // 从机地址 BUFF2[len++] = 2;//req->cmd; // 命令代码 BUFF2[len++] = 0; BUFF2[len++] = 1; //LEN BUFF2[len++] = 1; // 计算CRC crc = MODBUS_RTU_CRC16(BUFF2, len); crc = htons(crc); memmove(BUFF2 + len, &crc, 2); len += 2; RS485_SendDataByte(BUFF2, len); if(req->index==req->all) { boxCnt.count=req->all; bottleCnt.count = req->all; FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t)); FRAM_SaveInfo(FRAM_BOTTLE_INFO_BASE, (uint8_t *) &bottleCnt, sizeof(ext_count_t)); osDelay(500); HAL_NVIC_SystemReset(); } } else if(req->cmd == 0x05) { if(LoopBuff_GetCount(&Modbus_SendM)) { // 取数据 memmove(&Gprs, LoopBuff_GetDataPtr(&Modbus_SendM, Modbus_SendM.info.rdPtr), sizeof(ext_data_t)); LoopBuff_RemoveItems(&Modbus_SendM, 1); i = pack_modbus_tran_data(&Gprs); // TODO: 发送数据到上位机,不等待返回 RS485_SendDataByte(Modbus_sendBuff, i); } } } // 任务主体 uint8_t BUFF[1000] = {0}; void ReadModbus_Task(uint8_t c) { static uint8_t len = 0; static uint16_t data_len = 0; static uint16_t data_len2 = 0; // // 取数据 // if((len==0)&&(c=='L')) len++; // else return; // if((len==1)&&(c=='S')) len++; // else return; // // 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); // } // } switch(len) { case 0: BUFF[len]=c; if(c=='L') len++; else len=0; break; case 1: BUFF[len]=c; if(c=='S') len++; else len=0; break; case 2: BUFF[len++]=c; break; case 3: BUFF[len]=c; if(c==2) len++; else if(c==5)len+=2; else len=0; break; case 4: BUFF[len]=c; data_len=c<<8; len++; break; case 5: BUFF[len]=c; data_len|=c; len++; break; case 6: BUFF[6+data_len2++]=c; if(data_len2+1>data_len) len++; break; case 7: BUFF[6+data_len2++]=c; len++; break; case 8: BUFF[6+data_len2]=c; len=0; break; default: len=0; break; } if((len==0)&&(data_len2>1)) { if(MODBUS_RTU_CRC16(BUFF, 7+data_len2) == 0) { MODBUS_RTU_CMD((modbus_request_t *) BUFF); } data_len2=0; } else if(BUFF[3]==5) { MODBUS_RTU_CMD((modbus_request_t *) BUFF); data_len2=0; } }