STM32F1与STM32CubeIDE快速入门-定时器PWM模式

定时器PWM模式

在本文中,将讨论在 PWM 模式下使用 STM32 定时器模块的 STM32 PWM 生成。将了解 PWM 信号是如何产生的,如何控制其频率、占空比,以及如何估计 PWM 分辨率。 以及如何设置定时器模块以在 PWM 模式下工作,并编写一个简单的应用程序来制作 LED 调光器。
在这里插入图片描述

1、定时器PWM模式介绍

正如我们在之前的文章中所讨论的,定时器模块可以运行多种模式,其中一种模式是 PWM 模式。当定时器从内部源获得时钟并计数到自动重载寄存器值时,输出通道引脚被驱动为高电平。它一直保持到定时器计数达到 CCRx 寄存器值,匹配事件导致输出通道引脚被驱动为低电平。它一直保持到定时器计数到自动重载寄存器值,依此类推。

产生的波形称为 PWM(脉宽调制)信号。其频率由内部时钟、预分频器和 ARRx 寄存器决定。其占空比由通道 CCRx 寄存器值定义。 PWM 并不总是必须遵循与 PWM 生成完全相同的程序,但是,它是非常基本的程序,并且更容易理解这个概念。它被称为递增计数 PWM 模式。

下图显示了 ARR 值如何影响 PWM 信号的周期(频率)。以及 CCRx 值如何影响相应 PWM 信号的占空比。并说明了加计数正常模式下PWM信号产生的全过程。

在这里插入图片描述

** 1)、STM32 定时器-PWM 输出通道**

每个捕获/比较通道都围绕一个捕获/比较寄存器(包括一个影子寄存器(Shadow Register))、一个捕获输入级(带有数字滤波器、多路复用和预分频器)和一个输出级(带有比较器和输出控制)构建。 输出级生成一个中间波形,然后用作参考:OCxRef(高电平有效)。 极性作用于链的末端。如下图所示,捕获/比较通道 1 完整电路:

在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5W9d3Dj-1646611543012)(images/10-2.png)]

驱动 OCx 引脚的输出级的示意图如下:

单个 STM32 定时器通常有多个通道(4、6 或数据表中的任何内容)。 因此,使用单个定时器当然可以独立生成多个具有不同占空比的 PWM 信号,但它们将共享相同的时序(相同的频率),并且所有这些信号都将同步。

如下图所示,通用 计时器Timer2框架,其中突出显示了多个输出比较通道和输出驱动器:

在这里插入图片描述

2)、STM32定时器的PWM模式类型

存器的 OCxM 位中写入 110(PWM 模式 1)或‘111(PWM 模式 2),可以在每个通道上独立选择 PWM 模式(每个 OCx 输出一个 PWM)。用户必须通过设置 TIMx_CCMRx 寄存器中的 OCxPE 位来启用相应的预加载寄存器,并最终通过设置 TIMx_CR1 寄存器中的 ARPE 位来启用自动重加载预加载寄存器。

OCx 极性可使用 TIMx_CCER 寄存器中的 CCxP 位进行软件编程。它可以被编程为高电平有效或低电平有效。对于需要生成互补 PWM 信号的应用,此选项将适合您。

在 PWM 模式(1 或 2)下,总是比较 TIMx_CNT 和 TIMx_CCRx,以确定是 TIMx_CCRx≤TIMx_CNT 还是 TIMx_CNT≤TIMx_CCRx(取决于计数器的方向)。

根据 TIMx_CR1 寄存器中的 CMS 位,定时器能够在边沿对齐模式或中心对齐模式下生成 PWM。

1
2
注意:PWM 信号有很多我们需要在各种应用中控制的特性。 首先是信号的频率。 其次,可能也是最重要的一个,是占空比。 第三,是PWM分辨率。 在后面的教程中还有更多要讨论的内容,我们将在下面的下一节中介绍这 3 个属性。

