1938 lines
49 KiB
C
1938 lines
49 KiB
C
/**
|
|
******************************************************************************
|
|
* @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<len;i++){
|
|
CRCData.b16 = CRC16Table[CRCData.b8[0]^ *pdata++] ^ CRCData.b8[1];
|
|
}
|
|
return CRCData;
|
|
}
|
|
|
|
/****************************************
|
|
**** 按顺序读记录 *****
|
|
** M: A1 dd 10 00 00 00 CRCL H **
|
|
** S: A1 dd 10 00 d0-51 CRCL H **
|
|
*****************************************/
|
|
void UART1_ReadRecord(void)
|
|
{
|
|
BYTE2 crc16;
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) )
|
|
{
|
|
modbusFddRxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
**** 清除EEPROM内的记录 *****
|
|
** M: A2 ee 00 55 00 aa CRCL H **
|
|
** S: A2 ee 00 55 00 aa CRCL H **
|
|
*****************************************/
|
|
void UART1_ClearRecord(void)
|
|
{
|
|
BYTE2 crc16;
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) )
|
|
{
|
|
EEPROM_RdMulByte(EE_SOE_NUM,&modbusBuf[2]); //当前序号
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
modbusBuf[6] = crc16.b8[0];
|
|
modbusBuf[7] = crc16.b8[1];
|
|
|
|
modbusFeeRxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
**** 选择协议 *****
|
|
** M: Addr f1 00 num 00 10 CRCL H **
|
|
** Succ: Addr f1 nameLen name[0]~name[15] CRCL H **
|
|
** Fail: Addr f1 0 CRCL CRCH **
|
|
*****************************************/
|
|
void UART1_ProtocolSwitch(void)
|
|
{
|
|
uint8_t i;
|
|
BYTE2 crc16;
|
|
uint8_t num;
|
|
uint8_t namelen;
|
|
char name[16];
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) )
|
|
{
|
|
num = modbusBuf[3];
|
|
|
|
if((int)num>=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<namelen;i++)
|
|
{
|
|
modbusBuf[i+3] = name[i];
|
|
}
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, namelen+3);
|
|
modbusBuf[namelen+3] = crc16.b8[0];
|
|
modbusBuf[namelen+4] = crc16.b8[1];
|
|
}
|
|
else
|
|
{
|
|
protocolSwitchFail = 1; //不存在
|
|
}
|
|
|
|
modbusFf1RxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
}
|
|
|
|
//接收广播MOS控制标志
|
|
void MODBUS_CtrlMOS_Rx(uint8_t *mem)
|
|
{
|
|
BYTE2 crc16;
|
|
uint8_t len;
|
|
|
|
len = modbusBuf[6];
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, len+7);
|
|
if( (modbusBuf[len+8] == crc16.b8[1]) && (modbusBuf[len+7] == crc16.b8[0]) )
|
|
{
|
|
memcpy(mem, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
modbusBuf[6] = crc16.b8[0];
|
|
modbusBuf[7] = crc16.b8[1];
|
|
|
|
MODBUS_Init(); //因为是广播,所以不考虑回复
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
//UART中断接收数据
|
|
void MODBUS_IT_Receive(void)
|
|
{
|
|
modbusMoniCount = MODBUS_MON_CNT;
|
|
|
|
//接收数据
|
|
modbusBuf[modbusBufIndex] = USART_ReceiveData(MODBUS_UART);
|
|
modbusBufIndex++;
|
|
|
|
//防止数组溢出
|
|
if(modbusBufIndex >= 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<len;)
|
|
{
|
|
modbusBuf[4+i] = *data;
|
|
data++;
|
|
modbusBuf[3+i] = *data;
|
|
data++;
|
|
i++;
|
|
i++;
|
|
}
|
|
|
|
//低字节在前
|
|
// memcpy(&modbusBuf[3], mem+adr, len);
|
|
crc16 = CRC16_Cal(modbusBuf, len+3);
|
|
modbusBuf[len+3] = crc16.b8[0];
|
|
modbusBuf[len+4] = crc16.b8[1];
|
|
|
|
modbusF03RxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
/***********************************************
|
|
**** MBUS_PUTN 写多个寄存器报文解析 *****
|
|
** 01 10 ADRH L 0 LENTH 2LETH DATAn CRCL H **
|
|
** 01 10 ADRH L 0 LENTH CRCL CRCH **
|
|
************************************************/
|
|
//mem point to bmsMem
|
|
void MODBUS_F10_Rx(uint8_t *mem)
|
|
{
|
|
BYTE2 crc16;
|
|
uint16_t adr;
|
|
uint8_t len;
|
|
|
|
adr = (uint16_t)modbusBuf[3] <<1;
|
|
len = modbusBuf[6];
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, len+7);
|
|
if( (modbusBuf[len+8] == crc16.b8[1]) && (modbusBuf[len+7] == crc16.b8[0]) )
|
|
{
|
|
uint8_t i;
|
|
uint8_t *data;
|
|
uint8_t tmpWr[16];
|
|
|
|
//上位机写BMS_SN,固定9+1字节,需要检测CRC8
|
|
if((modbusBuf[1] == 0x56) && (modbusBuf[3] == 0x04))
|
|
{
|
|
data = (uint8_t *)&modbusBuf[7];
|
|
for(i=0;i<9;i++)
|
|
{
|
|
tmpWr[i] = *data;
|
|
data++;
|
|
}
|
|
tmpWr[9] = CRC8_Cal(&tmpWr[0],9);
|
|
|
|
if(tmpWr[9] == modbusBuf[7+9]) //crc校验正确
|
|
{
|
|
memcpy(mem+adr, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
modbusBuf[6] = crc16.b8[0];
|
|
modbusBuf[7] = crc16.b8[1];
|
|
|
|
modbusF10RxFlg = 1;
|
|
}
|
|
}
|
|
//上位机写PACK_SN,固定15+1字节,需要检测CRC8
|
|
else if((modbusBuf[1] == 0x56) && (modbusBuf[3] == 0x09))
|
|
{
|
|
data = (uint8_t *)&modbusBuf[7];
|
|
for(i=0;i<15;i++)
|
|
{
|
|
tmpWr[i] = *data;
|
|
data++;
|
|
}
|
|
tmpWr[15] = CRC8_Cal(&tmpWr[0],15);
|
|
|
|
if(tmpWr[15] == modbusBuf[7+15]) //crc校验正确
|
|
{
|
|
memcpy(mem+adr, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
modbusBuf[6] = crc16.b8[0];
|
|
modbusBuf[7] = crc16.b8[1];
|
|
|
|
modbusF10RxFlg = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//上位机写SOC=0的补丁 Adr 10 00 4a 00 01 02 00 00 crc1 crc2
|
|
if((modbusBuf[1] == 0x10) && (modbusBuf[2] == 0x00) && (modbusBuf[3] == 0x4a) && (modbusBuf[7] == 0x00) && (modbusBuf[8] == 0x00))
|
|
{
|
|
//这个报文的说明是写SOC且写的是0,需要特殊处理
|
|
bmsMem.write_Soc = 0xAA;
|
|
}
|
|
//上位机写循环次数,把累积容量也清空 Adr 10 00 25 00 01 02 numL numH crc1 crc2
|
|
else if((modbusBuf[1] == 0x10) && (modbusBuf[2] == 0x00) && (modbusBuf[3] == 0x25))
|
|
{
|
|
cumuliCapClear_flag = 1;
|
|
memcpy(mem+adr, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
}
|
|
//上位机写屏幕版本号,注意只有1字节
|
|
else if((modbusBuf[1] == 0x56) && (modbusBuf[3] == 0x01))
|
|
{
|
|
adr += 1;
|
|
memcpy(mem+adr, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
}
|
|
else
|
|
{
|
|
uint16_t sc_mode_old = paraMem.sc_mode;
|
|
|
|
memcpy(mem+adr, &modbusBuf[7], len); //将modbusBuf数组数据COPY到置定结构体,注意大小端
|
|
|
|
if(paraMem.sc_mode == 0) //被意外置0,恢复
|
|
{
|
|
paraMem.sc_mode = sc_mode_old;
|
|
}
|
|
}
|
|
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
modbusBuf[6] = crc16.b8[0];
|
|
modbusBuf[7] = crc16.b8[1];
|
|
|
|
modbusF10RxFlg = 1;
|
|
}
|
|
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
**** MODBUS FAA CADC零点校准 *****
|
|
** M: 01 AA 5A A5 01 02 CRCL H **
|
|
** S: 01 AA 5A A5 03 04 CRCL H OK **
|
|
** S: 01 AA 5A A5 05 06 CRCL H FAIL **
|
|
*****************************************/
|
|
void MODBUS_Faa_Rx(uint8_t *mem)
|
|
{
|
|
BYTE2 crc16;
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) )
|
|
{
|
|
cali.cmdZero = 1;
|
|
// if( (modbusBuf[2] == 0x5a) && (modbusBuf[3] == 0xa5) && (modbusBuf[4] == 0x01) && (modbusBuf[5] == 0x02) )
|
|
// {
|
|
// cali.cmdZero = 1;
|
|
// }
|
|
|
|
// crc16 = CRC16_Cal(modbusBuf, 6);
|
|
// modbusBuf[6] = crc16.b8[0];
|
|
// modbusBuf[7] = crc16.b8[1];
|
|
|
|
// modbusFaaRxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
**** MODBUS Fbb CADC增益校准 *****
|
|
** M: 01 BB D1 D2 D3 D4 CRCL H **
|
|
** S: 01 BB 5B B5 03 04 CRCL H OK **
|
|
** S: 01 BB 5B B5 05 06 CRCL H FAIL**
|
|
*****************************************/
|
|
void MODBUS_Fbb_Rx(uint8_t *mem)
|
|
{
|
|
BYTE2 crc16;
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, 6);
|
|
if( (modbusBuf[7] == crc16.b8[1]) && (modbusBuf[6] == crc16.b8[0]) )
|
|
{
|
|
cali.current = modbusBuf[2]<<24 | modbusBuf[3]<<16 | modbusBuf[4]<<8 | modbusBuf[5];
|
|
cali.cmdGain = 1;
|
|
|
|
// crc16 = CRC16_Cal(modbusBuf, 6);
|
|
// modbusBuf[6] = crc16.b8[0];
|
|
// modbusBuf[7] = crc16.b8[1];
|
|
|
|
// modbusFbbRxFlg = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
MODBUS_Init(); //没加这个时,换地址通讯连接不上,待监控时间到重新初始化之后才恢复连接
|
|
}
|
|
}
|
|
|
|
//初始化MODBUS通讯
|
|
void MODBUS_Init(void)
|
|
{
|
|
modbusCurSta = 0; //主机当前采集状态
|
|
modbusCurDev = 2; //主机当前采集设备,从从机2开始
|
|
modbusCurF03RxFlag = 0;
|
|
modbusCurF10RxFlag = 0;
|
|
|
|
modbusBufIndex = 0;
|
|
modbusF03RxFlg = 0;
|
|
modbusF10RxFlg = 0;
|
|
modbusFaaRxFlg = 0;
|
|
modbusFbbRxFlg = 0;
|
|
modbusFddRxFlg = 0;
|
|
modbusFeeRxFlg = 0;
|
|
modbusFf1RxFlg = 0;
|
|
modbusMoniCount = MODBUS_MON_CNT;
|
|
|
|
uf_UART1_Init(9600);
|
|
}
|
|
|
|
//初始化MODBUS轮询数据
|
|
void MODBUS_Poll_Init(void)
|
|
{
|
|
canMem[0].status_byte1 = bmsMem.can_status_byte1;
|
|
canMem[0].status_byte2 = bmsMem.can_status_byte2;
|
|
canMem[0].status_byte3 = bmsMem.can_status_byte3;
|
|
canMem[0].status_byte4 = bmsMem.can_status_byte4;
|
|
canMem[0].soc = bmsMem.soc;
|
|
canMem[0].soh = bmsMem.soh;
|
|
canMem[0].cur = (int16_t)bmsMem.can_cur;
|
|
canMem[0].temp = (int16_t)bmsMem.can_temp;
|
|
|
|
canMem[0].VolMax = bmsMem.can_VolMax;
|
|
canMem[0].VolMin = bmsMem.can_VolMin;
|
|
canMem[0].VolMaxIndex = bmsMem.can_VolMaxIndex;
|
|
canMem[0].VolMinIndex = bmsMem.can_VolMinIndex;
|
|
canMem[0].TempMax = bmsMem.can_TempMax;
|
|
canMem[0].TempMin = bmsMem.can_TempMin;
|
|
canMem[0].TempMaxIndex = bmsMem.can_TempMaxIndex;
|
|
canMem[0].TempMinIndex = bmsMem.can_TempMinIndex;
|
|
|
|
//Wh版屏幕
|
|
canMem[0].cumuliCap = bmsMem.can_cumuliCap;
|
|
canMem[0].cycleCnt = bmsMem.can_cycleCnt;
|
|
|
|
//负值矫正
|
|
canMem[0].cellVoltageMax = (int16_t)(canMem[0].VolMax*32/5)*5/32;
|
|
canMem[0].cellVoltageMin = (int16_t)(canMem[0].VolMin*32/5)*5/32;
|
|
|
|
OnlineNum = 1;
|
|
bmsMem.E2_485Snum = 1;
|
|
|
|
#if Addr_SetAuto
|
|
assignAddr_485num = 1;
|
|
#endif
|
|
}
|
|
|
|
//一定时间没有接收到数据,初始化MODBUS通讯
|
|
void MODBUS_TIM_Moni(void)
|
|
{
|
|
modbusMoniCount--;
|
|
if(modbusMoniCount == 0)
|
|
{
|
|
MODBUS_Poll_Init();
|
|
MODBUS_Init();
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
**** MODBUS F03 读报文 *****
|
|
** M: 01 03 00 addr 00 lenth CRCL H **
|
|
** S: 01 03 2*lenth DATA0-N CRCL H **
|
|
*****************************************/
|
|
void MODBUS_MASTER_F03_Rx(void)
|
|
{
|
|
BYTE2 crc16;
|
|
uint8_t len;
|
|
|
|
len = modbusBuf[2];
|
|
|
|
//CRC判断
|
|
crc16 = CRC16_Cal(modbusBuf, len+3);
|
|
if( (modbusBuf[len+4] == crc16.b8[1]) && (modbusBuf[len+3] == crc16.b8[0]) )
|
|
{
|
|
modbusCurF03RxFlag = 1;
|
|
MODBUS_UART_IT_RX_DISABLE;
|
|
}
|
|
#if Addr_SetAuto
|
|
else
|
|
{
|
|
/*若轮询大于当前在线个数的地址时有不符合的乱码,记录为启动自动分配条件*/
|
|
if((paraMem.addr_FREE_Flg == 0) && (modbusCurStatus == 1) && (modbusCurDev > 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;i<len;)//高字节在前
|
|
{
|
|
*data = modbusBuf[4+i];
|
|
data++;
|
|
*data = modbusBuf[3+i];
|
|
data++;
|
|
i++;
|
|
i++;
|
|
}
|
|
|
|
//更新该从机对应的canMem结构体,方便进行并机总值的计算
|
|
if(canMem[scr_RdData_Index].com != 0)
|
|
{
|
|
canMem[scr_RdData_Index].status_byte1 = bmsMem_slave.bStatus1;
|
|
canMem[scr_RdData_Index].status_byte2 = bmsMem_slave.bStatus2;
|
|
canMem[scr_RdData_Index].status_byte3 = bmsMem_slave.bStatus3;
|
|
canMem[scr_RdData_Index].status_byte4 = bmsMem_slave.temperaStatus;
|
|
}
|
|
|
|
modbusCurF03RxFlag = 0;
|
|
}
|
|
else
|
|
{
|
|
data = (uint8_t *)&bmsMem_slave.vCell[0];
|
|
|
|
for(i=0;i<92;i++)//清空结构体
|
|
{
|
|
*data = 0;
|
|
data++;
|
|
}
|
|
}
|
|
}
|
|
//主机发送对固定从机的读取
|
|
if(modbusCurSta == 0)
|
|
{
|
|
modbusBufIndex = 0;
|
|
modbusBuf[0] = scr_RdData_Index;
|
|
modbusBuf[1] = 0x03;
|
|
modbusBuf[2] = 0x00;
|
|
modbusBuf[3] = 0x00;
|
|
modbusBuf[4] = 0x00;
|
|
modbusBuf[5] = 0x2e;
|
|
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;
|
|
}
|
|
}
|
|
|
|
//主机持续向指定从机写地址,收到写入成功的回复后,才退出
|
|
void MODBUS_Screen_WrSlaveAddr_Tx(void)
|
|
{
|
|
uint8_t tmp[2];
|
|
|
|
BYTE2 crc16;
|
|
|
|
if(modbusCurStatus != 4)
|
|
{
|
|
modbusCurStatus = 4;
|
|
MODBUS_Init();
|
|
}
|
|
|
|
//主机接收上一帧的数据并处理
|
|
if(modbusCurSta == 1)
|
|
{
|
|
modbusCurSta = 0;
|
|
|
|
if(modbusCurF10RxFlag == 1) //收到数据且CRC校验正确
|
|
{
|
|
modbusCurF10RxFlag = 0;
|
|
sdwa_WrAddr_Flg = 2;
|
|
}
|
|
else
|
|
{
|
|
sdwa_WrAddr_Failcount++;
|
|
if(sdwa_WrAddr_Failcount>3)
|
|
{
|
|
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<len;)//高字节在前
|
|
{
|
|
*data = modbusBuf[4+i];
|
|
data++;
|
|
*data = modbusBuf[3+i];
|
|
data++;
|
|
i++;
|
|
i++;
|
|
}
|
|
|
|
//更新该从机对应的canMem结构体,方便进行并机总值的计算
|
|
if(canMem[ConfigData_Index].com != 0)
|
|
{
|
|
canMem[ConfigData_Index].status_byte1 = bmsMem_slave.bStatus1;
|
|
canMem[ConfigData_Index].status_byte2 = bmsMem_slave.bStatus2;
|
|
canMem[ConfigData_Index].status_byte3 = bmsMem_slave.bStatus3;
|
|
canMem[ConfigData_Index].status_byte4 = bmsMem_slave.temperaStatus;
|
|
}
|
|
|
|
modbusCurF03RxFlag = 0;
|
|
}
|
|
else
|
|
{
|
|
Online_Flag = 0; //下次上位机询问,不回复
|
|
|
|
data = (uint8_t *)&bmsMem_slave.vCell[0];
|
|
|
|
for(i=0;i<92;i++)//清空结构体
|
|
{
|
|
*data = 0;
|
|
data++;
|
|
}
|
|
}
|
|
}
|
|
//主机发送对固定从机的读取
|
|
if(modbusCurSta == 0)
|
|
{
|
|
modbusBufIndex = 0;
|
|
modbusBuf[0] = ConfigData_Index;
|
|
modbusBuf[1] = 0x03;
|
|
modbusBuf[2] = 0x00;
|
|
modbusBuf[3] = 0x00;
|
|
modbusBuf[4] = 0x00;
|
|
modbusBuf[5] = 0x2e;
|
|
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;
|
|
}
|
|
}
|
|
|