1054 lines
22 KiB
C
1054 lines
22 KiB
C
/**
|
|
******************************************************************************
|
|
* @file gpio.c
|
|
* @author Jerry Cai
|
|
* @version V2.1
|
|
* @date 19-April-2022
|
|
* @brief gpio program body.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "stm32f10x.h"
|
|
#include "global.h"
|
|
|
|
//GPIOA
|
|
//#define PIN_VPRO GPIO_Pin_6 //AFE -EEPROM烧写电源控制
|
|
#define PIN_DO GPIO_Pin_6 //DO:输出继电器启动信号,高电平启动
|
|
#define PIN_SHIP GPIO_Pin_7 //AFE -仓运模式控制
|
|
#define PIN_LED_RUN GPIO_Pin_15 //LED -运行状态指示灯
|
|
|
|
//GPIOB
|
|
#define PIN_LED2 GPIO_Pin_8 //LED2-电量指示
|
|
#define PIN_LED3 GPIO_Pin_5 //LED3-电量指示
|
|
#define PIN_LED4 GPIO_Pin_4 //LED4-电量指示
|
|
#define PIN_LED_ALARM GPIO_Pin_3 //LED -报警和保护指示
|
|
#define PIN_CTLC GPIO_Pin_0 //DI/急停
|
|
#define PIN_AFE_ALARM GPIO_Pin_1 //AFE -采集模式下,正常输出高电平,在ALARM事件发生时,输出1ms低电平脉冲, 软件这里暂时还没有处理
|
|
|
|
//GPIOC
|
|
#define PIN_LED1 GPIO_Pin_6 //LED1-电量指示
|
|
#define PIN_KEY GPIO_Pin_0 //按键 电平检测管脚
|
|
//#define PIN_BAL_OUT GPIO_Pin_1 //主动均衡板启动信号,高电平启动
|
|
#define PIN_LED_POWER GPIO_Pin_3 //LED电源指示灯
|
|
#define PIN_PCHG_CTRL GPIO_Pin_5 //预充控制脚
|
|
#define PIN_ADDR_RANK GPIO_Pin_7 //自动分配地址输入脚IO3,当输入低电平时,说明自身是从机
|
|
#define PIN_ADDR_IN GPIO_Pin_8 //自动分配地址输入脚IO1
|
|
#define PIN_ADDR_OUT GPIO_Pin_9 //自动分配地址输出脚IO2
|
|
#define PIN_POWER GPIO_Pin_13 //电源维持控制管脚
|
|
|
|
|
|
uint8_t balancing;
|
|
uint16_t balCount;
|
|
|
|
uint8_t DIMoniCount;
|
|
uint8_t DIFlag;
|
|
|
|
uint8_t PCHG_startFlag; //开机预充标志 0:没执行 1:已完成
|
|
uint8_t PCHG_startCnt; //延时计数
|
|
|
|
uint8_t PCHG_Flag; //放电MOS开启前开启预充的标志 1:执行 2:完成可以打开放电MOS 0:不用预充
|
|
uint8_t PCHG_Cnt; //延时计数
|
|
|
|
uint8_t TSC_Flag; //AFE短路发生后,判断是否是真短路的标志 [=>关闭充放MOS、预充]
|
|
uint8_t tscTimeCount; //AFE短路发生后,若第一时间检测的负载电压值<4V,显示“真短路”
|
|
|
|
|
|
uint8_t pchgTimeCount; //AFE短路结束后,单次预充时间,到点后会关闭预充检测负载电压
|
|
|
|
uint8_t TSC_detectFlag; //不开启预充时,AFE短路发生后,判断是否是真短路的标志 0;不执行 1:要执行 2:执行完成,回到正常 0xAA:检测到真短路
|
|
|
|
uint16_t ADDR_Moni_Count; //自动分配地址前,因为短接脚而该改变自身的地址 每次10ms
|
|
|
|
uint8_t ClearArray_Flag; //在定时器函数中,执行清空队列标志的标志
|
|
|
|
|
|
/*6.3.L非自锁按键-长按*/
|
|
#define ON_WAIT 100 //100*10ms=1s
|
|
#define RST_WAIT 100 //100*10ms=1s
|
|
#define OFF_WAIT 300 //300*10ms=3s
|
|
|
|
uint8_t ON_confirm_flg; //程序运行后,先确认开机 1:按键按下2s确认开机 2:确认开机后按键松开,可以监测下一次按键按下以判断复位和重启
|
|
uint8_t RST_confirm_flg; //按钮按下后,通过时长判断执行复位
|
|
uint8_t OFF_confirm_flg; //按钮按下后,通过时长判断确认断开电源维持,等按钮松开就关机
|
|
|
|
uint8_t key_state; //按键状态 0:未按下, 1:按下
|
|
uint8_t power_state; //电源脚输出 0:应输出低,1:应输出高
|
|
|
|
uint8_t led_toggle_step; //执行复位时,LED灯同步闪烁
|
|
/*6.3.L非自锁按键*/
|
|
|
|
|
|
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
|
|
{
|
|
uint32_t odr;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_GPIO_PIN(GPIO_Pin));
|
|
|
|
/* get current Ouput Data Register value */
|
|
odr = GPIOx->ODR;
|
|
|
|
/* Set selected pins that were at low level, and reset ones that were high */
|
|
GPIOx->BSRR = ((odr & GPIO_Pin) << 16u) | (~odr & GPIO_Pin);
|
|
}
|
|
|
|
//LED
|
|
//---------------------------------------------
|
|
void LED_RUN_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOA, PIN_LED_RUN);
|
|
}
|
|
|
|
void LED_RUN_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOA, PIN_LED_RUN);
|
|
}
|
|
|
|
void LED_ALARM_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOB, PIN_LED_ALARM);
|
|
}
|
|
|
|
void LED_ALARM_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOB, PIN_LED_ALARM);
|
|
}
|
|
|
|
void LED1_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOC, PIN_LED1);
|
|
}
|
|
|
|
void LED1_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOC, PIN_LED1);
|
|
}
|
|
|
|
void LED2_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOB, PIN_LED2);
|
|
}
|
|
|
|
void LED2_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOB, PIN_LED2);
|
|
}
|
|
|
|
void LED3_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOB, PIN_LED3);
|
|
}
|
|
|
|
void LED3_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOB, PIN_LED3);
|
|
}
|
|
|
|
void LED4_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOB, PIN_LED4);
|
|
}
|
|
|
|
void LED4_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOB, PIN_LED4);
|
|
}
|
|
|
|
void LED_RUN_Toggle(void)
|
|
{
|
|
HAL_GPIO_TogglePin(GPIOA, PIN_LED_RUN);
|
|
}
|
|
|
|
void LED_ALARM_Toggle(void)
|
|
{
|
|
HAL_GPIO_TogglePin(GPIOB, PIN_LED_ALARM);
|
|
}
|
|
|
|
void LED_ALL_ON(void)
|
|
{
|
|
LED_RUN_On();
|
|
LED_ALARM_On();
|
|
LED1_On();
|
|
LED2_On();
|
|
LED3_On();
|
|
LED4_On();
|
|
}
|
|
|
|
void LED_ALL_OFF(void)
|
|
{
|
|
LED_RUN_Off();
|
|
LED_ALARM_Off();
|
|
LED1_Off();
|
|
LED2_Off();
|
|
LED3_Off();
|
|
LED4_Off();
|
|
}
|
|
|
|
void LED_ALL_Toggle(void)
|
|
{
|
|
HAL_GPIO_TogglePin(GPIOA, PIN_LED_RUN);
|
|
HAL_GPIO_TogglePin(GPIOB, PIN_LED_ALARM);
|
|
HAL_GPIO_TogglePin(GPIOC, PIN_LED1);
|
|
HAL_GPIO_TogglePin(GPIOB, PIN_LED2);
|
|
HAL_GPIO_TogglePin(GPIOB, PIN_LED3);
|
|
HAL_GPIO_TogglePin(GPIOB, PIN_LED4);
|
|
}
|
|
|
|
void LED_RST_Toggle(void)
|
|
{
|
|
led_toggle_step++;
|
|
|
|
if(led_toggle_step == 1) //全亮
|
|
{
|
|
LED_ALL_ON();
|
|
}
|
|
else if(led_toggle_step <= 9) //闪烁:1亮-2灭-3亮-4灭-5亮-6灭-7亮-8灭-9亮
|
|
{
|
|
LED_ALL_Toggle();
|
|
}
|
|
|
|
#if Key_PressRST
|
|
else if(led_toggle_step == 6) //执行复位,保持常亮
|
|
{
|
|
uf_I2C1_Init(); //IIC复位
|
|
uf_SPI2_Init(); //SPI复位
|
|
uf_CAN1_Init(); //CAN复位
|
|
MODBUS_Init(); //485通信复位
|
|
MODBUS1_Init();
|
|
|
|
/*三选一模块*/
|
|
#if BLE_Conn
|
|
BLE_Init(); //蓝牙通信复位
|
|
BLE_Reset(); //蓝牙模块复位
|
|
#endif
|
|
#if WIFI_Conn
|
|
WIFI_Init(); //WIFI通信复位
|
|
WIFI_Reset(); //WIFI模块复位
|
|
#endif
|
|
#if LTE_Conn
|
|
LTE_4G_Init(); //4G通信复位
|
|
LTE_4G_Reset(); //4G模块复位
|
|
#endif
|
|
|
|
bmsMem.bStatus1 = 0; //保护/报警/故障标志复位
|
|
bmsMem.bStatus2 = 0;
|
|
bmsMem.bStatus3 = 0;
|
|
bmsMem.temperaStatus = 0;
|
|
bmsMem.balanceStatus = 0;
|
|
bmsMem.packStatus = 0;
|
|
|
|
uf_IWDG_Init(6,1250); //看门狗复位
|
|
}
|
|
#endif
|
|
|
|
else if(led_toggle_step >= 13) //结束
|
|
{
|
|
led_toggle_step = 0;
|
|
RST_confirm_flg = 2;
|
|
}
|
|
}
|
|
//--------------------------------------------
|
|
|
|
//模块已开机,存于Flash
|
|
#define POWER_FLAG 0x08020800
|
|
uint8_t power_old; //如果是正常工作时重启,保持开机
|
|
void POWER_Check(void)
|
|
{
|
|
uint32_t tmpRd;
|
|
|
|
//读取标志位
|
|
FLASH_RdWord(POWER_FLAG, &tmpRd, 1); //4/4=1
|
|
if(tmpRd == 0x20260325)
|
|
{
|
|
power_old = 1;
|
|
}
|
|
}
|
|
|
|
void POWER_On(void)
|
|
{
|
|
GPIO_SetBits(GPIOC, PIN_POWER);
|
|
GPIO_SetBits(GPIOC, PIN_LED_POWER); //电源指示灯亮
|
|
}
|
|
|
|
void POWER_Off(void)
|
|
{
|
|
GPIO_ResetBits(GPIOC, PIN_POWER);
|
|
GPIO_ResetBits(GPIOC, PIN_LED_POWER); //电源指示灯灭
|
|
}
|
|
|
|
void POWER_Ctrl(void)
|
|
{
|
|
if(power_old == 1) //重启,所以直接维持输出高
|
|
{
|
|
power_state = 1;
|
|
}
|
|
else if(power_old == 2) //检测到开机,记录到Flash
|
|
{
|
|
uint32_t tmpRd = 0x20260325;
|
|
|
|
//写入标志位
|
|
FLASH_WrData(POWER_FLAG, (uint16_t *)&tmpRd, 2); //4/2=2
|
|
delay_ms(2);
|
|
|
|
power_old = 3;
|
|
}
|
|
else if(power_old == 4) //检测到关机,记录到Flash
|
|
{
|
|
uint32_t tmpRd = 0xFFFFFFFF;
|
|
|
|
//写入标志位
|
|
FLASH_WrData(POWER_FLAG, (uint16_t *)&tmpRd, 2); //4/2=2
|
|
delay_ms(2);
|
|
|
|
power_old = 5;
|
|
}
|
|
|
|
if(power_state == 1) //正常维持输出高
|
|
{
|
|
POWER_On();
|
|
}
|
|
else //判定按钮长按后,输出置低,等按钮松开就断电
|
|
{
|
|
POWER_Off();
|
|
}
|
|
}
|
|
|
|
//输入电平检测
|
|
uint8_t KEY_IN(void)
|
|
{
|
|
uint8_t status;
|
|
status = GPIO_ReadInputDataBit(GPIOC,PIN_KEY);
|
|
|
|
return status;
|
|
}
|
|
|
|
//按键状态监测函数
|
|
uint16_t KEY_INH_Count;
|
|
uint16_t KEY_INL_Count;
|
|
void KEY_TIM_Moni(void)
|
|
{
|
|
key_state = KEY_IN();
|
|
|
|
if(power_old == 1)
|
|
{
|
|
ON_confirm_flg = 2;
|
|
}
|
|
|
|
//开机后,延时2s确认保持开机
|
|
if(ON_confirm_flg == 0)
|
|
{
|
|
if(key_state == 1) //输入高电平
|
|
{
|
|
KEY_INH_Count++;
|
|
if(KEY_INH_Count > ON_WAIT)
|
|
{
|
|
KEY_INH_Count = 0;
|
|
ON_confirm_flg = 1;
|
|
|
|
power_old = 2; //写入开机
|
|
power_state = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KEY_INH_Count = 0;
|
|
}
|
|
}
|
|
//确认开机后,要监测到按键松开才能进行对下一次按键摁下监测
|
|
else if(ON_confirm_flg == 1)
|
|
{
|
|
if(key_state == 0) //输入低电平
|
|
{
|
|
KEY_INL_Count++;
|
|
if(KEY_INL_Count > 3) //防抖动
|
|
{
|
|
KEY_INL_Count = 0;
|
|
ON_confirm_flg = 2;
|
|
|
|
RST_confirm_flg = 0;
|
|
OFF_confirm_flg = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KEY_INL_Count = 0;
|
|
}
|
|
}
|
|
//确认保持开机后,监测按键下一次按下的时长
|
|
else
|
|
{
|
|
if(OFF_confirm_flg == 0)
|
|
{
|
|
if(key_state == 1) //输入高电平
|
|
{
|
|
KEY_INL_Count = 0;
|
|
|
|
KEY_INH_Count++;
|
|
if((KEY_INH_Count > OFF_WAIT) && (OFF_confirm_flg == 0)) //按下3s,执行关机操作
|
|
{
|
|
KEY_INH_Count = 0;
|
|
RST_confirm_flg = 0;
|
|
OFF_confirm_flg = 1;
|
|
|
|
power_old = 4; //写入关机
|
|
power_state = 0;
|
|
}
|
|
else if((KEY_INH_Count > RST_WAIT) && (RST_confirm_flg == 0)) //按下1s,执行复位操作
|
|
{
|
|
RST_confirm_flg = 1;
|
|
led_toggle_step = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KEY_INH_Count = 0;
|
|
|
|
if(RST_confirm_flg == 2) //复位完成后,在按键松开后清零标志
|
|
{
|
|
KEY_INL_Count++;
|
|
if(KEY_INL_Count > 3) //防抖动
|
|
{
|
|
KEY_INL_Count = 0;
|
|
RST_confirm_flg = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////ON: ≥100uS
|
|
//void BAL_On(void)
|
|
//{
|
|
// GPIO_ResetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(200);
|
|
// GPIO_SetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(200);
|
|
// GPIO_ResetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(200);
|
|
//}
|
|
|
|
////OFF: 20-50uS
|
|
//void BAL_Off(void)
|
|
//{
|
|
// GPIO_ResetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(20);
|
|
// GPIO_SetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(20);
|
|
// GPIO_ResetBits(GPIOC, PIN_BAL_OUT);
|
|
// delay_us(20);
|
|
//}
|
|
|
|
//1S
|
|
void MCU_BalanceProcess(void)
|
|
{
|
|
//高温关闭均衡
|
|
if( ((bmsMem.bStatus2 & 0x0A) !=0) || ((bmsMem.temperaStatus & 0x03) !=0) )
|
|
{
|
|
if((bmsMem.balanceStatus & 0x01) != 0)
|
|
{
|
|
// BAL_Off();
|
|
bmsMem.balanceStatus &= 0xfffe;
|
|
}
|
|
|
|
balancing = 0;
|
|
}
|
|
else
|
|
{
|
|
if( (cellVoltageMax - cellVoltageMin) > paraMem.act_bal_startV)
|
|
{
|
|
if((bmsMem.balanceStatus & 0x01) == 0)
|
|
{
|
|
// BAL_On();
|
|
// bmsMem.balanceStatus |= 0x01; //BAL status set to 1
|
|
}
|
|
|
|
balancing = 1;
|
|
balCount = 0;
|
|
}
|
|
else if( (cellVoltageMax - cellVoltageMin) < paraMem.act_bal_stopV)
|
|
{
|
|
balCount++;
|
|
if(balCount >= paraMem.act_bal_stopT)
|
|
{
|
|
if((bmsMem.balanceStatus & 0x01) != 0)
|
|
{
|
|
// BAL_Off();
|
|
bmsMem.balanceStatus &= 0xfffe;
|
|
}
|
|
|
|
balancing = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DO_On(void) //DO控制继电器开启
|
|
{
|
|
GPIO_SetBits(GPIOA, PIN_DO);
|
|
}
|
|
|
|
void DO_Off(void) //DO控制继电器关闭
|
|
{
|
|
GPIO_ResetBits(GPIOA, PIN_DO);
|
|
}
|
|
|
|
//void WARM_On(void) //加热开启
|
|
//{
|
|
// GPIO_SetBits(GPIOC, PIN_WARM);
|
|
//}
|
|
|
|
//void WARM_Off(void) //加热关闭
|
|
//{
|
|
// GPIO_ResetBits(GPIOC, PIN_WARM);
|
|
//}
|
|
|
|
////加热触发与控制
|
|
//uint8_t warm_flag; //加热启动标志
|
|
//uint8_t warm_count;
|
|
//uint8_t warmr_count;
|
|
//void WARM_Ctrl(void)
|
|
//{
|
|
// uint16_t utc = bmsMem.mcu_utc * 10 + 2731;
|
|
// uint16_t utcr = bmsMem.mcu_utcr * 10 + 2731;
|
|
//
|
|
// //加热触发
|
|
// if((bmsMem.bStatus1 & 0x0202) == 0) //触发总体/单体欠压,禁止加热
|
|
// {
|
|
// if((warm_flag == 0) && (bCHGING == 1))
|
|
// {
|
|
// if(TemperatureMin < utc)
|
|
// {
|
|
// warm_count++;
|
|
// if(warm_count > 3)
|
|
// {
|
|
// warm_flag = 1;
|
|
// warm_count = 0;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// warm_count = 0;
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// warm_flag = 0;
|
|
// warm_count = 0;
|
|
// warmr_count = 0;
|
|
// }
|
|
//
|
|
// //加热释放
|
|
// if(warm_flag == 1)
|
|
// {
|
|
// if(TemperatureMin > utcr+20) //比释放值高2度
|
|
// {
|
|
// warmr_count++;
|
|
// if(warmr_count > 3)
|
|
// {
|
|
// warm_flag = 0;
|
|
// warmr_count = 0;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// warmr_count = 0;
|
|
// }
|
|
// }
|
|
//
|
|
// //加热控制
|
|
// if(warm_flag == 1)
|
|
// {
|
|
// WARM_On();
|
|
// }
|
|
// else
|
|
// {
|
|
// WARM_Off();
|
|
// }
|
|
//}
|
|
|
|
void PCHG_On(void) //预充开启
|
|
{
|
|
GPIO_SetBits(GPIOC, PIN_PCHG_CTRL);
|
|
}
|
|
|
|
void PCHG_Off(void) //预充关闭
|
|
{
|
|
GPIO_ResetBits(GPIOC, PIN_PCHG_CTRL);
|
|
}
|
|
|
|
void PCHG_StartCtrl(void) //开机开启预充
|
|
{
|
|
//开始节点是1,结束是paraMem.pchg_startTime+1
|
|
PCHG_startCnt++;
|
|
|
|
//通过负载电压判断是否是真短路
|
|
if(PCHG_startCnt == 2) //此时已充了1s
|
|
{
|
|
PCHG_Off();
|
|
bmsMem.bStatus3 &= ~0x0004; //预充MOS关闭
|
|
|
|
delay_ms(2);
|
|
LOAD_VOL();
|
|
if(loadvol < paraMem.pchg_scVol*1000) //负载电压小于10V说明短路;如果是空载则≈电池电压
|
|
{
|
|
bmsMem.bStatus2 |= 0x0010; //显示“真短路保护”,不能继续预充
|
|
return;
|
|
}
|
|
}
|
|
|
|
//预充开启定时
|
|
if(PCHG_startCnt <= paraMem.pchg_startTime)
|
|
{
|
|
PCHG_On();
|
|
bmsMem.bStatus3 |= 0x0004; //预充MOS打开
|
|
bmsMem.bStatus3 |= 0x0020; //预充状态开启
|
|
}
|
|
else
|
|
{
|
|
PCHG_startFlag = 1;
|
|
PCHG_startCnt = 0;
|
|
|
|
PCHG_Off();
|
|
bmsMem.bStatus3 &= ~0x0004; //预充MOS关闭
|
|
bmsMem.bStatus3 &= ~0x0020; //预充状态关闭
|
|
|
|
delay_ms(2);
|
|
CTRL_On();
|
|
}
|
|
}
|
|
|
|
void PCHG_Ctrl(void) //开放电MOS前开启预充
|
|
{
|
|
//开始节点是1,结束是paraMem.pchg_startTime+1
|
|
PCHG_Cnt++;
|
|
|
|
//通过负载电压判断是否是真短路
|
|
if(PCHG_Cnt == 2) //此时已充了1s
|
|
{
|
|
PCHG_Off();
|
|
bmsMem.bStatus3 &= ~0x0004; //预充MOS关闭
|
|
|
|
delay_ms(2);
|
|
LOAD_VOL();
|
|
if(loadvol < paraMem.pchg_scVol*1000) //负载电压小于10V说明短路;如果是空载则≈电池电压
|
|
{
|
|
CTRL_Off();
|
|
bmsMem.bStatus2 |= 0x0010; //显示“真短路保护”,不能继续预充
|
|
return;
|
|
}
|
|
}
|
|
|
|
//预充开启定时
|
|
if(PCHG_Cnt <= paraMem.pchg_Time)
|
|
{
|
|
PCHG_On();
|
|
bmsMem.bStatus3 |= 0x0004; //预充MOS打开
|
|
bmsMem.bStatus3 |= 0x0020; //预充状态开启
|
|
}
|
|
else
|
|
{
|
|
PCHG_Flag = 2;
|
|
PCHG_Cnt = 0;
|
|
|
|
PCHG_Off();
|
|
bmsMem.bStatus3 &= ~0x0004; //预充MOS关闭
|
|
bmsMem.bStatus3 &= ~0x0020; //预充状态关闭
|
|
|
|
delay_ms(2);
|
|
CTRL_On();
|
|
}
|
|
}
|
|
|
|
//在触发浪涌短路时,执行真短路判定
|
|
void TSC_Detect(void)
|
|
{
|
|
/**正常情况下**/
|
|
if(TSC_detectFlag == 1)
|
|
{
|
|
CTRL_Off();
|
|
|
|
delay_ms(2);
|
|
|
|
LOAD_VOL();
|
|
if(loadvol < paraMem.sp_scVol*1000) //认为是短路情况,显示“真短路保护”
|
|
{
|
|
TSC_detectFlag = 0xAA;
|
|
}
|
|
else //检测正常后,回到正常控制
|
|
{
|
|
CTRL_On();
|
|
TSC_detectFlag = 2;
|
|
}
|
|
}
|
|
/**遇到[真短路]的情况,控制充放MOS关闭不变**/
|
|
else if(TSC_detectFlag == 0xAA)
|
|
{
|
|
CTRL_Off();
|
|
bmsMem.bStatus2 |= 0x0010; //显示“真短路保护”
|
|
}
|
|
}
|
|
|
|
#if Addr_SetAuto
|
|
//输入电平检测
|
|
uint8_t IO3_IN(void)
|
|
{
|
|
uint8_t status;
|
|
status = GPIO_ReadInputDataBit(GPIOC,PIN_ADDR_RANK);
|
|
|
|
return status;
|
|
}
|
|
|
|
//输出置高,让下一个从机进入待分配状态
|
|
void IO2_OUTSet(void)
|
|
{
|
|
GPIO_SetBits(GPIOC, PIN_ADDR_OUT);
|
|
}
|
|
|
|
//输出置低,转回正常状态
|
|
void IO2_OUTReset(void)
|
|
{
|
|
GPIO_ResetBits(GPIOC, PIN_ADDR_OUT);
|
|
}
|
|
|
|
//输入电平检测
|
|
uint8_t IO1_IN(void)
|
|
{
|
|
uint8_t status;
|
|
status = GPIO_ReadInputDataBit(GPIOC,PIN_ADDR_IN);
|
|
|
|
return status;
|
|
}
|
|
|
|
//根据IO1的不同电平,进行地址修改操作
|
|
uint8_t IO1_INH_Count;
|
|
uint8_t IO1_INL_Count;
|
|
void ADDR_Assign_Moni(void)
|
|
{
|
|
if(((bmsMem.E2_485Addr >=2) && (bmsMem.E2_485Addr <= AddrMax+1))) //地址为实地址的从机 and 特定虚地址的从机(避免分配时出现意外)
|
|
{
|
|
if( IO1_IN() == 1 ) //输入高电平
|
|
{
|
|
if(IO1_INH_Count < 10)
|
|
{
|
|
IO1_INH_Count++; //等待100ms
|
|
}
|
|
else
|
|
{
|
|
bmsMem.E2_485Addr = 99; //修改为虚地址
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IO1_INH_Count = 0;
|
|
}
|
|
}
|
|
else if(bmsMem.E2_485Addr > AddrMax+1)//地址本身就为虚地址的从机
|
|
{
|
|
if( IO1_IN() == 0 ) //输入低电平
|
|
{
|
|
if(IO1_INL_Count < 10)
|
|
{
|
|
IO1_INL_Count++; //等待100ms
|
|
}
|
|
else
|
|
{
|
|
bmsMem.E2_485Addr = AddrMax+1; //修改为特定的虚地址
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IO1_INL_Count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//根据IO3的不同电平,确定自身是主机/从机
|
|
void ADDR_Rank_Moni(void)
|
|
{
|
|
//地址原来是1,过1s后设2
|
|
if(bmsMem.E2_485Addr == 1)
|
|
{
|
|
if(assignAddr_State != 1) //进行分配时不动作
|
|
{
|
|
if( IO3_IN() == 0 ) //短接
|
|
{
|
|
ADDR_Moni_Count++;
|
|
if(ADDR_Moni_Count > 100)
|
|
{
|
|
bmsMem.E2_485Addr = 2;
|
|
bmsMem.write_Addr = bmsMem.E2_485Addr; //用于之后写入EEPROM
|
|
scr_RdData_Index = bmsMem.E2_485Addr;
|
|
|
|
ADDR_Moni_Count = 0;
|
|
MODBUS_Init();
|
|
|
|
bmsMem.can_ArrayIndex = 0;
|
|
ClearArray_Flag = 1; //用于之后写入EEPROM
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ADDR_Moni_Count = 0;
|
|
}
|
|
}
|
|
}
|
|
//地址原不是1,过5s后设1(可能只是调线子要有容错)
|
|
else
|
|
{
|
|
if( IO3_IN() != 0 ) //没有短接
|
|
{
|
|
ADDR_Moni_Count++;
|
|
if(ADDR_Moni_Count > 500)
|
|
{
|
|
assignAddr_State = 0;
|
|
assignAddr_relay = 2;//变1后也有可能变回去
|
|
|
|
bmsMem.E2_485Addr = 1;
|
|
bmsMem.write_Addr = bmsMem.E2_485Addr; //用于之后写入EEPROM
|
|
scr_RdData_Index = bmsMem.E2_485Addr;
|
|
|
|
ADDR_Moni_Count = 0;
|
|
MODBUS_Init();
|
|
|
|
bmsMem.can_ArrayIndex = 0;
|
|
ClearArray_Flag = 1; //用于之后写入EEPROM
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ADDR_Moni_Count = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//IO初始化
|
|
void uf_GPIO_Init(void)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
|
|
|
|
//PB3,PB4,PA15用作普通IO时需要禁用JTAG保留SWD, 并REMAP
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
|
|
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
|
|
|
|
//LED
|
|
GPIO_InitStructure.GPIO_Pin = PIN_LED2 | PIN_LED3 | PIN_LED4 | PIN_LED_ALARM;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
|
|
|
GPIO_InitStructure.GPIO_Pin = PIN_LED1;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
GPIO_InitStructure.GPIO_Pin = PIN_LED_RUN;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
#if Key_PressLong
|
|
//上电后灯全灭,之后全亮
|
|
GPIO_ResetBits(GPIOA, PIN_LED_RUN);
|
|
GPIO_ResetBits(GPIOC, PIN_LED1);
|
|
GPIO_ResetBits(GPIOB, PIN_LED2);
|
|
GPIO_ResetBits(GPIOB, PIN_LED3);
|
|
GPIO_ResetBits(GPIOB, PIN_LED4);
|
|
GPIO_ResetBits(GPIOB, PIN_LED_ALARM);
|
|
#else
|
|
//上电后灯全亮
|
|
GPIO_SetBits(GPIOA, PIN_LED_RUN);
|
|
GPIO_SetBits(GPIOC, PIN_LED1);
|
|
GPIO_SetBits(GPIOB, PIN_LED2);
|
|
GPIO_SetBits(GPIOB, PIN_LED3);
|
|
GPIO_SetBits(GPIOB, PIN_LED4);
|
|
GPIO_SetBits(GPIOB, PIN_LED_ALARM);
|
|
#endif
|
|
|
|
|
|
//PCHG预充控制
|
|
GPIO_InitStructure.GPIO_Pin = PIN_PCHG_CTRL;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//DO继电器控制
|
|
GPIO_InitStructure.GPIO_Pin = PIN_DO;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
// //BAL主动均衡器控制
|
|
// GPIO_InitStructure.GPIO_Pin = PIN_BAL_OUT;
|
|
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
// GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//控制引脚初始电平
|
|
GPIO_ResetBits(GPIOC, PIN_PCHG_CTRL); //预充控制脚,默认关闭状态
|
|
GPIO_ResetBits(GPIOA, PIN_DO); //DO继电器控制脚,默认关闭状态
|
|
// GPIO_ResetBits(GPIOC, PIN_BAL_OUT); //主动均衡控制脚,默认关闭状态
|
|
|
|
|
|
#if DO2_Warm
|
|
//加热控制
|
|
GPIO_InitStructure.GPIO_Pin = PIN_WARM;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
GPIO_ResetBits(GPIOC, PIN_WARM); //加热控制脚,默认关闭状态
|
|
#endif
|
|
|
|
|
|
#if Key_PressLong
|
|
//按键电平检测
|
|
GPIO_InitStructure.GPIO_Pin = PIN_KEY;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//电源维持控制
|
|
GPIO_InitStructure.GPIO_Pin = PIN_POWER;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//电源指示灯
|
|
GPIO_InitStructure.GPIO_Pin = PIN_LED_POWER;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
if(power_old == 1)
|
|
{
|
|
GPIO_SetBits(GPIOC, PIN_POWER); //电源维持控制脚,置高
|
|
GPIO_SetBits(GPIOC, PIN_LED_POWER); //电源指示灯亮
|
|
}
|
|
else
|
|
{
|
|
GPIO_ResetBits(GPIOC, PIN_POWER); //电源维持控制脚,开机后默认置低
|
|
GPIO_ResetBits(GPIOC, PIN_LED_POWER); //电源指示灯先不亮
|
|
}
|
|
#else
|
|
//电源指示灯
|
|
GPIO_InitStructure.GPIO_Pin = PIN_LED_POWER;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
GPIO_SetBits(GPIOC, PIN_LED_POWER); //电源指示灯直接亮
|
|
#endif
|
|
|
|
|
|
#if Addr_SetAuto
|
|
//ADDR_IN IO1
|
|
GPIO_InitStructure.GPIO_Pin = PIN_ADDR_IN;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//ADDR_OUT IO2
|
|
GPIO_InitStructure.GPIO_Pin = PIN_ADDR_OUT;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//ADDR_RANK IO3
|
|
GPIO_InitStructure.GPIO_Pin = PIN_ADDR_RANK;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
//地址分配引脚初始电平
|
|
GPIO_ResetBits(GPIOC, PIN_ADDR_OUT); //初始化时所有OUT引脚置低
|
|
#endif
|
|
|
|
|
|
//AFE-ALARM
|
|
GPIO_InitStructure.GPIO_Pin = PIN_AFE_ALARM;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
|
|
|
//AFE- VPRO/SHIP
|
|
GPIO_InitStructure.GPIO_Pin = PIN_SHIP;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
//AFE-CTL(急停控制)
|
|
GPIO_InitStructure.GPIO_Pin = PIN_CTLC;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
|
|
|
//AFE引脚初始电平
|
|
GPIO_SetBits(GPIOA, PIN_SHIP); //初始置高,表示退出仓运模式
|
|
|
|
#if Key_PressLong
|
|
if(power_old == 1)
|
|
{
|
|
GPIO_SetBits(GPIOB, PIN_CTLC);//因为是重启,初始置高,不控制MOS
|
|
PCHG_startFlag = 1; //也不执行开机预充
|
|
}
|
|
else
|
|
{
|
|
GPIO_ResetBits(GPIOB, PIN_CTLC);//初始置低,控制MOS全关
|
|
}
|
|
#else
|
|
GPIO_ResetBits(GPIOB, PIN_CTLC);//初始置低,控制MOS全关
|
|
#endif
|
|
|
|
|
|
CHG_LIMIT_Init();
|
|
}
|
|
|
|
|
|
//AFE_ALARM 外部EXTI中断配置
|
|
void uf_EXTI_Init(void)
|
|
{
|
|
// EXTI_InitTypeDef EXTI_InitStructure;
|
|
// NVIC_InitTypeDef NVIC_InitStructure;
|
|
|
|
// //BKP_TamperPinCmd(DISABLE);
|
|
|
|
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //外部中断,需要使能AFIO时钟
|
|
|
|
// GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
|
|
// EXTI_InitStructure.EXTI_Line=EXTI_Line9;
|
|
// EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
|
// EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿 触发
|
|
// EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
|
// EXTI_Init(&EXTI_InitStructure);
|
|
|
|
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
|
|
|
// NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
|
|
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
|
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
|
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
|
// NVIC_Init(&NVIC_InitStructure);
|
|
}
|
|
|
|
|
|
////用定时器还是用外部中断去读数据,纠结中...
|
|
////用外部中断考虑外部硬件连接有问题会导致读取不到数据
|
|
//void EXTI9_5_IRQHandler(void)
|
|
//{
|
|
// bAlarmFlag = 1;
|
|
// EXTI_ClearITPendingBit(EXTI_Line9); //清除EXTI0线路挂起位
|
|
//}
|
|
|