//

rt-thread使用hwtimer不工作的问题

使用hwtimer可以提高定时精度和us级定时,配合回调函数和信号量也不用担心系统自带的us延迟函数 void rt_hw_us_delay(rt_uint32_t us)造成的阻塞问题

芯片:stm32g070

使用hwtimer需要改动的地方如下

  1. board.h中打开timer的相关宏定义,比如使用timer15就打开
  2. board.c中添加对应timer的HAL_TIM_Base_MspInit();初始化函数,实际就是打开定时器的时钟
  3. drivers下stm32g0xx_hal_conf.h中打开#define HAL_TIM_MODULE_ENABLED
  4. tim_config.h中添加定时器的默认配置

 

//board.h
#define
BSP_USING_TIM #ifdef BSP_USING_TIM #define BSP_USING_TIM15 /*#define BSP_USING_TIM16*/ /*#define BSP_USING_TIM17*/ #endif
//tim_config.h
#ifdef BSP_USING_TIM15 #ifndef TIM15_CONFIG
#define TIM15_CONFIG \ { \ .tim_handle.Instance = TIM15, \ .tim_irqn = TIM15_IRQn, \ .name = "timer15", \ } #endif /* TIM15_CONFIG */ #endif /* BSP_USING_TIM15 */

 

问题现象和解决

根据例程添加hwtimer组件和相关驱动代码的完善后发现启动定时器后无法进入回调函数

问题原因:timer的中断函数名不对

原来的代码如下

drv_hwtimer.c中 TIM1_BRK_TIM15_IRQHandler是错误的

#ifdef BSP_USING_TIM15
void TIM1_BRK_TIM15_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    HAL_TIM_IRQHandler(&stm32_hwtimer_obj[TIM15_INDEX].tim_handle);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

应该改为TIM15_IRQHandler,如下

void TIM15_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    HAL_TIM_IRQHandler(&stm32_hwtimer_obj[TIM15_INDEX].tim_handle);
    /* leave interrupt */
    rt_interrupt_leave();
}

 

利用hwtimer实现精确定时

#define HWTIMER_DEV_NAME   "timer15"     /* 定时器名称 */
rt_sem_t tim_sem;
rt_device_t tim_dev = RT_NULL;   /* 定时器设备句柄 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size);

int tim_init(void)
{
    /* 初始化信号量*/
    tim_sem = rt_sem_create("timer", 0, RT_IPC_FLAG_FIFO);
    if (tim_sem == RT_NULL)
    {
        LOG_E("init tim_sem failed.\n");
    }
    /* 查找定时器设备 */
    tim_dev = rt_device_find(HWTIMER_DEV_NAME);
    if (tim_dev == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", HWTIMER_DEV_NAME);
        return RT_ERROR;
    }
    /* 以读写方式打开设备 */
    ret = rt_device_open(tim_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
        return ret;
    }

    /* 设置超时回调函数 */
    rt_device_set_rx_indicate(tim_dev, timeout_cb);

#if 0  //默认配置就行,无需配置
        /* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
        rt_device_control(tim_dev, HWTIMER_CTRL_FREQ_SET, &freq);
        /* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
        mode = HWTIMER_MODE_ONESHOT;
        ret = rt_device_control(tim_dev, HWTIMER_CTRL_MODE_SET, &mode);
        if (ret != RT_EOK)
        {
            rt_kprintf("set mode failed! ret is :%d\n", ret);
            return ret;
        }
#endif
return 0;
}
//回调
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(tim_sem);
    return RT_EOK;
}
void hwtimer_delay_us(uint32_t us)
{
    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
    /* 设置定时器超时值并启动定时器 */
    timeout_s.sec = 0;      /**/
    timeout_s.usec = us;     /* 微秒 */
    rt_sem_control(tim_sem, RT_IPC_CMD_RESET, RT_NULL);
    if (rt_device_write(tim_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        //rt_kprintf("set timeout value failed\n");
        return ;
    }
    rt_sem_take(tim_sem, RT_WAITING_FOREVER);
}

 

posted @ 2024-07-24 00:06  一只鱼在水杯里  阅读(264)  评论(0)    收藏  举报