You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

28 KiB

[TOC]

1. 定时器概述

定时器的工作如同闹钟,单不只是闹钟这么简单。

1.1. 定时器工作原理

  1. 计数模式:对引脚输人的外部脉冲信号进行计数(如何实现?)。
  2. 定时模式对处理器内部的周期性时钟信号进行计数时钟信号的频率是确定的设置一个数一个时钟信号递减1当减少到0的时候这个过程的时间就是定时的时间
  3. 定时时钟:在定时模式下,输人定时器的周期性时钟信号称为定时时钟(为定时器提供的稳定时钟信号)。
  4. 计数时间:在定时模式下,定时器内部的计数单元记一次数所花费的时间称为计数时间,该值为定时时钟频率的倒数。

根据定时时钟和计数时间的定义,我们可以得到定时器的定时时间计算公式:

定时时间=计数值x计数时间

定时时间=计数值/定时时钟频率

1.2. STM32定时器介绍

image-20240917190453681

专用定时器(略):

  1. 开门狗(什么是看门狗?有什么用?);
  2. 实时时钟:就是我们所说的时间和日期;
  3. 低功耗定时器:低功耗模式(如休眠)下任然工作,用于休眠中唤醒的定时器。

常规定时器:

  1. 基本定时器:几乎没有任何对外的输入/输出通道,常用作时间基准(时基),实现基本的定时功能。
  2. 通用定时器:具备多路独立的捕获/比较通道,可以完成定时/计数、输入捕获、输出比较等功能还可以连接其他的传感器接口,如编码器和霍尔传感器。
  3. 高级定时器:高级定时器的功能最为强大,除了具备通用定时器的功能外,还增加了重复计数器带死区控制的互补信号输出等功能,可用于电机控制等领域。

视频-时钟树

image-20240922094517185

总线结构中文手册25页

image-20240917193958697

视频-定时器

无论哪一种定时器,最基本的功能都是定时和计数在这两个功能的基础上又衍生出其他的功能。在实际的工程应用中最常用的定时器功能有以下三种P205 ① 定时/计数功能:用于产生时间基准以及测量外部脉冲的个数。 ②输出比较功能:包括 PWM 输出、电平翻转、单脉冲输出以及强制输出等功能。 ③ 输入捕获功能:用于测量输人信号的脉冲宽度。

2. HAL库外设模块设计方法

2.1. 外设句柄设计略p205

本质上是用一个结构体来描述一个外设定时器、串口、I2C等寄存器等

image-20240922194116122

2.2. 外设编程模型

HAL库根据微控制器和外设的数据传输方式设计了轮询一般在主程序中去读取外设的状态从而进行相应的处理、中断通过中断服务进行外设状态变化的函数回调和 DMA类似中断不过关联了DMA的功能 三种编程模型,用于外设的数据传输。 以定时器的定时功能为例,三种编程模型下的接口函数分别是:

image-20240922194440003

在下面的例子中我们将会使用到中断方式启用外设。DMA方式将在下一章串口中进行讲解。

2.3. 外设通用接口函数设计p208

  1. 初始化函数;
  2. I/O操作函数
  3. 控制函数;
  4. 状态函数;

3. 定时/计数功能

3.1. 时钟源

时钟源主要有四种p209我们目前主要介绍内部时钟源CK_INT。注意这里所说的内部时钟源是统称表示总线上的是时钟不是指MCU提供时钟的时钟源。为MCU提供时钟信号的也分为内部和外部但最终都会形成总线上的时钟信号AHB

通过设置相关的寄存器选择对应的时钟源后该时钟源将作为时基单元的预分频时钟CK_PSC送人时基单元。时钟源选择的示意图如图8-3所示。

image-20240922105450832

3.2. 时基单元

时基单元是定时器的核心控制单元,负责时钟源的分频、计数和溢出重载等基本功能。它主要由三个模块组成:预分频模块、计数模块和自动重载模块。时基单元的功能框图如图 8-4所示。

image-20240922105559848

3.2.1. 预分频模块

