/** ****************************************************************************** * @file RS485_Modbus.c * @author * @version * @date * @brief ****************************************************************************** * @attention * * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "global.h" #include "string.h" #include "rtc.h" #include "soe.h" #define MODBUS_UART USART1 #define MODBUS_UART_SendMulByte USART1_SendMulByte //发送多字节 #define MODBUS_UART_TIM TIM4 #define MODBUS_UART_IT_RX_DISABLE USART_ITConfig(USART1, USART_IT_RXNE, DISABLE) #define MODBUS_UART_IT_RX_ENABLE USART_ITConfig(USART1, USART_IT_RXNE, ENABLE) #define MODBUS_MEM_PT (uint8_t *)&bmsMem.vCell[0] //通讯内存开始地址 #define MODBUS_VersionMEM_PT (uint8_t *)&VersionMem.Hardware[0]//上位机请求版本号通讯内存开始地址 #define MODBUS_TimeMEM_PT (uint8_t *)&calendar_WRITE.sec #define MODBUS_ParaMEM_PT (uint8_t *)¶Mem.act_bal_startV//上位机弹窗读写配置 #define MODBUS_CtrlMEM_PT (uint8_t *)&CTRL_Order //上位机控制MOS关闭(一次性的,永久的在paraMem里) #define MODBUS_MON_CNT paraMem.PACK_NUM==1?MODBUS_MON_CNT1:MODBUS_MON_CNT2 #define MODBUS_MON_CNT1 3000 //3000*10ms = 30s(因为轮询速度加快,该时间也加快) #define MODBUS_MON_CNT2 paraMem.PACK_NUM*150+200 //最大20对应32s,最小2对应5s #define MODBUS_BUF_LEN 220 #define MODBUS_ASSIGN_INADDR AddrMax+1 uint8_t modbusBuf[MODBUS_BUF_LEN]; uint8_t modbusBufIndex; uint16_t modbusMoniCount; uint8_t modbusF03RxFlg; //读数据接收正确标记 uint8_t modbusF10RxFlg; //写数据接收正确标记 uint8_t modbusFaaRxFlg; //CADC零点校准数据接收正确标记 uint8_t modbusFbbRxFlg; //CADC增益校准数据接收正确标记 uint8_t modbusFddRxFlg; //读取记录 接收正确标记 uint8_t modbusFeeRxFlg; //清除记录 接收正确标记 uint8_t modbusFf1RxFlg; //选择协议 接收正确标记 uint8_t modbusCurF03RxFlag;//主机收到03回复 接收正确标记 uint8_t modbusCurF10RxFlag;//主机收到10回复 接收正确标记 uint8_t modbusCurStatus; //主机当前执行的功能——每当变化,会初始化收发状态 0:刚开机/刚初始化过 1:基础轮询 2:自动分配地址 3:屏幕持续读从机 4:屏幕写从机地址 5:上位机持续读从机 uint8_t modbusCurDev; //主机当前的轮询对象 uint8_t modbusCurSta; //主机当前的收发状态 uint8_t modbusCurLastAddr; //最后一个能通信到的并机地址 uint8_t chg_forbidFlg; //禁充标志,SOC大于100%的时候启用 uint8_t dsg_forbidFlg; //禁放标志,SOC小于10%的时候启用 uint8_t chg_forceFlg; //强充标志,SOC小于10%的时候启用 uint16_t RequestFlag; //充放电允许位 uint8_t chg_curlimitFlg; //充电限流(固定40A)的标志,出现总体过压或单体过压的时候启用 uint8_t ReAskFlag; //主机轮询遇报警,再次询问的标志 uint8_t sleepOFFcount; //3.4网口的主从机轮询,可能有个时间差 uint8_t sdwa_WrAddr; //屏幕通过主机写从机地址的值 uint8_t sdwa_WrAddr_Flg; //屏幕通过主机写从机地址的标志 0不在写 1尝试中 2成功 3失败 uint8_t sdwa_WrAddr_Failcount; //连续写地址失败的计数 #if Addr_SetAuto uint8_t assignAddr_relay; //主机开机后延时2s再开始通信,等待地址变化 uint8_t assignAddr_State; //自动分配地址的状态 0未开始 1进行中 2结束 uint8_t assignAddr_Step; //自动分配地址当前步骤 uint8_t assignAddr_Failcount; //连续分配地址失败的计数 uint8_t assignAddr_485num; //分配地址后的在线个数,若存在从机(此值>2)才下发队列标志 uint16_t assignAddr_random; //主机完成分配后生成的随机数(AddrMax+1~65535),用来识别队列 uint8_t assignAddr_WrIndex_Flg;//主机执行下发队列标志数的标志 uint8_t assign_ready_count1;//主机再次分配的启用条件计数,1.最后一个在线从机的序号不等于总在线个数,说明中间有地址缺失,发现2次就执行 uint8_t assign_ready_count2;//主机再次分配的启用条件计数,2.始终找不到任何从机,发现3次就执行 uint8_t assign_ready_count3;//主机再次分配的启用条件计数,3.从机的队列标志和主机的不同,发现2次就执行 uint8_t assign_ready_count4;//主机再次分配的启用条件计数,4.在线总个数外的地址有不符合的乱码 uint8_t assign_ready_count5;//主机再次分配的启用条件计数,5.在线总个数内的地址有回复但字节数超出 #endif uint8_t AnswerFlag1; //轮询在线总个数外的地址有不符合的乱码 uint8_t AnswerFlag2; //轮询在线总个数内的地址有回复但字节数超出 uint8_t PollStop_flag; //主机暂停发送轮询的标志位。在1口,除了7E/03/10/控制MOS的/升级的,其他报文都会恢复不再暂停。在3.4口, uint8_t PollStop_count; //主机暂停发送轮询的倒计时,再次收到则清零,30s const uint16_t CRC16Table[256]= { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 }; // CRC 校验函数,返回CRC BYTE2 CRC16_Cal(uint8_t *pdata, uint16_t len) { uint16_t i; BYTE2 CRCData; CRCData.b16=0XFFFF; for(i=0;i=0 && num<=protocolNum) { if(num==0) //2026.2.10增加读协议 { num = protocol; } protocolSwitchFail = 0; //存在该协议,选中,并返回协议名称 protocol = num; //将选中的字符串复制到一个新的字符数组中,获取字符串的长度 strcpy(name,protocolStrings[num-1]); namelen = strlen(name); //生成输出报文 modbusBuf[2] = namelen; for(i=0;i= MODBUS_BUF_LEN ) { modbusBufIndex = 0; } //每次接收数据中断清除定时器计数器并启动计数器 //如定时器溢出中断,表示一帧数据接收完成 TIM_SetCounter(MODBUS_UART_TIM, 0); TIM_Cmd(MODBUS_UART_TIM, ENABLE); } //查询发送数据 void MODBUS_IQ_Transmit(void) { BYTE2 crc16; if(modbusF03RxFlg == 1) { modbusF03RxFlg = 0; modbusBufIndex = 0; MODBUS_UART_SendMulByte(modbusBuf, (5 + modbusBuf[2]) ); MODBUS_UART_IT_RX_ENABLE; } else if(modbusF10RxFlg == 1) { modbusF10RxFlg = 0; modbusBufIndex = 0; if(modbusBuf[1] == 0x10) //写参数需要存入flash { //bmsMem中数据更新到FLASH A区和B区和AFE EEPORM if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0)) { staPack.bits.flashUpdate= 0; if(MEMORY_UpdateAFE() ==0) //更新AFE EEPROM内容 { staPack.bits.eepromUpdate = 0; MODBUS_UART_SendMulByte(modbusBuf, 8); } else { staPack.bits.eepromUpdate = 1; } } else { staPack.bits.flashUpdate= 1; } bmsMem.packStatus = staPack.byte; } else if(modbusBuf[1] == 0xf4) { if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0)) { staPack.bits.flashUpdate= 0; if(MEMORY_UpdateAFE() ==0) { staPack.bits.eepromUpdate = 0; MODBUS_UART_SendMulByte(modbusBuf, 8); } else { staPack.bits.eepromUpdate = 1; } } else { staPack.bits.flashUpdate= 1; } bmsMem.packStatus = staPack.byte; } else if(modbusBuf[1] == 0x56) //写SN号需要写入EEPROM //写4G通信凭证需要存入flash { uint8_t i; uint8_t *data; uint8_t tmpWr[16]; if(modbusBuf[3] == 0x00) //对应硬件版本号的地址 { MODBUS_UART_SendMulByte(modbusBuf, 8); EEPROM_WrMulByte(EE_Hardware,VersionMem.Hardware); delay_ms(5); //填充HardwareVersion Refresh_HardwareVersion(); } else if(modbusBuf[3] == 0x01) //对应屏幕号的地址 { MODBUS_UART_SendMulByte(modbusBuf, 8); EEPROM_WrMulByte(EE_Screen,&VersionMem.Screen); delay_ms(5); //填充ScreenVersion Refresh_ScreenVersion(); } else if(modbusBuf[3] == 0x04) //对应BMS的SN号的地址 { data = (uint8_t *)&VersionMem.BMS_SN[0]; for(i=0;i<9+1;i++) { tmpWr[i] = *data; data++; } MODBUS_UART_SendMulByte(modbusBuf, 8); EEPROM_WrMulByte(EE_BMS_SN,tmpWr); delay_ms(5); /*三选一模块*/ #if BLE_Conn BLE_WriteName(); //锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 #endif #if LTE_Conn LTE_UNSUB_Flag = 1; //因为订阅主题变动,需要对此前的订阅进行取消绑定 EEPROM_WrMulByte(EE_UNSUB,<E_UNSUB_Flag); delay_ms(5); if(LTE_LINK_flag == 1) //若原来已连接4G服务器,断开并重新正确连接 { LTE_LINK_flag = 0; //已连接标志清零 MQTT_RST_flag = 1; //断开再连接MQTT服务器 MQTT_RST_step = 0; MQTT_START_flag = 0; MQTT_READY_flag = 0; MQTT_timed_count = 0; //清零定时上报倒计时 LTE_OTA_Flag = 0; //OTA升级标志清零 } LTE_4G_Domain_ChangeSN(); //更新4G通信凭证 #endif } else if(modbusBuf[3] == 0x09) //对应PACK的SN号的地址 { data = (uint8_t *)&VersionMem.PACK_SN[0]; for(i=0;i<15+1;i++) { tmpWr[i] = *data; data++; } MODBUS_UART_SendMulByte(modbusBuf, 8); EEPROM_WrMulByte(EE_PACK_SN,tmpWr); delay_ms(5); //填充PACK_SN Refresh_PACK_SN(); } #if LTE_Conn else if(modbusBuf[3] == 0x20) //对应4G通信凭证的起始地址 { if(LTE_LINK_flag == 1) { LTE_LINK_flag = 0; //已连接标志清零 MQTT_RST_flag = 1; //断开再连接MQTT服务器 MQTT_RST_step = 0; MQTT_START_flag = 0; MQTT_READY_flag = 0; MQTT_timed_count = 0; //清零定时上报倒计时 LTE_OTA_Flag = 0; //OTA升级标志清零 } //计算CRC校验值 static uint8_t temp[HOSTMEM_LEN]; memcpy(temp, &VersionMem.host[0], HOSTMEM_LEN); VersionMem.hostAll_crc = CRC8_Cal(&temp[0], 153); //更新Flash if((MEMORY_UpdateFlash(FLASH_DATA_A_BASE) == 0) && (MEMORY_UpdateFlash(FLASH_DATA_B_BASE) == 0)) { staPack.bits.flashUpdate = 0; } else { staPack.bits.flashUpdate = 1; } bmsMem.packStatus = staPack.byte; MODBUS_UART_SendMulByte(modbusBuf, 8); } #endif } else { MODBUS_UART_SendMulByte(modbusBuf, 8); } MODBUS_UART_IT_RX_ENABLE; } else if(modbusFaaRxFlg == 1) { modbusFaaRxFlg = 0; modbusBufIndex = 0; if(cali.flagZeroCaliFail ==0) //ok { // 01 AA 5A A5 03 04 CRCL H modbusBuf[0] = bmsMem.E2_485Addr; modbusBuf[1] = 0xaa; modbusBuf[2] = 0x5a; modbusBuf[3] = 0xa5; modbusBuf[4] = 0x03; modbusBuf[5] = 0x04; crc16 = CRC16_Cal(modbusBuf, 6); modbusBuf[6] = crc16.b8[0]; modbusBuf[7] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 8); } else //fail { // 01 AA 5A A5 05 06 CRCL H modbusBuf[0] = bmsMem.E2_485Addr; modbusBuf[1] = 0xaa; modbusBuf[2] = 0x5a; modbusBuf[3] = 0xa5; modbusBuf[4] = 0x05; modbusBuf[5] = 0x06; crc16 = CRC16_Cal(modbusBuf, 6); modbusBuf[6] = crc16.b8[0]; modbusBuf[7] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 8); } MODBUS_UART_IT_RX_ENABLE; } else if(modbusFbbRxFlg == 1) { modbusFbbRxFlg = 0; modbusBufIndex = 0; if(cali.flagGainCaliFail ==0) //ok { // 01 AA 5A A5 03 04 CRCL H modbusBuf[0] = bmsMem.E2_485Addr; modbusBuf[1] = 0xbb; modbusBuf[2] = 0x5b; modbusBuf[3] = 0xb5; modbusBuf[4] = 0x03; modbusBuf[5] = 0x04; crc16 = CRC16_Cal(modbusBuf, 6); modbusBuf[6] = crc16.b8[0]; modbusBuf[7] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 8); } else //fail { // 01 AA 5A A5 05 06 CRCL H modbusBuf[0] = bmsMem.E2_485Addr; modbusBuf[1] = 0xbb; modbusBuf[2] = 0x5b; modbusBuf[3] = 0xb5; modbusBuf[4] = 0x05; modbusBuf[5] = 0x06; crc16 = CRC16_Cal(modbusBuf, 6); modbusBuf[6] = crc16.b8[0]; modbusBuf[7] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 8); } MODBUS_UART_IT_RX_ENABLE; } else if(modbusFddRxFlg == 1) //按顺序读记录 { uint8_t adrh,adrl; modbusFddRxFlg = 0; modbusBufIndex = 0; adrh = modbusBuf[2]; adrl = modbusBuf[3]; EEPROM_RdMulByte(EE_SOE, &modbusBuf[4]); //read extend cell17~20 if new format(0xA6) if(modbusBuf[4+63] == 0xA6) { uint16_t rec_addr = ((uint16_t)modbusBuf[2] << 8) | modbusBuf[3]; uint16_t ext_addr = 0x2900 + (rec_addr - 0x1000) * 6 / 64; adrh = (ext_addr>>8) & 0xff; adrl = ext_addr & 0xff; EEPROM_RdMulByte(EE_SOE_EXT, &modbusBuf[4+64]); } else { memset(&modbusBuf[4+64], 0, 6); } crc16 = CRC16_Cal(modbusBuf, 70+4); modbusBuf[70+4] = crc16.b8[0]; modbusBuf[70+5] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 70+6); MODBUS_UART_IT_RX_ENABLE; } else if(modbusFeeRxFlg == 1) //清除记录 { uint16_t i; uint16_t pc; //待写入地址 uint8_t adrh,adrl; uint8_t wrBuf[64]; if(soe.num != 0) //存在记录,才去删除记录 { //先清空具体内容 pc = 0x1000; for(i=0;i<64;i++) { wrBuf[i] = 0xff; } for(i=0;i<100;i++) { adrh = (pc>>8) & 0xff; adrl = pc & 0xff; EEPROM_WrMulByte(EE_SOE,wrBuf); delay_ms(10); pc += 0x40; } //clear extend cell17~20 area pc = 0x2900; { uint8_t extClear[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; for(i=0;i<100;i++) { adrh = (pc>>8) & 0xff; adrl = pc & 0xff; EEPROM_WrMulByte(EE_CLEAR_EXT,extClear); delay_ms(10); pc += 6; } } //再清空统计数据 soe.index = 0; //起始序号0 soe.pc = 0x1000; //起始地址0x1000 soe.num = 0; //起始数量0 wrBuf[0] = (soe.index >> 24) & 0xff ; wrBuf[1] = (soe.index >> 16) & 0xff ; wrBuf[2] = (soe.index >> 8) & 0xff ; wrBuf[3] = (soe.index >> 0) & 0xff ; wrBuf[4] = (soe.pc >>8)&0XFF ; wrBuf[5] = soe.pc & 0xff ; wrBuf[6] = (soe.num >>8)&0XFF ; wrBuf[7] = soe.num & 0xff ; EEPROM_WrMulByte(EE_SOE_INF,wrBuf); delay_ms(10); } modbusFeeRxFlg = 0; modbusBufIndex = 0; MODBUS_UART_SendMulByte(modbusBuf, 8 ); MODBUS_UART_IT_RX_ENABLE; scr_RdRecord_Flg = 1; } else if(modbusFf1RxFlg == 1) //选择通信协议 { modbusFf1RxFlg = 0; modbusBufIndex = 0; if(protocolSwitchFail == 0) //锟斤拷锟截讹拷应协锟斤拷 { MODBUS_UART_SendMulByte(modbusBuf, (5 + modbusBuf[2]) ); EEPROM_WrMulByte(EE_PROTOCOL,&protocol); delay_ms(5); uf_CAN1_Init();//CAN的波特率更新 //SCR_DispProcotol(); //屏幕显示更新 } else { //失败的回复 modbusBuf[0] = bmsMem.E2_485Addr; modbusBuf[1] = 0xf1; modbusBuf[2] = 0x00; crc16 = CRC16_Cal(modbusBuf, 3); modbusBuf[3] = crc16.b8[0]; modbusBuf[4] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 5 ); } MODBUS_UART_IT_RX_ENABLE; } } //接收一帧数据,帧间断小于x ms仍然认为是一帧 //定时器中断里进行接收数据解析并准备回送数据 void MODBUS_IT_TIMUpdate(void) { if(bmsMem.E2_485Addr == 1 )//485主机模式 { if(modbusBufIndex > 2) { //要休眠,却还收到了通信,可能是有时间差,多确认几次再退出 if(sleep_flag == 1) { sleepOFFcount++; } else { sleepOFFcount=0; } //网口3.4确定有通讯,退出休眠且更新计时起点 if(sleepOFFcount >= 5) { sleep_flag = 0; sleepOFFcount=0; SLEEP_Refresh(); SLEEP2_Refresh(); } if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x03) ) //读数据处理 { MODBUS_F03_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x10) ) //写数据处理 { MODBUS_F10_Rx(MODBUS_MEM_PT); } /*V3上位机*/ else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x33) ) //上位机读数据处理 { PollStop_flag = 1; //3.4口兼容V3 PollStop_count = 0; ConfigData_Index = 1; //主机看从机值更新回1 scr_RdData_Index = 1; MODBUS_F03_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x55) ) //上位机读取版本号 { MODBUS_F03_Rx(MODBUS_VersionMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x56) ) //上位机写硬件版本号/屏幕号/SN号 { MODBUS_F10_Rx(MODBUS_VersionMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x66) ) //上位机写时间 { if(LSEErrFlag!=1) MODBUS_F10_Rx(MODBUS_TimeMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xaa) ) //CADC零点校准处理 { MODBUS_Faa_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xbb) ) //CADC增益校准处理 { MODBUS_Fbb_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0Xdd) ) //读取记录 { UART1_ReadRecord(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xee) ) //清除记录 { UART1_ClearRecord(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf1) ) //F1 选择逆变器协议 { UART1_ProtocolSwitch(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf2) ) //F2 控制MOS强制关闭 { MODBUS_F10_Rx(MODBUS_CtrlMEM_PT); } else if((modbusBuf[0] == 0xff) && (modbusBuf[1] == 0xf2) ) // 广播控制MOS强制关闭 { MODBUS_CtrlMOS_Rx(MODBUS_CtrlMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf3) ) //F3 弹窗读参数 { MODBUS_F03_Rx(MODBUS_ParaMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf4) ) //F4 弹窗写参数 { MODBUS_F10_Rx(MODBUS_ParaMEM_PT); } //上位机持续询问指定从机数据 else if((ConfigData_Index>=2) && (ConfigData_Index<=paraMem.PACK_NUM)) { /*主机收集[上位机]指定从机数据*/ if((modbusBuf[0] == ConfigData_Index) && (modbusBuf[1] == 0x03) ) //从机返回的读数据处理 { MODBUS_MASTER_F03_Rx(); } #if Addr_SetAuto /*自动分配地址 的回复*/ else if((modbusBuf[0] == MODBUS_ASSIGN_INADDR) && (modbusBuf[1] == 0x10) ) //写数据回复的处理 { MODBUS_MASTER_F10_Rx(); } #endif else { MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接 } } //屏幕查看指定从机数据 else if((scr_RdData_Index>=2) && (scr_RdData_Index<=paraMem.PACK_NUM)) { /*主机收集[屏幕]指定从机数据*/ if((modbusBuf[0] == scr_RdData_Index) && (modbusBuf[1] == 0x03) ) //单独请求从机,返回的读数据处理 { MODBUS_MASTER_F03_Rx(); } else if((modbusBuf[0] == scr_RdData_Index) && (modbusBuf[1] == 0x10) ) //从机对修改地址成功的回复 { MODBUS_MASTER_F10_Rx(); } #if Addr_SetAuto /*自动分配地址 的回复*/ else if((modbusBuf[0] == MODBUS_ASSIGN_INADDR) && (modbusBuf[1] == 0x10) ) //写数据回复的处理 { MODBUS_MASTER_F10_Rx(); } #endif else { MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接 } } //正常轮询 else { /*主机轮询*/ if((modbusBuf[0] == modbusCurDev) && (modbusBuf[1] == 0x03) ) //从机返回的读数据处理 { MODBUS_MASTER_F03_Rx(); } #if Addr_SetAuto /*自动分配地址 的回复*/ else if((modbusBuf[0] == MODBUS_ASSIGN_INADDR) && (modbusBuf[1] == 0x10) ) //写数据回复的处理 { MODBUS_MASTER_F10_Rx(); } else { //轮询在询问但回复是乱码,作为自动分配启动条件 if((paraMem.addr_FREE_Flg == 0) && (modbusCurStatus == 1) && (modbusCurDev >= 2) && (modbusCurDev <= bmsMem.E2_485Snum) && (modbusBufIndex > 10)) { AnswerFlag2 = 1; } MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接 } #else { MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接 } #endif } } } else //485从机 { if(modbusBufIndex > 2) { //要休眠,却还收到了通信,可能是有时间差,多确认几次再退出 if(sleep_flag == 1) { sleepOFFcount++; } else { sleepOFFcount=0; } //网口3.4确定有通讯,退出休眠且更新计时起点 if(sleepOFFcount >= 5) { sleep_flag = 0; sleepOFFcount=0; SLEEP_Refresh(); SLEEP2_Refresh(); } if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x03) ) //主机轮询从机 { MODBUS_F03_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x10) ) //写数据处理 { MODBUS_F10_Rx(MODBUS_MEM_PT); } /*V3上位机*/ else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x33) ) //上位机读数据处理 { MODBUS_F03_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x55) ) //上位机读取版本号 { MODBUS_F03_Rx(MODBUS_VersionMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x56) ) //上位机写硬件版本号/屏幕号/SN号 { MODBUS_F10_Rx(MODBUS_VersionMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0x66) ) //上位机写时间 { if(LSEErrFlag!=1) MODBUS_F10_Rx(MODBUS_TimeMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xaa) ) //CADC零点校准处理 { MODBUS_Faa_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xbb) ) //CADC增益校准处理 { MODBUS_Fbb_Rx(MODBUS_MEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0Xdd) ) //读取记录 { UART1_ReadRecord(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xee) ) //清除记录 { UART1_ClearRecord(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf1) ) //F1 选择逆变器协议 { UART1_ProtocolSwitch(); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf2) ) //F2 控制MOS强制关闭 { MODBUS_F10_Rx(MODBUS_CtrlMEM_PT); } else if((modbusBuf[0] == 0xff) && (modbusBuf[1] == 0xf2) ) // 广播控制MOS强制关闭 { MODBUS_CtrlMOS_Rx(MODBUS_CtrlMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf3) ) //F3 弹窗读参数 { MODBUS_F03_Rx(MODBUS_ParaMEM_PT); } else if((modbusBuf[0] == bmsMem.E2_485Addr) && (modbusBuf[1] == 0xf4) ) //F4 弹窗写参数 { MODBUS_F10_Rx(MODBUS_ParaMEM_PT); } #if Addr_SetAuto else if((modbusBuf[0] == 0xff) && (modbusBuf[1] == 0x10) ) //主机广播写队列标志位 { MODBUS_WrIndex_Rx(); } #endif else { MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接 } } } } /**************************************** **** MODBUS F03 读报文 ***** ** M: 01 03 00 addr 00 lenth CRCL H ** ** S: 01 03 2*lenth DATA0-N CRCL H ** *****************************************/ void MODBUS_F03_Rx(uint8_t *mem) { uint8_t i; BYTE2 crc16; uint16_t adr; uint8_t len; uint8_t *data; //CRC判断 crc16 = CRC16_Cal(modbusBuf, 6); if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) ) { adr = (uint16_t)modbusBuf[3] <<1; len = modbusBuf[5] <<1; modbusBuf[2] = len; //高字节在前 data = mem+adr; for(i=0;i bmsMem.E2_485Snum) && (modbusBufIndex > 10)) { AnswerFlag1 = 1; } } /*若在CRC校验码之后还有报文,记录为启动自动分配条件*/ if((paraMem.addr_FREE_Flg == 0) && (modbusCurStatus == 1) && (modbusBuf[len+5] != 0) && (modbusBuf[len+6] != 0)) { AnswerFlag2 = 1; } #endif } /*********************************************** **** MODBUS F10 写报文回复报文的解析 ***** ** M: 01 10 ADRH L 0 LENTH 2LETH DATAn CRCL H ** ** S: 01 10 ADRH L 0 LENTH CRCL CRCH ** ************************************************/ void MODBUS_MASTER_F10_Rx(void) { BYTE2 crc16; //CRC判断 crc16 = CRC16_Cal(modbusBuf, 6); if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) ) { modbusCurF10RxFlag = 1; MODBUS_UART_IT_RX_DISABLE; } } //设为主机时,500MS调用1次 void MODBUS_MASTER_Polling_Tx(void) { uint8_t i; uint16_t tmp; BYTE2 crc16; if(modbusCurStatus != 1) { modbusCurStatus = 1; MODBUS_Init(); } //主机接收上一帧的数据并处理 if(modbusCurSta == 1) { modbusCurSta = 0; if(modbusCurF03RxFlag == 1) //收到数据且CRC校验正确 { modbusCurF03RxFlag = 0; canMem[modbusCurDev].status_byte1 = modbusBuf[3]<<8 | modbusBuf[4]; canMem[modbusCurDev].status_byte2 = modbusBuf[5]<<8 | modbusBuf[6]; canMem[modbusCurDev].status_byte3 = modbusBuf[7]<<8 | modbusBuf[8]; canMem[modbusCurDev].status_byte4 = modbusBuf[9]<<8 | modbusBuf[10]; canMem[modbusCurDev].soc = modbusBuf[12]; canMem[modbusCurDev].soh = modbusBuf[11]; canMem[modbusCurDev].cur = (int16_t)(modbusBuf[13]<<8 | modbusBuf[14]); canMem[modbusCurDev].temp = (int16_t)(modbusBuf[15]<<8 | modbusBuf[16]); canMem[modbusCurDev].VolMax = modbusBuf[17]<<8 | modbusBuf[18]; canMem[modbusCurDev].VolMin = modbusBuf[19]<<8 | modbusBuf[20]; canMem[modbusCurDev].VolMaxIndex = modbusBuf[21]<<8 | modbusBuf[22]; canMem[modbusCurDev].VolMinIndex = modbusBuf[23]<<8 | modbusBuf[24]; canMem[modbusCurDev].TempMax = modbusBuf[25]<<8 | modbusBuf[26]; canMem[modbusCurDev].TempMin = modbusBuf[27]<<8 | modbusBuf[28]; canMem[modbusCurDev].TempMaxIndex = modbusBuf[29]<<8 | modbusBuf[30]; canMem[modbusCurDev].TempMinIndex = modbusBuf[31]<<8 | modbusBuf[32]; //Wh版屏幕 canMem[modbusCurDev].cumuliCap = modbusBuf[35]<<8 | modbusBuf[36]; canMem[modbusCurDev].cycleCnt = modbusBuf[37]<<8 | modbusBuf[38]; //负值矫正 canMem[modbusCurDev].cellVoltageMax = (int16_t)(canMem[modbusCurDev].VolMax*32/5)*5/32; canMem[modbusCurDev].cellVoltageMin = (int16_t)(canMem[modbusCurDev].VolMin*32/5)*5/32; tmp = modbusBuf[33]<<8 | modbusBuf[34]; if(tmp > AddrMax) //队列标志的取值范围在AddrMax+1~65535 { canMem[modbusCurDev].com = tmp; //赋值队列标志 } else { canMem[modbusCurDev].com = 1; //接收数据OK } } else //未收到回复 { canMem[modbusCurDev].status_byte1 = 0; canMem[modbusCurDev].status_byte2 = 0; canMem[modbusCurDev].status_byte3 = 0; canMem[modbusCurDev].status_byte4 = 0; canMem[modbusCurDev].soc = 0; canMem[modbusCurDev].soh = 0; canMem[modbusCurDev].cur = 0; canMem[modbusCurDev].temp = 0; canMem[modbusCurDev].VolMax = 0; canMem[modbusCurDev].VolMin = 0; canMem[modbusCurDev].VolMaxIndex = 0; canMem[modbusCurDev].VolMinIndex = 0; canMem[modbusCurDev].TempMax = 0; canMem[modbusCurDev].TempMin = 0; canMem[modbusCurDev].TempMaxIndex = 0; canMem[modbusCurDev].TempMinIndex = 0; //Wh版屏幕 canMem[modbusCurDev].cumuliCap = 0; canMem[modbusCurDev].cycleCnt = 0; //负值矫正 canMem[modbusCurDev].cellVoltageMax = 0; canMem[modbusCurDev].cellVoltageMin = 0; canMem[modbusCurDev].com = 0;//接收数据FAIL } //无报警正常轮询下一个,有报警的话再询问一遍(为简单,对满充时的充电过压不报警不做区分,这里不考虑) if(((canMem[modbusCurDev].status_byte1 & 0x067e) != 0) || ((canMem[modbusCurDev].status_byte2 & 0x00ff) != 0) || ((canMem[modbusCurDev].status_byte3 & 0x0008) != 0) || ((canMem[modbusCurDev].status_byte4 & 0x0f7f) != 0)) { if(ReAskFlag == 0) { //再问一遍,此时modbusCurDev不变 ReAskFlag = 1; } else { ReAskFlag = 0; modbusCurDev++; } } else { ReAskFlag = 0; modbusCurDev++; } //当轮询02~paraMem.PACK_NUM结束后,汇总数据、分析数据 if(modbusCurDev > paraMem.PACK_NUM) { /*收集最后一个在线BMS的地址*/ bmsMem.E2_485Snum = 1; modbusCurLastAddr = 1; for(i=2;i<=paraMem.PACK_NUM;i++) { if(canMem[i].com != 0) //引入队列标志位后的改动 { bmsMem.E2_485Snum++; modbusCurLastAddr = i; } } #if Addr_SetAuto /**** 分配地址启用条件判断 ****/ if(paraMem.addr_FREE_Flg == 0) { //1.当在线个数和最后一个在线的通信地址的值不同,说明中间有地址不在,需要启动分配地址 if(bmsMem.E2_485Snum != modbusCurLastAddr) { assign_ready_count1++; if(assign_ready_count1 >= 2) //出现2次后触发,约20s { assignAddr_State = 1; assign_ready_count1 = 0; } } else { assign_ready_count1 = 0; } //2.当持续搜不到从机时,需要启动分配地址 if(bmsMem.E2_485Snum == 1) { assign_ready_count2++; if(assign_ready_count2 >= AddrMax-paraMem.PACK_NUM+2) //防止在并联数很少的情况时,因找不到从机而反复启动分配 { assignAddr_State = 1; assign_ready_count2 = 0; } } else { assign_ready_count2 = 0; } //3.当发现在线但 没有标志位/标志位和主机上次分配时不同时,需要启动分配地址 uint8_t IndexFlag = 0;//用来遍历可能在线的从机,判断是否有队列标志不同的在线从机 for(i=2;i<=paraMem.PACK_NUM;i++) { if((canMem[i].com != 0) && (canMem[i].com != canMem[1].com)) { IndexFlag = 1; } } if(IndexFlag == 1) { assign_ready_count3++; if(assign_ready_count3 >= 2) //出现2次后触发,约20s { assignAddr_State = 1; assign_ready_count3 = 0; } } else { assign_ready_count3 = 0; } //4.当发现对在线总个数以外的地址有回复但是乱码时,需要启动分配地址 if(AnswerFlag1 == 1) { AnswerFlag1 = 0; assign_ready_count4++; if(assign_ready_count4 >= 2) //出现2次后触发,约20s { assignAddr_State = 1; assign_ready_count4 = 0; } } else { assign_ready_count4 = 0; } //5.当发现对在线总个数内的地址有回复但字节数超出时,需要启动分配地址 if(AnswerFlag2 == 1) { AnswerFlag2 = 0; assign_ready_count5++; if(assign_ready_count5 >= 10) //出现10次后触发,约100s { assignAddr_State = 1; assign_ready_count5 = 0; } } else { assign_ready_count5 = 0; } } #endif modbusCurDev = 2; } } //主机发送对下一个从机的轮询 if(modbusCurSta == 0) { modbusBufIndex = 0; modbusBuf[0] = modbusCurDev; modbusBuf[1] = 0x03; modbusBuf[2] = 0x00; modbusBuf[3] = 0x4B; modbusBuf[4] = 0x00; modbusBuf[5] = 0x12; //增加最大最小值相关 //增加队列标志 //标志位变u16 //Wh版屏幕,增加循环次数和累计容量 crc16 = CRC16_Cal(modbusBuf, 6); modbusBuf[6] = crc16.b8[0]; modbusBuf[7] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 8); modbusCurSta = 1; modbusCurF03RxFlag = 0; MODBUS_UART_IT_RX_ENABLE; } } #if Addr_SetAuto //主机先置高OUT初始化所有从机地址,再置低OUT让第一个从机为21,然后向地址21传正确地址 void MODBUS_AddrAssign_Tx(void) { uint8_t tmp[2]; BYTE2 crc16; if(assignAddr_Step == 0) { IO2_OUTSet(); //OUT引脚置高,让从机1地址99,输出置高 assignAddr_Step = 1; } else if(assignAddr_Step == 1) { IO2_OUTReset(); //OUT引脚置低,让从机1地址AddrMax+1 assignAddr_Step = 2; } else if((assignAddr_Step >= 2) && (assignAddr_Step <= paraMem.PACK_NUM)) //分配地址,和并机总数有关 { if(modbusCurStatus != 2) { modbusCurStatus = 2; MODBUS_Init(); } /*写地址时间稍长,真正时序是1s1次*/ //主机接收上一帧的数据并处理 if(modbusCurSta == 2) //主机接收数据处理 { modbusCurSta = 0; if(modbusCurF10RxFlag == 1) //收到数据且CRC校验正确,准备询问下一个 { modbusCurF10RxFlag = 0; assignAddr_Failcount = 0; if(assignAddr_Step < paraMem.PACK_NUM) //非最后1个 { assignAddr_Step++; } else { //当可用地址的最后一个也分配成功,已经配置完所有在线从机 assignAddr_State = 2;//已执行过分配 assignAddr_485num = assignAddr_Step; assignAddr_Step = 0; //清空 MODBUS_Init(); //初始化 assignAddr_random = get_random(); assignAddr_WrIndex_Flg = 1; return; //退出,不执行发送 } } else //未接收数据或数据错误,继续发送原写寄存器报文 { assignAddr_Failcount++; if(assignAddr_Failcount > 5) { assignAddr_Failcount = 0; //发送多次还未收到正确回复,认为已经配置完所有在线从机 assignAddr_State = 2;//已执行过分配 assignAddr_485num = assignAddr_Step-1; assignAddr_Step = 0; //清空 MODBUS_Init(); //初始化 assignAddr_random = get_random(); if(assignAddr_485num > 1) //存在从机才要下发队列标志 { assignAddr_WrIndex_Flg = 1; } return; //退出,不执行发送 } } } //主机发送对下一个从机的分配地址 if(modbusCurSta == 0) { tmp[0] = assignAddr_Step; tmp[1] = CRC8_Cal(tmp,1); modbusBufIndex = 0; modbusBuf[0] = MODBUS_ASSIGN_INADDR; modbusBuf[1] = 0x10; modbusBuf[2] = 0x00; modbusBuf[3] = 0x48; modbusBuf[4] = 0x00; modbusBuf[5] = 0x01; modbusBuf[6] = 0x02; modbusBuf[7] = tmp[0]; modbusBuf[8] = tmp[1]; crc16 = CRC16_Cal(modbusBuf, 9); modbusBuf[9] = crc16.b8[0]; modbusBuf[10] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 11); modbusCurSta = 1; modbusCurF10RxFlag = 0; MODBUS_UART_IT_RX_ENABLE; } //1,给从机反应时间 else { modbusCurSta++; } } } //主机广播队列标志 void MODBUS_WrIndex_Tx(void) { BYTE2 crc16; modbusBufIndex = 0; modbusBuf[0] = 0xff; modbusBuf[1] = 0x10; modbusBuf[2] = 0x00; modbusBuf[3] = 0x00; modbusBuf[4] = 0x00; modbusBuf[5] = 0x01; modbusBuf[6] = 0x02; modbusBuf[7] = assignAddr_random & 0xff; modbusBuf[8] = (assignAddr_random>>8) & 0xff; crc16 = CRC16_Cal(modbusBuf, 9); modbusBuf[9] = crc16.b8[0]; modbusBuf[10] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 11); MODBUS_UART_IT_RX_ENABLE; } //从机收到广播的队列标志 void MODBUS_WrIndex_Rx(void) { BYTE2 crc16; //CRC判断 crc16 = CRC16_Cal(modbusBuf, 2+7); if( (modbusBuf[2+8] == crc16.b8[1]) && (modbusBuf[2+7] == crc16.b8[0]) ) { if(assignAddr_State == 2) //经历过自动分配地址 { uint8_t tmp[2]; bmsMem.can_ArrayIndex = modbusBuf[8]<<8 | modbusBuf[7]; tmp[0] = modbusBuf[8]; tmp[1] = modbusBuf[7]; EEPROM_WrMulByte(EE_ASSIGN,tmp); delay_ms(5); } MODBUS_Init(); } } #endif //主机因[屏幕]获取固定从机数据,并显示在屏幕上 void MODBUS_Screen_RdSlave_Tx(void) { uint8_t *data; uint8_t len; uint8_t i; BYTE2 crc16; if(modbusCurStatus != 3) { modbusCurStatus = 3; MODBUS_Init(); } //主机接收上一帧的数据并处理 if(modbusCurSta == 1) { modbusCurSta = 0; if(modbusCurF03RxFlag == 1) //收到数据且CRC校验正确 { data = (uint8_t *)&bmsMem_slave.vCell[0]; len = modbusBuf[2]; for(i=0;i3) { sdwa_WrAddr_Failcount = 0; sdwa_WrAddr_Flg = 3; } } } //主机发送对固定从机的写地址 if(modbusCurSta == 0) { tmp[0] = sdwa_WrAddr; tmp[1] = CRC8_Cal(tmp,1); modbusBufIndex = 0; modbusBuf[0] = scr_RdData_Index; modbusBuf[1] = 0x10; modbusBuf[2] = 0x00; modbusBuf[3] = 0x48; modbusBuf[4] = 0x00; modbusBuf[5] = 0x01; modbusBuf[6] = 0x02; modbusBuf[7] = tmp[0]; modbusBuf[8] = tmp[1]; crc16 = CRC16_Cal(modbusBuf, 9); modbusBuf[9] = crc16.b8[0]; modbusBuf[10] = crc16.b8[1]; MODBUS_UART_SendMulByte(modbusBuf, 11); modbusCurSta = 1; modbusCurF10RxFlag = 0; MODBUS_UART_IT_RX_ENABLE; } } //主机因[上位机]获取固定从机数据,并在下一次上位机询问时回复 void MODBUS_Config_RdSlave_Tx(void) { uint8_t *data; uint8_t len; uint8_t i; BYTE2 crc16; if(modbusCurStatus != 5) { modbusCurStatus = 5; MODBUS_Init(); } //主机接收上一帧的数据并处理 if(modbusCurSta == 1) { modbusCurSta = 0; if(modbusCurF03RxFlag == 1) //收到数据且CRC校验正确 { Online_Flag = 1; //下次上位机询问,可以回复 data = (uint8_t *)&bmsMem_slave.vCell[0]; len = modbusBuf[2]; for(i=0;i