飞书文档https://x509p6c8to.feishu.cn/wiki/JkzfwSoFBiUKc4kh8IoccTfyndg
一、什么是****PWM ?
PWM是脉冲宽度调制的缩写,它是一种通过调整脉冲信号的高电平和低电平时间比例来控制电路输出的技术。简单来说,PWM是一种控制电子设备输出电压或电流的方法,它可以通过调整脉冲信号的宽度来控制输出信号的平均电压或电流,常应用于电机控速,开关电源等领域。
二、PWM的频率与占空比
在PWM波形中有两个重要的参数,分别是:频率、占空比;
pwm 的频率:
是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);
如果频率为1000Hz ,也就是说1秒内来回了1000次,那每次的时间就是1ms,那此信号一个周期就是1ms

占空比:
是一个脉冲周期内,高电平的时间与整个周期时间的比例

调节占空比最终会反映到输出的电流、电压上,或者可以理解为输出的总能量变化,100%占空比时输出100%能量,50%占空比时,只会输出一半的能量,例如50%占空比控制LED会比较暗,控制电机力气会比较小。
三、呼吸灯控制
下面使用IO模拟的方式,实时修改占空比,控制LED的呼吸灯效果:
优化
#include <reg52.h>
sbit led = P2^7;
void Delayus(int t) //@11.0592MHz
{
while(t--){
unsigned char i;
i = 2;
while (--i);
}
}
void main()
{
int time = 0;
led = 0;
while(1)
{
for(time = 0;time < 300;time ++){ //从暗逐渐变亮的过程
led = 0;
Delayus(time);
led = 1;
Delayus(300 - time);
}
for(time = 0;time < 300;time ++){ //从亮逐渐变暗的过程
led = 1;
Delayus(time);
led = 0;
Delayus(300 - time);
}
}
}
除了使用IO模拟的方式,我们也可以通过定时器功能,产生更加精确的PWM波形;设置定时器的溢出时间可以改变PWM的周期频率;设置比较值大小可以调节PWM的占空比;
下面我们以直流电机为例,看看如何使用计数器输出PWM控制电机运动:
三、直流电机控制

直流电机是指能将直流电能转换成机械能转动的设备。
|---------------------------------------------------------------------------------------------------------------------------|
| 直流电机的结构是由定子和转子组成。直流电机运动时,不动的部分称为定子,定子的主要作用是产生磁场。运行时转动的部分称为转子,其主要作用是产生电磁转矩和感应电动势。 直流电机没有正负之分,在两端加上直流电就能工作。交换电极可以改变电机旋转的方向; |
51单片机作为一个开发板,起到的主要作用是控制,而直流电机作为一个较大功率的器件,当然不能通过51单片机的IO引脚进行驱动,需要使用一些驱动电路或者芯片进行驱动,板卡上用的是TC118S。


简单正反转驱动
#include <reg52.h>
sbit dc_an2= P2^3;
sbit dc_an1= P2^4;
//带参延时函数
void delay_ms(unsigned int xms) //@12MHz
{
unsigned int i, j;
for(i=xms;i>0;i--)
{
for(j=124;j>0;j--)
{}
}
}
void main()
{
while(1)
{
//正转2s
dc_an2 = 0;
dc_an1 = 1;
delay_ms(2000);
//停止2s
dc_an2 = 0;
dc_an1 = 0;
delay_ms(2000);
//反转2s
dc_an2 = 1;
dc_an1 = 0;
delay_ms(2000);
//停止2s
dc_an2 = 0;
dc_an1 = 0;
delay_ms(2000);
}
}
PWM速度控制
#include <reg52.h>
//约1ms溢出
#define TIMS (65536 - 922)
sbit dc_an2= P2^3;
sbit dc_an1= P2^4;
unsigned char speed,compare;
//延时ms函数,参数用来改变延时的具体时间
void delay_ms(unsigned int xms) //@12MHz
{
unsigned int i, j;
for(i=xms;i>0;i--)
{
for(j=124;j>0;j--)
{}
}
}
void main()
{
TMOD = 0x01; //配置定时器0为16位定时器,TH0、TL0全用
TH0 = TIMS >> 8; //设置定时初值高8位
TL0 = TIMS; //设置定时初值低8位
ET0 = 1; //开启定时器0中断
EA = 1; //开启全局中断
TR0 = 1; //定时器0开始计数
//初始化电机,停止运行
dc_an1 = 0;
dc_an2 = 0;
while(1){
compare=10;
delay_ms(5000);
compare=30;
delay_ms(5000);
compare=60;
delay_ms(5000);
compare=90;
delay_ms(5000);
}
}
//1ms触发执行一次
void Timer0() interrupt 1
{
//每次产生中断后重新设置下次定时器初值 - 1毫秒产生1次中断
TH0 = TIMS >> 8;
TL0 = TIMS;
//当compare为10时,输出10ms高电平,90ms低电平
//当compare为60时,输出60ms高电平,40ms低电平
//当compare为90时,输出90ms高电平,10ms低电平
speed++;//定时计数器的计数值,1ms加1
speed%=100;//限制speed在0-100内
if(speed<compare)//计数值与比较值进行比较
{
dc_an2=1;
}
else
{
dc_an2=0;
}
}