RT-Thread Studio学习(二)HWTIMER
简介
本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下使用HWTIMER设备。
新建项目并使用外部时钟
打开RT-Thread Studio软件新建基于芯片的项目,并使用外部时钟系统,具体参见《RT-Thread Studio学习之使用外部时钟系统》
启用HWTIMER
根据board.h
文件中的描述,启用HWTIMER需要完成如下四个步骤:
/*-------------------------- HARDWARE TIMER CONFIG BEGIN --------------------------*/
/** if you want to use hardware timer you can use the following instructions.
*
* STEP 1, open hwtimer driver framework support in the RT-Thread Settings file
*
* STEP 2, define macro related to the hwtimer
* such as #define BSP_USING_TIM and
* #define BSP_USING_TIM1
*
* STEP 3, copy your hardwire timer init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file
* such as void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
*
* STEP 4, modify your stm32xxxx_hal_config.h file to support hardwere timer peripherals. define macro related to the peripherals
* such as #define HAL_TIM_MODULE_ENABLED
*
*/
- 打开HWTIMER驱动框架
在RT-Thread Setting
文件中借助图形化配置工具打开软件 HWTIMER的驱动框架,如下图所示
- 定义HWTIMER相关的宏
在board.h
中定义需要使用的定时器:
#define BSP_USING_TIM
#ifdef BSP_USING_TIM
#define BSP_USING_TIM1
#define BSP_USING_TIM10
/*#define BSP_USING_TIM15*/
/*#define BSP_USING_TIM16*/
/*#define BSP_USING_TIM17*/
#endif
- 复制HWTIMER初始化函数
打开STM32CubeMX软件,根据实际情况完成对应TIM的配置。在本文中,使用了TIM1和TIM10,这两个TIM的Clock Source
都使用Internal Clock
,具体如下图:
从生成后的工程文件stm32xxxx_hal_msp.c中复制函数void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
到board.c的末尾。
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim_base->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspInit 0 */
/* USER CODE END TIM1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/**TIM1 GPIO Configuration
PE9 ------> TIM1_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* USER CODE BEGIN TIM1_MspInit 1 */
/* USER CODE END TIM1_MspInit 1 */
}
else if(htim_base->Instance==TIM10)
{
/* USER CODE BEGIN TIM10_MspInit 0 */
/* USER CODE END TIM10_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM10_CLK_ENABLE();
/* USER CODE BEGIN TIM10_MspInit 1 */
/* USER CODE END TIM10_MspInit 1 */
}
}
- 定义
stm32xxxx_hal_config.h
中的相关宏
在stm32f4xx_hal_conf.h
中定义需要使用的模块:
#define HAL_TIM_MODULE_ENABLED
另外,还需要修改tim_config.h
和drv_hwtimer.c
文件。项目中tim_config.h
文件的路径为drivers\include\config\tim_config.h
,完整代码如下:
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-12-11 zylx first version
*/
#ifndef __TIM_CONFIG_H__
#define __TIM_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef TIM_DEV_INFO_CONFIG
#define TIM_DEV_INFO_CONFIG \
{ \
.maxfreq = 1000000, \
.minfreq = 3000, \
.maxcnt = 0xFFFF, \
.cntmode = HWTIMER_CNTMODE_UP, \
}
#endif /* TIM_DEV_INFO_CONFIG */
#ifdef BSP_USING_TIM1
#ifndef TIM1_CONFIG
#define TIM1_CONFIG \
{ \
.tim_handle.Instance = TIM1, \
.tim_irqn = TIM1_UP_TIM10_IRQn, \
.name = "timer1", \
}
#endif /* TIM11_CONFIG */
#endif /* BSP_USING_TIM11 */
#ifdef BSP_USING_TIM10
#ifndef TIM10_CONFIG
#define TIM10_CONFIG \
{ \
.tim_handle.Instance = TIM10, \
.tim_irqn = TIM1_UP_TIM10_IRQn, \
.name = "timer10", \
}
#endif /* TIM10_CONFIG */
#endif /* BSP_USING_TIM10 */
#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_TIM11
#ifndef TIM11_CONFIG
#define TIM11_CONFIG \
{ \
.tim_handle.Instance = TIM11, \
.tim_irqn = TIM1_TRG_COM_TIM11_IRQn, \
.name = "timer11", \
}
#endif /* TIM11_CONFIG */
#endif /* BSP_USING_TIM11 */
#ifdef BSP_USING_TIM13
#ifndef TIM13_CONFIG
#define TIM13_CONFIG \
{ \
.tim_handle.Instance = TIM13, \
.tim_irqn = TIM8_UP_TIM13_IRQn, \
.name = "timer13", \
}
#endif /* TIM13_CONFIG */
#endif /* BSP_USING_TIM13 */
#ifdef BSP_USING_TIM14
#ifndef TIM14_CONFIG
#define TIM14_CONFIG \
{ \
.tim_handle.Instance = TIM14, \
.tim_irqn = TIM8_TRG_COM_TIM14_IRQn, \
.name = "timer14", \
}
#endif /* TIM14_CONFIG */
#endif /* BSP_USING_TIM14 */
#ifdef __cplusplus
}
#endif
#endif /* __TIM_CONFIG_H__ */
修改drv_hwtimer.h
文件:
注释掉drv_hwtimer.c
中的#include "drv_config.h"
。
向drv_hwtimer.c
添加#include <rtdevice.h>
。
向drv_hwtimer.c
添加#include <tim_config.h>
。
修改drv_hwtimer.h
中HAL_TIM_PeriodElapsedCallback
,为使用的定时器添加回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
#ifdef BSP_USING_TIM1
if (htim->Instance == TIM1)
{
rt_device_hwtimer_isr(&stm32_hwtimer_obj[TIM1_INDEX].time_device);
}
#endif
......
#ifdef BSP_USING_TIM10
if (htim->Instance == TIM10)
{
rt_device_hwtimer_isr(&stm32_hwtimer_obj[TIM10_INDEX].time_device);
}
#endif
......
}
添加中断函数入口:
#if defined( BSP_USING_TIM1) ||defined(BSP_USING_TIM10)
void TIM1_UP_TIM10_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
#ifdef BSP_USING_TIM1
if (__HAL_TIM_GET_FLAG(&stm32_hwtimer_obj[TIM1_INDEX].tim_handle,TIM_IT_UPDATE) != RESET)
HAL_TIM_IRQHandler(&stm32_hwtimer_obj[TIM1_INDEX].tim_handle);
#endif
#ifdef BSP_USING_TIM10
if (__HAL_TIM_GET_FLAG(&stm32_hwtimer_obj[TIM10_INDEX].tim_handle,TIM_IT_UPDATE) != RESET)
HAL_TIM_IRQHandler(&stm32_hwtimer_obj[TIM10_INDEX].tim_handle);
#endif
/* leave interrupt */
rt_interrupt_leave();
}
#endif
测试
main.c测试代码如下:
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-16 RT-Thread first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include <rtdevice.h>
#include "drv_common.h"
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define LED_PIN GET_PIN(F, 9)
#define LED0_PIN GET_PIN(F, 10)
static int rt_hw_pin_init()
{
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
return 0;
}
INIT_BOARD_EXPORT(rt_hw_pin_init);
/* 定时器超时回调函数 */
static rt_err_t timeout_cb1(rt_device_t dev, rt_size_t size)
{
static int i = 0;
i++;
rt_pin_write(LED_PIN, i % 2);
return 0;
}
static int hw1timer_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
rt_device_t hw_dev = RT_NULL; /* 定时器设备句柄 */
rt_hwtimer_mode_t mode; /* 定时器模式 */
/* 查找定时器设备 */
hw_dev = rt_device_find("timer1");
/* 以读写方式打开设备 */
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout_cb1);
/* 设置模式为周期性定时器 */
mode = HWTIMER_MODE_PERIOD;
ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
/* 设置定时器超时值为2s并启动定时器 */
timeout_s.sec = 2; /* 秒 */
timeout_s.usec = 0; /* 微秒 */
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;
}
return ret;
}
MSH_CMD_EXPORT(hw1timer_sample, hw1timer_sample);
int main(void)
{
int count = 1;
while (count++)
{
/* set LED0 pin level to high or low */
rt_pin_write(LED0_PIN, count % 2);
// LOG_D("Hello RT-Thread!");
rt_thread_mdelay(1000);
}
return RT_EOK;
}
通过msh运行hw1timer_sample即可看到效果。