预分频模块的工作原理如下:定时器启动后预分频计数器的初值为0。预分频时钟CK_PSC每输入一个脉冲预分频计数器的计数值就自动加一。当计数值等于预分频寄存器中存放的预分频系数PSC时计数值清零并开始下一轮计数。

image-20240922105932899

预分频时钟 CK_PSC 经过预分频模块后得到计数时钟CK_CNT它的计算公式如下

image-20240922140840757

注意0表示不分频1表示2分频因此需要PSC+1

3.2.2. 计数模块

计数模块由核心计数器和计数器寄存器TIMx_CNT组成核心计数器用来对预分频模块输出的计数时钟 CK_CNT进行二次计数。计数时钟CK_CNT每输入一个脉冲核心计数器的计数值就自动加一或减一(根据用户设置的不同计数模式来决定是加一还是减一)。计数器寄存器则用来存放核心计数器运行时的计数值,便于用户读取。

3.2.3. 自动重载模块

自动重载模块由自动重载寄存器TIMx_ARR构成用来设置计数器的计数终值或计数初值,决定计数脉冲的多少(计数模式)或定时周期(定时模式)的长短。我们将TMx_ARR寄存器的内容记为自动重载值ARR。当定时器设置为递增计数模式时ARR作为计数器的计数终值表示记到ARR时发生溢出。当定时器设置为递减计数模式时ARR作为计数器的计数初值表示从ARR开始向下计数。

3.2.4. 计数模式

定时器的计数模块支持三种计数模式:递增计数、递减计数和中心对齐计数,并产生溢出事件,作为定时器的更新中断(定时中断)。

  1. 递增计数计数器从0开始向上计数当计数值等于ARR时产生计数器上溢事件并从0开始新一轮的计数周期。

  2. 递减计数计数器从ARR开始向下计数当计数值等于0时产生计数器下溢事件并从ARR开始新一轮的计数周期。

  3. 中心对齐计数(递增/递减计数)计数器从0开始向上计数当计数值等于ARR-1时产生计数器上溢事件然后从ARR 开始向下计数当计数值等于1时产生计数器下溢事件。之后再从0开始新一轮的计数周期。

三种计数模式的计数过程如图 8-6所示。

image-20240922110842727

预装载功能和影子寄存器p212

3.2.5. 定时时间计算公式

当定时器工作于定时模式时,预分频时钟 CK_PSC 等于定时时钟 TIMx_CLK。定时时间由 TIMx_CLK 的频率、预分频系数 PSC 和自动重载值 ARR 三者决定。

假设PSC=1ARR=36采用递增计数模式计数器寄存器的初值为0。定时器的时序如图 8-7 所示。

image-20240922111151540

预分频时钟 CK_PSC经过分频后得到计数时钟CK_CNT,送入计数器。计数器的计数时间为1/C_KCNT代入式(8-3),可以得到计数时间为(PSC+1)/CK_PSC。由于实际的计数值为 ARR+1将计数值和计数时间代入式(8-1),可以得到定时时间的计算公式:

image-20240922111416244

image-20240922111452751

3.3. 外部脉冲计数p214略

对外部的脉冲信号进行计数例如通过传感器统计生产线上物料个数。这是外部传感器在有物料通过时可以产生一个脉冲输入到MCU使用定时器的计数模式进行统计。

定时器的计数模式在硬件上有极性选择、分频、滤波等电路,可以实现较高频率的脉冲计数,同时可以对输入波形进行滤波,减少干扰的影响。

其实如果对低频脉冲的统计可以使用IO的外部中断即可每个中断对全局变量进行累加但是IO中断并不提供分频、滤波等功能因此不适合高频率的脉冲抗干扰能力也较弱。

image-20240922195130424

定时器的ETR引脚和书上的不一致请参考芯片手册。

3.4. 定时/计数功能的数据类型p215

在 stm32f1xx_hal_tim.h 的大约 46 行:

typedef struct
{
  uint32_t Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.
                                   This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  uint32_t CounterMode;       /*!< Specifies the counter mode.
                                   This parameter can be a value of @ref TIM_Counter_Mode */

  uint32_t Period;            /*!< Specifies the period value to be loaded into the active
                                   Auto-Reload Register at the next update event.
                                   This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF.  */

  uint32_t ClockDivision;     /*!< Specifies the clock division.
                                   This parameter can be a value of @ref TIM_ClockDivision */

  uint32_t RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounter
                                    reaches zero, an update event is generated and counting restarts
                                    from the RCR value (N).
                                    This means in PWM mode that (N+1) corresponds to:
                                        - the number of PWM periods in edge-aligned mode
                                        - the number of half PWM period in center-aligned mode
                                     GP timers: this parameter must be a number between Min_Data = 0x00 and
                                     Max_Data = 0xFF.
                                     Advanced timers: this parameter must be a number between Min_Data = 0x0000 and
                                     Max_Data = 0xFFFF. */

  uint32_t AutoReloadPreload;  /*!< Specifies the auto-reload preload.
                                   This parameter can be a value of @ref TIM_AutoReloadPreload */
} TIM_Base_InitTypeDef;

image-20240922201006253

ClockDivision 用于计数和输入捕获的滤波(略)。

image-20240922201054848

image-20240922201213498

3.5. 定时/计数功的接口函数p217

3.5.1. 时基单元初始化函数(HAL_TIM_Base_Init)

该函数用于时基单元的初始化,将用户设定的配置参数写人对应的寄存器,具体描述如表 8-7 所示。

image-20240922201428110

3.5.2. 定时器轮询方式启动函数(HAL_TIM_Base_Start)

该函数用于在轮询方式下启动定时器运行,具体描述如表 8-8所示。

image-20240922201535346

3.5.3. 定时器中断方式启动函数(HAL_TIM_Base_Start_IT)

该函数用于在中断方式下启动定时器运行,具体描述如表8-9所示。

image-20240922201635738

3.5.4. 定时器中断通用处理函数(HAL_TIM_IROHandler)

该函数是所有定时器中断发生后的通用处理程序。任何一个定时器的相关中断(如更新中断或捕获中断)发生后都会通过中断向量表中的定时器中断服务程序TMxIROHandler()(x表示定时器编号1~11)调用该函数。在函数内部会进行中断类型的判断,并清除对应的中断标志,然后再根据不同的中断类型,调用不同的回调函数来完成具体的中断处理任务。具体描述如表 8-10所示。

image-20240922201819520

3.5.5. 定时器更新中断回调函数(HAL_TIM_PeriodElapsedCallback)

该函数用于处理发生更新中断后的具体任务。任何一个定时器发生更新中断后,都会调用更新中断回调函数。因此,在函数内部需要判断是哪一个定时器产生的本次更新中断然后再执行具体的中断处理任务。具体描述如表8-11所示。

image-20240922201943442

注意这个函数有缺省的实现是用weak标识的因此一般情况下需要重新定义该函数来完成用户逻辑的处理。

3.5.6. 定时器中断标志清除函数(__HAL_TIM_CLEAR_IT)

该函数用于清除定时器的各类中断标志,采用带参数的宏实现(宏函数),与普通函数相比,宏函数省去了函数调用的过程,执行效率较高。具体描述如表 8-12所示。

image-20240922202146788

3.5.7. 定时器计数值读取函数(__HAL_TIM_GET_COUNTER)

该函数用于读取定时器的计数值,采用带参数的宏实现(宏函数),具体描述如表 8-13 所示。

image-20240922202324216

3.6. 基础任务:定时闪烁指示灯

3.6.1. 实现过程

使用绿色LEDPA7进行显示定时器4以中断方式运行每隔1秒钟切换一次电平。

  1. 以前面讲的方式建立一个项目,名称是 TimerLED
  2. 设置PA7为输出模式并设置标签为LED
  3. 使用TIM4作为定时器。检查TIM4挂接的总线STM32定时器介绍,知道是挂接在APB1上
  4. 检查时钟配置:

image-20240922185613665

知道APB1的定时器时钟是8M。注意定时器的中断时间是需要按照定时器所在总线的时钟进行设置的。

  1. 配置时钟:

image-20240922191931460

