历史上的今天
今天是:2024年12月17日(星期二)
2020年12月17日 | STM32F7xx —— Timer
2020-12-17 来源:eefocus
作用:输出PWM,测量脉冲长度,定时等。
一、基础定时器配置
// 基本定时器
#define TIMER_CHANNEL TIM3
#define TIMER_PREEMPT_PRIO TIM_PRIORITY
#define TIMER_RCC_FUNC __HAL_RCC_TIM3_CLK_ENABLE
#define TIMER_IRQ TIM3_IRQn
#define TIMER_IRQ_FUNC TIM3_IRQHandler
#define TIMER_DIV (10800 - 1)
#define TIMER_PERIOD (100 - 1)
static TIM_HandleTypeDef timer_handler; // 定时器操作句柄
// Period:自动重装值。 Prescaler:时钟预分频数
// 定时器溢出时间计算方法:Tout=((Period+1)*(Prescaler+1))/Ft us.
// Ft=定时器工作频率,单位:Mhz
void TimerInit(void)
{
timer_handler.Instance = TIMER_CHANNEL;
timer_handler.Init.Prescaler = TIMER_DIV;
timer_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
timer_handler.Init.Period = TIMER_PERIOD;
timer_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&timer_handler);
HAL_TIM_Base_Start_IT(&timer_handler);
}
// 定时器底层驱动 开启时钟 设置中断优先级
// 此函数会被 HAL_TIM_Base_Init()函数调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *timer)
{
TIMER_RCC_FUNC();
HAL_NVIC_SetPriority(TIMER_IRQ, TIM_PRIORITY, 1);
HAL_NVIC_EnableIRQ(TIMER_IRQ);
}
void TIMER_IRQ_FUNC(void)
{
HAL_TIM_IRQHandler(&timer_handler);
}
// 中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *timer)
{
if(timer == (&timer_handler))
{
// do something
}
}
二、带回调定时器
使用回调函数,以链表的方式管理所有的定时器。检测时间到,执行回调函数。TimerRun定时运行,TimerCreate创建一个定时器,TimerStart开启定时器。这里只是写了一个比较简单的定时器,操作系统里面也有类似的定时接口。
#define TIMER_CHANNEL TIM3
#define TIMER_PREEMPT_PRIO TIM_PRIORITY
#define TIMER_RCC_FUNC __HAL_RCC_TIM3_CLK_ENABLE
#define TIMER_IRQ TIM3_IRQn
#define TIMER_IRQ_FUNC TIM3_IRQHandler
#define TIMER_DIV (10800 - 1)
#define TIMER_PERIOD (100 - 1)
static struct
{
timer_t *next;
} timer_run;
static volatile uint32_t timer_ticks;
static uint32_t timer_ticks_run;
static TIM_HandleTypeDef timer_handler; // 定时器操作句柄
// Period:自动重装值。 Prescaler:时钟预分频数
// 定时器溢出时间计算方法:Tout=((Period+1)*(Prescaler+1))/Ft us.
// Ft=定时器工作频率,单位:Mhz
void TimerInit(void)
{
timer_run.next = NULL;
timer_handler.Instance = TIMER_CHANNEL;
timer_handler.Init.Prescaler = TIMER_DIV;
timer_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
timer_handler.Init.Period = TIMER_PERIOD;
timer_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&timer_handler);
HAL_TIM_Base_Start_IT(&timer_handler);
}
// 定时器底层驱动 开启时钟 设置中断优先级
// 此函数会被 HAL_TIM_Base_Init()函数调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *timer)
{
TIMER_RCC_FUNC();
HAL_NVIC_SetPriority(TIMER_IRQ, TIM_PRIORITY, 1);
HAL_NVIC_EnableIRQ(TIMER_IRQ);
}
void TIMER_IRQ_FUNC(void)
{
HAL_TIM_IRQHandler(&timer_handler);
}
// 中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *timer)
{
if(timer == (&timer_handler))
{
++timer_ticks;
}
}
//======================================================================================================
void TimerRun(void)
{
timer_t *timer;
timer_t *timer_done;
timer_done = NULL;
while(timer_ticks_run != timer_ticks)
{
timer = timer_run.next;
if(timer)
{
if(timer->ticks)
{
++timer_ticks_run;
timer->ticks--;
}
// 将后续超时的定时器都移除
while(timer && (0 == timer->ticks))
{
timer_run.next = timer->next;
timer->next = timer_done;
timer_done = timer;
timer = timer_run.next;
}
}
else
{
++timer_ticks_run;
}
}
while(timer_done)
{
timer = timer_done;
timer_done = timer->next;
timer->next = NULL;
timer->handler(timer->param);
}
}
void TimerCreate(timer_t *timer, timer_cb_t handler, void *param)
{
timer->handler = handler;
timer->param = param;
}
void TimerStart(timer_t *timer, uint32_t timeout)
{
timer_t *p;
uint32_t ticks = (timeout + 9) / 10;
TimerCancel(timer);
p = (timer_t *)&timer_run;
while(p->next)
{
if(ticks <= p->next->ticks)
{
p->next->ticks -= ticks;
break;
}
else
{
ticks -= p->next->ticks; // ticks 有可能为 0
}
p = p->next;
}
timer->ticks = ticks;
timer->next = p->next;
p->next = timer;
}
void TimerCancel(timer_t *timer)
{
timer_t *p;
if(NULL == timer)
{
return;
}
p = (timer_t *)&timer_run;
while(p->next)
{
if(p->next == timer)
{
if(timer->next)
{
timer->next->ticks += timer->ticks;
}
p->next = timer->next;
timer->next = NULL;
break;
}
p = p->next;
}
}
static timer_t timer;
static void handler(void *param)
{
TimerStart(&timer, 1000);
printf("TimerStartrn");
}
TimerCreate(&timer, handler, NULL);
TimerStart(&timer, 1000);
TimerRun(); // 放在10ms任务中运行
史海拾趣
|
几天不拆东西手痒痒,拆就拆个没拆过的!这次对一个光驱里的激光管下手。 这个激光管俗称激光头,并不是打开光驱外壳直接看到的光头部分,而是真正发出激光的部分。我们打开光驱外壳能直接看到的只是光学透镜的一部分。 这种激光管有三个引脚,其 ...… 查看全部问答> |
|
搞了很久的Java和.net,现在想学习下嵌入式,不知道从和下手,麻烦高手指点下,谢谢。 会C/C++,能看懂汇编,熟悉Linux系统 不懂电路,硬件学得不好… 查看全部问答> |
|
个人心得:我是本人聋人嵌入式开发 有经验者请告诉我适合主机?RAM? 我是来自北京联大特殊教育学院 08应届生 大学大专 现在学习C和数据结构基础差不多啊准备下个月去嵌入式开发周末班学习 觉得学习完后我很担心找不到工作啊呀白学半年 所以请求有经验者建议 哪里方面不足告诉我 谢谢 顶 全天在线 … 查看全部问答> |
|
EVC 编译TCPMP的时候,没有的选择ARMV4,是什么原因? EVC 编译TCPMP的时候,没有的选择ARMV4,是什么原因? 是下载的是0.72RC1的TCPMP源码,请问该如何处理?有做过的吗?网上的编译过程没有说到这个问题的。 请过的DX麻烦了… 查看全部问答> |
|
2440+WINCE5.0 扩充128M SDRAM的问题。 我使用2440+wince5.0的平台,原先使用2片共64M字节的SDRAM,每片256bit,16bit位宽;现在想使用128M SDRAM,所以用了4片和原先一模一样的SDRAM芯片,在硬件连接上4片sdram芯片的BA0都与addr24连接,BA1都与addr25连接,另外其中两片 ...… 查看全部问答> |
|
串的操作 要求: (1)字符串采用数组存储,建立两个字符串String1和String2。输出两个字符串。 (2)将字符串String2的头n个字符添加到String1的尾部。输出结果。 (3)查找串String3在串String1中的位置,若String3在String1中不存在,则插入 ...… 查看全部问答> |
|
欢迎满足以下条件之一的有识之士与我们联系,公司网址: www.nerc.com.cn,发送简历邮箱地址:whl668@epri.ac.cn。 1.具有2年以上电力行业嵌入式产品开发经验。 2. ...… 查看全部问答> |
|
最近网友问到OSSchedLock()这个函数的问题,当时我也搞得半昏迷状态。 这个函数又叫上锁函数,如果在一个任务里面调用了上锁函数,那么OSSched()这个任务切换函数就不会执行也就是说不会进任务调度。 调用OSSchedLock()以后,用户 ...… 查看全部问答> |