3)、STM32 PWM 频率

在各种应用中,需要生成具有特定频率的 PWM 信号。 在伺服电机控制、LED 驱动器、电机驱动器以及更多需要为输出 PWM 信号设置所需频率的情况下。

PWM 周期 (1/

F

P

W

M

F_{PWM}

FPWM​) 由以下参数定义:ARR 值、预分频器值和驱动定时器模块

F

C

L

K

F_{CLK}

FCLK​ 的内部时钟本身。 下面的公式用于计算输出的 FPWM。 您可以设置您正在使用的时钟、预分频器,并求解 ARR 值,以便控制 $F_{PWM}并获得想要的结果。

F



P


W


M

F

C

L

K

(

A

R

R

+

1

)

×

(

P

S

C

+

1

)

F_{PWM} = \frac{F_{CLK}}{(ARR + 1) \times (PSC + 1)}

FPWM​=(ARR+1)×(PSC+1)FCLK​​

4)、STM32 PWM 占空比

在正常设置中,假设在 PWM 模式下使用定时器模块并在边沿对齐模式递增计数配置中生成 PWM 信号。 占空比百分比通过更改 CCRx 寄存器的值来控制。 占空比等于 (CCRx/ARR) [%]。

D


u


t


y


C


y


c


l



e



P


W


M




[


%


]

C

C

R

x

A

R

R

x

[

%

]

DutyCycle_{PWM}[%] = \frac{CCRx}{ARRx}[%]

DutyCyclePWM​[%]=ARRxCCRx​[%]

**5)、STM32 PWM 分辨率 **

PWM 信号最重要的特性之一是分辨率。 这是可以将其设置为的离散占空比级别的数量。 这个数字决定了占空比在达到最大值之前可以采取多少步。 因此,步长或占空比步数可以告诉您如何精细地改变占空比以达到某个百分比。 这在某些音频应用、电机控制甚至灯光控制系统中可能非常重要。

下面公式是STM32 PWM分辨率公式,可以用来计算PWM信号在特定频率甚至相反频率下的分辨率。:

R


e


s


o


l


u


t


i


o



n



P


W


M

log

(

F

C

L

K

F

P

W

M

)

log

(

2

)

[

B

i

t

s

]

Resolution_{PWM} = \frac{\log( \frac{F_{CLK}}{F_{PWM}} )}{\log(2)}[Bits]

ResolutionPWM​=log(2)log(FPWM​FCLK​​)​[Bits]

在其他情况下,需要调整 ARR 值。 因此,需要了解它与 PWM 分辨率之间的关系。 这不是一个新公式,它源自第一个公式和在本文前面看到的

F

P

W

M

F_{PWM}

FPWM​ 公式。 我们将在后面的教程中使用它来设计我们的电机驱动程序库和一些其他应用程序。

R


e


s


o


l


u


t


i


o



n



P


W


M




[


B


i


t


s


]

log

(

A

R

R

+

1

)

log

(

2

)

Resolution_{PWM}[Bits] = \frac{\log(ARR + 1)}{\log(2)}

ResolutionPWM​[Bits]=log(2)log(ARR+1)​

下表显示了一些示例频率和每个

F

P

W

M

F_{PWM}

FPWM​ 频率下的 PWM 分辨率。

在这里插入图片描述

6)STM32 PWM 不同模式

PWM 信号的生成可以在不同的模式下完成,将在本节中讨论其中的两种。 边缘对齐( Edge-Aligned Mode)模式和**中心对齐模式(**Center-Aligned Mode)**。

边缘对齐模式

在边沿对齐的 PWM 模式中,存在几种可能的配置:

  • 递增计数配置
  • 递减计数配置

在以下示例中,我们考虑 PWM 模式 1。只要

T

I

M

x

C

N

T

<

T

I

M

x

C

C

R

x

TIMx_CNT <TIMx_CCRx

