本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下使用定时器对输入脉冲进行计数。
硬件及开发环境如下:
打开RT-Thread Studio软件新建基于芯片的项目,并使用外部时钟系统,具体参见《RT-Thread Studio学习(一)使用外部时钟系统》。
打开PWM驱动框架
在RT-Thread Setting
中借助图形化配置工具打开组件中的HWTIMER的驱动框架,如下图所示:
定义TIM相关的宏
将TIM5配置为PWM输入模式,在board.h
文件中使能宏定义:
#define BSP_USING_TIM
#ifdef BSP_USING_TIM
#define BSP_USING_TIM5
#endif
External Clock Mode 1
,设置Trigger Source为TI1FP1
。具体如下图:再重新生成STM32CubeMX代码,将.\cubemx\Src\tim.c
中的函数HAL_TIM_Base_MspInit
和HAL_TIM_MspPostInit
复制到board.c
的末尾。
再次复制函数HAL_TIM_Base_MspInit
到board.c
的末尾,并将其函数名改成HAL_TIM_PWM_MspInit
。
在Application文件夹中添加头文件pwm_input.h
,代码如下:
#ifndef APPLICATIONS_PWM_INPUT_H_
#define APPLICATIONS_PWM_INPUT_H_
#include <rtthread.h>
#include <board.h>
extern uint16_t PWM_RisingCount;
extern uint16_t PWM_FallingCount;
extern float duty;
extern TIM_HandleTypeDef htim5;
void MX_TIM2_Init(void);
void MX_TIM5_Init(void);
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
#endif /* APPLICATIONS_PWM_INPUT_H_ */
在上文《RT-Thread Studio学习(十五)PWM测量》的源文件pwm_input.c
添加代码:
TIM_HandleTypeDef htim5;
/* TIM5 init function */
void MX_TIM5_Init(void)
{
/* USER CODE BEGIN TIM5_Init 0 */
/* USER CODE END TIM5_Init 0 */
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM5_Init 1 */
/* USER CODE END TIM5_Init 1 */
htim5.Instance = TIM5;
htim5.Init.Prescaler = 0;
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = 4294967295;
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim5) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
sSlaveConfig.TriggerFilter = 0;
if (HAL_TIM_SlaveConfigSynchro(&htim5, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM5_Init 2 */
HAL_TIM_Base_Start(&htim5);
/* USER CODE END TIM5_Init 2 */
}
修改.\drivers\include\config\tim_config.h
文件,在tim_config.h
中添加代码:
#ifdef BSP_USING_TIM5
#ifndef TIM5_CONFIG
#define TIM5_CONFIG \
{ \
.tim_handle.Instance = TIM5, \
.tim_irqn = TIM5_IRQn, \
.name = "timer5", \
}
#endif /* TIM5_CONFIG */
#endif /* BSP_USING_TIM5 */
.\cubemx\Inc\stm32f4xx_hal_conf.h
中的相关宏#define HAL_TIM_MODULE_ENABLED
修改main.c
的代码为:
#include <rtthread.h>
#include "stm32f4xx.h"
#include <rtdevice.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "pwm_input.h"
// PD12 ------> TIM4_CH1
// PA6 ------> TIM13_CH1
// PA7 ------> TIM14_CH1
// PA1 ------> TIM2_CH2
// PA0-WKUP------> TIM5_CH1
#define PWM4_DEV_NAME "pwm4" /* PWM设备名称 */
#define PWM13_DEV_NAME "pwm13" /* PWM设备名称 */
#define PWM14_DEV_NAME "pwm14" /* PWM设备名称 */
#define PWM_DEV_CHANNEL 1 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM设备句柄 */
rt_uint32_t channel[4], period[4], pulse[4];
int pwm_init(void)
{
for (int i=0; i<2; i++)
{
period[i] = 1000000; /* 周期为1ms,单位为纳秒ns */
pulse[i] = 400000; /* PWM脉冲宽度值,单位为纳秒ns */
}
/* 初始化设备PWM4 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM4_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM4_DEV_NAME);
return RT_ERROR;
}
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period[0], pulse[0]);
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
/* 初始化设备PWM13 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM13_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM13_DEV_NAME);
return RT_ERROR;
}
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period[0], pulse[0]);
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
/* 初始化设备PWM14 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM14_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM14_DEV_NAME);
return RT_ERROR;
}
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period[1], pulse[1]);
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
return 0;
}
// 第一个参数为命令,第二个参数为 PWM 设备名称,第 3 个参数为 PWM 通道,
// 第 4 个参数为周期(单位纳秒),第 5 个参数为脉冲宽度(单位纳秒)
static int pwm_set(int argc, char *argv[])
{
if(argc!=5)
{
rt_kprintf("Usage: pwm_set <device name> <channel> <period> <pulse>\n");
rt_kprintf("Example: pwm_set pwm13 1 100000 50000\n");
return RT_ERROR;
}
rt_uint32_t period, pulse;
char pwmdevname[RT_NAME_MAX];
rt_strncpy(pwmdevname, argv[1], RT_NAME_MAX);
if((!strcmp(argv[1], "pwm4")) || (!strcmp(argv[1], "pwm13")) || (!strcmp(argv[1], "pwm14")))
{
period = atoi(argv[3]); /* PWM period, ns */
pulse = atoi(argv[4]); /* PWM pulse, ns */
}
else
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", pwmdevname);
return RT_ERROR;
}
pwm_dev = (struct rt_device_pwm *)rt_device_find(pwmdevname);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", pwmdevname);
return RT_ERROR;
}
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
rt_kprintf("pwm_set %s channel:%d period:%dns pulse:%dns\n", pwmdevname, PWM_DEV_CHANNEL, period, pulse);
return 0;
}
int main(void)
{
int count = 1;
LOG_D("Hello RT-Thread! 2024.1.17");
LOG_D("System CLock information");
LOG_D("SYSCLK_Frequency = %d", HAL_RCC_GetSysClockFreq());
LOG_D("HCLK_Frequency = %d", HAL_RCC_GetHCLKFreq());
LOG_D("PCLK1_Frequency = %d", HAL_RCC_GetPCLK1Freq());
LOG_D("PCLK2_Frequency = %d", HAL_RCC_GetPCLK2Freq());
LOG_D("SysTick->LOAD = %d", SysTick->LOAD);
LOG_D("Current tick = %d", rt_tick_get());
pwm_init();
MX_TIM2_Init();
MX_TIM5_Init();
while (count++)
{
if(count%60 == 0) LOG_D("Hello RT-Thread! %d", rt_tick_get());
if(count%20 == 0)
{
rt_kprintf("PWM_Duty=%d% ",(int)duty);
rt_kprintf(" FCNT=%d RCNT=%d \r\n", PWM_FallingCount, PWM_RisingCount);
}
if(count%2 == 0)
{
rt_kprintf("ETRCNT=%d \r\n", __HAL_TIM_GET_COUNTER(&htim5));
}
rt_thread_mdelay(1000);
}
return RT_EOK;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pwm_set, set pwm4 period/pulse. Usage: pwm_set pwm4 1 10000 5000);
在工程中,还使能了TIM4、TIM13和TIM14为PWM输出,TIM2为PWM输入。操作参见《RT-Thread Studio学习(三)PWM》 和《RT-Thread Studio学习(十五)PWM测量》 。
将PWM输入引脚PA1和PWM输出引脚PD12短接,将PA1和PA0短接,运行结果如下:
用逻辑分析仪查看3个PWM的输出引脚PA6、PA7和PD12: