单片机重要部分-PWM

1.PWM?
Pulse Width Modulation,脉冲宽度调制**的缩写。

2.基本原理:
.控制方式就是对***逆变电路开关器件***的通断进行控制,使输出端得到***一系列幅值相等的脉冲***,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的***半个周期***中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。

***我的应用场景,pmw-开关:***按一定的规则对各脉冲的宽度进行调制,即可改变逆变电路输出电压的大小,也可改变输出频率。在这里插入图片描述

***应用方法:***就是控制在一个周期内,控制高电平多长时间,低电平多长时间,在数字电路中IO口就只有两种状态,0和1(高低)***,对应就是0和5V或者0和3.3V)。也就是说***通过调节高低电平时间的变化来调节信号、能量等的变化
在这里插入图片描述
图为周期4毫秒的PWM波形

{详细解析可忽略:把正弦半波波形分成N等份,就可把正弦半波看成由N个彼此相连的脉冲所组成的波形。这些脉冲宽度相等,都等于 π/n ,但幅值不等,且脉冲顶部不是水平直线,而是曲线,各脉冲的幅值按正弦规律变化。如果把上述脉冲序列用同样数量的等幅而不等宽的矩形脉冲序列代替,使矩形脉冲的中点和相应正弦等分的中点重合,且使矩形脉冲和相应正弦部分面积(即冲量)相等,就得到一组脉冲序列,这就是PWM波形。可以看出,各脉冲宽度是按正弦规律变化的。根据冲量相等效果相同的原理,PWM波形和正弦半波是等效的。对于正弦的负半周,也可以用同样的方法得到PWM波形.}

3.频率
频率是指每秒钟信号从***高电平***到***低电平***再回到***高电平***的***次数*** 上图中频率=1/(0.003+0.001)=250 HZ,

4.占空比
是指 高电平持续 时间 一个 周期持续时间
上图中占空=1/(1+3)=25%,
所以可以通过控制占空比,来控制输出的等效电压。所以对于方波的话,频率和占空比就确定了一个波。

5.如何产生一个pwm波形
1).芯片内置pwm,
2).利用IO口高低电平转变输出PWM信号,,比如上图中先把电平置1,维持1ms,然后将电平拉低,维持3ms,再将电平置高,如此循环往复下去,就可以产生一个周期4毫秒占空比为25%的PWM波了。具体方法就是给IO口加一个定时器,用定时器中断来实现及时切换高低电平。

6.定时器?
解释:定时计数器,因为它既能计时也能计数。定时器的***实质***是由机器频率向一个16位寄存器/2^16(每一种类型的单片机位是不一样的)累加,满溢出时触发一个中断,为了产生一个我们想要的时间间隔,比如说1s,所以我们要在这个寄存器里设定一个初值,以至于它在这个初始值上累加可以产生一个1s的倍数,这样我们就可以得到稳定的间隔。
这个寄存器位TH(高八位)和TL(低八位)。所以我们需要把计算好的初值分成两部分,分别放入TH和TL中。
过程
首先,我们通过单片机的***晶振频率***得知其***时钟周期***,再尤其***乘以12***得到机器周期。每一个机器周期在寄存器内+1,直到加满溢出产生中断。
举例说明
若单片机频率为12Mhz,其时钟周期就是1/12μs,机器周期为1μs,也就是每1μs寄存器+1。16位的寄存器加到溢出最多需要(2^16)-1=65535μs,溢出也需要一个机器周期,所以总共要65536μs。但这个值太别扭,和我们要的1s没什么关系。我们最好让它记50000μs产生一次中断,所以其初值就设为65536-50000=15536。但我们还要将这个值分别放在***高八位***和***低八位***,所以要将这个十进制数,转换为4位十六进制数再分开赋值。
十进制计算法:
TH = 15536/256;
TL = 15536%256;
进制计算问题这里不细讨论。这样的话,每50ms就会产生一次中断。我们只要用程序判断其中断20次就记1s。

7.PWM的应用
1)输出模拟电压(通过电压的高低来控制如LED的亮度,直流电机的速度等)。
2)PWM对模拟信号电平进行数字编码的方法,计算机只能输出0或5V的数字电压值而不能输出模拟电压,而我们如果想获得一个模拟电压值(介于0 - 5V的电压值),则需通过使用高分辨率计数器,改变方波的占空比来对一个模拟信号的电平进行编码。电压是以一种连接(1)或断开(0)的重复脉冲序列被夹到模拟负载上去的,连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,只要带宽足够,可以输出任意不大于最大电压值的模拟电压。
输出电压=(接通时间/脉冲时间)*最大电压值12
在这里插入图片描述
2 控制舵机
 舵机的控制就是通过一个固定周期但是不同占空比来控制舵机摆角的位置的。
  舵机的控制一般需要一个20ms左右的时基脉冲(频率为50HZ),该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;在这里插入图片描述