勾选2位置以便使用内部时钟指APB总线时钟不是外部时钟晶体和内部RC时钟源在3位置设置PSC为7999在4位置设置ARR为999根据8-4公式可以知道此时的时钟计时周期为1秒

  1. 开启TIM4的全局中断并保存生成代码框架。

image-20240922192310094

  1. 在 main.c 的 /* USER CODE BEGIN 2 */ 位置插入下列代码:
	/* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim4);
	/* USER CODE END 2 */
  1. 在 main.c 文件的 /* USER CODE BEGIN 0 */ 位置插入定时中断回调函数:
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	if (htim->Instance == TIM4)
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
/* USER CODE END 0 */

好了下载到开发板后绿色LED应该亮一秒灭一秒一直循环。

3.6.2. 代码分析

main.c 的 43 行定义了外设TIM4的句柄

TIM_HandleTypeDef htim4;

这个书上没有讲,其实就是针对 TIM4 这个外设的结构体包括配置信息和相关的操作函数指针有点像Java中的类定义有兴趣可以看看。

main.c 的 147 行左右是定时器的初始化:

static void MX_TIM4_Init(void) {

	/* USER CODE BEGIN TIM4_Init 0 */

	/* USER CODE END TIM4_Init 0 */

	TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
	TIM_MasterConfigTypeDef sMasterConfig = { 0 };

	/* USER CODE BEGIN TIM4_Init 1 */

	/* USER CODE END TIM4_Init 1 */
	htim4.Instance = TIM4;
	htim4.Init.Prescaler = 7999;
	htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim4.Init.Period = 999;
	htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	if (HAL_TIM_Base_Init(&htim4) != HAL_OK) {
		Error_Handler();
	}
	sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
	if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) {
		Error_Handler();
	}
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig)
			!= HAL_OK) {
		Error_Handler();
	}
	/* USER CODE BEGIN TIM4_Init 2 */

	/* USER CODE END TIM4_Init 2 */

}

/* USER CODE BEGIN 2 */ 位置的代码:

HAL_TIM_Base_Start_IT(&htim4);

表示以中断方式启动TIM4

stm32f1xx_it.c 的大约 204 行:

void TIM4_IRQHandler(void)
{
  /* USER CODE BEGIN TIM4_IRQn 0 */

  /* USER CODE END TIM4_IRQn 0 */
  HAL_TIM_IRQHandler(&htim4);
  /* USER CODE BEGIN TIM4_IRQn 1 */

  /* USER CODE END TIM4_IRQn 1 */
}

此代码是自动生成的,函数 TIM4_IRQHandler(void) 是 TIM4 溢出中断调用的函数,该函数调用了 HAL_TIM_IRQHandler(),这个函数,并传入了 htim4 这个结构体的指针标识TIM4中断接着看 stm32f1xx_hal_tim.c 的大约 3882 行开始的 HAL_TIM_IRQHandler() 这个函数这个函数很复杂在大约3959行调用了 HAL_TIM_PeriodElapsedCallback(htim); 这个函数。因此该中断的调用过程是:

TIM4_IRQHandler->HAL_TIM_IRQHandler->HAL_TIM_PeriodElapsedCallback

HAL_TIM_PeriodElapsedCallback 是我们在主函数中定义的用户逻辑函数。

3.7. 进阶任务:外部脉冲计数(略)

4. PWM输出功能

什么是PWM

image-20240923144915112

上述视频是以电压来讲的,我们试图用能量的方式给大家理解:

占空比100%

上图是占空比 100% 的波形,显然就是直流。那么我们看做功的关系应该怎么计算?

功率U2/R

做功TxU2/R

显然这里负责的R应该是一个常量。

占空比70%

同样占空比为70%的波形做功应该是:

做功DxTxU2/R

这里的D表示占空比。

如果负载是一个LED做功多就亮做功少就暗这就达到了调光的效果同样也可以调整电机的快慢。

