【自学嵌入式:51单片机】直流电机驱动(PWM)和呼吸灯
所有自学嵌入式:51单片机系列的操作相关器件的代码都汇总到了:https://gitee.com/qin-ruiqian/Qin51
直流电机

直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电机正接时,电机正转,当电极反接时,电机反转。直流电机主要由永磁体(定子)、线圈(转子)和换向器组成。除直流电机外,常见的电机还有步进电机、舵机、无刷电机、空心杯电机等。
步进电机机壳上分布一圈电磁铁,转子是一个永磁体,对不同角度的磁铁通电,以圆形的脉冲进行旋转,永磁体也按照脉冲进行旋转,可以精密控制。

上图是舵机,一个直流电机加一个控制器,有三根线,正负极和编码器控制线,通过调整控制线的脉冲调整舵机的角度。
电机驱动电路

电机直接接单片机I/O口会损坏I/O口,所以要通过一个驱动电路间接连接
- 大功率器件直接驱动:驱动的电机只能朝着一个方向转,它不具备调换电机正反方向的功能,利用PNP三极管(MOS管)让更大电压的电路导通,需要加一个续流二极管,防止电流突变,电流突变,让二极管把电流释放掉。
- H桥驱动:它可以控制电机正反转
PWM
PWM(Pulse Width Modulation)即脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速、开关电源等领域。通过让电机转1ms停1ms等操作让电机转的快或慢。
PWM重要参数
\[\text{频率}=\frac{1}{T_{S}}
\]
\[\text{占空比}=\frac{T_{\text{ON}}}{T_{S}}
\]
\[\text{精度}=\text{占空比变化步距}
\]
其中\(T_{\text{ON}}\)是打开的时间,占空比变化步距,比如从1%,2%...占空比变化步距就是1%,如果是从1.1%,1.2%...占空比变化步距就是0.1%.

我们想要控制电机调速,就要不断控制电机电平变化的频率。
PWM呼吸灯
代码实现
main.c:
#include <REGX52.H>
sbit LED=P2^0;
//延迟1微秒
void Delayus(unsigned int t)
{
while(t--);
}
void main()
{
unsigned char Time = 0;
unsigned char i = 0;
while(1)
{
//亮度由低变高
for(Time = 0; Time<100; Time++)
{
//让每一个亮度变化延缓20次
for(i=0; i<20; i++)
{
LED = 0;
Delayus(Time);
LED = 1;
Delayus(100 - Time);
}
}
//亮度由高变低
for(Time=100; Time>0; Time--)
{
//让每一个亮度变化延缓20次
for(i=0; i<20; i++)
{
LED = 0;
Delayus(Time);
LED = 1;
Delayus(100 - Time);
}
}
}
}
时序分析

20次内周期是恒定的

外层循环控制着高低电平的间隔大小
一般用定时器来控制呼吸灯,更高端的单片机有硬件pwm模块
PWM调节LED灯亮度
代码实现
#include <REGX52.H>
#include "Key.h"
#include "Nixie.h"
sbit LED = P2^0;
unsigned char Counter, Compare; //Counter计数器,Compare比较值设置越大,低电平(亮的)时间越长
unsigned char KeyNum; //按键键码
unsigned char Speed; //呼吸灯速度
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
//初始化定时器,100微秒为周期
void initTimer0(void)
{
TMOD = 0x01; //只开启定时器0
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1; //允许中断
ET0 = 1; //允许定时器0中断
}
//每隔100微秒中断一次
void Timer0_Routine() interrupt 1
{
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter %= 100; //到100的时候自动变0
//计数变量到比较值的时候自动灭(亮的时间最多100微秒)
if(Counter < Compare)
{
LED = 0;
}
else
{
LED = 1;
}
}
void main()
{
initTimer0();
Compare = 5; //比较值设置越大,低电平(亮的)时间越长
while(1)
{
KeyNum = Key();
if(KeyNum == 1)
{
Speed++;
Speed%=4;
//不同速度的比较值,也代表着LED灯不同的亮度
if(Speed == 0)
{
Compare = 0;
}
if(Speed == 1)
{
Compare = 5;
}
if(Speed == 2)
{
Compare = 50;
}
if(Speed == 3)
{
Compare = 100;
}
}
Nixie_Scan(1, Speed); //数码管显示当前速度
}
}
PWM直流电机调速
产生PWM方法

通过改变比较值得数值,控制其占空比,比较直越大,其占空比就越小
代码实现
代码实现和PWM调节LED灯亮度一样,就是把LED口换成电机口,然后LED灯我的是0亮1灭,把0和1换个位置就行

#include <REGX52.H>
#include "Key.h"
#include "Nixie.h"
sbit Motor = P1^0; //接电路中第一个端口,用out1输出
unsigned char Counter, Compare; //Counter计数器,Compare比较值设置越大,低电平(亮的)时间越长
unsigned char KeyNum; //按键键码
unsigned char Speed; //呼吸灯速度
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
//初始化定时器,100微秒为周期
void initTimer0(void)
{
TMOD = 0x01; //只开启定时器0
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1; //允许中断
ET0 = 1; //允许定时器0中断
}
//每隔100微秒中断一次
void Timer0_Routine() interrupt 1
{
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter %= 100; //到100的时候自动变0
//计数变量到比较值的时候自动变低电平
//这样通过调节占空比来调节电机转速
if(Counter < Compare)
{
Motor = 1;
}
else
{
Motor = 0;
}
}
void main()
{
initTimer0();
Compare = 5; //比较值设置越大,高电平时间越长
while(1)
{
KeyNum = Key();
if(KeyNum == 1)
{
Speed++;
Speed%=4;
//不同速度的比较值,也代表着电机不同转速
//比较值大一些,让电机转起来
if(Speed == 0)
{
Compare = 0;
}
if(Speed == 1)
{
Compare = 50;
}
if(Speed == 2)
{
Compare = 75;
}
if(Speed == 3)
{
Compare = 100;
}
}
Nixie_Scan(1, Speed); //数码管显示当前速度
}
}
浙公网安备 33010602011771号