TIMxC​NT<TIMxC​CRx,参考 PWM 信号 OCxREF 就为高电平,否则变为低电平。 如果 TIMx_CCRx 中的比较值大于自动重载值(在 TIMx_ARR 中),则 OCxREF 保持为 1。 如果比较值为 0,则 OCxREF 保持为 0。

在这里插入图片描述

中心对齐模式

根据 CMS 位配置,当计数器向上计数时或向下计数时或两者时向上计数和向下计数时设置比较标志。 TIMx_CR1 寄存器中的方向位 (DIR) 由硬件更新,不得由软件更改。
下图显示了一些中心对齐的 PWM 波形示例,其中: TIMx_ARR=8,PWM 模式为 PWM 模式 1。
在这里插入图片描述

2、PWM配置

下面通过如下设置将实现LED调光器功能:

  • 设置定时器 2 以使用内部时钟在 PWM 模式下工作。 并使CH1 为PWM 输出通道。
  • 将 ARR 值设置为最大 65535,因此频率应为 1098Hz
  • 通过写入 CCR1 寄存器来控制占空比
  • 使占空比扫描从 0% 到 100% 来回

第一步、创建工程

在这里插入图片描述

第二步、选择芯片

在这里插入图片描述

第三步、配置系统时钟

在这里插入图片描述

在这里插入图片描述

第四步、配置定时器

在这里插入图片描述

第五步、设置系统调试

在这里插入图片描述

保存配置生成工程代码

3、生成代码及功能实现

STM32Cube IDE生成的主要代码如下:

1)定时器TIM2初始化

main.c文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/\*\*
\* @brief TIM2 Initialization Function
\* @param None
\* @retval None
\*/
static void MX\_TIM2\_Init(void) {

/\* USER CODE BEGIN TIM2\_Init 0 \*/

/\* USER CODE END TIM2\_Init 0 \*/

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

/\* USER CODE BEGIN TIM2\_Init 1 \*/

/\* USER CODE END TIM2\_Init 1 \*/
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL\_TIM\_Base\_Init(&htim2) != HAL_OK) {
Error\_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL\_TIM\_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
Error\_Handler();
}
if (HAL\_TIM\_PWM\_Init(&htim2) != HAL_OK) {
Error\_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL\_TIMEx\_MasterConfigSynchronization(&htim2, &sMasterConfig)
!= HAL_OK) {
Error\_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL\_TIM\_PWM\_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1)
!= HAL_OK) {
Error\_Handler();
}
/\* USER CODE BEGIN TIM2\_Init 2 \*/

/\* USER CODE END TIM2\_Init 2 \*/
HAL\_TIM\_MspPostInit(&htim2);

}

2)GPIO初始化

main.c文件中

1
2
3
4
5
6
7
8
9
10
11
12
/\*\*
\* @brief GPIO Initialization Function
\* @param None
\* @retval None
\*/
static void MX\_GPIO\_Init(void) {

/\* GPIO Ports Clock Enable \*/
\_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE();

}

3)主程序入口及功能实现

main.c文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/\*\*
\* @brief The application entry point.
\* @retval int
\*/
int main(void) {
/\* USER CODE BEGIN 1 \*/
int32_t CH1_DC = 0;
/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/
/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_TIM2\_Init();
/\* USER CODE BEGIN 2 \*/
HAL\_TIM\_PWM\_Start(&htim2, TIM_CHANNEL_1);
/\* USER CODE END 2 \*/

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

/\* USER CODE BEGIN 3 \*/
while (CH1_DC < 65535) {
TIM2->CCR1 = CH1_DC;
CH1_DC += 70;
HAL\_Delay(1);
}
while (CH1_DC > 0) {
TIM2->CCR1 = CH1_DC;
CH1_DC -= 70;
HAL\_Delay(1);
}
}
/\* USER CODE END 3 \*/
}


4、程序运行结果

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/123321524