Electricity/FWLIB/source/ENS1_TIMER.c

571 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ENS1_TIMER.h"
#include "ENS_CURRENT_CALIBRATION.h"
#include "ENS1_CLOCK.h"
#include <string.h>
uint8_t ems_control_count = 0; // 电刺激控制计数器
uint8_t ems_state = 0; // 电刺激状态0=关闭1=开启
uint16_t time_count = 0;
void TIMER0_Init(uint32_t Int_Period) //形参,输入中断触发周期 单位ms
{
PCLK_Enable(TIMER0_PCLK_EN);
NVIC_DisableIRQ(TIMER0_IRQn);
NVIC_ClearPendingIRQ(TIMER0_IRQn);
CMSDK_timer_Init(CMSDK_TIMER0,(uint32_t)(APB_Clock_Freq / 1000 *Int_Period) , 1); //
NVIC_EnableIRQ(TIMER0_IRQn);
}
void TIMER1_Init(uint32_t Int_Period)
{
PCLK_Enable(TIMER1_PCLK_EN);
NVIC_DisableIRQ(TIMER1_IRQn);
NVIC_ClearPendingIRQ(TIMER1_IRQn);
CMSDK_timer_Init(CMSDK_TIMER1,(uint32_t)(APB_Clock_Freq / 1000 * Int_Period) , 1); // 1ms
NVIC_EnableIRQ(TIMER1_IRQn);
}
/*使能定时器中断*/
void CMSDK_timer_EnableIRQ(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
CMSDK_TIMER->CTRL |= CMSDK_TIMER_CTRL_IRQEN_Msk;
}
/*禁止定时器中断*/
void CMSDK_timer_DisableIRQ(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
CMSDK_TIMER->CTRL &= ~CMSDK_TIMER_CTRL_IRQEN_Msk;
}
/*启动定时器*/
void CMSDK_timer_StartTimer(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
CMSDK_TIMER->CTRL |= CMSDK_TIMER_CTRL_EN_Msk;
}
/*停止定时器*/
void CMSDK_timer_StopTimer(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
CMSDK_TIMER->CTRL &= ~CMSDK_TIMER_CTRL_EN_Msk;
}
/*获取定时器当前值*/
uint32_t CMSDK_timer_GetValue(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
return CMSDK_TIMER->VALUE;
}
/*设置定时器当前值*/
void CMSDK_timer_SetValue(CMSDK_TIMER_TypeDef *CMSDK_TIMER, uint32_t value)
{
CMSDK_TIMER->VALUE = value;
}
/*获取定时器重装载值*/
uint32_t CMSDK_timer_GetReload(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
return CMSDK_TIMER->RELOAD;
}
/*设置定时器重装载值*/
void CMSDK_timer_SetReload(CMSDK_TIMER_TypeDef *CMSDK_TIMER, uint32_t value)
{
CMSDK_TIMER->RELOAD = value;
}
void CMSDK_timer_ClearIRQ(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
CMSDK_TIMER->INTCLEAR = CMSDK_TIMER_INTCLEAR_Msk;
}
/*获取定时器中断状态*/
uint32_t CMSDK_timer_StatusIRQ(CMSDK_TIMER_TypeDef *CMSDK_TIMER)
{
return CMSDK_TIMER->INTSTATUS;
}
/*初始化定时器*/
void CMSDK_timer_Init(CMSDK_TIMER_TypeDef *CMSDK_TIMER, uint32_t reload, uint8_t irq_en)
{
uint32_t new_ctrl = 0;
CMSDK_TIMER->VALUE = reload;
CMSDK_TIMER->RELOAD = reload;
if (irq_en!=0)
new_ctrl |= CMSDK_TIMER_CTRL_IRQEN_Msk; /* non zero - enable IRQ */
new_ctrl |= CMSDK_TIMER_CTRL_EN_Msk; /* enable timer */
CMSDK_TIMER->CTRL = new_ctrl;
}
/**
*
* @param *CMSDK_TIMER Timer Pointer
* @param reload The value to which the timer is to be set after an underflow has occurred
* @param irq_en Defines whether the timer IRQ is to be enabled
* @return none
* @brief Initialises the timer to use the external clock and specifies the timer reload value and whether IRQ is enabled or not.
*/
void CMSDK_timer_Init_ExtClock(CMSDK_TIMER_TypeDef *CMSDK_TIMER, uint32_t reload,uint32_t irq_en)
{
CMSDK_TIMER->CTRL = 0;
CMSDK_TIMER->VALUE = reload;
CMSDK_TIMER->RELOAD = reload;
if (irq_en!=0) /* non zero - enable IRQ */
CMSDK_TIMER->CTRL = (CMSDK_TIMER_CTRL_IRQEN_Msk |
CMSDK_TIMER_CTRL_SELEXTCLK_Msk |CMSDK_TIMER_CTRL_EN_Msk);
else { /* zero - do not enable IRQ */
CMSDK_TIMER->CTRL = ( CMSDK_TIMER_CTRL_EN_Msk |
CMSDK_TIMER_CTRL_SELEXTCLK_Msk); /* enable timer */
}
}
/**
*
* @brief Initialises the timer to use the internal clock but with an external enable. It also specifies the timer reload value and whether IRQ is enabled or not.
*
* @param *CMSDK_TIMER Timer Pointer
* @param reload The value to which the timer is to be set after an underflow has occurred
* @param irq_en Defines whether the timer IRQ is to be enabled
* @return none
* Timer 0 only
*
*/
void CMSDK_timer_Init_ExtEnable(CMSDK_TIMER_TypeDef *CMSDK_TIMER, uint32_t reload,uint32_t irq_en)
{
CMSDK_TIMER->CTRL = 0;
CMSDK_TIMER->VALUE = reload;
CMSDK_TIMER->RELOAD = reload;
if (irq_en!=0) /* non zero - enable IRQ */
CMSDK_TIMER->CTRL = (CMSDK_TIMER_CTRL_IRQEN_Msk | CMSDK_TIMER_CTRL_SELEXTEN_Msk | CMSDK_TIMER_CTRL_EN_Msk);
else{ /* zero - do not enable IRQ */
CMSDK_TIMER->CTRL = ( CMSDK_TIMER_CTRL_EN_Msk | CMSDK_TIMER_CTRL_SELEXTEN_Msk); /* enable timer */
}
}
/*DUAL Timer driver functions*/
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Start timer in dual timers.
*/
/* Start Timer */
void CMSDK_dualtimer_start(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx)
{
CMSDK_DUALTIMERx->TimerControl |= CMSDK_DUALTIMER_CTRL_EN_Msk;
}
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Stop timer in dual timers.
*/
/* Stop Timer */
void CMSDK_dualtimer_stop(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx)
{
CMSDK_DUALTIMERx->TimerControl &= ~CMSDK_DUALTIMER_CTRL_EN_Msk;
}
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Clear the interrupt request in dual timers.
*/
/* Clear the Interrupt */
void CMSDK_dualtimer_irq_clear(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx)
{
CMSDK_DUALTIMERx->TimerIntClr = 0;
}
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Setup Free running mode in dual timers.
*/
/* Free running timer mode */
void CMSDK_dualtimer_setup_freerunning(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx,
unsigned int cycle, unsigned int prescale, unsigned int interrupt, unsigned int size)
{
int ctrl_val;
CMSDK_DUALTIMERx->TimerControl = 0; /* Disable during programming */
/* Previous timer activities might have trigger interrupt flag,
so need to clear it */
CMSDK_dualtimer_irq_clear(CMSDK_DUALTIMERx);
CMSDK_DUALTIMERx->TimerLoad = cycle;
ctrl_val = (prescale & 0x3) << CMSDK_DUALTIMER_CTRL_PRESCALE_Pos |
(interrupt & 0x1) << CMSDK_DUALTIMER_CTRL_INTEN_Pos |
(size & 0x1) << CMSDK_DUALTIMER_CTRL_SIZE_Pos |
CMSDK_DUALTIMER_CTRL_EN_Msk;
CMSDK_DUALTIMERx->TimerControl = ctrl_val;
}
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Setup Periodic mode in dual timers.
*/
/* Periodic timer mode */
void CMSDK_dualtimer_setup_periodic(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx,
unsigned int cycle, unsigned int prescale,
unsigned int interrupt, unsigned int size)
{
int ctrl_val;
CMSDK_DUALTIMERx->TimerControl = 0; /* Disable during programming */
/* Previous timer activities might have trigger interrupt flag,
so need to clear it */
CMSDK_dualtimer_irq_clear(CMSDK_DUALTIMERx);
CMSDK_DUALTIMERx->TimerLoad = cycle;
ctrl_val = (prescale & 0x3) << CMSDK_DUALTIMER_CTRL_PRESCALE_Pos |
(interrupt & 0x1) << CMSDK_DUALTIMER_CTRL_INTEN_Pos |
(size & 0x1) << CMSDK_DUALTIMER_CTRL_SIZE_Pos |
CMSDK_DUALTIMER_CTRL_EN_Msk |
CMSDK_DUALTIMER_CTRL_MODE_Msk;
CMSDK_DUALTIMERx->TimerControl = ctrl_val;
}
/**
*
* @param *CMSDK_DUALTIMER DUAL Timer Pointer
* @return none
*
* @brief Setup One shot mode in dual timers.
*/
/* One shot timer mode */
void CMSDK_dualtimer_setup_oneshot(CMSDK_DUALTIMER_TypeDef *CMSDK_DUALTIMERx,
unsigned int cycle, unsigned int prescale,
unsigned int interrupt, unsigned int size)
{
int ctrl_val;
CMSDK_DUALTIMERx->TimerControl = 0; /* Disable during programming */
/* Previous timer activities might have trigger interrupt flag,
so need to clear it */
CMSDK_dualtimer_irq_clear(CMSDK_DUALTIMERx);
CMSDK_DUALTIMERx->TimerLoad = cycle;
ctrl_val = (prescale & 0x3) << CMSDK_DUALTIMER_CTRL_PRESCALE_Pos |
(interrupt & 0x1) << CMSDK_DUALTIMER_CTRL_INTEN_Pos |
(size & 0x1) << CMSDK_DUALTIMER_CTRL_SIZE_Pos |
CMSDK_DUALTIMER_CTRL_EN_Msk |
CMSDK_DUALTIMER_CTRL_ONESHOT_Msk;
CMSDK_DUALTIMERx->TimerControl = ctrl_val;
}
/*RTC driver functions*/
/**
*
* @param *CMSDK_RTC RTC Pointer
* @return none
*
* @brief Initialize RTC Calender
*/
void CMSDK_RTC_Init_Calender(uint16_t prescaler, uint8_t data_mode, uint8_t hour_mode,
uint32_t init_time, uint32_t init_date)
{
uint32_t new_reg_ctrl = 0;
//wait for rtc prescaler sync ready
while(!((CMSDK_RTC->SR & CMSDK_RTC_PRES_SYNC_READY_Msk) >> CMSDK_RTC_PRES_SYNC_READY_Pos));
//set prescaler
CMSDK_RTC->PR = prescaler;
//config data/hour mode
if(data_mode != 0) new_reg_ctrl |= CMSDK_RTC_DATA_MODE_Msk;
if(hour_mode != 0) new_reg_ctrl |= CMSDK_RTC_HOUR_MODE_Msk;
CMSDK_RTC->CR = new_reg_ctrl;
//wait for init sync ready
while(!(CMSDK_RTC->SR & CMSDK_RTC_INIT_SYNC_READY_Msk));
//set INIT
CMSDK_RTC->CR |= CMSDK_RTC_INIT_EN_Msk;
//Set Initial Time & Date
CMSDK_RTC->TR = init_time;
CMSDK_RTC->DR = init_date;
//Clear INIT bit
CMSDK_RTC->CR &= ~CMSDK_RTC_INIT_EN_Msk;
//wait for init sync ready
while(!(CMSDK_RTC->SR & CMSDK_RTC_INIT_SYNC_READY_Msk));
return;
}
/**
*
* @param *CMSDK_RTC RTC Pointer
* @return none
*
* @brief Config RTC Alarm
*/
void CMSDK_RTC_Config_Alarm(uint16_t prescaler, uint8_t data_mode, uint8_t hour_mode,
uint32_t init_time, uint32_t init_date, uint32_t alarm_time,
uint32_t alarm_date)
{
uint32_t new_reg_ctrl = 0;
//wait for rtc prescaler sync ready
while(!((CMSDK_RTC->SR & CMSDK_RTC_PRES_SYNC_READY_Msk) >> CMSDK_RTC_PRES_SYNC_READY_Pos));
//set prescaler
CMSDK_RTC->PR = prescaler;
//config data/hour mode
if(data_mode != 0) new_reg_ctrl |= CMSDK_RTC_DATA_MODE_Msk;
if(hour_mode != 0) new_reg_ctrl |= CMSDK_RTC_HOUR_MODE_Msk;
CMSDK_RTC->CR = new_reg_ctrl;
//wait for init sync ready
while(!(CMSDK_RTC->SR & CMSDK_RTC_INIT_SYNC_READY_Msk));
//set INIT
CMSDK_RTC->CR |= CMSDK_RTC_INIT_EN_Msk;
//Set Initial Time & Date
CMSDK_RTC->TR = init_time;
CMSDK_RTC->DR = init_date;
//Set Alarm Time & Date
CMSDK_RTC->TAR = alarm_time;
CMSDK_RTC->DAR = alarm_date;
//Alarm enabled
CMSDK_RTC->CR |= CMSDK_RTC_ALARM_EN_Msk;
//Clear INIT bit
CMSDK_RTC->CR &= ~CMSDK_RTC_INIT_EN_Msk;
return;
}
/**
*
* @param *CMSDK_RTC RTC Pointer
* @return none
*
* @brief Config Period Wakeup
*/
void CMSDK_RTC_Config_PeriodWake(uint8_t clock_sel, uint16_t prescaler, uint16_t period_time)
{
if(clock_sel) {
CMSDK_RTC->CR |= CMSDK_RTC_WUT_CLK_EN_Msk;
//wait for rtc prescaler sync ready
while(!((CMSDK_RTC->SR & CMSDK_RTC_PRES_SYNC_READY_Msk) >> CMSDK_RTC_PRES_SYNC_READY_Pos));
//set prescaler
CMSDK_RTC->PR = prescaler;
}
else {
CMSDK_RTC->CR &= ~CMSDK_RTC_WUT_CLK_EN_Msk;
//wait for wut prescaler sync ready
while(!((CMSDK_RTC->SR & CMSDK_RTC_WUT_PRES_SYNC_READY_Msk) >> CMSDK_RTC_WUT_PRES_SYNC_READY_Pos));
//set prescaler
CMSDK_RTC->WPR = prescaler;
}
//wait for wut value sync ready
while(!((CMSDK_RTC->SR & CMSDK_RTC_WUT_VAL_SYNC_READY_Msk) >> CMSDK_RTC_WUT_VAL_SYNC_READY_Pos));
//set Wakeup time register
CMSDK_RTC->WTR = period_time;
//Config CR with Periodic Wakeup timer enabled
CMSDK_RTC->CR |= CMSDK_RTC_WUT_EN_Msk;
return;
}
void Fuse_result(void)
{
// 获取时间标志位
Time_Flag_TypeDef* time_flags = Time_Manager_GetFlags();
// 处理电刺激(在主循环中运行)
// 注意这里不再直接调用EMS_Process(),而是通过状态控制
if (time_flags->T_1ms) {
// 1ms周期任务 - 高频控制任务
time_count++;
EMS_Process();
time_flags->T_1ms = 0; // 清除标志位
}
// 基于时间标志位执行不同周期的任务
if (time_flags->T_2ms) {
// 2ms周期任务 - 高频控制任务
time_flags->T_2ms = 0; // 清除标志位
}
if (time_flags->T_10ms) {
// 10ms周期任务 - 中频控制任务
time_flags->T_10ms = 0; // 清除标志位
}
if (time_flags->T_100ms) {
// 100ms周期任务 - 低频控制任务
time_flags->T_100ms = 0; // 清除标志位
}
if (time_flags->T_1s) {
GPIO_Overturn(GPIO_19);
// 1s周期任务 - 超低频任务
ems_control_count++; // 每秒递增计数器
// 间断性放电控制逻辑
if (ems_control_count <= 10) {
// 前10秒开启电刺激
if (ems_state == 0) {
ems_state = 1;
EMS_Start(); // 启动电刺激
}
// 处理电刺激
} else if (ems_control_count <= 20) {
// 后10秒关闭电刺激
if (ems_state == 1) {
ems_state = 0;
EMS_Stop(); // 停止电刺激
}
} else {
// 重置计数器,开始新的周期
ems_control_count = 0;
}
time_flags->T_1s = 0; // 清除标志位
}
// 定时器中断处理在 TIMER0_Handler() 中
}
// --------------------------------------------------------------- //
// 时间管理全局变量
// --------------------------------------------------------------- //
static Time_Flag_TypeDef g_time_flags = {0};
static Time_Counter_TypeDef g_time_counters = {0};
// --------------------------------------------------------------- //
// 时间管理函数实现
// --------------------------------------------------------------- //
/**
* @brief 初始化时间管理器
*/
void Time_Manager_Init(void)
{
// 清零所有标志位和计数器
memset(&g_time_flags, 0, sizeof(Time_Flag_TypeDef));
memset(&g_time_counters, 0, sizeof(Time_Counter_TypeDef));
}
/**
* @brief 时间管理处理函数(在定时器中断中调用)
* 基于1ms定时器中断实现不同时间周期的任务调度
*/
void Time_Manager_Process(void)
{
// 所有计数器递增
g_time_counters.t_1ms++;
g_time_counters.t_2ms++;
g_time_counters.t_6ms++;
g_time_counters.t_10ms++;
g_time_counters.t_20ms++;
g_time_counters.t_100ms++;
g_time_counters.t_1s++;
// 2ms控制周期
if (g_time_counters.t_1ms >= 1)
{
g_time_counters.t_1ms = 0;
g_time_flags.T_1ms = 1;
/* code */
}
if (g_time_counters.t_2ms >= 2) {
g_time_counters.t_2ms = 0;
g_time_flags.T_2ms = 1;
}
// 6ms控制周期
if (g_time_counters.t_6ms >= 6) {
g_time_counters.t_6ms = 0;
g_time_flags.T_6ms = 1;
}
// 10ms控制周期
if (g_time_counters.t_10ms >= 10) {
g_time_counters.t_10ms = 0;
g_time_flags.T_10ms = 1;
}
// 20ms控制周期
if (g_time_counters.t_20ms >= 20) {
g_time_counters.t_20ms = 0;
g_time_flags.T_20ms = 1;
}
// 100ms控制周期
if (g_time_counters.t_100ms >= 100) {
g_time_counters.t_100ms = 0;
g_time_flags.T_100ms = 1;
}
// 1s控制周期
if (g_time_counters.t_1s >= 1000) {
g_time_counters.t_1s = 0;
g_time_flags.T_1s = 1;
}
Fuse_result();
}
/**
* @brief 获取时间标志位
* @return 时间标志位结构体指针
*/
Time_Flag_TypeDef* Time_Manager_GetFlags(void)
{
return &g_time_flags;
}
/**
* @brief 清除所有时间标志位
*/
void Time_Manager_ClearFlags(void)
{
memset(&g_time_flags, 0, sizeof(Time_Flag_TypeDef));
}
/**
* @brief 重置时间管理器
*/
void Time_Manager_Reset(void)
{
Time_Manager_Init();
}
// --------------------------------------------------------------- //
// TIMER0_IRQ
// --------------------------------------------------------------- //
uint32_t timer0_irq_occurred=0;
uint32_t time_flag =0;
void TIMER0_Handler(void){
CMSDK_TIMER0->INTCLEAR = 1;
timer0_irq_occurred++;
// 调用时间管理处理函数
Time_Manager_Process();
// 注意GPIO翻转现在通过时间管理系统在主循环中处理
// 这里不再直接翻转GPIO避免重复操作
}
// --------------------------------------------------------------- //
// TIMER1_IRQ
// --------------------------------------------------------------- //
uint32_t timer1_irq_occurred=0;
void TIMER1_Handler(void){
CMSDK_TIMER1->INTCLEAR = 1;
timer1_irq_occurred++;
}