• RT-Thread 设备驱动-硬件定时器浅析与使用


    RT-Thread 4.0.0

    访问硬件定时器设备

    应用程序通过 RT-Thread 提供的 I/O 设备管理接口来访问硬件定时器设备,相关接口如下所示:

    函数描述
    rt_device_find() 查找定时器设备
    rt_device_open() 以读写方式打开定时器设备
    rt_device_set_rx_indicate() 设置超时回调函数
    rt_device_control() 控制定时器设备,可以设置定时模式(单次/周期)/计数频率,或者停止定时器
    rt_device_write() 设置定时器超时值,定时器随即启动
    rt_device_read() 获取定时器当前值
    rt_device_close() 关闭定时器设备

    RT-Thread 提供的 I/O 设备硬件定时器,示例仅提供最通用简单的定时功能,其他定时器高级功能需自行在control中添加;

    下面对基于CubeMX、Hal库的BSP的硬件定时器的使用做简单描述。

    配置CubeMX

    配置之后生成代码,

    在 stm32f4xx_hal_conf.h 中 会实现 hal模块驱动

    #define HAL_TIM_MODULE_ENABLED

    修改工程目录下的 Kconfig

     在 Kconfig 中添加对 TIM的支持

        menuconfig BSP_USING_TIM
            bool "Enable Hardware TIM"
            default n
            select RT_USING_HWTIMER
            if BSP_USING_TIM
                config BSP_USING_TIM1
                    bool "Enable TIM1"
                    default n
                
                config BSP_USING_TIM2
                    bool "Enable TIM2"
                    default n
                
                config BSP_USING_TIM3
                    bool "Enable TIM3"
                    default n
                
                config BSP_USING_TIM4
                    bool "Enable TIM4"
                    default n
                
                config BSP_USING_TIM5
                    bool "Enable TIM5"
                    default n
                
                config BSP_USING_TIM6
                    bool "Enable TIM6"
                    default n

    然后使用Env工具 menuconfig 中使能 TIM3、TIM4

     

    然后 scons --target=mdk5

    用keil打开工程后在 tim_config.h 中 添加 TIM3、TIM4的配置

    #ifdef BSP_USING_TIM3
    #ifndef TIM3_CONFIG
    #define TIM3_CONFIG                                        
        {                                                       
           .tim_handle.Instance     = TIM3,                    
           .tim_irqn                = TIM3_IRQn,  
           .name                    = "timer3",                
        }
    #endif /* TIM3_CONFIG */
    #endif /* BSP_USING_TIM3 */
    
    #ifdef BSP_USING_TIM4
    #ifndef TIM4_CONFIG
    #define TIM4_CONFIG                                        
        {                                                       
           .tim_handle.Instance     = TIM4,                    
           .tim_irqn                = TIM4_IRQn,  
           .name                    = "timer4",                
        }
    #endif /* TIM4_CONFIG */
    #endif /* BSP_USING_TIM4 */    

    然后就可以在应用中直接操作设备名为 "timer3" 和 "timer4" 的设备了。

     设备驱动分析

    定时器设备 I/O 实现

    hwtimer.c  hwtimer.h

    定时器底层驱动实现(操作Hal库)

    drv_hwtimer.c  drv_hwtimer.h

    下面主要追踪以下定时器设备的注册及其初始化

    在 drv_hwtimer.c 中  定时器自动初始化,并注册设备

    static int stm32_hwtimer_init(void)
    
    INIT_BOARD_EXPORT(stm32_hwtimer_init);

    其中 hwtimer_ops.rt_hwtimer_init 会 调用 timer_init

    static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
    {
        uint32_t prescaler_value = 0;
        TIM_HandleTypeDef *tim = RT_NULL;
        struct stm32_hwtimer *tim_device = RT_NULL;
    
        RT_ASSERT(timer != RT_NULL);
        if (state)
        {
            tim = (TIM_HandleTypeDef *)timer->parent.user_data;
            tim_device = (struct stm32_hwtimer *)timer;
    
            /* time init */
    #if defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
            if (tim->Instance == TIM9 || tim->Instance == TIM10 || tim->Instance == TIM11)
    #elif defined(SOC_SERIES_STM32L4)
            if (tim->Instance == TIM15 || tim->Instance == TIM16 || tim->Instance == TIM17)
    #elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0)
            if (0)
    #endif
            {
    #ifndef SOC_SERIES_STM32F0
                prescaler_value = (uint32_t)(HAL_RCC_GetPCLK2Freq() * 2 / 10000) - 1;
    #endif
            }
            else
            {
                prescaler_value = (uint32_t)(HAL_RCC_GetPCLK1Freq() * 2 / 10000) - 1;
            }
            tim->Init.Period            = 10000 - 1;
            tim->Init.Prescaler         = prescaler_value;
            tim->Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
            if (timer->info->cntmode == HWTIMER_CNTMODE_UP)
            {
                tim->Init.CounterMode   = TIM_COUNTERMODE_UP;
            }
            else
            {
                tim->Init.CounterMode   = TIM_COUNTERMODE_DOWN;
            }
            tim->Init.RepetitionCounter = 0;
    #if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0)
            tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    #endif
            if (HAL_TIM_Base_Init(tim) != HAL_OK)
            {
                LOG_E("%s init failed", tim_device->name);
                return;
            }
            else
            {
                /* set the TIMx priority */
                HAL_NVIC_SetPriority(tim_device->tim_irqn, 3, 0);
    
                /* enable the TIMx global Interrupt */
                HAL_NVIC_EnableIRQ(tim_device->tim_irqn);
    
                /* clear update flag */
                __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
                /* enable update request source */
                __HAL_TIM_URS_ENABLE(tim);
    
                LOG_D("%s init success", tim_device->name);
            }
        }
    }

    我们发现之前设置的配置并没有使用,而是直接默认设置成频率10K,周期1s的定时器;

    可根据情况后面用control修改,或注释掉 tim->Init. 的几条赋值语句,使用 user_data 传递过来的默认配置;

    同时 stm32f4xx_hal_msp.c 中的TIM硬件初始化,也仅仅只是打开TIM外设时钟,所有锁CubeMX中只要使能对应TIM即可,无需配置;

    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
    {
      if(htim_base->Instance==TIM3)
      {
      /* USER CODE BEGIN TIM3_MspInit 0 */
    
      /* USER CODE END TIM3_MspInit 0 */
        /* Peripheral clock enable */
        __HAL_RCC_TIM3_CLK_ENABLE();
      /* USER CODE BEGIN TIM3_MspInit 1 */
    
      /* USER CODE END TIM3_MspInit 1 */
      }
      else if(htim_base->Instance==TIM4)
      {
      /* USER CODE BEGIN TIM4_MspInit 0 */
    
      /* USER CODE END TIM4_MspInit 0 */
        /* Peripheral clock enable */
        __HAL_RCC_TIM4_CLK_ENABLE();
      /* USER CODE BEGIN TIM4_MspInit 1 */
    
      /* USER CODE END TIM4_MspInit 1 */
      }
    
    }
  • 相关阅读:
    <置顶>Eclipse和myeclipse常用快捷键-操作-设置
    Eclipse : Loading descriptor for ...错误解决
    ORA-00937: 不是单组分组函数
    An error has occurred,See error log for more details 错误解决办法
    [Error Code: 942, SQL State: 42000] ORA-00942: 表或视图不存在
    ORA-00001: 违反唯一约束条件
    eclipse 出现user operation is waiting
    [空格][空白][特殊]字符/文字
    powerdesigner16.5安装教程及破解步骤
    mybatis遇到日期类型数据时String到date的转化
  • 原文地址:https://www.cnblogs.com/silencehuan/p/10938498.html
Copyright © 2020-2023  润新知