注意PWM并不适合所有的功率调节例如LED灯的调光如果使用简单的PWM其实是LED不断的闪烁亮的时间和灭的时间比例。如果闪烁频率低会造成人眼的疲劳导致眼睛的疾病。目前的LED调光大多是使用调整电压电流来进行的。对电压或者电流的调整基础一般还是PWM不过后级需要更多的滤波电路以及电压电流检测电路来形成反馈回路使得输出更为稳定。

4.1. 捕获/比较通道

动画讲解轻松学会STM32的PWM

image-20240923145011576

  1. 输入捕获单元:用于信号测量;
  2. 捕获/比较寄存器TIMx_CCR在输入模式下用于存放存放事件的计数边缘检测时计数是多少可以测量波长和占空比输出模式下存放一个比较值用于和计数器寄存器CNT进行比较实现信号的反转从而实现PWM的占空比调整后面讲
  3. 输出比较单元:根据 CCR/ARR/CNT来产生波形PWM

每个定时器都有14个上述的电路通道。因此一个时钟可以同时进行1-4个不同的PWM或者输入信号测量。后续的代码演示中我们一般只使用一个确定定时器的一个通道。

4.2. PWM实现原理p233

image-20240923160332784

  1. 缺省情况下,输出为高电平;
  2. TIMx_CLK经过PSC分频后为定时器提供计数脉冲
  3. 计数脉冲使得CNT的计数从0进行累加
  4. 当CNT和CCR的值相等后输出极性反转从高电平变为低电平
  5. CNT持续计数
  6. 当CNT与ARR值相等的时候极性再次反转从低电平变成高电平一个周期结束CNT被重新设置成0

因此:

  1. CK_PSCTIMx_CLK、PSC、ARR 共同决定了PWM波形输出的频率这一点和作为定时器是一致的
  2. CCR和ARR+1的比值决定了占空比

image-20240923161420980

公式8-7与公式8-4是一致的其基本原理也是一致的。

课堂练习:

如图所示:

image-20240923162226052

需要一个频率1000Hz占空比 30 % 的PWM 应该如何进行设置?

如果选用TIM1作为PWM的时钟PSC、ARR、CCR的值应该如何选取

如果选用TIM4作为PWM的时钟PSC、ARR、CCR的值应该如何选取

如果选用TIM2作为PWM的时钟PSC、ARR、CCR的值应该如何选取

4.3. PWM输出功能的数据类型p234

typedef struct
{
  uint32_t OCMode;        /*!< Specifies the TIM mode.
                               This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */

  uint32_t Pulse;         /*!< Specifies the pulse value to be loaded into the Capture Compare Register.
                               This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  uint32_t OCPolarity;    /*!< Specifies the output polarity.
                               This parameter can be a value of @ref TIM_Output_Compare_Polarity */

  uint32_t OCNPolarity;   /*!< Specifies the complementary output polarity.
                               This parameter can be a value of @ref TIM_Output_Compare_N_Polarity
                               @note This parameter is valid only for timer instances supporting break feature. */

  uint32_t OCFastMode;    /*!< Specifies the Fast mode state.
                               This parameter can be a value of @ref TIM_Output_Fast_State
                               @note This parameter is valid only in PWM1 and PWM2 mode. */


  uint32_t OCIdleState;   /*!< Specifies the TIM Output Compare pin state during Idle state.
                               This parameter can be a value of @ref TIM_Output_Compare_Idle_State
                               @note This parameter is valid only for timer instances supporting break feature. */

  uint32_t OCNIdleState;  /*!< Specifies the TIM Output Compare pin state during Idle state.
                               This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State
                               @note This parameter is valid only for timer instances supporting break feature. */
} TIM_OC_InitTypeDef;

4.3.1. OCMode

image-20240923164850677

4.3.2. Pulse(CCR)

整形这个值与ARR共同确定占空比。

4.3.3. OCPolarity

输出极性,如果是低电平有效,相当于占空反向;

image-20240923165059143

4.3.4. OCFastMode

PWM快速模式使能

image-20240923165314079

4.3.5. PWM1/PWM2

image-20240923165429185

其实就是极性发转。注意通常使用PWM1方式如果是PWM2方式占空比是100%-(CCR/(ARR+1)x100%)。

