rtthread studio与正点原子apollo[3]--硬件定时器HTIMER
前言
本文介绍RT-Thread中如何使用硬件定时器。通过硬件定时器的中断实现LED周期控制的示例,说明硬件定时器的配置及相关API函数的使用。
一、软件定时器和硬件定时器?
1、软件定时器
关于软件定时器的使用可以参考官方文档
RT-Thread时钟管理
软件定时器是RT-Thread提供一类系统接口,优势是定时器的数量不受限制,缺点是定时的精确度相比于硬件定时器要低。
RT-Thread 的定时器提供两类定时器机制:单次触发和周期性触发。
RT-Thread 的软件定时器有两种模式:HARD_TIMER模式和SOFT_TIMER模式。
注意:软件定时的两种模式的区别是--超时函数执行时所处的上下文环境,SOFT_TIMER模式的定时器超时函数在都会在 timer 线程的上下文环境中执行,而HARD_TIMER 模式的定时器超时函数在中断上下文环境中执行
软件定时器的模式默认为**HARD_TIMER 模式**
2.硬件定时器
Apollo使用的STM32F767芯片内部包含15个定时器,有高级定时器、通用定时器、基本定时器和低功耗定时器,可以根据需要选择使用。一般应用中,通用定时器使用较多,STM32F767的通过用定时器有TIM2 ~ TIM5,TIM9 ~ TIM14。
关于RT-Thread中硬件定时器的使用说明可以参考官方文档
HTIMER设备管理
二、HTIMER使用详解
1.RT-Thread studio配置
在使用硬件定时器前需要在RT-Thread studio环境中启动硬件定时器并做相应的配置:
(1)首先,启动硬件定时器功能,按下图配置:
(2)打开board.h文件,根据提示配置定时器,如下图:
定时器的配置按提示进行:
第一步:在(1)中已经完成;
第二步:取消宏定义BSP_USING_TIM的注释,并根据实际需求启动相应的定时器,本例中使用定时器3,因此宏定义BSP_USING_TIM3
第三步:在stm32cubemx配置定时器,并将生成的HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)函数拷贝到board.c文件中
第四步:将stm32xxxx_hal_config.h文件中的#define HAL_TIM_MODULE_ENABLED的宏定义功能开启
注意事项
在配置定时器时,由于RT-Thread并未将所有的资源进行配置,因此需要手动添加代码以实现相应的功能。
例如,在使用定时器时,我们需要打开tim_config.h文件,根据代码添加自己的功能代码,如下图所示:
另外,在设置中断入口函数名时,名称是有区别的,如果不清楚该如何修改,可以右键根据引导找到相应的定义
2.功能代码实现
根据官方文档,调用相关API函数实现硬件定时器的使用
参考代码如下:
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define LED0 GET_PIN(B,0)
#define HWTIMER_DEV_NAME "timer3"//定义定时器名称
rt_device_t hwtim_dev;//设备句柄
static struct rt_semaphore hwtim3_sem;
static rt_err_t timeout_cb(void)
{
rt_sem_release(&hwtim3_sem);
return RT_EOK;
}
static int hwtimer_sample(void)
{
rt_err_t ret=RT_EOK;
rt_hwtimerval_t timeout_s;
rt_hwtimer_mode_t mode;
rt_uint32_t freq=10000;
hwtim_dev=rt_device_find(HWTIMER_DEV_NAME);//查找定时器
if(hwtim_dev==RT_NULL)
{
rt_kprintf("hwtimer sample run failed! can't find %s device!\n",HWTIMER_DEV_NAME);
return RT_ERROR;
}
ret=rt_device_open(hwtim_dev, RT_DEVICE_OFLAG_RDWR);//读写方式开启定时器
if(ret!=RT_EOK)
{
rt_kprintf("open %s device failed!\n",HWTIMER_DEV_NAME);
return RT_ERROR;
}
rt_device_set_rx_indicate(hwtim_dev, timeout_cb);//设置中断回调函数
ret=rt_device_control(hwtim_dev, HWTIMER_CTRL_FREQ_SET, &freq);//设置定时器工作频率
if(ret!=RT_EOK)
{
rt_kprintf("set frequency failed! ret is :%d\n", ret);
return ret;
}
mode=HWTIMER_MODE_PERIOD;
ret=rt_device_control(hwtim_dev, HWTIMER_CTRL_MODE_SET,&mode);//设置定时器为周期性
if(ret!=RT_EOK)
{
rt_kprintf("set mode failed! ret is :%d\n", ret);
return ret;
}
timeout_s.sec=1;
timeout_s.usec=0;//设置定时器中断时间
if(rt_device_write(hwtim_dev, 0, &timeout_s, sizeof(timeout_s))!=sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
return RT_ERROR;
}
return RT_EOK;
}
int main(void)
{
rt_uint8_t i=0;
rt_pin_mode(LED0, PIN_MODE_OUTPUT);
rt_pin_write(LED0, PIN_HIGH);
rt_sem_init(&hwtim3_sem,"timer3_sem" ,0, RT_IPC_FLAG_FIFO);
hwtimer_sample();
while (1)
{
if(rt_sem_take(&hwtim3_sem, RT_WAITING_FOREVER)==RT_EOK)
{
i++;
if(i%2==0)
{
rt_pin_write(LED0, PIN_HIGH);
i=0;
}
else
{
rt_pin_write(LED0, PIN_LOW);
}
}
}
return RT_EOK;
}
总结
本文介绍了RT-Thread中硬件定时器的配置使用方法,及使用时的注意事项。