Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
TIM
硬件定时器
TIM,硬件定时器驱动程序
发布于 2024-04-30 10:11:06 浏览:300
订阅该版
```c /* ********************************************************************************************************* * 模块名称 : 硬件定时器驱动 * 文件名称 : bsp_hwtimer.c * 版 本 : V1.0 * 说 明 : 源文件,硬件定时器最小定时时间可到达us级,可以用来进行串口数据的断帧处理,表中的div变量决定计数的频率 ********************************************************************************************************* */ #include "bsp_hwtimer.h" #ifdef BSP_USING_TIM #define TIM_NUM 4 //开启的定时器通道个数也可以认为是表的行数 typedef struct { //定时器结构体 TIM_TypeDef* TIMx; //定时器TIM2/TIM3.... void (*init)(TIM_TypeDef* TIMx,uint16_t Prescaler); //定时器初始化函数 uint32_t div; //分频系数1/div 秒 uint32_t *timeout; //定时时间 rt_hwtimer_mode_t *mode; //模式HWTIMER_MODE_ONESHOT单次/HWTIMER_MODE_PERIOD重复 uint16_t capture_compare_channel; //TIM_CHANNEL_1-4 HAL_TIM_ActiveChannel active_channel; //定时器通道,取值HAL_TIM_ACTIVE_CHANNEL_1-4 } Timer_struct; /*定时器初始化函数*/ static void bsp_InitHardTimer(TIM_TypeDef* TIMx,uint16_t div); //定时器的初始化函数,作为表的回调函数,每个定时器只需要初始化一次即可, static uint32_t time_out[TIM_NUM]; //用户调用函数注册时设置的时间。无需更改 static rt_hwtimer_mode_t mode[TIM_NUM]; /*根据实际定时器数量修改*/ static void (*h_TIM_CallBack[TIM_NUM])(void *parameter); //定时器超时回调函数数组数组长度与下表行数有关 static void *uaser_parameter[TIM_NUM]; const Timer_struct timer_struct_par[] = { //按实际情况更改此表数据,表改完后需要对应修改 TIM_NUM #ifdef BSP_USING_TIM2 {TIM2, bsp_InitHardTimer, 1000*1000, &time_out[0], &mode[0], TIM_CHANNEL_1, HAL_TIM_ACTIVE_CHANNEL_1}, {TIM2, RT_NULL, RT_NULL, &time_out[1], &mode[1], TIM_CHANNEL_2, HAL_TIM_ACTIVE_CHANNEL_2}, {TIM2, RT_NULL, RT_NULL, &time_out[2], &mode[2], TIM_CHANNEL_3, HAL_TIM_ACTIVE_CHANNEL_3}, {TIM2, RT_NULL, RT_NULL, &time_out[3], &mode[3], TIM_CHANNEL_4, HAL_TIM_ACTIVE_CHANNEL_4}, #endif }; uint8_t timer_dev_num = sizeof(timer_struct_par)/sizeof(timer_struct_par[0]);//计算表的长度 /* ********************************************************************************************************* * 函 数 名: bsp_InitHardTimer * 功能说明: 配置 TIMx,用于us级别硬件定时。TIMx将自由运行,永不停止. * TIMx可以用TIM2 - TIM5 之间的TIM, 这些TIM有4个通道, 挂在 APB1 上 * 形 参: TIMx :定时器 * div :分频值分频值为1000时单位为1ms,分频值为1000*1000时单位为1us * 返 回 值: 无 ********************************************************************************************************* APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14 APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11 */ static void bsp_InitHardTimer(TIM_TypeDef* TIMx,uint16_t div) { TIM_HandleTypeDef TimHandle = {0}; uint32_t Period; uint16_t Prescaler; rt_uint32_t flatency = 0; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &flatency); uint32_t pclk1_doubler = 1; uint32_t pclk2_doubler = 1; if (RCC_ClkInitStruct.APB1CLKDivider != RCC_HCLK_DIV1) pclk1_doubler = 2;//APB1CLKDivider != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 ; if (RCC_ClkInitStruct.APB2CLKDivider != RCC_HCLK_DIV1) pclk2_doubler = 2;//prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 ; if ((rt_uint32_t)TIMx >= APB2PERIPH_BASE) Prescaler = (uint32_t)(HAL_RCC_GetPCLK2Freq() * pclk2_doubler / div) - 1; else Prescaler = (uint32_t)(HAL_RCC_GetPCLK1Freq() * pclk1_doubler / div) - 1; #ifdef SOC_SERIES_STM32F1 Period = 0xFFFF;//F1的芯片定时器有TIM1-TIM4,均是16位定时器,最大计数值是65535, #endif #ifdef SOC_SERIES_STM32F4 if(TIMx == TIM2 || TIMx == TIM5) usPeriod = 0xFFFFFFFF;//F4的芯片定时器有TIM1-TIM14,TIM2、TIM5是32位其余为16位。 else usPeriod = 0xFFFF; #endif TimHandle.Instance = TIMx; TimHandle.Init.Prescaler = Prescaler; //设置分频 TimHandle.Init.Period = Period; //设置最大计数值 TimHandle.Init.ClockDivision = 0; TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; TimHandle.Init.RepetitionCounter = 0; TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK) _Error_Handler(__FILE__, __LINE__); if(TIMx == TIM1) /* 配置定时器中断,给CC捕获比较中断使用 */ { HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 1); HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); } else if(TIMx == TIM2) { HAL_NVIC_SetPriority(TIM2_IRQn, 0, 2); HAL_NVIC_EnableIRQ(TIM2_IRQn); } else if(TIMx == TIM3) { HAL_NVIC_SetPriority(TIM3_IRQn, 0, 3); HAL_NVIC_EnableIRQ(TIM3_IRQn); } else if(TIMx == TIM4) { HAL_NVIC_SetPriority(TIM4_IRQn, 0, 4); HAL_NVIC_EnableIRQ(TIM4_IRQn); } HAL_TIM_Base_Start(&TimHandle);/* 启动定时器 */ } /* 无需更改 ********************************************************************************************************* * 函 数 名: timer_init * 功能说明: 定时器初始化函数 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ static int timer_init(void) { for(uint8_t i = 0;i < timer_dev_num;i++) { if(timer_struct_par[i].init != RT_NULL) timer_struct_par[i].init(timer_struct_par[i].TIMx,timer_struct_par[i].div);//调用初始化函数,初始化定时器的分频,计数模式等。 } } INIT_DEVICE_EXPORT(timer_init);//自动初始化 /* 无需更改 ********************************************************************************************************* * 函 数 名: start_period_time * 功能说明: 重复循环的定时器重新开启 * 形 参:htim 定时器句柄,index表中的行 * 返 回 值: 无 ********************************************************************************************************* */ static void start_period_time(TIM_HandleTypeDef *htim,uint8_t index) { uint32_t cnt_tar; cnt_tar = timer_struct_par[index].TIMx->CNT + *timer_struct_par[index].timeout; /* 计算捕获的计数器值 */ __HAL_TIM_SET_COMPARE(htim,timer_struct_par[index].capture_compare_channel,cnt_tar); /* 设置捕获比较计数器CC*/ HAL_TIM_OC_Start_IT(htim,timer_struct_par[index].capture_compare_channel); /* 使能CC中断 */ } /* 无需更改 ********************************************************************************************************* * 函 数 名: HAL_TIM_OC_DelayElapsedCallback * 功能说明: TIM 中断服务程序中调用的回调函数,先关闭定时器调用回调函数,然后再重新开启定时器。 * 形 参:定时器句柄 * 返 回 值: 无 ********************************************************************************************************* */ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) { for(uint8_t i = 0;i < timer_dev_num;i++) { if(timer_struct_par[i].TIMx == htim->Instance && timer_struct_par[i].active_channel == htim->Channel) {//找到对应表的第几行 HAL_TIM_OC_Stop_IT(htim,timer_struct_par[i].capture_compare_channel);/* 禁能CC中断 */ if(h_TIM_CallBack[i] != RT_NULL) h_TIM_CallBack[i](uaser_parameter[i]);//调用用户注册的回调函数 if(*timer_struct_par[i].mode == HWTIMER_MODE_PERIOD) start_period_time(htim,i);//重复的定时器重新开启定时器 } } } /* 在适当位置调用,用于设置某个定时器的某通道定时时间,循环模式,及回调函数 ********************************************************************************************************* * 函 数 名: bsp_StartHardTimer * 功能说明: 使用TIM2-5做单次定时器使用, 定时时间到后执行回调函数。可以同时启动4个定时器通道,互不干扰。 * 定时精度正负1us (主要耗费在调用本函数的执行时间) * TIM2和TIM5 是32位定时器。定时范围很大 * TIM3和TIM4 是16位定时器。 * 形 参: TIMx :定时器 * Channel : 捕获比较通道几 * _uiTimeOut : 超时时间, 单位 1us. 对于16位定时器,最大 65.5ms; 对于32位定时器,最大 4294秒 * _pCallBack : 定时时间到后,被执行的函数 * 返 回 值: 无void (*timeout)(void *parameter) ********************************************************************************************************* */ void bsp_StartHardTimer(TIM_TypeDef* TIMx, rt_hwtimer_mode_t mode, uint16_t capture_compare_channel, uint32_t _uiTimeOut, void (*_pCallBack)(void *parameter), void *parameter) { uint32_t cnt_tar; TIM_HandleTypeDef htim;//构造一个定时器句柄,变量中的某些结构体数据不是正确的,不可乱用(初始化时没有保存正确的句柄导致此处问题) htim.Instance = TIMx; cnt_tar = TIMx->CNT + _uiTimeOut; /* 计算捕获的计数器值 */ for(uint8_t i = 0;i < timer_dev_num;i++) { if(timer_struct_par[i].TIMx == TIMx && timer_struct_par[i].capture_compare_channel == capture_compare_channel) {//找到对应表的第几行 *timer_struct_par[i].timeout = _uiTimeOut; //用户设置的超时时间放入表内 *timer_struct_par[i].mode = mode; //用户设置的循环模式放入表内 h_TIM_CallBack[i] = _pCallBack; //用户设置的回调函数放在表内 uaser_parameter[i] = parameter; __HAL_TIM_SET_COMPARE(&htim,capture_compare_channel,cnt_tar); /* 设置捕获比较计数器CC*/ TIM_CHANNEL_STATE_SET(&htim,capture_compare_channel,HAL_TIM_CHANNEL_STATE_READY);//只有初始化完成后才能使用这个函数 HAL_TIM_OC_Start_IT(&htim,capture_compare_channel);/* 使能CC中断 */ } } } #endif ```
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
aeniac
这家伙很懒,什么也没写!
文章
6
回答
42
被采纳
1
关注TA
发私信
相关文章
1
dac设备可以使用dma+TIM定时器触发模式吗
2
关于在L4潘多拉上定时器TIM3跑hwtimer_sample例程出错的问题
3
如何添加HAL库的源文件?
4
RT-Thread中,如何使用TIM触发ADC采样?
5
在RT-Thread adc驱动中加入外部触发采集,有什么好的解决方案吗?
6
rt-thread有没有一次采样多个数据的函数?
7
ADC采样波形异常求教
8
stm32f407 pwm1配置
9
在stm32中移植了ADC+DMA+TIM周期采集电池电压,第二次调用会出现IBUSERR的段错误
10
配置华大的外设驱动,添加不存在的PWM和TIM配置失败
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
8
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部