Files
CHJ/user/MCU/lhl_timer.c
2026-03-20 21:19:04 +08:00

320 lines
11 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 "../main/SystemInclude.h"
/*-=====================================================================================================
//TIMER1
-=====================================================================================================*/
/**------------------------------------------------------------------------
* @brief 通用周期定时器(自适应时钟周期)
* @note 时钟源APB2_CLK
* @param uploadCounter: 期望的周期,单位:毫秒 范围:(1~4000)
* @example: StartTimer1(10); // 启动10ms周期定时器
**/
void StartTimer1_UIE(u16 uploadCounter)
{
if(uploadCounter>4000)uploadCounter = 4000;
if(uploadCounter<= 0)uploadCounter = 1;
u32 APB2_CLK = LHL_RCC_GetPCLK2Freq();
u32 prescaler = (APB2_CLK / 16000UL) - 1; //固定分频系数 (APB1_CLK / 32000UL) - 1;
u32 period =(u32)(16UL * uploadCounter);//动态ARR计数 (uint32_t)(32000UL * uploadCounter) / 1000UL;
TIM_InitTypeDef TIM_InitStructure;
TIM_InitStructure.Period = period;
TIM_InitStructure.Prescaler = prescaler;
TIM_InitStructure.ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.CounterMode = TIM_COUNTERMODE_UP;
TIM_InitStructure.AutoReloadPreload = ENABLE;
LHL_TIM_Init(TIM1, &TIM_InitStructure);
/*使能TIM1更新中断UIE */
LHL_TIM_ITConfig(TIM1, TIM_IT_UPDATE, ENABLE);
NVIC_EnableIRQ(TIM1_IRQn);
NVIC_SetPriority(TIM1_IRQn,1);
LHL_TIM_Start(TIM1);
}
/**------------------------------------------------------------------------
* @brief 通用周期定时器(自适应时钟周期)修改周期
* @note 时钟源APB2_CLK
* @param uploadCounter: 期望的周期,单位:毫秒 范围:(1~4000)
* @example: ResetTimer1_UIE(20); // 定时器周期改为20ms
**/
void ResetTimer1_UIE( u16 uploadCounter )
{
// 参数检查
if(uploadCounter>4000)uploadCounter = 4000;
if(uploadCounter<= 0)uploadCounter = 1;
// 计算新ARR的值
u32 period =(u32)(16UL * uploadCounter); //PSC不变ARR计算与StartTimer1相同
TIM1->CNT = 0; //先重置计数器 再设置ARR避免立即溢出
LHL_TIM_ClearPending(TIM1, TIM_IT_UPDATE);//当前CNT已经接近或超过ARR这里可能产生更新事件 所以需要先清除标志
TIM1->ARR = (u16)period ; //修改ARR 如果PSC需要改变必须停止定时器
LHL_TIM_Start(TIM1); //确保定时器启用
}
/**------------------------------------------------------------------------
* @brief 通用比较定时器(无电平输出)
* @note 时钟源APB2_CLK
* @param uploadCounter: 计数值(1~65535),需要换算成期望周期 计数值=65535/4000*t
* @example: StartTimer1(327); //启动20ms比较定时器 327=65535/4000*20
**/
void StartTimer1_CC1(u16 uploadCounter)
{
TIM_InitTypeDef TIM_InitStructure;
TIM_InitStructure.Period = 65535;
TIM_InitStructure.Prescaler = 244;
TIM_InitStructure.ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.CounterMode = TIM_COUNTERMODE_UP;
TIM_InitStructure.AutoReloadPreload = DISABLE;
LHL_TIM_Init(TIM1, &TIM_InitStructure);
TIM1->CCR1 = uploadCounter;
TIM1->CNT = 0;
LHL_TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);/* 使能TIM1比较中断CC1 */
NVIC_EnableIRQ(TIM1_IRQn);
NVIC_SetPriority(TIM1_IRQn, 1);
LHL_TIM_Start(TIM1); /* 运行TIM1 */
}
/**------------------------------------------------------------------------
* @brief 通用比较定时器无电平输出不重置TIM1->CNT 更新比较值
* @note 时钟源APB2_CLK
* @param uploadCounter: 计数值(1~65535),需要换算成期望周期 计数值=65535/4000*t
* @example: ResetTimer1_CC1(327+TIM1->CNT); // 下个20ms进入比较中断
**/
void ResetTimer1_CC1( u16 uploadCounter )
{
TIM1->CCR1 = uploadCounter;
TIM1->SR = (uint16_t)~TIM_IT_CC1;
LHL_TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
}
/**------------------------------------------------------------------------
* @brief 停用定时器
* @note
* @param
* @example
**/
void StopTimer1(void)
{
LHL_TIM_Stop(TIM1);
NVIC_DisableIRQ( TIM1_IRQn );
LHL_TIM_ClearFlag(TIM1, TIM_IT_UPDATE|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_TRIGGER);
LHL_TIM_ITConfig( TIM1, TIM_IT_UPDATE|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_TRIGGER, DISABLE );
}
/*-=====================================================================================================
//TIMER2
-=====================================================================================================*/
/**------------------------------------------------------------------------
* @brief 通用定时器启动(自适应时钟周期)
* @note 时钟源APB1_CLK
* @param uploadCounter: 期望的周期,单位:毫秒 范围:(1~4000)
* @example: StartTimer2(10); // 启动10ms周期定时器
**/
void StartTimer2_UIE(u16 uploadCounter)
{
if(uploadCounter>4000)uploadCounter = 4000;
if(uploadCounter<= 0)uploadCounter = 1;
u32 APB1_CLK = LHL_RCC_GetPCLK1Freq();
u32 prescaler = (APB1_CLK / 16000UL) - 1; //固定分频系数 (APB1_CLK / 32000UL) - 1;
u32 period =(u32)(16UL * uploadCounter);//动态ARR计数 (uint32_t)(32000UL * uploadCounter) / 1000UL;
TIM_InitTypeDef TIM_InitStructure;
TIM_InitStructure.Period = period;
TIM_InitStructure.Prescaler = prescaler;
TIM_InitStructure.ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.CounterMode = TIM_COUNTERMODE_UP;
TIM_InitStructure.AutoReloadPreload = ENABLE;
LHL_TIM_Init(TIM2, &TIM_InitStructure);
/*使能TIM1更新中断UIE */
LHL_TIM_ITConfig(TIM2, TIM_IT_UPDATE, ENABLE);
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
LHL_TIM_Start(TIM2);
}
/**------------------------------------------------------------------------
* @brief 通用周期定时器(自适应时钟周期)修改周期
* @note 时钟源APB1_CLK
* @param uploadCounter: 期望的周期,单位:毫秒 范围:(1~4000)
* @example: ResetTimer2_UIE(20); // 定时器周期改为20ms
**/
void ResetTimer2_UIE(u16 uploadCounter)
{
// 参数检查
if(uploadCounter>4000)uploadCounter = 4000;
if(uploadCounter<= 0)uploadCounter = 1;
// 计算新ARR的值
u32 period =(u32)(16UL * uploadCounter); //PSC不变ARR计算与StartTimer1相同
TIM2->CNT = 0; //先重置计数器 再设置ARR避免立即溢出
LHL_TIM_ClearPending(TIM2, TIM_IT_UPDATE);//当前CNT已经接近或超过ARR这里可能产生更新事件 所以需要先清除标志
TIM2->ARR = (u16)period ; //修改ARR 如果PSC需要改变必须停止定时器
LHL_TIM_Start(TIM2); //确保定时器启用
}
/**------------------------------------------------------------------------
* @brief 停用定时器
* @note
* @param
* @example
**/
void StopTimer2(void)
{
LHL_TIM_Stop(TIM2);
NVIC_DisableIRQ( TIM2_IRQn );
LHL_TIM_ClearFlag(TIM2, TIM_IT_UPDATE|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_TRIGGER);
LHL_TIM_ITConfig( TIM2, TIM_IT_UPDATE|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_TRIGGER, DISABLE );
}
/**------------------------------------------------------------------------
* @brief 输出定时器
* @note 时钟源APB2_CLK
* @param uploadCounter: PWM期望的周期单位Hz 范围:(1~400)
duty :PWM占空比 范围:(0-100)
* @example: StartTimer1_PWM(10,50); // 启动10Hz(100ms)周期定时器,PWM输出占空比50%
StartTimer1_PWM(400,50); //启动400Hz(2.5ms)周期定时器,PWM输出占空比50%
**/
void StartTimer1_PWM(u16 freq_hz , u16 duty)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_InitTypeDef TIM_InitStructure;
TIM_PWMInitTypeDef TIM_PWMInitStructure;
u32 APB2_CLK = LHL_RCC_GetPCLK2Freq();
u16 period =10000; //固定ARR计数
u32 prescaler = (APB2_CLK /(period*freq_hz) )-1;
u16 dutyValue = period*duty/100;
/* 1. TIM1 通道1 GPIO复用配置 */
GPIO_InitStructure.Pin = GPIO_PIN_5; // P0.5->TIM1 CHANNEL1
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Current = GPIO_CURRENT_16mA;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.SchmittTrigger = ENABLE;
GPIO_InitStructure.Alternate = GPIO0_5_AF_TIM1_CH1;
LHL_GPIO_Init(pGPIO0, &GPIO_InitStructure);
/* 2. TIM1 时基配置 */
TIM_InitStructure.Prescaler = prescaler; // 设置定时器时钟
TIM_InitStructure.Period = period-1; // 设置定时器周期
TIM_InitStructure.ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.CounterMode = TIM_COUNTERMODE_UP;
TIM_InitStructure.AutoReloadPreload = ENABLE; // 开启ARR预加载
LHL_TIM_Init(TIM1, &TIM_InitStructure);
/* 3. TIM1 通道1输出PWM配置 */
TIM_PWMInitStructure.Pulse = dutyValue; // 设置占空比
TIM_PWMInitStructure.PWMMode = TIM_PWMMODE_PWM1; // PWM模式1
TIM_PWMInitStructure.PWMPolarity = TIM_PWMPOLARITY_ACTIVE_HIGH; // PULSE期间输出有效电平
TIM_PWMInitStructure.PWMPreload = ENABLE; // 开启CCR预加载
TIM_PWMInitStructure.PWMFastMode = DISABLE;
LHL_TIM_PWM_Init(TIM1, &TIM_PWMInitStructure, TIM_CHANNEL_1);
/* 4. 开启TIM1 的PWM输出 */
LHL_TIM_Start(TIM1);
}
void ResetTimer1_PWM(u16 duty)
{
//限幅
if(duty > 100)duty = 100;
if(duty < 0)duty = 0;
u16 dutyValue = 100*duty ; //10000*duty/100;
//更新占空比
LHL_TIM_PWM_SetDutyCycle(TIM1, dutyValue, TIM_CHANNEL_1);
}
/*-=====================================================================================================
//定时器中断回调
-=====================================================================================================*/
/**------------------------------------------------------------------------
* @brief 定时器回调函数注册
* @note
* @param TIM_TypeDef *timerpTIM1 pTIM2 timer_irq_callback_t tim_irq_callback :自定义回调函数名
* @example: Timer_register_irq_callback(pTIM1,callback1);
**/
static timer_irq_callback_t tim1_irq_callback ,tim2_irq_callback;
void Timer_register_irq_callback(TIM_TypeDef *timer, timer_irq_callback_t tim_irq_callback)
{
if(timer == TIM1) {tim1_irq_callback = tim_irq_callback; NVIC_EnableIRQ(TIM1_IRQn);}
else if(timer == TIM2) {tim2_irq_callback = tim_irq_callback; NVIC_EnableIRQ(TIM2_IRQn);}
}
/**------------------------------------------------------------------------
* @brief 低功耗定时器1中断函数
* @note 中断类型:
* TIM_IT_UPDATE
* TIM_IT_CC1
* TIM_IT_CC2
* TIM_IT_TRIGGER
**/
void TIM1_IRQHandler(void)
{
uint16_t irq_type = TIM1->SR ; //中断标志
if (irq_type & TIM_IT_CC1) { // 处理比较中断
if (tim1_irq_callback != NULL) tim1_irq_callback();// 调用用户注册的回调函数
}
TIM1->SR = (uint16_t)~irq_type; //清除中断标志
/*
if (LHL_TIM_GetPending(TIM1, TIM_IT_UPDATE)== SET) // 判断是否TIM1 Update中断
{
LHL_TIM_ClearPending(TIM1, TIM_IT_UPDATE); // 清除中断标志
}
if (LHL_TIM_GetPending(TIM1, TIM_IT_CC1) == SET) // 判断是否TIM1 CC1中断
{
LHL_TIM_ClearPending(TIM1, TIM_IT_CC1); // 清除中断标志
}
if (LHL_TIM_GetPending(TIM1, TIM_IT_CC2) == SET)
{
LHL_TIM_ClearPending(TIM1, TIM_IT_CC2);
}
if (LHL_TIM_GetPending(TIM1, TIM_IT_TRIGGER) == SET)
{
LHL_TIM_ClearPending(TIM1, TIM_IT_TRIGGER);
}
*/
}
/**------------------------------------------------------------------------
* @brief 低功耗定时器2中断函数
**/
void TIM2_IRQHandler(void)
{
uint16_t irq_type = TIM2->SR ; //中断标志
if (tim2_irq_callback != NULL) tim2_irq_callback();// 调用用户注册的回调函数
TIM2->SR = (uint16_t)~irq_type; //清除中断标志
}