打印
[应用相关]

【转】对教程的补充:PWM互补输出及死区时间代码和详解

[复制链接]
747|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
conjunction|  楼主 | 2020-3-21 16:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
原贴链接:http://www.openedv.com/forum.php?mod=viewthread&tid=62861&extra=page%3D1%26filter%3Ddigest%26digest%3D1


一直跟着原子哥的教程一直学到PWM这一章发现一头雾水,自己也没发过什么分享帖,感觉原子哥对PWM这章讲的比较少(mini板教程),后面自己上网找了些资料,网上关于PWM讲的也不多,所以学起来也挺困难的,一直对TIM1有7路PWM不理解,自己只能输出4路,另外三路也不知道怎么输出,通过网上少量资料和自己研究发现这三路用于互补输出,互补输出调试出来了发现又有死区时间,主要用于电机的H桥方面的控制,后面附上自己对高级定时器互补输出和死区时间设置的代码和详解。花了两小时整理了下资料,初学者难免有错希望指出,也希望对跟我一样的初学者学习PWM有点帮助

使用特权

评论回复
沙发
conjunction|  楼主 | 2020-3-21 16:47 | 只看该作者
先简单了解下PWM和死区时间

脉冲宽度调制(PWM),是英文“Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,高级定时器 TIM1 和TIM8 可以同时产生多达 7 路的PWM 输出。而通用定时器也能同时产生多达 4路的PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!

使用特权

评论回复
板凳
conjunction|  楼主 | 2020-3-21 16:49 | 只看该作者
PWM的死区时间:

死区,简单解释:通常,大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。每个桥的上半桥和下半桥是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。(就是上、下半桥的元件都是关断的)死区时间控制在通常的低端单片机所配备的PWM中是没有的。
PWM的上下桥臂的三极管是不能同时导通的。如果同时导通就会是电源两端短路。所以,两路触发信号要在一段时间内都是使三极管断开的。这个区域就叫做“死区”优点就不用说了。缺点是使谐波的含量有所增加。

使用特权

评论回复
地板
conjunction|  楼主 | 2020-3-21 16:50 | 只看该作者
7路PWM:


使用特权

评论回复
5
conjunction|  楼主 | 2020-3-21 16:50 | 只看该作者
代码和详解:
//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        
        }
}

使用特权

评论回复
6
conjunction|  楼主 | 2020-3-21 16:54 | 只看该作者
①自动重载,这里重载值为500,50ms一个周期

②预分频:7200分频,频率为10KHZ




TIM1->CCER|=1<<0;//位0为使能位,位1~3都默认为0,即高电平有效,关闭输入捕获,互补输出极性为“高电平有效”,所谓的”有效”跟④有关,如下

使用特权

评论回复
7
conjunction|  楼主 | 2020-3-21 16:55 | 只看该作者



CCMR1的4~6位为模式设置,,由于我们上面设置为高电平“有效”,这里又设置为PWM2模式,在⑦没有设置TIM1_CR1的DIR位,所以默认为0,也就是向上计数,如下

使用特权

评论回复
8
conjunction|  楼主 | 2020-3-21 16:56 | 只看该作者

可以推出TIMx_CNT从0开始往上计数,在小于CCR1(第⑨有设置)时会输出无效电平也就是低电平,当大于的时候输出有效电平也就是高电平,这样就达到了设置占空比的目的。一开始我们设ARR为500,CCR1为250,所以一开始输出低电平占50%,高电平也是50%

使用特权

评论回复
9
conjunction|  楼主 | 2020-3-21 16:58 | 只看该作者
⑤死区时间设置TIM1_BDTR(位7:0),我们上面设置的是0x14

DT表示死区持续时间,Tdts为系统时钟周期,Tdtg表示乘以倍数后死区设置时间步进值。


TIM1_BDTR = 0x14是高3位为000,也就是调用以下这个公式(第一个公式),高3位可以根据自己需要设置

可以看到第⑧可以得知Tdts = 10Khz,Tdtg = Tdts = 10Khz,DT = 20(0x14) * 100us(10Khz) = 2000us = 2ms,也就是死区持续时间为2ms,最后配置输出使能⑥

使用特权

评论回复
10
conjunction|  楼主 | 2020-3-21 17:00 | 只看该作者
下面是输出的波形

通道1(低电平27ms,高电平23ms)
互补输出的通道(CH1N)(高电平23ms,低电平27ms)

使用特权

评论回复
11
conjunction|  楼主 | 2020-3-21 17:00 | 只看该作者

通道2(7ms)

使用特权

评论回复
12
conjunction|  楼主 | 2020-3-21 17:01 | 只看该作者

通道3(14.5ms)

使用特权

评论回复
13
conjunction|  楼主 | 2020-3-21 17:02 | 只看该作者

通道4(2.5ms)

使用特权

评论回复
14
conjunction|  楼主 | 2020-3-21 17:02 | 只看该作者

死区时间(2ms)

使用特权

评论回复
15
conjunction|  楼主 | 2020-3-21 17:03 | 只看该作者

由于互补输出且有死区时间所以CH1加了2ms,而CH1N减了2ms,死区时间跟计算的一样是2ms,而最后一个CH4没有互补

使用特权

评论回复
16
conjunction|  楼主 | 2020-3-21 17:04 | 只看该作者
输出所以自然是2.5ms不变,由于我们设置的10KHZ,而手册是以8M为例子的,大家也可以试一下,亲测没有问题,如果

是8M死区时间精度也更高可以,可以设为us和ns级别。下面附上这个例程的代码

使用特权

评论回复
17
conjunction|  楼主 | 2020-3-21 17:04 | 只看该作者
PWM输出实验(寄存器).zip (979.52 KB)

使用特权

评论回复
18
heimaojingzhang| | 2020-4-7 13:19 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
19
keaibukelian| | 2020-4-7 13:23 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
20
labasi| | 2020-4-7 13:24 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

196

帖子

0

粉丝