[STM32F1官方例程讲解1] TIM外设输出PWM波
第一章 PWM波
PWM的全称为Pulse-width modulation,是一种通过有效地将电信号切成离散部分来降低电信号传递的平均功率的方法。通过快速打开和关闭电源和负载之间的开关,可以控制进入负载的电压(和电流)的平均值。与关闭时间相比,开关打开的时间越长,提供给负载的总功率就越高。PWM常用于控制惯性负载(例如电机)。PWM的主要优点是开关器件的功耗非常低。当开关断开时,几乎没有电流,而当开关导通且功率正在传递到负载时,开关两端几乎没有压降。因此,作为电压和电流的乘积的功率损耗在两种情况下都接近于零。PWM还可以与数字控件配合使用,由于其开/关特性,可以轻松设置所需的占空比,进而完成控制任务。PWM在Boost-buck电路,电机控制,开关切换,呼吸灯中都有着极其重要的地位。本文基于stm32f10x_stdperiph_lib_um.chm文档中的TIM_PWM_Output章节编写。
1.1 PWM波的主要参数
参数 | 定义 |
---|---|
周期T | 一次高低电平结束的时间 |
频率f | 1/T |
占空比Duty Cycle | 在一个脉冲循环内,通电时间(高电平)占周期的比例。 |
1.2 STM32F1平台的PWM外设
1.2.1 PWM外设映射关系
在STM32F1平台上,PWM外设隶属于TIMER外设。以STM32F103C8T6芯片为例,通过查阅数据手册,确定TIMER外设在引脚上的映射关系。
引脚 | 默认映射 | 重映射 |
---|---|---|
PA0 | TIM2_CH1_ETR | 无 |
PA1 | TIM2_CH2 | 无 |
PA2 | TIM2_CH3 | 无 |
PA3 | TIM2_CH4 | 无 |
PA6 | TIM3_CH1 | TIM1_CH1_BKIN |
PA7 | TIM3_CH2 | TIM1_CH1_CH1N |
PA8 | TIM1_CH1 | 无 |
PA9 | TIM1_CH2 | 无 |
PA10 | TIM1_CH3 | 无 |
PA11 | TIM1_CH4 | 无 |
PA12 | TIM1_ETR | 无 |
PA15 | 无 | TIM2_CH1_ETR |
PB0 | TIM3_CH3 | TIM1_CH2N |
PB1 | TIM3_CH4 | TIM1_CH3N |
PB3 | 无 | TIM2_CH2 |
PB4 | 无 | TIM2_CH3 |
PB5 | 无 | TIM2_CH4 |
PB6 | TIM4_CH1 | 无 |
PB7 | TIM4_CH2 | 无 |
PB8 | TIM4_CH3 | 无 |
PB9 | TIM4_CH4 | 无 |
PB10 | 无 | TIM2_CH3 |
PB11 | 无 | TIM2_CH4 |
其中,TIM1属于高级定时器(advanced-control timer),一些带后缀的功能不在这里讨论(如ETR,互补输出CHxN等)。后面程序中选用的是通用定时器(general -purpose timer)TIM3的CH1~CH4作为PWM波的输出口。
1.2.2 PWM外设的寄存器的配置过程
首先,对于一个外设而言,最重要的就是时钟的使能与配置,相关操作见2.1 时钟配置。查阅参考手册的相应章节,可知时钟可由外部输入产生,也可通过使能内部RCC(Reset and clock control)上的TIM外设来利用系统的时钟CK_INT(STM32F103为72MHz)。在这里我们选择的是后一种方法。
在产生了CK_INT内部TIM时钟信号后,先进入PSC Prescaler寄存器进行预分频(由TIM_Prescaler +1决定,定时器实际获得的计数频率为
f
C
K
_
C
N
T
=
f
C
K
_
I
N
T
/
(
T
I
M
_
P
r
e
s
c
a
l
e
r
+
1
)
f_{CK\_CNT} = f_{CK\_INT}/(TIM\_Prescaler +1)
fCK_CNT=fCK_INT/(TIM_Prescaler+1))。而后,APR寄存器的值(由TIM_Period决定)决定了PWM波的周期。外设以
f
C
K
_
C
N
T
f_{CK\_CNT}
fCK_CNT 的频率计数,并存储在CNT counter寄存器内,这部分内容详见2.3 定时器配置中的TIM_TimeBaseInit()函数。当CNT counter寄存器内的值与APR寄存器的值相等时,产生中断(在此例子中未用到),并置零CNT counter寄存器(根据设置)。此外,CNT counter寄存器内的值还与Capture/Compare x register内的值(由TIM_Pulse决定)进行比对,可分别设置大于/小于时的输出电平。
综上,可得PWM波的频率为 f P W M f_{PWM} fPWM :
f P W M = f C K _ I N T / ( T I M _ P r e s c a l e r + 1 ) / ( T I M _ P e r i o d + 1 ) f_{PWM}=f_{CK\_INT}/(TIM\_Prescaler+1)/(TIM\_Period+1) fPWM=fCK_INT/(TIM_Prescaler+1)/(TIM_Period+1)
占空比(假设CNT counter寄存器内的值比Capture/Compare x register内的值小时输出高电平)为:
D u t y C y c l e = ( T I M _ P u l s e + 1 ) / ( T I M _ P e r i o d + 1 ) Duty Cycle=(TIM\_Pulse+1)/(TIM\_Period+1) DutyCycle=(TIM_Pulse+1)/(TIM_Period+1)
同样的,可以看出对于同一个TIM外设,4通道的PWM波输出周期是相同的,而占空比是可分别调节的。
第二章 相关函数配置
2.1 时钟配置
需要使能挂载在APB1上的TIM3时钟,与挂载在APB2上的GPIOA,GPIOB的时钟。具体如下所示:
void RCC_Configuration(void)
{
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
}
2.2 GPIO配置
STM32F103C8T6属于的类型是STM32F10X_MD,中等存储容量Medium-density的STM32F10X系列产品,进入的是下半部分的程序(即else之后的代码)。
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
#ifdef STM32F10X_CL
/*GPIOB Configuration: TIM3 channel1, 2, 3 and 4 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
#else
/* GPIOA Configuration:TIM3 Channel1, 2, 3 and 4 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
#endif
}
上述代码使能了STM32F103C8T6的PA6, PA7, PB0, PB1引脚(分别对应TIM3的CH1~CH4),并将其设置为复用推挽模式。
2.3 定时器配置
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t CCR1_Val = 333;
uint16_t CCR2_Val = 249;
uint16_t CCR3_Val = 166;
uint16_t CCR4_Val = 83;
uint16_t PrescalerValue = 0;
PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
/* -----------------------------------------------------------------------
TIM3 Configuration: generate 4 PWM signals with 4 different duty cycles:
The TIM3CLK frequency is set to SystemCoreClock (Hz), to get TIM3 counter
clock at 24 MHz the Prescaler is computed as following:
- Prescaler = (TIM3CLK / TIM3 counter clock) - 1
SystemCoreClock is set to 72 MHz for Low-density, Medium-density, High-density and Connectivity line devices and to 24 MHz for Low-Density Value line and Medium-Density Value line devices
The TIM3 is running at 36 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1) = 24 MHz / 666 = 36 KHz
TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
-----------------------------------------------------------------------
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 665; //装载入ARR中的系数
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; //预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //外部输入分频,在PWM输出时无作用效果
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OC4Init(TIM3, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
在如上配置下,可以通过计算得到PWM波的频率:
f
P
W
M
=
f
C
K
_
I
N
T
/
(
T
I
M
_
P
r
e
s
c
a
l
e
r
+
1
)
/
(
T
I
M
_
P
e
r
i
o
d
+
1
)
=
72
M
H
z
/
(
2
+
1
)
/
(
665
+
1
)
=
36.04
k
H
z
f_{PWM}=f_{CK\_INT}/(TIM\_Prescaler+1)/(TIM\_Period+1)=72MHz/(2+1)/(665+1)=36.04kHz
fPWM=fCK_INT/(TIM_Prescaler+1)/(TIM_Period+1)=72MHz/(2+1)/(665+1)=36.04kHz
各通道的占空比Duty Cycle为:
通道 | 引脚 | 占空比 |
---|---|---|
CH1 | PA6 | 50% |
CH2 | PA7 | 37.5% |
CH3 | PB0 | 25% |
CH4 | PB1 | 25% |
第三章 实现效果
采用便携式示波器测试,结果如下,能够很好地与前文所述的设置匹配上。
之后,我有时间的话会把STM32官方库的所有例程讲解一遍,敬请期待