4.4. PWM输出功能的接口函数、

4.4.1. PWM 轮询方式启动函数(HAL_TIM_PWM_Start)

该函数用于在轮询方式下启动PWM信号的输出具体描述如表8-18所示。

image-20240923165831385

4.4.2. 捕获/比较寄存器设置函数(__HAL_TIM_SET_COMPARE)

该函数用于设置捕获/比较寄存器TIMxCCRn的内容采用带参数的宏实现(宏函数),具体描述如表 8-19 所示。该函数可以在任何时间改变CCR的值用于动态改变占空比。

image-20240923165956941

4.5. 基础任务输出PWM信号注意与书上不一致

使用定时器产生一个频率为1000Hz占空比为50%的方波,用于驱动蜂鸣器。

4.5.1. 实现过程

  1. 建立一个项目 Buzzer
  2. 蜂鸣器是在PB9上设置PB9的功能是 TIM4_CH4

image-20240924181442772

  1. 配置TIM4

image-20240924182053112

注意这里缺省配置的APB1上的定时器时钟是8M要实现1000Hz的频率PSC=79ARR=99。注意在设置的时候ARR+1最好是100或者是1000等10的整数倍数。因为Pulse和ARR+1的比值决定了占空比。设置Pulse(CCR)为50这样就有了1000Hz50%的占空比。

  1. 在main.c 的大约92行加入代码
  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
  /* USER CODE END 2 */
  1. 编译下载后,可以听到蜂鸣器的声音。

4.5.2. 代码分析

main.c 大约147行左右是定时器的初始化

static void MX_TIM4_Init(void) {

	/* USER CODE BEGIN TIM4_Init 0 */

	/* USER CODE END TIM4_Init 0 */

	TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
	TIM_MasterConfigTypeDef sMasterConfig = { 0 };
	TIM_OC_InitTypeDef sConfigOC = { 0 };

	/* USER CODE BEGIN TIM4_Init 1 */

	/* USER CODE END TIM4_Init 1 */
	htim4.Instance = TIM4;
	htim4.Init.Prescaler = 79;
	htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim4.Init.Period = 99;
	htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	if (HAL_TIM_Base_Init(&htim4) != HAL_OK) {
		Error_Handler();
	}
	sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
	if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) {
		Error_Handler();
	}
	if (HAL_TIM_PWM_Init(&htim4) != HAL_OK) {
		Error_Handler();
	}
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig)
			!= HAL_OK) {
		Error_Handler();
	}
	sConfigOC.OCMode = TIM_OCMODE_PWM1;
	sConfigOC.Pulse = 50;
	sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
	sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
	if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4)
			!= HAL_OK) {
		Error_Handler();
	}
	/* USER CODE BEGIN TIM4_Init 2 */

	/* USER CODE END TIM4_Init 2 */
	HAL_TIM_MspPostInit(&htim4);

}

main.c 的92行用户代码

  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
  /* USER CODE END 2 */

上述代码是以查询方式启动TIM4的PWM因为没有使用中断。htim4是TIM4的结构体该结构书上没有说明和定时中断中的结构体是一致的可以理解成C语言的对象包括数据与很多函数指针。

4.6. 进阶任务:实现呼吸灯

  1. 查看绿色LED所属的定时器通道是TIM3的通道2
  2. 设置TIM3

image-20240929150617735

  1. 加入代码:
	/* USER CODE BEGIN 2 */
	int duty = 0;
	int step = 1;
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
	/* USER CODE END 2 */

和:

	/* USER CODE BEGIN WHILE */
	while (1) {
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */
		for (duty = 0; duty < 100; duty = duty + step) {
			__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, duty);
			HAL_Delay(50);
		}
	}
	/* USER CODE END 3 */

问题:这里的呼吸灯不是真正的呼吸,而是逐渐变到最亮后突然变暗;请思考如何改进?

5. 输入捕获功能

5.1. 输入捕获功能概述

5.2. 输入捕获功能的数据类型

5.3. 输入捕获功能的接口函数

5.4. 挑战任务:信号测量