读者可访问 GitHub – lc-guo/STM32CubeMX-Series-Tutorial 获取原始工程代码

1、准备材料

开发板(STM32F407G-DISC1

STM32CubeMX软件(Version 6.10.0

keil µVision5 IDE(MDK-Arm

ST-LINK/V2驱动

杜邦线一根

XCOM V2.6串口助手

2、实验目标

使用STM32CubeMX软件配置STM32F407通用定时器TIM9为输入捕获模式,捕获由上一实验输出的可变占空比的PWM波型周期和占空比

3、实验流程

3.0、前提知识

本实验需要使用串口输出PWM波形的周期和占空比信息,因此需要读者知道如何使用串口,如果不知道如何使用串口请阅读本系列教程“STM32CubeMX教程9 USART/UART 异步通信”实验

输入捕捉的功能是记录下要捕捉的边沿出现的时刻,如果你仅仅捕捉下降沿,那么两次捕捉的差表示输入信号的周期,即两次下降沿之间的时间。

如果要测量低电平的宽度,你应该在捕捉到下降沿的中断处理中把捕捉边沿改变为上升沿,然后把两次捕捉的数值相减就得到了需要测量的低电平宽度 (注释1)

输入捕获有 ① Input Capture direct mode和 ② Input Capture indirect mode两种模式可选,但是在没有通道 选择 直接模式输入捕获时,非直接模式的输入捕获是不可选择的,这个也很好理解,直接模式输入捕获会将捕获通道设置到某一个具体的引脚上,而非直接模式的输入捕获不会将捕获通道设置到某一个具体的引脚上,而是使用和直接模式输入捕获同一引脚作为捕获输入

所有拥有2/4个捕获/比较通道的通用定时器以Channel1/2、Channel3/4为两组,每一组的两个通道可以设置为① 全部使用直接输入捕获模式、② 一个通道直接输入捕获另一个通道非直接输入捕获 两种模式,而剩下的只有1个捕获/比较通道的通用定时器只能使用直接输入捕获模式

输入捕获中还有一个特殊模式,即PWM输入模式,利用联合通道 Combined Channels 可以直接测量出PWM波形的周期和占空比,非常方便,另外Combined Channels还可以选择① 编码器模式、② 通道1PWM输入、③ 通道2PWM输入和④ 传感器XOR功能四种模式,模式②③均是使用的通用定时器的Channel1/2

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示


开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示


详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立

3.1.1、时钟树配置

系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

本实验需要需要初始化USART2作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信

在Pinout & Configuration页面右边芯片引脚预览Pinout view中找到PD12引脚,左键单击将其设定为TIM4_CH1

然后在页面左侧功能分类栏目中点开Timers栏目,单击栏目下的TIM4,按照上一个实验的配置对通道1配置为PWM输出

具体配置如下图所示

然后单击Timers栏目中的TIM9,配置其 Combined Channels 为通道1输入捕获/通道2输入捕获,这两个选项除了通道对应的引脚不同外,其余均一致,这里通道1对应的是PE5,而通道2对应的是PE6

接下来对页面中间的 Combined Channels 两个通道参数进行配置,首先对于计数器参数的设置,如PSC、计数模式、ARR等之前的实验已有讲解,在此不再说明

然后对于通道1PWM输入,其 Input Trigger Slave Mode Controller (从机模式控制器)两个参数选项唯一,不可设置

最后设置通道1的 Polarity Selection (参数极性)选择上升沿, IC Selection (输入捕获类型)选择直接模式

通道2的 Polarity Selection 只能选择与通道1设置的相反, IC Selection 选择非直接模式,其他分频和滤波不做设置,具体配置如下图所示

为什么要这么设置?

当配置为Combined Channels的PWM输入模式时,如果通道1设置为上升沿,则在PWM输入引脚PE5检测到输入的PWM波第一个上升沿时,会将当前计数器CNT的值锁存在TIM9_CCR1寄存器中,并且将寄存器复位,使CNT为0从这个上升沿重新开始计数,然后当检测到下降沿时,会将当前计数器CNT的值锁存在TIM9_CCR2寄存器中,因此TIM9_CCR2寄存器中的值即为PWM波高电平持续的计数频率次数,然后再次遇到上升沿时重复上述过程,因此TIM9_CCR1寄存器中的值即为PWM波的周期

如下图举例所示

3.1.3、外设中断配置

在Pinout & Configuration页面左边System Core/NVIC中勾选TIM9全局中断,然后选择合适的中断优先级即可

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of ‘c/h’ files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示


详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、外设初始化函数调用流程

首先在生成的工程代码主函数main()中调用了MX_TIM9_Init()函数完成了对TIM9基本定时器参数,输入捕获通道1/2参数的配置

然后在HAL_TIM_IC_Init()函数中调用了HAL_TIM_IC_MspInit()函数对TIM9时钟和中断进行了使能,并对中断优先级进行了配置,最后对TIM9的两个输入捕获通道引脚进行了复用设置,从而完成了整个初始化过程

如下图所示为TIM4输出比较初始化的具体函数调用流程

3.2.2、外设中断函数调用流程

使能定时器全局中断后在stm32f4xx_it.c中自动生成了TIM9的中断处理函数TIM1_BRK_TIM9_IRQHandler()

TIM1_BRK_TIM9_IRQHandler()函数调用了HAL库的定时器中断处理函数HAL_TIM_IRQHandler(),这个函数负责处理所有的定时器相关中断

通过判断中断来源及相关寄存器,最终调用输入捕获事件完成的回调函数为HAL_TIM_IC_CaptureCallback(),该函数为虚函数,需要用户重新实现

如下图所示为TIM9输入捕获中断回调的具体函数调用流程

3.2.3、添加其他必要代码

在tim.c中重新实现输入捕获中断回调函数HAL_TIM_IC_CaptureCallback(),当捕获到上升沿/下降沿时会进入该中断回调函数中,然后读取TIM9_CCR1寄存器的值,该值即为PWM波形周期,然后读取TIM9_CCR2寄存器的值,该值即为PWM波形高电平持续计数值,具体代码如下图所示

源代码如下所示

/*输入捕获中断回调函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    uint16_t IC1_Width = __HAL_TIM_GET_COMPARE(&htim9,TIM_CHANNEL_1);
    uint16_t IC2_Pulse = __HAL_TIM_GET_COMPARE(&htim9,TIM_CHANNEL_2);
    if((IC1_Width==0) || (IC2_Pulse==0))
        return;
 
    printf("IC1_Width:%d,IC2_Pulse:%d\r\n", IC1_Width, IC2_Pulse);
}

在主函数中启动通用定时器TIM4的PWM输出,以中断的方式启动通用定时器TIM9,并启动其通道1/2的输入捕获,最后在主函数主循环中轮询按键,当按键按下时更改通用定时器TIM4的PWM输出占空比即可,如下图所示为具体代码

源代码如下所示

/*主函数外变量定义*/
uint16_t pulseWidth=0;
uint8_t dirInc=1;
 
/*主循环外启动代码*/
HAL_TIM_Base_Start(&htim4);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&htim9);
HAL_TIM_IC_Start_IT(&htim9, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim9, TIM_CHANNEL_2);
 
/*主循环内代码*/
if(HAL_GPIO_ReadPin(USER_KEY_GPIO_Port,USER_KEY_Pin) == GPIO_PIN_SET)
{
	HAL_Delay(10);
	if(HAL_GPIO_ReadPin(USER_KEY_GPIO_Port,USER_KEY_Pin) == GPIO_PIN_SET)
	{
		if(dirInc == 1)
		{
			pulseWidth ++;
			if(pulseWidth >= 195)
			{
				pulseWidth = 195;
				dirInc = 0;
			}
		}
		else
		{
			pulseWidth --;
			if(pulseWidth <= 5)
			{
				pulseWidth = 5;
				dirInc = 1;
			}
		}
	}
	__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, pulseWidth);
}

值得提醒的是我们的PWM波输出引脚为PD12,而我们PWM输入捕获引脚为PE5,因此需要一根杜邦线将开发板上的PD12和PE5短接

4、常用函数

/*启动输入捕获*/
HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
 
/*停止输入捕获*/
HAL_StatusTypeDef HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
 
/*以中断方式启动输入捕获*/
HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
 
/*停止以中断方式的输入捕获*/
HAL_StatusTypeDef HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
 
/*输入捕获回调函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

5、烧录验证

烧录程序,开发板上电后打开串口,串口会不断的输出当前测量到的PWM波形周期为固定的199,然后按下用户按键USER_KEY会发现,输出的PWM波形的占空比不停变化,变化规律和上一个实验中LED呼吸灯变化情况一致,同时还可以观察到GREEN_LED的亮度不断地变化,下图为串口输出的详细信息

6、注释详解

注释1:请阅读在针对计数功能中,Input Capture direct mode和IO中断有什么区别 (stmicroelectronics.cn)

参考资料

STM32Cube高效开发教程(基础篇)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。