新手入门
- 积分
- 8
- 金钱
- 8
- 注册时间
- 2018-9-8
- 在线时间
- 8 小时
|
22金钱
本帖最后由 Zidone 于 2022-7-21 10:41 编辑
1.首先说明一下,我的目的是实现微秒级别的延时。我使用的单片机是STM32H750,主频目前跑在480MHz,使用的TIM2挂载在APB1总线上,APB1总线目前时钟频率是120MHz。
APB21 prescaler != 1, 所以APB1上的TIM2CLK = APB1 x 2 = 240MHz。我把定时器的分频Prescaler设置为240,这样就得到1MHz(1us)的定时器时钟。
另外,定时器2是32位的,那么最大的溢出值Period位2的32次方,即0xFFFF FFFF。
##############################分割线#################################################
# 以下内容位于bsp_timer.c
/* 保存 TIM定时中断到后执行的回调函数指针 */
static void (*TIM2_CallBack1)(void);
static void (*TIM2_CallBack2)(void);
static void (*TIM2_CallBack3)(void);
static void (*TIM2_CallBack4)(void);
/*下面这个函数初始化定时器2的配置,配置定时器时钟位1Mhz,配置定时器中断,启动定时器*/
void InitTIM2forTimer(void){
TIM_HandleTypeDef TIM_HandleStruct = {0};
__HAL_RCC_TIM2_CLK_ENABLE(); /* 使能TIM2时钟 */
TIM_HandleStruct.Instance = TIM2;
TIM_HandleStruct.Init.Prescaler = 240;//240MHz / 240 = 1MHz(TIM2CLK)
TIM_HandleStruct.Init.Period = 0xFFFFFFFF;
TIM_HandleStruct.Init.ClockDivision = 0;
TIM_HandleStruct.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM_HandleStruct.Init.RepetitionCounter = 0;
TIM_HandleStruct.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&TIM_HandleStruct) != HAL_OK){
Error_Handler();
}
/* 配置定时器中断,给CC捕获比较中断使用 */
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* 启动定时器 */
HAL_TIM_Base_Start(&TIM_HandleStruct);
}
/*这个函数用于启动定时器2用于定时,usChannel用于选择定时器的通道(1-4),usTimeOut用于定时多少us,void (*pCallBack)(void)是回调函数*/
void StartTIM2forTimer(uint8_t usChannel, uint32_t usTimeOut, void (*pCallBack) (void))
{
/* H750速度较快,无需补偿延迟,实测精度正负1us */
switch (usChannel){
case 1:
TIM2_CallBack1 = pCallBack;
TIM2->CCR1 = TIM2->CNT + usTimeOut; /* 设置捕获比较计数器CC1 */
TIM2->SR = (uint32_t)~TIM_IT_CC1; /* 清除CC1中断标志 */
TIM2->DIER |= TIM_IT_CC1; /* 使能CC1中断 */
break;
case 2:
TIM2_CallBack2 = pCallBack;
TIM2->CCR2 = TIM2->CNT + usTimeOut; /* 设置捕获比较计数器CC2 */
TIM2->SR = (uint32_t)~TIM_IT_CC2; /* 清除CC2中断标志 */
TIM2->DIER |= TIM_IT_CC2; /* 使能CC2中断 */
break;
case 3:
TIM2_CallBack3 = pCallBack;
TIM2->CCR3 = TIM2->CNT + usTimeOut; /* 设置捕获比较计数器CC3 */
TIM2->SR = (uint32_t)~TIM_IT_CC3; /* 清除CC3中断标志 */
TIM2->DIER |= TIM_IT_CC3; /* 使能CC3中断 */
break;
case 4:
TIM2_CallBack4 = pCallBack;
TIM2->CCR4 = TIM2->CNT + usTimeOut; /* 设置捕获比较计数器CC4 */
TIM2->SR = (uint32_t)~TIM_IT_CC4; /* 清除CC4中断标志 */
TIM2->DIER |= TIM_IT_CC4; /* 使能CC4中断 */
break;
default:
Error_Handler();/*总共只可选通道1-4,选其它的就错误了*/
}
}
/*这是定时器2的中断服务函数,在指定定时器通道的cnt到达cnt+usTimeout触发该中断,触发后执行回调函数,关闭定时器中断*/
void TIM2_IRQHandler(void)
{
uint32_t itstatus = 0x0, itenable = 0x0;
itstatus = TIM2->SR & TIM_IT_CC1;
itenable = TIM2->DIER & TIM_IT_CC1;
if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET))
{
TIM2->SR = (uint32_t)~TIM_IT_CC1;
TIM2->DIER &= (uint32_t)~TIM_IT_CC1; /* 禁能CC1中断 */
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
TIM2_CallBack1();
}
itstatus = TIM2->SR & TIM_IT_CC2;
itenable = TIM2->DIER & TIM_IT_CC2;
if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET))
{
TIM2->SR = (uint32_t)~TIM_IT_CC2;
TIM2->DIER &= (uint32_t)~TIM_IT_CC2; /* 禁能CC2中断 */
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
TIM2_CallBack2();
}
itstatus = TIM2->SR & TIM_IT_CC3;
itenable = TIM2->DIER & TIM_IT_CC3;
if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET))
{
TIM2->SR = (uint32_t)~TIM_IT_CC3;
TIM2->DIER &= (uint32_t)~TIM_IT_CC3; /* 禁能CC2中断 */
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
TIM2_CallBack3();
}
itstatus = TIM2->SR & TIM_IT_CC4;
itenable = TIM2->DIER & TIM_IT_CC4;
if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET))
{
TIM2->SR = (uint32_t)~TIM_IT_CC4;
TIM2->DIER &= (uint32_t)~TIM_IT_CC4; /* 禁能CC4中断 */
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
TIM2_CallBack4();
}
}
##############################分割线#################################################
# 以下内容位于main.c
bool flag = true;
/*TIM2通道1的回调函数*/
static void TIM2_CallBack1(void);
InitTIM2forTimer();//首先调用定时器2初始化
while (1){
while(flag){
StartTIM2forTimer(1 ,100 0000, TIM2_CallBack1);//定时一秒
flag = false;
}
}
static void TIM2_CallBack1(void){
LED1_Toggle();
flag = true;
}
##############################分割线#################################################
但是从实验结果来看,好像确实能进入到上面这个回调函数,但是这个定时好像极其不准确,LED闪烁的超级快。之前做定时器中断的实验以及定时器用作PWM输出的实验时间都是非常准确的。
麻烦论坛各位大佬和原子哥能否帮忙看一下,提出一些建议,实在找不到问题所在了。
|
|