#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; // 二值信号量句柄 #pragma pack(pop) // 发送心跳报文缓冲 #define HEART_SENDBUFF_SIZE 64 uint8_t Heart_sendBuff[HEART_SENDBUFF_SIZE]; // 发送数据报文缓冲 uint8_t Modbus_sendBuff[TASK_SENDBUFF_SIZE]; static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes) { /* Send data */ UART_Transmit(&huart4, pu8TxBuf, u32WriteBytes); } 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); } } }