794 lines
20 KiB
C
794 lines
20 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 "rtc.h"
|
||
#include "global.h"
|
||
|
||
|
||
#define sleepEnd 60*(paraMem.sleep_min_disable&0x7FFF) //休眠1等待时长min,单位1s
|
||
#define sleep2End 60*(paraMem.sleep2_min_disable&0x7FFF) //休眠2等待时长min,单位1s
|
||
#define sleep2Vol paraMem.sleep2_vol //休眠方案2对应休眠电压,单位1mV
|
||
#define uvoffEnd 300 //强制欠压复位等待时长5min,单位1s
|
||
#define ocvEnd 60*(paraMem.ocv_min_disable&0x7FFF) //开路电压校准等待时长min,单位1s
|
||
#define fcccaliEnd 60*(paraMem.cali_min_disable&0x7FFF) //校准满充容量等待时长min,单位1s
|
||
|
||
_calendar_obj calendar; //时钟结构体
|
||
_calendar_obj calendar_WRITE;
|
||
_calendar_obj calendar_BACKUP;
|
||
|
||
uint8_t const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //平年的月修正数据表(基准是1900年1月1日),闰年其他相同只是1.2月要-1
|
||
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //平年的月份日期表.闰年的2月有29天
|
||
|
||
uint32_t timecount; //当前计时s
|
||
uint32_t oldtimecnt; //上一秒的计时s
|
||
|
||
uint8_t LSEErrFlag; //外部低频晶振有问题的标志,需要让屏幕的时间不再显示
|
||
uint8_t LSEErrCount;//时间不走的计数,满足了会把时间清零,标志置1
|
||
|
||
uint8_t sleep_flag; //休眠执行标志位
|
||
uint8_t sleep_enableflag;//开启休眠功能标志位
|
||
|
||
uint32_t sleeptimecount; //休眠1的计时起点s
|
||
uint32_t sleeptime; //休眠启动的倒计时数
|
||
|
||
uint32_t sleep2timecount; //休眠2的计时起点s
|
||
uint32_t sleep2time; //休眠2启动的倒计时数
|
||
|
||
uint32_t uvofftimecount; //关闭欠压功能后的计时起点
|
||
uint16_t uvofftime; //关闭欠压功能的倒计时数(会在屏幕显示故只设uint16)
|
||
|
||
uint32_t ocvtimecount; //开路电压法的计时起点
|
||
uint32_t ocvtime; //开路电压法的倒计时数
|
||
|
||
uint32_t fcc_Calitimecount; //校准满充容量的计时起点
|
||
uint32_t fcc_Calitime; //校准满充容量的倒计时数,超过则不可更新
|
||
|
||
uint8_t RTC_UpdateFlag; //起始点刷新标志位,用以刷新休眠和欠压强制复位的时间
|
||
|
||
|
||
/*
|
||
* 函数名:Is_Leap_Year
|
||
* 描述 :判断是否为闰年
|
||
月份 1 2 3 4 5 6 7 8 9 10 11 12
|
||
闰年 31 29 31 30 31 30 31 31 30 31 30 31
|
||
非闰年 31 28 31 30 31 30 31 31 30 31 30 31
|
||
* 输入 :年份
|
||
* 输出 :该年份是不是闰年.1,是.0,不是
|
||
* 调用 :
|
||
*/
|
||
uint8_t Is_Leap_Year(uint8_t yed)
|
||
{
|
||
uint8_t year;
|
||
|
||
year=2000+yed;
|
||
if(year%4==0) //必须能被4整除
|
||
{
|
||
if(year%100==0)
|
||
{
|
||
if(year%400==0)
|
||
return 1;//如果以00结尾,还要能被400整除
|
||
else
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数名:RTC_Get_Week
|
||
* 描述 :输入公历日期得到星期
|
||
* 输入 :公历年月日
|
||
* 输出 :星期号
|
||
* 调用 :
|
||
*/
|
||
uint8_t RTC_Get_Week(uint8_t ye, uint8_t month, uint8_t day)
|
||
{
|
||
uint16_t temp2;
|
||
uint16_t year;
|
||
uint8_t yearH,yearL;
|
||
|
||
ye=ye/16*10+ye%16; //十六进制转十进制
|
||
month=month/16*10+month%16;
|
||
day=day/16*10+day%16;
|
||
|
||
year=2000+ye; //(输入格式决定了必定是21世纪)
|
||
yearH=year/100;//用于判断是21世纪
|
||
yearL=year%100;//用于计算多的年数
|
||
|
||
//计算自1900年1月1日以来积累的多出来的天数
|
||
temp2=yearL+yearL/4; //平年365%7=1 闰年366%7=2 (自动把可以略去的7的倍数略掉了)(不用计算/100和/400)
|
||
temp2=temp2%7;
|
||
temp2=temp2+day+table_week[month-1];
|
||
|
||
// 21世纪需要加6(因为1900年1月1日是星期一,2000年1月1日是星期六)
|
||
if(yearH == 20)
|
||
{
|
||
temp2+=6;
|
||
}
|
||
|
||
//若日期是闰年的1.2月,星期修正要-1
|
||
if(yearL%4==0&&month<3)
|
||
{
|
||
temp2--;
|
||
}
|
||
|
||
return(temp2%7!=0)?temp2%7:7; //周一到周日=1~7
|
||
}
|
||
|
||
/*
|
||
* 函数名:RTC_Get
|
||
* 描述 :根据RTC计算器值计算当前年/月/日/时/分/秒/星期放入calendar结构体
|
||
* 输入 :无
|
||
* 输出 :0,成功;其他:错误代码
|
||
* 调用 :
|
||
*/
|
||
uint8_t RTC_Get(void)
|
||
{
|
||
static uint16_t daycnt=0;
|
||
uint32_t temp=0;
|
||
uint16_t temp1=0;
|
||
uint16_t tempppy;
|
||
|
||
timecount=RTC_GetCounter();
|
||
|
||
/*时分秒的计算*/
|
||
#if LTE_Conn
|
||
temp=(timecount+28800)/86400; //得到(总秒钟数对应的)天数 //在计算年月日时,中国时区-8h
|
||
#else
|
||
temp=timecount/86400; //得到(总秒钟数对应的)天数
|
||
#endif
|
||
|
||
if(daycnt!=temp)//超过一天了
|
||
{
|
||
daycnt=temp;
|
||
|
||
temp1=1970; //计算年份,从1970年开始
|
||
while(temp>=365)
|
||
{
|
||
if(Is_Leap_Year(temp1))//闰年-366
|
||
{
|
||
if(temp>=366)temp-=366;
|
||
else {temp1++;break;}
|
||
}
|
||
else temp-=365; //平年-365
|
||
temp1++;
|
||
}
|
||
tempppy=temp1;
|
||
|
||
temp1=0; //计算月份,最后的temp就是日期
|
||
while(temp>=28)
|
||
{
|
||
if(Is_Leap_Year(tempppy)&&temp1==1)//闰年且是2月份-29
|
||
{
|
||
if(temp>=29)temp-=29;
|
||
else break;
|
||
}
|
||
else
|
||
{
|
||
if(temp>=mon_table[temp1])temp-=mon_table[temp1];//其他都按表上来
|
||
else break;
|
||
}
|
||
temp1++;
|
||
}
|
||
|
||
tempppy=tempppy-2000;//得到年份
|
||
calendar.w_year =(tempppy/10)*16+(tempppy%10);
|
||
|
||
temp1=temp1+1; //得到月份
|
||
calendar.w_month=(temp1/10)*16+(temp1%10);
|
||
|
||
temp=temp+1; //得到日期
|
||
calendar.w_date=(temp/10)*16+(temp%10);
|
||
}
|
||
|
||
#if LTE_Conn
|
||
temp=(timecount+28800)%86400; //得到(去掉天数后 当天的)秒钟数 //在计算年月日时,中国时区-8h
|
||
#else
|
||
temp=timecount%86400; //得到(去掉天数后 当天的)秒钟数
|
||
#endif
|
||
|
||
tempppy=temp/3600; //得到小时
|
||
calendar.hour=(tempppy/10)*16+(tempppy%10);
|
||
|
||
tempppy=(temp%3600)/60;//得到分钟
|
||
calendar.min=(tempppy/10)*16+(tempppy%10);
|
||
|
||
tempppy=(temp%3600)%60;//得到秒钟
|
||
calendar.sec=(tempppy/10)*16+(tempppy%10);
|
||
calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期
|
||
|
||
|
||
/*判断合法*/
|
||
//在初始化后的第一次调用时,oldtimecnt还未赋值,此时将合法的当前时间写入EEPROM
|
||
if(oldtimecnt==0)
|
||
{
|
||
oldtimecnt = timecount;
|
||
|
||
if(calendar.w_month != 0)
|
||
{
|
||
uint8_t tmpRd[6];
|
||
tmpRd[0] = calendar.w_year;
|
||
tmpRd[1] = calendar.w_month;
|
||
tmpRd[2] = calendar.w_date;
|
||
tmpRd[3] = calendar.hour;
|
||
tmpRd[4] = calendar.min;
|
||
tmpRd[5] = calendar.sec;
|
||
|
||
EEPROM_WrMulByte(EE_TIME_BACKUP,tmpRd);
|
||
delay_ms(5);
|
||
}
|
||
}
|
||
|
||
//当时钟一直不走,判定有问题
|
||
if(timecount==oldtimecnt)
|
||
{
|
||
LSEErrCount++;
|
||
if(LSEErrCount>10)
|
||
{
|
||
LSEErrFlag=1;
|
||
sleep_Moni_Count=SLEEP_MON_CNT;
|
||
sleep2_Moni_Count = SLEEP2_MON_CNT;
|
||
|
||
calendar.w_year = 0; //结构体清零,方便此时的报警记录计入的时间为全0无效值
|
||
calendar.w_month = 0;
|
||
calendar.w_date = 0;
|
||
calendar.week = 0;
|
||
calendar.hour = 0;
|
||
calendar.min = 0;
|
||
calendar.sec = 0;
|
||
|
||
return 1; //数据异常,返回1
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LSEErrCount=0;
|
||
oldtimecnt = timecount;
|
||
}
|
||
|
||
|
||
//休眠功能-RTC,比较当前秒与开始秒的差别来定时
|
||
//方案1
|
||
if((sleep_flag == 0) && ((sleep_enableflag & 0x01) != 0)) //未进入休眠+启用休眠方案1
|
||
{
|
||
if(sleeptimecount != 0)
|
||
{
|
||
if(RTC_UpdateFlag == 1)
|
||
{
|
||
sleeptimecount = timecount - (sleepEnd - sleeptime); //更新起始点=当前时间-已消耗时间,此时剩余时间保持原值
|
||
}
|
||
else
|
||
{
|
||
sleeptime = sleepEnd - (timecount - sleeptimecount); //更新剩余时间
|
||
}
|
||
|
||
if((sleeptime == 0) || (sleeptime > sleepEnd))
|
||
{
|
||
sleep_flag = 1;
|
||
|
||
#if LTE_Conn
|
||
pre_sleep_flag = 2;
|
||
pre_sleep_waitCnt = 0;
|
||
sleepOn_time=timecount;
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sleeptimecount = timecount;
|
||
}
|
||
}
|
||
//方案2
|
||
if((sleep_flag == 0) && ((sleep_enableflag & 0x02) != 0)) //未进入休眠+启用休眠方案2
|
||
{
|
||
//满足休眠电压,无充电电流
|
||
if((cellVoltageMin <= sleep2Vol) && (bmsMem.packCurrent < 500))
|
||
{
|
||
if(sleep2timecount != 0)
|
||
{
|
||
if(RTC_UpdateFlag == 1)
|
||
{
|
||
sleep2timecount = timecount - (sleep2End - sleep2time); //更新起始点=当前时间-已消耗时间,此时剩余时间保持原值
|
||
}
|
||
else
|
||
{
|
||
sleep2time = sleep2End - (timecount - sleep2timecount); //更新剩余时间
|
||
}
|
||
|
||
if((sleep2time == 0) || (sleep2time > sleep2End))
|
||
{
|
||
#if Key_PressLong
|
||
power_old = 4; //写入关机
|
||
power_state = 0;
|
||
#else
|
||
sleep_flag = 1;
|
||
|
||
#if LTE_Conn
|
||
pre_sleep_flag = 2;
|
||
pre_sleep_waitCnt = 0;
|
||
sleepOn_time=timecount;
|
||
#endif
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sleep2timecount = timecount;
|
||
}
|
||
}
|
||
//否则停止计时
|
||
else
|
||
{
|
||
sleep2timecount = 0;
|
||
}
|
||
}
|
||
//不启用任何休眠方案
|
||
if(sleep_enableflag == 0)
|
||
{
|
||
sleep_flag = 0;
|
||
}
|
||
|
||
//屏幕手动关欠压启动了
|
||
if((bmsMem.balanceStatus & 0x20) != 0)
|
||
{
|
||
if(RTC_UpdateFlag == 1)
|
||
{
|
||
uvofftimecount = timecount - (uvoffEnd - uvofftime); //更新起始点=当前时间-已消耗时间,此时剩余时间保持原值
|
||
}
|
||
else
|
||
{
|
||
uvofftime = uvoffEnd - (timecount - uvofftimecount);
|
||
}
|
||
|
||
if((uvofftime == 0) || (uvofftime > uvoffEnd)) //防止反向溢出
|
||
{
|
||
bmsMem.balanceStatus &= 0xffdf;
|
||
}
|
||
}
|
||
|
||
//开路电压法校准SOC启动了
|
||
if(OCV_Wait_flag == 1)
|
||
{
|
||
if(RTC_UpdateFlag == 1)
|
||
{
|
||
ocvtimecount = timecount - (ocvEnd - ocvtime); //更新起始点=当前时间-已消耗时间,此时剩余时间保持原值
|
||
}
|
||
else
|
||
{
|
||
ocvtime = ocvEnd - (timecount - ocvtimecount);
|
||
}
|
||
|
||
if((ocvtime == 0) || (ocvtime > ocvEnd)) //防止反向溢出
|
||
{
|
||
OCV_CaliSOC_flag = 1;
|
||
}
|
||
}
|
||
|
||
//充电校准满充容量的倒计时启动了
|
||
if(fcc_CaliStartFlag == 1)
|
||
{
|
||
if(RTC_UpdateFlag == 1)
|
||
{
|
||
fcc_Calitimecount = timecount - (fcccaliEnd - fcc_Calitime); //更新起始点=当前时间-已消耗时间,此时剩余时间保持原值
|
||
}
|
||
else
|
||
{
|
||
fcc_Calitime = fcccaliEnd - (timecount - fcc_Calitimecount);
|
||
}
|
||
|
||
if((fcc_Calitime == 0) || (fcc_Calitime > fcccaliEnd)) //防止反向溢出
|
||
{
|
||
fcc_CaliStartFlag = 0;
|
||
|
||
EEPROM_WrMulByte(EE_FCC_TIME,ClearEE);
|
||
delay_ms(5);
|
||
}
|
||
}
|
||
|
||
//该刷新的都刷新后,标志置0
|
||
if(RTC_UpdateFlag != 0)
|
||
{
|
||
RTC_UpdateFlag = 0;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数名:RTC_Set
|
||
* 描述 :把输入的年/月/日/时/分/秒转换为秒钟 写入RTC计数器
|
||
以1970年1月1日为基准
|
||
* 输入 :无
|
||
* 输出 :0,成功;1:错误代码
|
||
* 调用 :
|
||
*/
|
||
uint8_t RTC_Set(uint8_t ear,uint8_t smon,uint8_t sday,uint8_t hour,uint8_t min,uint8_t sec)
|
||
{
|
||
uint16_t t,syear;
|
||
uint32_t seccount=0;
|
||
|
||
ear=(ear/16)*10+ear%16;
|
||
smon=(smon/16)*10+smon%16;
|
||
sday=(sday/16)*10+sday%16;
|
||
hour=(hour/16)*10+hour%16;
|
||
min=(min/16)*10+min%16;
|
||
sec=(sec/16)*10+sec%16;
|
||
|
||
syear=2000+ear;
|
||
if(syear<1970||syear>2099) //1970~2099年为合法年份
|
||
{
|
||
return 1;
|
||
}
|
||
for(t=1970;t<syear;t++) //把所有年份的秒钟相加
|
||
{
|
||
if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
|
||
else seccount+=31536000; //平年的秒钟数
|
||
}
|
||
smon-=1;
|
||
for(t=0;t<smon;t++) //把前面月份的秒钟数相加
|
||
{
|
||
seccount+=(u32)mon_table[t]*86400; //各月份的秒钟数
|
||
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
|
||
}
|
||
seccount+=(u32)(sday-1)*86400; //把前面日期的秒钟数相加
|
||
|
||
seccount+=(u32)hour*3600;//小时的秒钟数
|
||
seccount+=(u32)min*60; //分钟的秒钟数
|
||
seccount+=sec; //最后的秒钟加上去
|
||
|
||
#if LTE_Conn
|
||
//4G的timecount是世界时间,中国对应显示需+8h,存储就要比电脑写入的少8h=28800s
|
||
seccount -= 28800;
|
||
#endif
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
|
||
PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问
|
||
RTC_SetCounter(seccount); //设置RTC计数器的值
|
||
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
//RTC_Get();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数名:RTC_GetSynchro
|
||
* 描述 :由函数RTC_WaitForSynchro()改得,增加超时判断说明晶振出现问题
|
||
* 输入 :无
|
||
* 输出 :0,成功;1:错误代码
|
||
* 调用 :
|
||
*/
|
||
uint8_t RTC_GetSynchro(void)
|
||
{
|
||
uint16_t temp=0;
|
||
|
||
/* Clear RSF flag */
|
||
RTC->CRL &= (uint16_t)~RTC_FLAG_RSF;
|
||
/* Loop until RSF flag is set */
|
||
while ((RTC->CRL & RTC_FLAG_RSF) == (uint16_t)RESET)
|
||
{
|
||
temp++;
|
||
if(temp>=2000) return 1; //初始化时钟失败,晶振有问题
|
||
delay_ms(1); //1ms延时,总共2s
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数名:uf_RTC_Init
|
||
* 描述 :RTC初始化配置.第一次配置时会写入2023-6-25 14:00:00.
|
||
* 输入 :无
|
||
* 输出 :0,成功;1:错误代码
|
||
* 调用 :
|
||
*/
|
||
//开机执行一次
|
||
//第一次配置写入2023-6-25 14:00:00,此后正常读RTC后备寄存器的存值。若RTC值意外丢失则读EEPROM存值使用
|
||
uint8_t uf_RTC_Init(void)
|
||
{
|
||
uint16_t temp=0;
|
||
uint8_t tmpRd[6];
|
||
|
||
//上电读备份的时间信息
|
||
EEPROM_RdMulByte(EE_TIME_BACKUP,tmpRd);
|
||
if((tmpRd[0]!=0xff) && (tmpRd[1]!=0xff) && (tmpRd[2]!=0xff) && (tmpRd[3]!=0xff) && (tmpRd[4]!=0xff) && (tmpRd[5]!=0xff)) //时分秒格式存储,不可能存在0xff
|
||
{
|
||
calendar_BACKUP.w_year = tmpRd[0];
|
||
calendar_BACKUP.w_month = tmpRd[1];
|
||
calendar_BACKUP.w_date = tmpRd[2];
|
||
calendar_BACKUP.hour = tmpRd[3];
|
||
calendar_BACKUP.min = tmpRd[4];
|
||
calendar_BACKUP.sec = tmpRd[5];
|
||
}
|
||
else
|
||
{
|
||
//0x23,0x06,0x25,0x14,0x00,0x00
|
||
calendar_BACKUP.w_year = 0x23;
|
||
calendar_BACKUP.w_month = 0x06;
|
||
calendar_BACKUP.w_date = 0x25;
|
||
calendar_BACKUP.hour = 0x14;
|
||
calendar_BACKUP.min = 0x00;
|
||
calendar_BACKUP.sec = 0x00;
|
||
}
|
||
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
|
||
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
|
||
|
||
if(BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //检查是不是第一次配置时钟
|
||
{
|
||
// /*使用内部低速晶振*/
|
||
// BKP_DeInit(); //复位备份区域
|
||
// RCC_LSICmd(ENABLE); //使能LSI时钟
|
||
// while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) //等待LSI晶振就绪
|
||
// {
|
||
// temp++;
|
||
// if(temp>=5000) return 1; //持续5s无法起振,初始化时钟失败,晶振有问题
|
||
// delay_ms(1); // 1ms延时
|
||
// }
|
||
// RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟(RTCCLK),选择LSI作为RTC的时钟源
|
||
// RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// RTC_WaitForSynchro(); //等待RTC寄存器同步
|
||
// RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// RTC_EnterConfigMode(); //允许配置
|
||
// RTC_SetPrescaler(40000 - 1); //设置RTC预分频的值40kHz
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// /*使用内部低速晶振*/
|
||
|
||
/*使用外部低速晶振*/
|
||
BKP_DeInit(); //复位备份区域
|
||
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
|
||
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪
|
||
{
|
||
temp++;
|
||
if(temp>=5000) return 1; //持续5s无法起振,初始化时钟失败,晶振有问题
|
||
delay_ms(1); // 1ms延时
|
||
}
|
||
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
|
||
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
RTC_WaitForSynchro(); //等待RTC寄存器同步
|
||
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
RTC_EnterConfigMode(); // 允许配置
|
||
RTC_SetPrescaler(32767); //设置RTC预分频的值
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
/*使用外部低速晶振*/
|
||
|
||
|
||
//RTC_Set(0x23,0x06,0x25,0x14,0x00,0x00);
|
||
RTC_Set(calendar_BACKUP.w_year,calendar_BACKUP.w_month,calendar_BACKUP.w_date,calendar_BACKUP.hour,calendar_BACKUP.min,calendar_BACKUP.sec);
|
||
|
||
RTC_ExitConfigMode(); //退出配置模式
|
||
BKP_WriteBackupRegister(BKP_DR1, 0x5050); //向指定的后备寄存器中写入指定数据
|
||
}
|
||
else//系统继续计时
|
||
{
|
||
// /*使用内部低速晶振*/
|
||
// RCC_LSICmd(ENABLE); //使能LSI时钟
|
||
// while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) //等待LSI晶振就绪
|
||
// {
|
||
// temp++;
|
||
// if(temp>=5000) return 1; //持续5s无法起振,初始化时钟失败,晶振有问题
|
||
// delay_ms(1); // 1ms延时
|
||
// }
|
||
// RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
||
// /*使用内部低速晶振*/
|
||
|
||
if(RTC_GetSynchro() == 1)return 1; //等待RTC寄存器同步 //10.8 晶振坏了这里会卡死,所以增加超时失败退出
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
}
|
||
|
||
|
||
/**更多功能**/
|
||
//更新当前时间
|
||
timecount=RTC_GetCounter();
|
||
|
||
//若启用休眠1,则以当前秒数为起始点
|
||
if((paraMem.sleep_min_disable & 0x8000) == 0) //0代表启用休眠
|
||
{
|
||
sleep_enableflag |= 0x01;
|
||
|
||
sleeptimecount=timecount;
|
||
}
|
||
else
|
||
{
|
||
sleep_enableflag &= 0xfe;
|
||
}
|
||
//若启用休眠2,则判断此时最低电压是否满足条件,满足则以当前秒数为起始点
|
||
if((paraMem.sleep2_min_disable & 0x8000) == 0) //0代表启用休眠
|
||
{
|
||
sleep_enableflag |= 0x02;
|
||
|
||
//满足休眠电压,无均衡,无电流
|
||
if((cellVoltageMin <= sleep2Vol) && ((bmsMem.balanceStatus & 0x0001) == 0) && (bmsMem.packCurrent > (-200)) && (bmsMem.packCurrent < 200))
|
||
{
|
||
//无除过压以外的保护
|
||
if(((bmsMem.bStatus1 & 0x067e) == 0) && ((bmsMem.bStatus2 & 0x00ff) == 0) && ((bmsMem.bStatus3 & 0x0008) == 0) && ((bmsMem.temperaStatus & 0x0f7f) == 0))
|
||
{
|
||
sleep2timecount=timecount;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sleep_enableflag &= 0xfd;
|
||
}
|
||
|
||
return 0; //ok
|
||
}
|
||
|
||
/*
|
||
* 函数名:uf_RTC_Update
|
||
* 描述 :将calendar_WRITE结构体的值写入RTC时间
|
||
* 输入 :无
|
||
* 输出 :0,成功;1:错误代码
|
||
* 调用 :
|
||
*/
|
||
uint8_t uf_RTC_Update(void)
|
||
{
|
||
if(calendar_WRITE.w_month != 0) //有写入的数组
|
||
{
|
||
uint16_t temp=0;
|
||
uint8_t Wrtime[6];
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
|
||
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
|
||
|
||
|
||
// /*使用内部低速晶振*/
|
||
// BKP_DeInit(); //复位备份区域
|
||
// RCC_LSICmd(ENABLE); //使能LSI时钟
|
||
// while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) //等待LSI晶振就绪
|
||
// {
|
||
// temp++;
|
||
// if(temp>=5000) return 1; //持续5s无法起振,初始化时钟失败,晶振有问题
|
||
// delay_ms(1); // 1ms延时
|
||
// }
|
||
// RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟(RTCCLK),选择LSI作为RTC的时钟源
|
||
// RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// RTC_WaitForSynchro(); //等待RTC寄存器同步
|
||
// RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// RTC_EnterConfigMode(); //允许配置
|
||
// RTC_SetPrescaler(40000 - 1); //设置RTC预分频的值40kHz
|
||
// RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
// /*使用内部低速晶振*/
|
||
|
||
/*使用外部低速晶振*/
|
||
BKP_DeInit(); //复位备份区域
|
||
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
|
||
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪
|
||
{
|
||
temp++;
|
||
if(temp>=5000) return 1; //持续5s无法起振,初始化时钟失败,晶振有问题
|
||
delay_ms(1); // 1ms延时
|
||
}
|
||
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
|
||
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
RTC_WaitForSynchro(); //等待RTC寄存器同步
|
||
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
RTC_EnterConfigMode(); // 允许配置
|
||
RTC_SetPrescaler(32767); //设置RTC预分频的值
|
||
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
||
/*使用外部低速晶振*/
|
||
|
||
|
||
RTC_Set(calendar_WRITE.w_year,calendar_WRITE.w_month,calendar_WRITE.w_date,calendar_WRITE.hour,calendar_WRITE.min,calendar_WRITE.sec);
|
||
|
||
RTC_ExitConfigMode(); //退出配置模式
|
||
BKP_WriteBackupRegister(BKP_DR1, 0x5050); //向指定的后备寄存器中写入用户程序数据
|
||
|
||
//刷新休眠和欠压复位的时间
|
||
RTC_UpdateFlag = 1;
|
||
//存储时间备份
|
||
Wrtime[0] = calendar_WRITE.w_year;
|
||
Wrtime[1] = calendar_WRITE.w_month;
|
||
Wrtime[2] = calendar_WRITE.w_date;
|
||
Wrtime[3] = calendar_WRITE.hour;
|
||
Wrtime[4] = calendar_WRITE.min;
|
||
Wrtime[5] = calendar_WRITE.sec;
|
||
EEPROM_WrMulByte(EE_TIME_BACKUP,Wrtime);
|
||
delay_ms(5);
|
||
//清零
|
||
calendar_WRITE.w_year = 0;
|
||
calendar_WRITE.w_month = 0;
|
||
calendar_WRITE.w_date = 0;
|
||
calendar_WRITE.week = 0;
|
||
calendar_WRITE.hour = 0;
|
||
calendar_WRITE.min = 0;
|
||
calendar_WRITE.sec = 0;
|
||
}
|
||
|
||
return 0; //ok
|
||
}
|
||
|
||
//用于处理因各种原因需要的时间备份
|
||
int32_t oldCur;
|
||
void RTC_BackUp(void)
|
||
{
|
||
uint8_t WrFlag=0;
|
||
|
||
//当正在充放电,开始时记录一次,之后每5分钟记录一次
|
||
if(bCHGING == 1)
|
||
{
|
||
if(oldCur <= 0) //原来在放电或待机
|
||
{
|
||
WrFlag = 1;
|
||
oldCur = bmsMem.packCurrent;
|
||
}
|
||
|
||
if((calendar.min%5 == 0x00) && (calendar.sec == 0x00))
|
||
{
|
||
WrFlag = 1;
|
||
}
|
||
}
|
||
else if(bDSGING == 1)
|
||
{
|
||
if(oldCur >= 0) //原来在充电或待机
|
||
{
|
||
WrFlag = 1;
|
||
oldCur = bmsMem.packCurrent;
|
||
}
|
||
|
||
if((calendar.min%5 == 0x00) && (calendar.sec == 0x00))
|
||
{
|
||
WrFlag = 1;
|
||
}
|
||
}
|
||
//在待机状态,每1h记录一次
|
||
else
|
||
{
|
||
oldCur = 0;
|
||
|
||
if((calendar.min == 0x00) && (calendar.sec == 0x00))
|
||
{
|
||
WrFlag = 1;
|
||
}
|
||
}
|
||
|
||
//需要写入备份时间,执行
|
||
if(WrFlag == 1)
|
||
{
|
||
if(calendar.w_month != 0)
|
||
{
|
||
uint8_t tmpRd[6];
|
||
tmpRd[0] = calendar.w_year;
|
||
tmpRd[1] = calendar.w_month;
|
||
tmpRd[2] = calendar.w_date;
|
||
tmpRd[3] = calendar.hour;
|
||
tmpRd[4] = calendar.min;
|
||
tmpRd[5] = calendar.sec;
|
||
|
||
EEPROM_WrMulByte(EE_TIME_BACKUP,tmpRd);
|
||
delay_ms(5);
|
||
}
|
||
}
|
||
}
|
||
|