淘先锋技术网

首页 1 2 3 4 5 6 7

NUCLEO-F411RE RT-Thread 体验 (8) - GCC环境 TIM定时器驱动移植与基本使用

驱动移植

定时器驱动文件位于drv_hwtimer.c中,对应components层的文件位于rt-thread/components/drivers/hwtimer/hwtimer.c中。

修改Makefile,将其编译进去。

在这里插入图片描述

在rtconfig.h中增加TIM的配置

在这里插入图片描述

在RT-Thread-basic/Core/Inc/stm32f4xx_hal_conf.h使能HAL_TIM_MODULE_ENABLED

在这里插入图片描述

修改RT-Thread-basic/Core/Src/stm32f4xx_hal_msp.c

在HAL_TIM_Base_MspInit增加Tim 时钟的初始化。这个函数是个WEAK函数,在HAL_TIM_Base_Init中被调用。而HAL_TIM_Base_Init又在drv_hwtimer.c中的timer_init被调用,所以这个函数一定要添加。
在这里插入图片描述

修改RT-Thread-basic/libraries/HAL_Drivers/config/f4/tim_config.h

查看是否有TIM3 的相关配置。如果没有,将其添加。
在这里插入图片描述

编译查看设备是否生成

在这里插入图片描述

测试APP的编写

用的是官方的demo修改而来。
hwtimer_sample on 定时器开启, LED快速闪烁
hwtimer_sample off 定时器关闭,LED 熄灭
其中freq = 10000,其实设置timer的prescaler = 100M/10000= 10000-1。
也就是计时1s需要计数10000次,一次0.1ms。单次计时在0.1ms-1ms之间
,但是hrtimer.c timeout_calc函数里做了一个转换,可以计时多余1s。

在这里插入图片描述

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-30     misonyo      first implementation.
 */
/*
 * 程序清单:这是一个 hwtimer 设备使用例程
 * 例程导出了 hwtimer_sample 命令到控制终端
 * 命令调用格式:hwtimer_sample
 * 程序功能:硬件定时器超时回调函数周期性10ms去改变LED的状态。
*/


#include <rtthread.h>
#include <rtdevice.h>
#include "led.h"

#ifdef BSP_USING_TIM3

#define HWTIMER_DEV_NAME   "timer3"     /* 定时器名称 */
/* 定时器超时回调函数 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    led_toggle();
    return 0;
}
rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
static int hwtimer_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
    rt_hwtimer_mode_t mode;         /* 定时器模式 */
    rt_uint32_t freq = 10000;       /* 计数频率 */

    if (argc == 2)
    {
        if (!rt_strncmp(argv[1],"on",2))
        {  
            /* 查找定时器设备 */
            hw_dev = rt_device_find(HWTIMER_DEV_NAME);
            if (hw_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(hw_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(hw_dev, timeout_cb);
            /* 设置计数频率(默认1Mhz或支持的最小计数频率) */
            ret = rt_device_control(hw_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(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
            if (ret != RT_EOK)
            {
                rt_kprintf("set mode failed! ret is :%d\n", ret);
                return ret;
            }
            /* 设置定时器超时值为5s并启动定时器 */
            timeout_s.sec = 0;              /* 秒 */
            timeout_s.usec = 20000;        /* 微秒 */
            if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
            {
                rt_kprintf("set timeout value failed\n");
                return RT_ERROR;
            }
        }
        else if (!rt_strncmp(argv[1],"off",3))
        {
            mode = HWTIMER_MODE_PERIOD;
            ret = rt_device_control(hw_dev, HWTIMER_CTRL_STOP, &mode);  
            rt_device_close(hw_dev);
        }
        else
        {
            rt_kprintf("Usage: hwtimer_sample on /off\n");
        }
    }
    else
    {
        rt_kprintf("Usage: hwtimer_sample on /off\n");
    }
    
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
#endif

代码

代码下载