/* **************************************************************************** ModBus主机协议 **************************************************************************** */ // #define DBG_TAG "modbus" // #define DBG_LVL DBG_LOG // #include #include #include "main.h" #include "modbus_host.h" #include "loar.h" #include "Host.h" #include "bsp_date.h" #define TIMEOUT 800 /* 接收命令超时时间, 单位ms */ // 部分传感器返回时间较长,由500改为800 #define NUM 1 /* 循环发送次数 */ MODH_T g_tModH; LOAR_Tx loar_t; uint8_t g_modh_timeout = 0; static void MODH_RxTimeOut(void); static void MODH_AnalyzeApp(uint8_t sort); // static void MODH_Read_01H(void); // static void MODH_Read_02H(void); void MODH_Read_03H(uint8_t sort); // static void MODH_Read_04H(void); // static void MODH_Read_05H(void); // static void MODH_Read_06H(void); // static void MODH_Read_10H(void); static void MODH_ReciveNew(uint8_t _data); VAR_T g_tVar; // 需要连接的外部接口函数 extern void (*RS485_ReceiveData)(uint8_t); // 接受数据,在串口中断接受到的数传递到此函数即可 extern void RS485_SendBuf(uint8_t *_ucaBuf, uint16_t _usLen, UART_HandleTypeDef *uart); // 发送数据 extern void bsp_StartHardTimer(uint32_t timeout, void *_pCallBack); // 开始计时3.5个字节的时间,单位为us // 以下两个函数用来测量间隔时间 extern uint32_t bsp_GetRunTime(void); // 返回当前时间,单位ms extern uint32_t bsp_CheckRunTime(int32_t _LastTime); // 返回与之前间隔的时间 extern uint8_t uart3_tx_buf[64]; extern uint8_t uart3_tx_count; /* ********************************************************************************************************* * 函 数 名: MODH_SendAckWithCRC * 功能说明: 发送应答,自动加CRC. * 形 参: 无。发送数据在 g_tModH.TxBuf[], [g_tModH.TxCount * 返 回 值: 无 ********************************************************************************************************* */ static void MODH_SendAckWithCRC(void) { uint16_t crc; crc = CRC16_Modbus(g_tModH.TxBuf, g_tModH.TxCount); g_tModH.TxBuf[g_tModH.TxCount++] = crc >> 8; g_tModH.TxBuf[g_tModH.TxCount++] = crc; RS485_SendBuf(g_tModH.TxBuf, g_tModH.TxCount, &huart2); } /* ********************************************************************************************************* * 函 数 名: LOAR_SendAckWithCRC * 功能说明: 发送应答,自动加CRC. * 形 参: 无。发送数据在 g_tModH.TxBuf[], [g_tModH.TxCount * 返 回 值: 无 ********************************************************************************************************* */ void LOAR_SendAckWithCRC(void) { uint16_t crc; crc = CRC16_Modbus(loar_t.TxBuf, loar_t.TxCount); loar_t.TxBuf[loar_t.TxCount++] = crc >> 8; loar_t.TxBuf[loar_t.TxCount++] = crc; RS485_SendBuf(loar_t.TxBuf, loar_t.TxCount, &huart3); loar_t.TxCount = 0; } /* ********************************************************************************************************* * 函 数 名: MODH_AnalyzeApp * 功能说明: 分析应用层协议。处理应答。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void MODH_AnalyzeApp(uint8_t sort) { switch (g_tModH.RxBuf[1]) /* 第2个字节 功能码 */ { /* case 0x01: 读取线圈状态 MODH_Read_01H(); break;*/ /* case 0x02: 读取输入状态 MODH_Read_02H(); break;*/ case 0x03: /* 读取保持寄存器 在一个或多个保持寄存器中取得当前的二进制值 */ MODH_Read_03H(sort); break; // case 0x04: /* 读取输入寄存器 */ // MODH_Read_04H(); // break; /* case 0x05: 强制单线圈 MODH_Read_05H(); break;*/ // case 0x06: /* 写单个寄存器 */ // MODH_Read_06H(); // break; // case 0x10: /* 写多个寄存器 */ // MODH_Read_10H(); // if(g_tModH.RxBuf[2] == 0x00)g_tModH.fAck10add = 1;/*接收到应答,非本库,后续添加(00 10 00 7C)*/ // PrintBuf(g_tModH.RxBuf,5); /* break;*/ /* case 0x20: 读取地址 g_tVar.ADD = g_tModH.RxBuf[2]; g_tModH.fAck20inquire = 1;*/ /*接收到应答,非本库,后续添加(00 20 address CRCH CRCL)*/ // PrintBuf(g_tModH.RxBuf,5); /* break; case 0xEE: 读取地址 g_tModH.fAckEE = 1;接收到应答,非本库,后续添加(00 10 00 7C) rt_kprintf("日照时数传感器写入时间成功!\n"); break;*/ default: // rt_kprintf("no match\n"); break; } } /* ********************************************************************************************************* * 函 数 名: MODH_Send01H * 功能说明: 发送01H指令,查询1个或多个保持寄存器 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _num : 寄存器个数 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send01H(uint8_t _addr, uint16_t _reg, uint16_t _num) //{ // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x01; /* 功能码 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8; /* 寄存器个数 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num; /* 寄存器个数 低字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // g_tModH.fAck01H = 0; /* 清接收标志 */ // g_tModH.RegNum = _num; /* 寄存器个数 */ // g_tModH.Reg01H = _reg; /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send02H * 功能说明: 发送02H指令,读离散输入寄存器 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _num : 寄存器个数 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send02H(uint8_t _addr, uint16_t _reg, uint16_t _num) //{ // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x02; /* 功能码 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8; /* 寄存器个数 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num; /* 寄存器个数 低字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // g_tModH.fAck02H = 0; /* 清接收标志 */ // g_tModH.RegNum = _num; /* 寄存器个数 */ // g_tModH.Reg02H = _reg; /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send03H * 功能说明: 发送03H指令,查询1个或多个保持寄存器 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _num : 寄存器个数 * 返 回 值: 无 ********************************************************************************************************* */ void MODH_Send03H(uint8_t _addr, uint16_t _reg, uint16_t _num) { g_tModH.TxCount = 0; g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ g_tModH.TxBuf[g_tModH.TxCount++] = 0x03; /* 功能码 */ g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8; /* 寄存器个数 高字节 */ g_tModH.TxBuf[g_tModH.TxCount++] = _num; /* 寄存器个数 低字节 */ /* rt_kprintf("g_tModH.TxBuf :%x %x %x %x %x %x %x %x ", g_tModH.TxBuf[0],g_tModH.TxBuf[1], g_tModH.TxBuf[2],g_tModH.TxBuf[3], g_tModH.TxBuf[4],g_tModH.TxBuf[5], g_tModH.TxBuf[6],g_tModH.TxBuf[7]); */ MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ g_tModH.fAck03H = 0; /* 清接收标志 */ g_tModH.RegNum = _num; /* 寄存器个数 */ g_tModH.Reg03H = _reg; /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */ } extern LOAR_Parameter loar_par; // 这里面存放loar的参数和ID extern Loar_Device Slave_list[]; // 存放已配对的从机的各种信息 extern uint8_t Freq; // 存放拨码开关读取到的频段号 extern Sensor sensor[MAX_SENSOR_NUM]; extern RTC_TimeTypeDef GetTime; extern uint8_t ReFlash_RTC(void); // 输入从机地址 即可发送对从机的配置包 void LOAR_SEND_DATA(uint8_t address, uint8_t Inclued_Sensor) { // LOG_I("LOAR_SEND_DATA address:%d", address); address--; // RTC_TimeTypeDef Get_real_Time; // uint32_t Timestamp = 0; if (address < 0 || address > MAX_Slave_NUM) { rt_kprintf("Addr ×"); return; } if (loar_t.TxCount != 0) { loar_t.TxCount = 0; } ReFlash_RTC(); /***********************************************************************************************/ /* 下发数据的消息定义 */ // 例: 5A datalen address ID(4字节) TFREQ RFREQ interval SF Hour Min Sec // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 // 5A 固定的消息头 // datalen 除帧头 CRC datalen之外的数据字节数 // address 从机地址 配网时分配 // ID 模块的ID 占用4字节 // TFREQ 发送频段标号 // RFREQ 接收频段标号 // interval 下发数据间隔1 // SF 扩频因子 // CRCH/L CRC校验 消息尾 // RTC 对时 时分秒 /// 5A 0C 06 13 12 40 80 00 00 0A 10 hour min sec /***********************************************************************************************/ loar_t.TxBuf[loar_t.TxCount++] = 0x5A; // 固定数据头 loar_t.TxCount += 1; // 留一位给数据长度 // LOG_I("Slave_number : %d", address); loar_t.TxBuf[loar_t.TxCount++] = Slave_list[address].Address; // 写入从机地址 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[address].ID[0]; // 把从机的ID填充到预发送buff loar_t.TxBuf[loar_t.TxCount++] = Slave_list[address].ID[1]; loar_t.TxBuf[loar_t.TxCount++] = Slave_list[address].ID[2]; loar_t.TxBuf[loar_t.TxCount++] = Slave_list[address].ID[3]; loar_t.TxBuf[loar_t.TxCount++] = Freq; // 写入发送频段 loar_t.TxBuf[loar_t.TxCount++] = Freq; // 写入接收频段 loar_t.TxBuf[loar_t.TxCount++] = sys_info.interval; // 写入上报数据的时间间隔 loar_t.TxBuf[loar_t.TxCount++] = loar_par.SF; // 写入扩频因子 loar_t.TxBuf[loar_t.TxCount++] = GetTime.Hours; // 写入当前时间 loar_t.TxBuf[loar_t.TxCount++] = GetTime.Minutes; loar_t.TxBuf[loar_t.TxCount++] = GetTime.Seconds; if (Inclued_Sensor == One) { for (uint8_t a = 0; a < MAX_SENSOR_NUM; a++) { if (sensor[a].cfged == 1) { loar_t.TxBuf[loar_t.TxCount++] = 's'; loar_t.TxBuf[loar_t.TxCount++] = a + 0x30; loar_t.TxBuf[loar_t.TxCount++] = sensor[a].sensor_addr; loar_t.TxBuf[loar_t.TxCount++] = (uint8_t)(sensor[a].start_reg >> 8); loar_t.TxBuf[loar_t.TxCount++] = (uint8_t)(sensor[a].start_reg & 0x00FF); loar_t.TxBuf[loar_t.TxCount++] = sensor[a].count; loar_t.TxBuf[loar_t.TxCount++] = sensor[a].d_pos; loar_t.TxBuf[loar_t.TxCount++] = sensor[a].d_length; } } } loar_t.TxBuf[1] = (loar_t.TxCount - 2); // 写完数据统计数据长度 并加到长度的位置 for (uint8_t b = 0; b < loar_t.TxCount; b++) { rt_kprintf("%02X ", loar_t.TxBuf[b]); if ((b + 1) % 16 == 0) { rt_kprintf("\n"); } } LOAR_SendAckWithCRC(); // 添加CRC并发送 rt_thread_mdelay(999); } /* ********************************************************************************************************* * 函 数 名: Loar_Send_Broadcast * 功能说明: laor配置模式下发送广播包 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void Loar_Send_Broadcast(void) { loar_t.TxCount = 0; // 给txcount清零 loar_t.TxBuf[loar_t.TxCount++] = 0x5A; // 放入帧头 loar_t.TxBuf[loar_t.TxCount++] = 0x05; // 放入数据长度 loar_t.TxBuf[loar_t.TxCount++] = loar_par.Address; // 放入数据长度 loar_t.TxBuf[loar_t.TxCount++] = loar_par.ID[0]; // 放入ID第一位 loar_t.TxBuf[loar_t.TxCount++] = loar_par.ID[1]; // 放入ID第二位 loar_t.TxBuf[loar_t.TxCount++] = loar_par.ID[2]; // 放入ID第三位 loar_t.TxBuf[loar_t.TxCount++] = loar_par.ID[3]; // 放入ID第四位 // rt_kprintf("Send broadcast packet\r\n"); LOAR_SendAckWithCRC(); // 添加CRC并发送 } /* ********************************************************************************************************* * 函 数 名: Loar_Send_CMD * 功能说明: 唤醒从机并发送指令 * 形 参: Address 命令指向的从机地址 * 形 参: Cmd 命令类型 * type 1 阀控1 开 * type 2 阀控1 关 * type 3 阀控2 开 * type 4 阀控2 关 * 返 回 值: 无 ********************************************************************************************************* */ void Loar_Send_CMD(uint8_t Address, uint8_t Cmd) { /* uint8_t time_count = 0; if (Cmd == 0xFF) { loar_t.TxCount = 0; // 给txcount清零 loar_t.TxBuf[loar_t.TxCount++] = 0x9A; // 放入帧头 } else { loar_t.TxCount = 0; // 给txcount清零 loar_t.TxBuf[loar_t.TxCount++] = 0x9A; // 放入帧头 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[Address - 1].ID[0]; // 放入ID第一位 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[Address - 1].ID[1]; // 放入ID第二位 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[Address - 1].ID[2]; // 放入ID第三位 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[Address - 1].ID[3]; // 放入ID第四位 loar_t.TxBuf[loar_t.TxCount++] = Slave_list[Address - 1].Address; // 放入数据长度 switch (Cmd) { case 1: loar_t.TxBuf[loar_t.TxCount++] = 0xA1; break; case 2: loar_t.TxBuf[loar_t.TxCount++] = 0xA0; break; case 3: loar_t.TxBuf[loar_t.TxCount++] = 0xB1; break; case 4: loar_t.TxBuf[loar_t.TxCount++] = 0xB0; break; default: break; } } rt_kprintf("-->CMD %02X\r\n", Cmd); if (Cmd < 16) { LOAR_SendAckWithCRC(); // 添加CRC并发送 } else { // for (uint8_t i = 0; i < loar_t.TxCount; i++) // { // rt_kprintf(" %02X\r\n", loar_t.TxBuf[i]); // } HAL_UART_Transmit(&huart3, loar_t.TxBuf, loar_t.TxCount, 1000); } while (1) { rt_thread_mdelay(30); time_count++; if (HAL_GPIO_ReadPin(TX_STU_GPIO_Port, TX_STU_Pin) == GPIO_PIN_RESET) break; } // 小于30ms 说明此时lora模块已经休眠了 先唤醒再用 if (time_count == 1) { rt_kprintf("<30 ms\r\n", Cmd); wakeup_lora(); HAL_UART_Transmit(&huart3, loar_t.TxBuf, loar_t.TxCount, 1000); while (1) { rt_thread_mdelay(30); time_count++; if (HAL_GPIO_ReadPin(TX_STU_GPIO_Port, TX_STU_Pin) == GPIO_PIN_RESET) break; } rt_kprintf("with %d ms rty\r\n", time_count * 30); } else rt_kprintf("with %d ms\r\n", time_count * 30); */ } /* ********************************************************************************************************* * 函 数 名: MODH_Send04H * 功能说明: 发送04H指令,读输入寄存器 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _num : 寄存器个数 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send04H(uint8_t _addr, uint16_t _reg, uint16_t _num) //{ // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x04; /* 功能码 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8; /* 寄存器个数 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num; /* 寄存器个数 低字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // g_tModH.fAck04H = 0; /* 清接收标志 */ // g_tModH.RegNum = _num; /* 寄存器个数 */ // g_tModH.Reg04H = _reg; /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send05H * 功能说明: 发送05H指令,写强置单线圈 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _value : 寄存器值,2字节 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send05H(uint8_t _addr, uint16_t _reg, uint16_t _value) //{ // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x05; /* 功能码 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _value >> 8; /* 寄存器值 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _value; /* 寄存器值 低字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // // g_tModH.fAck05H = 0; /* 如果收到从机的应答,则这个标志会设为1 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send06H * 功能说明: 发送06H指令,写1个保持寄存器 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _value : 寄存器值,2字节 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send06H(uint8_t _addr, uint16_t _reg, uint16_t _value) //{ // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x06; /* 功能码 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _value >> 8; /* 寄存器值 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _value; /* 寄存器值 低字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // // g_tModH.fAck06H = 0; /* 如果收到从机的应答,则这个标志会设为1 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send10H * 功能说明: 发送10H指令,连续写多个保持寄存器. 最多一次支持23个寄存器。 * 形 参: _addr : 从站地址 * _reg : 寄存器编号 * _num : 寄存器个数n (每个寄存器2个字节) 值域 * _buf : n个寄存器的数据。长度 = 2 * n * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send10H(uint8_t _addr, uint16_t _reg, uint8_t _num, const uint16_t *_buf) //{ // uint16_t i; // // g_tModH.fAck10H = 0; //将应答标志位置0 // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x10; /* 从站地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8; /* 寄存器编号 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _reg; /* 寄存器编号 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8; /* 寄存器个数 高字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _num; /* 寄存器个数 低字节 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 2 * _num; /* 数据字节数 */ // // for (i = 0; i < _num; i++) // { // if (g_tModH.TxCount > H_RX_BUF_SIZE - 3) // { // return; /* 数据超过缓冲区超度,直接丢弃不发送 */ // } // g_tModH.TxBuf[g_tModH.TxCount++] = (uint8_t)((*_buf)>>8); // g_tModH.TxBuf[g_tModH.TxCount++] = (uint8_t)(*_buf); // _buf++; // } // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // } /* ********************************************************************************************************* * 函 数 名: MODH_ReciveNew * 功能说明: 串口接收中断服务程序会调用本函数。当收到一个字节时,执行一次本函数。 * 形 参: * 返 回 值: 1 表示有数据 ********************************************************************************************************* */ void MODH_ReciveNew(uint8_t _data) { /* 3.5个字符的时间间隔,只是用在RTU模式下面,因为RTU模式没有开始符和结束符, 两个数据包之间只能靠时间间隔来区分,Modbus定义在不同的波特率下,间隔时间是不一样的, 所以就是3.5个字符的时间,波特率高,这个时间间隔就小,波特率低,这个时间间隔相应就大 4800 = 7.297ms 9600 = 3.646ms 19200 = 1.771ms 38400 = 0.885ms */ uint32_t timeout; // if(DBG_kprintf)rt_kprintf(" _data is %d\n",_data); g_modh_timeout = 0; timeout = 35000000 / HBAUD485; /* 计算超时时间,单位us*/ /* 硬件定时中断,定时精度us 硬件定时器2用于MODBUS从机, 定时器3用于MODBUS从机主机*/ bsp_StartHardTimer(timeout, (void *)MODH_RxTimeOut); if (g_tModH.RxCount < H_RX_BUF_SIZE) { g_tModH.RxBuf[g_tModH.RxCount++] = _data; // if(DBG_kprintf)rt_kprintf("buf[%d] : %d \n",g_tModH.RxCount - 1, g_tModH.RxBuf[g_tModH.RxCount -1]); } } /* ********************************************************************************************************* * 函 数 名: MODH_RxTimeOut * 功能说明: 超过3.5个字符时间后执行本函数。 设置全局变量 g_rtu_timeout = 1; 通知主程序开始解码。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void MODH_RxTimeOut(void) { g_modh_timeout = 1; } /* ********************************************************************************************************* * 函 数 名: MODH_Poll * 功能说明: 接收控制器指令. 1ms 响应时间。 * 形 参: 无 * 返 回 值: 0 表示无数据 1表示收到正确命令 ********************************************************************************************************* */ uint8_t MODH_Poll(uint8_t sort) { uint16_t crc1; // 没有超多3.5个字节的时间,继续接受 if (g_modh_timeout == 0) /* 超过3.5个字符时间后执行MODH_RxTimeOut()函数。全局变量 g_rtu_timeout = 1 */ { return 0; } // 接受时间超过3.5个字节,一帧数据接受结束,进行处理 g_modh_timeout = 0; // 接受字节数小于4,接受错误 if (g_tModH.RxCount < 4) { g_tModH.RxCount = 0; rt_memset(g_tModH.RxBuf, 0, 64); return 0; } /* 计算CRC校验和 */ if (g_tModH.RxCount > 0) { crc1 = CRC16_Modbus(g_tModH.RxBuf, g_tModH.RxCount - 2); } if (((uint8_t)crc1 != g_tModH.RxBuf[g_tModH.RxCount - 1]) || (((uint8_t)(crc1 >> 8) != g_tModH.RxBuf[g_tModH.RxCount - 2]))) { g_tModH.RxCount = 0; return 0; } /* 分析应用层协议 */ // 对数据进行处理 // for(uint8_t a = 0; a < 12 ; a++) // { // rt_kprintf("%02X ",g_tModH.RxBuf[a]); // } MODH_AnalyzeApp(sort);//接收到数据经常 功能码处理 ->其实就处理了一个 03 // err_ret: g_tModH.RxCount = 0; /* 必须清零计数器,方便下次帧同步 */ return 1; } /* ********************************************************************************************************* * 函 数 名: LOARH_Poll * 功能说明: 接收控制器指令. 1ms 响应时间。 * 根据MODH_Poll又抄了一份给loar用 * 形 参: 无 * 返 回 值: 0 表示无数据 1表示收到正确命令 ********************************************************************************************************* */ // void LOARH_Poll(void) //{ // // uint16_t crc1; // //没有超多3.5个字节的时间,继续接受 // if (g_modh_timeout == 0) /* 超过3.5个字符时间后执行MODH_RxTimeOut()函数。全局变量 g_rtu_timeout = 1 */ // { // return; // } // //接受时间超过3.5个字节,一帧数据接受结束,进行处理 // g_modh_timeout = 0; // // //接受字节数小于4,接受错误 // if (g_tModH.RxCount < 4) // { // if (DBG_kprintf) // rt_kprintf("(g_tModH.RxCount < 4)"); // return; // } // // if (g_tModH.RxBuf[0] != g_tModH.slaveaddr) // { // // rt_kprintf("g_tModH.slaveaddr:%0x,%0x,%0x,%0x,%0x\r",g_tModH.RxBuf[0] , g_tModH.RxBuf[1], g_tModH.RxBuf[2], g_tModH.RxBuf[3], g_tModH.RxBuf[4], g_tModH.RxBuf[5], g_tModH.RxBuf[6], g_tModH.RxBuf[7]); // // rt_kprintf("g_tModH.slaveaddr:%0x\r",g_tModH.slaveaddr); // g_tModH.RxCount = 0; // rt_kprintf("(g_tModH.RxBuf[0] != g_tModH.slaveaddr)"); // return; // } // // /* 计算CRC校验和 */ // crc1 = CRC16_Modbus(g_tModH.RxBuf, g_tModH.RxCount - 2); // if (((uint8_t)crc1 != g_tModH.RxBuf[g_tModH.RxCount - 1]) || (((uint8_t)(crc1 >> 8) != g_tModH.RxBuf[g_tModH.RxCount - 2]))) // { // g_tModH.RxCount = 0; // return; // } // /* 分析应用层协议 */ // //对数据进行处理 // MODH_AnalyzeApp(9); // // // err_ret: // g_tModH.RxCount = 0; /* 必须清零计数器,方便下次帧同步 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_01H * 功能说明: 分析01H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // static void MODH_Read_01H(void) //{ // uint8_t *p; // if(g_tModH.RxBuf[0] == g_tModH.slaveaddr) // { // p = &g_tModH.RxBuf[3]; // g_tVar.D01 = BEBufToUint16(p); p += 2; /* 寄存器 */ // if(g_tModH.RxBuf[2]>2) // {g_tVar.D02 = BEBufToUint16(p); p += 2;} /* 寄存器 */ // if(g_tModH.RxBuf[2]>4) // {g_tVar.D03 = BEBufToUint16(p); p += 2;} /* 寄存器 */ // if(g_tModH.RxBuf[2]>6) // {g_tVar.D04 = BEBufToUint16(p); p += 2;} /* 寄存器 */ // g_tModH.fAck01H = 1; // } // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_02H * 功能说明: 分析02H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // static void MODH_Read_02H(void) //{ // uint8_t *p; // p = &g_tModH.RxBuf[3]; // g_tVar.T01 = BEBufToUint16(p); p += 2; /* 寄存器 */ // if(g_tModH.RxBuf[2]>2) // {g_tVar.T02 = BEBufToUint16(p); p += 2;} /* 寄存器 */ // if(g_tModH.RxBuf[2]>4) // {g_tVar.T03 = BEBufToUint16(p); p += 2;} /* 寄存器 */ // g_tModH.fAck02H = 1; // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_04H * 功能说明: 分析04H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // static void MODH_Read_04H(void) //{ // uint8_t *p; // p = &g_tModH.RxBuf[3]; // g_tVar.A01 = BEBufToUint16(p); p += 2; /* 寄存器 */ // g_tModH.fAck04H = 1; // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_05H * 功能说明: 分析05H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // static void MODH_Read_05H(void) //{ // g_tModH.fAck05H = 1; /* 接收到应答 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_06H * 功能说明: 分析06H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // static void MODH_Read_06H(void) //{ // g_tModH.fAck06H = 1; /* 接收到应答 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Read_03H * 功能说明: 分析03H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ extern uint16_t Read_data[MAX_SENSOR_NUM * 2]; extern Sensor sensor[MAX_SENSOR_NUM]; #define GPRS_ADDR 0x99 void MODH_Read_03H(uint8_t sort) { uint8_t *p; p = &g_tModH.RxBuf[3]; if(sort != GPRS_ADDR) { if (g_tModH.RxBuf[0] == sensor[sort].sensor_addr && g_tModH.RxBuf[2] == sensor[sort].count * 2) { for (uint8_t a = 1; a <= g_tModH.RxBuf[2]; a++) { if (a % 2 == 0) { Read_data[(a / 2) - 1] = BEBufToUint16(p); p += 2; g_tModH.RxCount += 2; } } g_tModH.fAck03H = 1; } else { g_tModH.fAck03H = 0; // rt_kprintf("Read_03H check fail\n"); } } else { if (g_tModH.RxBuf[0] == GPRS_ADDR && g_tModH.RxBuf[1] == 0x03) { for (uint8_t a = 1; a <= g_tModH.RxBuf[2]; a++) { if (a % 2 == 0) { Read_data[(a / 2) - 1] = BEBufToUint16(p); p += 2; } } g_tModH.fAck03H = 1; } else { g_tModH.fAck03H = 0; // rt_kprintf("Read_03H check fail\n"); } } } /* ********************************************************************************************************* * 函 数 名: MODH_Read_10H * 功能说明: 分析10H指令的应答数据 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Read_10H(void) //{ // g_tModH.fAck10H = 1; /* 接收到应答 */ // } /* ********************************************************************************************************* * 函 数 名: MODH_ReadParam_01H * 功能说明: 单个参数. 通过发送01H指令实现,发送之后,等待从机应答。 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_ReadParam_01H(uint16_t slaveAddr,uint16_t _reg, uint16_t _num) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send01H (slaveAddr, _reg, _num); /* 发送命令 */ // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) /* 等待应答,超时或接收到应答则break */ // { // MODH_Poll(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; /* 通信超时了 */ // } // // if (g_tModH.fAck01H > 0) // { // break; /* 接收到应答 */ // } // } // // if (g_tModH.fAck01H > 0) // { // break; /* 循环NUM次,如果接收到命令则break循环 */ // } // } // // if (g_tModH.fAck01H == 0) // { // return 0; // } // else // { // return 1; /* 01H 读成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_ReadParam_02H * 功能说明: 单个参数. 通过发送02H指令实现,发送之后,等待从机应答。 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_ReadParam_02H(uint16_t slaveAddr,uint16_t _reg, uint16_t _num) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send02H (slaveAddr, _reg, _num); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; /* 通信超时了 */ // } // // if (g_tModH.fAck02H > 0) // { // break; // } // } // // if (g_tModH.fAck02H > 0) // { // break; // } // } // // if (g_tModH.fAck02H == 0) // { // return 0; // } // else // { // return 1; /* 02H 读成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_ReadParam_03H * 功能说明: 单个参数. 通过发送03H指令实现,发送之后,等待从机应答。 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ uint8_t MODH_ReadParam_03H(uint16_t slaveAddr, uint16_t _reg, uint16_t _num, uint8_t sort) { uint8_t i, count = 0; g_tModH.slaveaddr = slaveAddr; for (i = 0; i < NUM; i++) { MODH_Send03H(slaveAddr, _reg, _num); while (1) { MODH_Poll(sort); if (count++ > 50) { break; rt_kprintf("Waiting for data timeout\r\n"); } if (g_tModH.fAck03H == 1) { break; } rt_thread_mdelay(10); } } if (g_tModH.fAck03H == 0) { // if(DBG_kprintf)rt_kprintf("通信超时了 "); return 0; /* 通信超时了 */ } else { // if(DBG_kprintf)rt_kprintf("写入03H参数成功"); return 1; /* 写入03H参数成功 */ } } /* ********************************************************************************************************* * 函 数 名: MODH_ReadParam_04H * 功能说明: 单个参数. 通过发送04H指令实现,发送之后,等待从机应答。 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_ReadParam_04H(uint16_t slaveAddr,uint16_t _reg, uint16_t _num) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send04H (slaveAddr, _reg, _num); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; /* 通信超时了 */ // } // // if (g_tModH.fAck04H > 0) // { // break; // } // } // // if (g_tModH.fAck04H > 0) // { // break; // } // } // // if (g_tModH.fAck04H == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 04H 读成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_WriteParam_05H * 功能说明: 单个参数. 通过发送05H指令实现,发送之后,等待从机应答。 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_WriteParam_05H(uint16_t slaveAddr,uint16_t _reg, uint16_t _value) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send05H (slaveAddr, _reg, _value); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll(); // // /* 超时大于 TIMEOUT,则认为异常 */ // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; /* 通信超时了 */ // } // // if (g_tModH.fAck05H > 0) // { // break; // } // } // // if (g_tModH.fAck05H > 0) // { // break; // } // } // // if (g_tModH.fAck05H == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 05H 写成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_WriteParam_06H * 功能说明: 单个参数. 通过发送06H指令实现,发送之后,等待从机应答。循环NUM次写命令 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_WriteParam_06H(uint16_t slaveAddr,uint16_t _reg, uint16_t _value) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send06H (slaveAddr, _reg, _value); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) //若等待100ms没有回应,则退出,通讯超时 // { // // MODH_Poll(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; // } // // if (g_tModH.fAck06H > 0) // { // break; // } // } // // if (g_tModH.fAck06H > 0) // { // break; // } // } // // if (g_tModH.fAck06H == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 写入06H参数成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_WriteParam_10H * 功能说明: 单个参数. 通过发送10H指令实现,发送之后,等待从机应答。循环NUM次写命令 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_WriteParam_10H(uint16_t slaveAddr,uint16_t _reg, uint8_t _num, const uint16_t *_buf) //{ // int32_t time1; // uint8_t i; // // g_tModH.slaveaddr = slaveAddr; // for (i = 0; i < NUM; i++) // { // MODH_Send10H(slaveAddr, _reg, _num, _buf); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; // } // // if (g_tModH.fAck10H > 0) // { // break; // } // } // // if (g_tModH.fAck10H > 0) // { // break; // } // } // // if (g_tModH.fAck10H == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 写入10H参数成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_Poll_add(非本库原版,后续添加) * 功能说明: 接收控制器指令. 1ms 响应时间,与void MODH_Poll(void)接收字节数的差别,地址为0 * 形 参: 无 * 返 回 值: 0 表示无数据 1表示收到正确命令 ********************************************************************************************************* */ // void MODH_Poll_add(void) //{ // uint16_t crc1; // //没有超多3.5个字节的时间,继续接受 // if (g_modh_timeout == 0) /* 超过3.5个字符时间后执行MODH_RxTimeOut()函数。全局变量 g_rtu_timeout = 1 */ // { // /* 没有超时,继续接收。不要清零 g_tModH.RxCount */ // return ; // } // //接受时间超过3.5个字节,一帧数据接受结束,进行处理 // g_modh_timeout = 0; // // //接受字节数小于2,接受错误 // if (g_tModH.RxCount < 2) // { // return; // } // // if(g_tModH.RxBuf[0] != 0x00) // { //// printf("g_tModH.slaveaddr:%0x,%0x,%0x,%0x,%0x\r",g_tModH.RxBuf[0] , g_tModH.RxBuf[1], g_tModH.RxBuf[2], g_tModH.RxBuf[3], g_tModH.RxBuf[4], g_tModH.RxBuf[5], g_tModH.RxBuf[6], g_tModH.RxBuf[7]); //// printf("g_tModH.slaveaddr:%0x\r",g_tModH.slaveaddr); // g_tModH.RxCount = 0; // return; // } // // /* 计算CRC校验和 */ // crc1 = CRC16_Modbus(g_tModH.RxBuf, g_tModH.RxCount-2); // if (((uint8_t)crc1 != g_tModH.RxBuf[g_tModH.RxCount-1])||(((uint8_t)(crc1>>8) != g_tModH.RxBuf[g_tModH.RxCount-2]))) // {g_tModH.RxCount = 0;return;} // /* 分析应用层协议 */ // //对数据进行处理 // MODH_AnalyzeApp(); // ////err_ret: // g_tModH.RxCount = 0; /* 必须清零计数器,方便下次帧同步 */ //} /* ********************************************************************************************************* * 函 数 名: MODH_Send10_add(非本库原版,后续添加) * 功能说明: 发送10H指令修改传感器地址 * 形 参: _addr : 从站地址 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send10_add(uint8_t _addr) //{ // // g_tModH.fAck10H = 0; //将应答标志位置0 // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = 00; /* 广播地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x10; /*10命令 */ // g_tModH.TxBuf[g_tModH.TxCount++] = _addr; /* 寄存器编号 高字节 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Send20_inquire(非本库原版,后续添加) * 功能说明: 发送20H指令查询传感器地址 * 返 回 值: 无 ********************************************************************************************************* */ // void MODH_Send20_inquire(void) //{ // // g_tModH.fAck20inquire = 0; //将应答标志位置0 // g_tModH.TxCount = 0; // g_tModH.TxBuf[g_tModH.TxCount++] = 00; /* 广播地址 */ // g_tModH.TxBuf[g_tModH.TxCount++] = 0x20; /*10命令 */ // // MODH_SendAckWithCRC(); /* 发送数据,自动加CRC */ // } /* ********************************************************************************************************* * 函 数 名: MODH_Poll_EE * 功能说明: 接收EE指令 * 形 参: 无 * 返 回 值: 0 表示无数据 1表示收到正确命令 ********************************************************************************************************* */ // void MODH_Poll_EE(void) //{ // uint16_t crc1; // //没有超多3.5个字节的时间,继续接受 // if (g_modh_timeout == 0) /* 超过3.5个字符时间后执行MODH_RxTimeOut()函数。全局变量 g_rtu_timeout = 1 */ // { // /* 没有超时,继续接收。不要清零 g_tModH.RxCount */ // return ; // } // //接受时间超过3.5个字节,一帧数据接受结束,进行处理 // g_modh_timeout = 0; // // //接受字节数小于4,接受错误 // if (g_tModH.RxCount < 2) // { // return; // } // // if(g_tModH.RxBuf[0] != g_tModH.slaveaddr) // { //// printf("g_tModH.slaveaddr:%0x,%0x,%0x,%0x,%0x\r",g_tModH.RxBuf[0] , g_tModH.RxBuf[1], g_tModH.RxBuf[2], g_tModH.RxBuf[3], g_tModH.RxBuf[4], g_tModH.RxBuf[5], g_tModH.RxBuf[6], g_tModH.RxBuf[7]); //// printf("g_tModH.slaveaddr:%0x\r",g_tModH.slaveaddr); // g_tModH.RxCount = 0; // return; // } // // /* 计算CRC校验和 */ // crc1 = CRC16_Modbus(g_tModH.RxBuf, g_tModH.RxCount-2); // if (((uint8_t)crc1 != g_tModH.RxBuf[g_tModH.RxCount-1])||(((uint8_t)(crc1>>8) != g_tModH.RxBuf[g_tModH.RxCount-2]))) // {g_tModH.RxCount = 0;return;} // /* 分析应用层协议 */ // //对数据进行处理 // MODH_AnalyzeApp(); // ////err_ret: // g_tModH.RxCount = 0; /* 必须清零计数器,方便下次帧同步 */ //} /* ********************************************************************************************************* * 函 数 名: MODH_Writ_10_add(非本库原版,后续添加) * 功能说明: 传感器写地址函数 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_Writ_10_add(uint16_t slaveAddr) //{ // int32_t time1; // // g_tModH.slaveaddr = slaveAddr; // // MODH_Send10_add(slaveAddr); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll_add(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; // } // // if (g_tModH.fAck10add > 0) // { // break; // } // } // // if (g_tModH.fAck10add == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 写入10H参数成功 */ // } // } /* ********************************************************************************************************* * 函 数 名: MODH_Writ_20_inquire(非本库原版,后续添加) * 功能说明: 查询传感器地址 * 形 参: 无 * 返 回 值: 1 表示成功。0 表示失败(通信超时或被拒绝) ********************************************************************************************************* */ // uint8_t MODH_Writ_20_inquire(void) //{ // int32_t time1; // // MODH_Send20_inquire(); // time1 = bsp_GetRunTime(); /* 记录命令发送的时刻 */ // // while (1) // { // MODH_Poll_add(); // // if (bsp_CheckRunTime(time1) > TIMEOUT) // { // break; // } // // if (g_tModH.fAck20inquire > 0) // { // break; // } // } // // if (g_tModH.fAck20inquire == 0) // { // return 0; /* 通信超时了 */ // } // else // { // return 1; /* 写入10H参数成功 */ // } // } void MODBUS_Init(void) { RS485_ReceiveData = MODH_ReciveNew; } INIT_APP_EXPORT(MODBUS_Init);