写在前言
此为博主自学江科大51单片机(B站)的笔记,方便后续重温知识
在后面的章节中,为了防止篇幅过长和易于查找,我把一个小节分成两部分来发,上章节主要是关于本节课的硬件介绍、电路图、原理图等理论知识,主要是为下章节的代码部分打基础。
我的单片机是24年12月在tb普中买的,型号是STC89C52,在原视频中引脚或接口不对应的我都会改正,保证在我的机子上能运行才发上来的,还有一些文字部分是我的理解,并非照搬,所以可能有理解不到位的现象。
如有误或交流,敬请指点提问
本节课一共两个代码,LED呼吸灯和直流电机调速
一、直流电机
1.介绍
- 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
- 直流电机主要由永磁体(定子)、线圈(转子)和换向器组成
- 除直流电机外,常见的电机还有步进电机(机壳装载了一圈电磁铁,对相对两个电磁铁进行一圈脉冲式通电,优点是严格控速精密)、舵机(跟船舵一样,方便控制转向)、无刷电机(转速特别快)、空心杯电机(体积很小)等
- 左1就是我们开发板里的电机,有两个电极;左1是N20,一个直流电机+减速箱;右1比左2还多带一个编码器(测速),PID算法(常用)控制电机速度
2.驱动电路
有两种方式
- 大功率器件直接驱动
不能正反转上面是一个三极管控制开关,下面是一个蓄流二极管,用于保护电路;因为电机(继电器)是感性负载元件,驱动的时候会出现很高的电压(电感的特效)
这个ULN2003里面也是一个大功率元件

- H桥驱动
能正反转因为我们使第二、四象限的二极管导通其余的截止,就会令电流向右走,如果反过来就可以令电流向左走;因为没有蓄流二极管保护,所以对mos管和晶体管的耐压特效要求比较高
二、PWM
PWM是控制直流电机调速的
1.介绍
- PWM(Pulse Width Modulation)即脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速、开关电源等领域
- PWM重要参数:
- 频率=1/Ts 占空比=Ton/Ts 精度=占空比变化步距
三、代码实战
1.LED呼吸灯
先定义一下引脚
然后再定义一个比较快的延时函数,让这个LED灯先亮一段时间,再灭一段时间,这就是PWM的工作原理,通常为了保证周期是稳定的,不随占空比变化而变化,所以亮和灭加起来的时间也要是个固定值
#include <REGX52.H>
sbit LED=P2^0;
void Delay(unsigned int t)
{
while(t--);
}
void main()
{
while(1)
{
LED=0;
Delay(5);
LED=1;
Delay(95);
}
}
接下来就是让亮和灭的值不断变化,从而实现呼吸灯的效果
我们就可以定义一个变量Time,让亮的时间为Time,灭的时间为100-Time,这样就可以实现两个数加起来是固定值,然后我们再对Time进行for循环,不断++
但是这个速度还是比较快,我们让他每次亮灭变换的时间再久一点,定义一个i,在for循环里嵌套再进行一次for循环,这样就可以实现LED一直从暗到亮
但是我们还想实现从暗到亮,再从亮到暗又怎么做呢,就是把之前的外层对Time的for循环反过来再依次--
#include <REGX52.H>
sbit LED=P2^0;
void Delay(unsigned int t)
{
while(t--);
}
void main()
{
unsigned char Time,i;
while(1)
{
for(Time=0;Time<100;Time++)
{
for(i=0;i<20;i++)
{
LED=0;
Delay(Time);
LED=1;
Delay(100-Time);
}
}
for(Time=100;Time>0;Time--)
{
for(i=0;i<20;i++)
{
LED=0;
Delay(Time);
LED=1;
Delay(100-Time);
}
}
}
}
这样就可以实现呼吸灯从暗到亮,再从亮到暗
但是会有一个缺点,就是占用了我们的主循环不断翻转IO口,还比较占用CPU
一般都会写到定时器上,或者从硬件上解决
所以在下面的代码中我们用定时器来实现
2.直流电机调速
在这个代码我们就用定时器来实现LED呼吸灯和直流电机调速功能
产生PWM方法

我们通过改变比较值就可以改变占空比
由于之前的定时器设置有点慢,我们让他快一点

这个PWM驱动电机在一定范围内是越快越好,一般设置在10K-20K范围里,如果频率比较低,电流就会抖动,如果在1K左右,就会产生一些蜂鸣器的声音
这个中断就是每隔100us中断一次
//timer0.c
#include <REGX52.H>
/**
* @brief 定时器0初始化,100us@12.000MHz
* @param 无
* @retval 无
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
由上面的图可以知道要定义两个值,计数值和比较值,
我们让计数值从0-100然后清零,实现定时自增
Counter++;
Counter%=100;
这样写和if(counter==100){清零}是一个效果
接下来再让计数值和比较值进行比较
可以观察到如果比较值越大,低电平时间越久,也就是越暗
这样我们通过控制比较值Compare就可以控制LED的亮度,还剩下下了主循环,接下来我们就实现按键功能
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"
sbit LED=P2^0;
unsigned char Counter,Compare;
void main()
{
Timer0_Init();
Compare=5;
while(1)
{
}
}
void Timer0_Routine() interrupt 1
{
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter%=100;
if(Counter<Compare)
{
LED=0;
}
else
{
LED=1;
}
}
注意后面取的Key函数,如果是拿的定时器扫描按键的那章写的Key函数,要在定时器中写上这个Key_Loop()
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"
sbit LED=P2^0;
unsigned char Counter,Compare;
unsigned char KeyNum,Speed;
void main()
{
Timer0_Init();
Compare=5;
while(1)
{
KeyNum=Key();
if(KeyNum==1)
{
Speed++;
Speed%=4;
}
Nixie(1,Speed);
}
}
void Timer0_Routine() interrupt 1
{
Key_Loop();
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter%=100;
if(Counter<Compare)
{
LED=0;
}
else
{
LED=1;
}
}
这样就可以实现按下按键1数码管显示++并且过3就清零
接下来将Speed跟Compare比较值对应起来,就可以实现按键调速并显示
这样就可以实现LED的亮度控制
if(Speed==0){Compare=5;}
if(Speed==1){Compare=5;}
if(Speed==2){Compare=50;}
if(Speed==3){Compare=100;}
那我们如果想控制电机,就直接把LED的端口改成电机的端口,而又因为我们的LED是给0亮给1灭,而电机是给1转给0灭,所以需要把极性反过来
这里有个小问题,在刚上电的时候,电机会转动,这是硬件的问题,因为单片机在复位的时候,IO口默认高电平,所以电机会转
#include <REGX52.H>
#include " Delay.h"
#include " Key.h"
#include " Nixie.h"
#include " Timer0.h"
sbit Motor=P1^0;
unsigned char Counter,Compare;
unsigned char KeyNum,Speed;
void main()
{
Timer0_Init();
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(1,Speed);
}
}
void Timer0_Routine() interrupt 1
{
Key_Loop();
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter%=100;
if(Counter<Compare)
{
Motor=1;
}
else
{
Motor=0;
}
}
这样就实现本节课的代码啦,按下按键调节电机的速度并且显示出来。