原文: http://www.openedv.com/thread-62861-1-1.html
一直跟着原子哥的教程一直学到PWM这一章发现一头雾水,自己也没发过什么分享帖,感觉原子哥对PWM这章讲的比较少(mini板教程),后面自己上网找了些资料,网上关于PWM讲的也不多,所以学起来也挺困难的,一直对TIM1有7路PWM不理解,自己只能输出4路,另外三路也不知道怎么输出,通过网上少量资料和自己研究发现这三路用于互补输出,互补输出调试出来了发现又有死区时间,主要用于电机的H桥方面的控制,后面附上自己对高级定时器互补输出和死区时间设置的代码和详解。花了两小时整理了下资料,初学者难免有错希望指出,也希望对跟我一样的初学者学习PWM有点帮助
先简单了解下PWM和死区时间
简介:
脉冲宽度调制(PWM),是英文“ Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出!
PWM的死区时间:
死区,简单解释:通常,大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。每个桥的上半桥和下半桥是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。(就是上、下半桥的元件都是关断的)死区时间控制在通常的低端单片机所配备的PWM中是没有的。
01
02
03
04
05
06
07
08
09
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
56
57
58
59
60
61
62
63
64
65
|
//TIM1_CH1 PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void
TIM1_PWM_Init(u16 arr,u16 psc)
{
RCC->APB2ENR|=1<<11;
//TIM1时钟使能
RCC->APB2ENR|=1<<2;
//使能PORTA时钟
RCC->APB2ENR|=1<<3;
//使能PORTB时钟
RCC->APB2ENR|=1<<0;
//开启复用时钟
GPIOA->CRH&=0XFFFF0000;
//PA8,9,10,11清除之前的设置
GPIOA->CRH|=0X0000BBBB;
//PA8,9,10,11复用功能输出
GPIOB->CRH&=0X000FFFFF;
//PB13,14,15清除之前的设置
GPIOB->CRH|=0XBBB00000;
//PB13,14,15复用功能输出
GPIOB->ODR|=1<<13;
//PB13 输出上拉,低电平有效
GPIOB->ODR|=1<<14;
//PB14
GPIOB->ODR|=1<<15;
//PB15
GPIOA->ODR|=1<<8;
//PA8
GPIOA->ODR|=1<<9;
//PA9
GPIOA->ODR|=1<<10;
//PA10
TIM1->ARR=arr;
//设定计数器自动重装值 ①1
TIM1->PSC=psc;
//预分频器设置 ②2
TIM1->CCER|=1<<0;
//TIM1CH1 输出使能,高电平有效 ③3
TIM1->CCER|=1<<4;
//TIM1CH2 输出使能
TIM1->CCER|=1<<8;
//TIM1CH3 输出使能
TIM1->CCER|=1<<12;
//TIM1CH4 输出使能
TIM1->CCER|=1<<2;
//TIM1CH1N 互补输出使能
TIM1->CCER|=1<<6;
//TIM1CH2N 互补输出使能
TIM1->CCER|=1<<10;
//TIM1CH3N 互补输出使能
TIM1->CCMR1|=7<<4;
//CH1 PWM2模式 ④4
TIM1->CCMR1|=1<<3;
//CH1预装载使能
TIM1->CCMR1|=7<<12;
//CH2 PWM2模式
TIM1->CCMR1|=1<<11;
//CH2预装载使能
TIM1->CCMR2|=7<<4;
//CH3 PWM2模式
TIM1->CCMR2|=1<<3;
//CH3预装载使能
TIM1->CCMR2|=7<<12;
//CH4 PWM2模式
TIM1->CCMR2|=1<<11;
//CH4预装载使能
TIM1->BDTR|=0x14;
//死区时间设置 ⑤5
TIM1->BDTR|=1<<15;
//MOE 主输出使能 ⑥6
TIM1->CR1 |= 0x80;
//ARPE使能,开始所有输出通道,默认向上计数 ⑦7
TIM1->CR1 |= 0x01;
//使能计数器
}
int
main(
void
)
{
Stm32_Clock_Init(9);
//系统时钟设置
delay_init(72);
//延时初始化
TIM1_PWM_Init(499,7199);
// 72M/7200=10khz, 1/10khz * 500=50ms ⑧8
while
(1)
{
TIM1->CCR1=250;
//占空比:50% 低电平时长25ms ⑨9
TIM1->CCR2=125;
//占空比:75% 低电平时长12.5ms
TIM1->CCR3=50;
//占空比:90% 低电平时长5ms
TIM1->CCR4=25;
//占空比:95% 低电平时长2.5ms
}
}
|
①自动重载,这里重载值为500,50ms一个周期
②预分频:7200分频,频率为10KHZ
③TIM1->CCER|=1<<0;//位0为使能位,位1~3都默认为0,即高电平有效,关闭输入捕获,互补输出极性为“高电平有效”,所谓的”有效”跟④有关,如下
④
⑤死区时间设置TIM1_BDTR(位7:0),我们上面设置的是0x14
DT表示死区持续时间,Tdts为系统时钟周期,Tdtg表示乘以倍数后死区设置时间步进值。
通道3(14.5ms)
通道4(2.5ms)
死区时间(2ms)
由于互补输出且有死区时间所以CH1加了2ms,而CH1N减了2ms,死区时间跟计算的一样是2ms,而最后一个CH4没有互补
输出所以自然是2.5ms不变,由于我们设置的10KHZ,而手册是以8M为例子的,大家也可以试一下,亲测没有问题,如果
是8M死区时间精度也更高可以,可以设为us和ns级别。下面附上这个例程的代码