此图可以表现脉冲宽度(也可以转换成占空比)和舵机摆臂的位置图

控制步进电机
一般涉及到精确控制位移的时候,这个时候往复式驱动原件(舵机)就不适合了,所以就会经常用到步进电机。
  ***步进电机***把电脉冲信号变换成角位移以控制转子转动的微特电机。在自动控制装置中作为执行元件。每输入一个脉冲信号,步进电动机前进一步,故又称脉冲电动机。 !!!这里注意一点,直接控制单片机的话是脉冲控制,就是进来一个脉冲信号,步进电机转动一个步进角(一般为1.8°)。所以控制步进电机速度的方式就是通过控制 频率 (占空比一般都是50%)但是!!!现在可以通过接入步进电机驱动板的方式(比如博主之前使用的一款步进电机驱动板Tb6560)细分步进角。比如细分为2,一个脉冲步进电机就转动半个脉冲(0.9°)

实战篇
  这里使用51和STM32实现呼吸灯的功能,同样原理也可以控制直流电机,舵机是频率一定的情况下控制占空比来控制摆臂的方向,而步进电机是通过控制频率的方式来控制速度。
51部分
  例程使用51单片机将P1.0接一个二极管。运用PWM输出等效模拟电压完成呼吸灯功能。

unsigned char PWM_COUNT;  //计数
unsigned int  HUXI_COUNT;    //占空比更新时间
unsigned char PWM_VLAUE;    //占空比比对值
bit direc_flag;             //占空比更新方向

void timer0_init()
{
    TMOD=0x02;          //模式设置,00010000,定时器0,工作于模式2(M1=1,M0=0)
    TH0=0x47;               //定时器溢出值设置,每隔200us发起一次中断。
    TL0=0X47;
    TR0=1;                  //定时器0开始计时
    ET0=1;                  //开定时器0中断
    EA=1;                       //开总中断
    PWM_COUNT =0;
}

void time0() interrupt 1
{   
    PWM_COUNT++;
    HUXI_COUNT++;
    if(PWM_COUNT == PWM_VLAUE)      //判断是否到了点亮LED的时候
        LED = 1;                    //点亮LED
    if(PWM_COUNT == 10)             //当前周期结束
    {
        LED = 0;                    //熄灭LED
        PWM_COUNT = 0;              //重新计时
    }

    if((HUXI_COUNT == 600) && (direc_flag == 0))
    {                               //占空比增加10%
        HUXI_COUNT = 0;
        PWM_VLAUE++;
        if(PWM_VLAUE == 9)          //占空比更改方向
            direc_flag = 1; 
    }

    if((HUXI_COUNT == 600) && (direc_flag == 1))
    {                               //占空比减少10%
        HUXI_COUNT = 0;
        PWM_VLAUE--;
        if(PWM_VLAUE == 1)          //占空比更改方向
            direc_flag = 0; 
    }   
}
void main()
{
    HUXI_COUNT = 0;
    PWM_COUNT = 0;
    PWM_VLAUE = 5;
    direc_flag = 0;
    LED = 1;            //默认LED熄灭   
    timer0_init();      //定时器0初始化
    while(1);
}

32部分
  转自正点原子库函数手册PWM部分教程
  这里用到了 TIM3 的部分重映射功能(重映射:可以理解成把管脚的外设功能映射到另一个管脚,具体哪个引脚可以映射见参考手册), 例程把 TIM3_CH2 直接映射到了 PB5 上。

//TIM3 PWM 部分初始化
//PWM 输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //①使能定时器 3 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|
    RCC_APB2Periph_AFIO, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //②重映射 TIM3_CH2->PB5
    //设置该引脚为复用输出功能,输出 TIM3 CH2 的 PWM 脉冲波形 GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure); //①初始化 GPIO
    //初始化 TIM3
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在自动重装载周期值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //③初始化 TIMx
    //初始化 TIM3 Channel2 PWM 模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择 PWM 模式 2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高
    TIM_OC2Init(TIM3, &TIM_OCInitStructure); //④初始化外设 TIM3 OC2
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器
    TIM_Cmd(TIM3, ENABLE); //⑤使能 TIM3
}


int main(void)
{
    u16 led0pwmval=0;
    u8 dir=1;
    delay_init(); //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2
    uart_init(115200); //串口初始化波特率为 115200
    LED_Init(); //LED 端口初始化
    TIM3_PWM_Init(899,0); //不分频,PWM 频率=72000/900=80Khz
    while(1)
    {
	    delay_ms(10);
	    if(dir)led0pwmval++;
	    else led0pwmval--;
	    if(led0pwmval>300)dir=0;
	    if(led0pwmval==0)dir=1;
	    TIM_SetCompare2(TIM3,led0pwmval);
    }
}

  • 8
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值