一、实验项目:
基于51单片机的直流电动机转速控制系统设计
二、实验目的:
本系统设计的目的是通过实践操作掌握Proteus硬件仿真软件的使用技巧和Keil uvision程序开发的使用技巧,理解单片机应用系统软硬件开发的过程,掌握基本的I/0控制方法。
基本要求: 选择一款直流电动机,利用51单片机控制该直流电动机的转速,设置五个按键,分别能够实现对直流电动机的加速、减速、正转、反转、停止的操作,给出上述功能系统的硬件设计电路和软件设计程序。
三、实验原理:
在本实验中,我们使用AT89C51单片机来搭载电机驱动模块,按键BUTTON来进行控制的操作。其中,通过L298电机驱动模块来实现对直流电机MOTOR-DC的加速、减速、正转、反转、停止的操作。
1、直流电机:输出或输入为直流电能得旋转电机,能实现直流电能和机械能互相转换的电机。当它作电动机运行时是直流电动机,将电能转换为机械能;作发电机运行时是直流发电机,将机械能转换为电能。
2、直流电动机的方向控制:直流电机只有正负极,只需交换正负极就可以调节正反转。
直流电动机的转速控制:在负载变化不大的时候,加在直流电动机两端的电压大小与其速度近似成正比。
3、对于直流电动机的具体的转速的控制,在这里利用PWM技术,通过调节高电平在信号传输的占空比的大小来实现电压大小的控制,并通过对电压的大小的调控,转化为直流电动机的转速控制。
占空比:D为PWM信号的占空比:D=t1/T(即高电平持续时间比整个周期的值),则电动机的电枢组两端电压平均值U为:U = (t1/T)Us=DUs。
四、硬件电路图:
在实验结果中,利用Proteus软件在进行仿真时,由于只能显示静态的变化,因此给出具体的现象显示。
1.在实现正转的情况下,可以通过调节加速和减速按键来实现直流电机的速度的变化,并且可以看到直流电机的电压的占空比的值为负值,实现正转。在实现正转的时候,先按下停止的按键,可以发现直流电机的转速明显下降,实现了转速的调控。
2.在实现反转的情况下,可以通过调节加速和减速按键来实现直流电机的速度的变化,并且可以看到直流电机的电压的占空比的值为正值,实现反转。在实现反转的时候,先按下停止的按键,可以发现直流电机的转速明显下降,实现了转速的调控。
3.基于上面的电动机的正转、反转,通过停止按键,可以实现电动机的停止。
五、C语言代码:
#include <reg51.h> // 包含 8051 系列单片机头文件
#define uint unsigned int // 定义 uint 为无符号整数类型 unsigned int
#define uchar unsigned char // 定义 uchar 为无符号字符类型 unsigned char
sbit IN1=P1^0; // 定义 P1.0 管脚为 IN1
sbit IN2=P1^1; // 定义 P1.1 管脚为 IN2
sbit ENA=P1^2; // 定义 P1.2 管脚为 ENA
sbit k0=P2^0; //正转,并对每一个管脚进行命名
sbit k1=P2^1; //反转
sbit k2=P2^2; //加速
sbit k3=P2^3; //减速
sbit k4=P2^4; //停止
// Counter 用于计数器计数,Compare 用于控制电机的占空比
uchar Counter=0,Compare=0;
//延时函数,传入参数 n 表示延时的时间,使用 for 循环进行延时。
void delay(uint n)
{
uint i=0,j=0;
for(i=0;i<n;i++)
{
for(j=0;j<120;j++);
}
}
//定时器初始化函数,设置定时器模式为模式1,计时初值为 0x9CFF,开启定时器中断,开启总中断,启动定时器0
void Timer0_init() //100us
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
ET0=1; //使能定时器0中断
EA=1; //开启总中断
TR0=1; //启动定时器0
}
void main()
{ ENA=0;
IN1=0;
IN2=0; //一开始让电机停止
Timer0_init(); //初始化定时器
Compare=50; //初始占空比为 50%
while(1)
{ if(k0==0)//正转
{
delay(100); //延时 100 毫秒
while(!k0); //等待按键释放
ENA=1; //使能电机
IN1=1; //IN1 管脚为高电平
IN2=0; //IN2 管脚为低电平
}
else if(k1==0)//反转
{
delay(100);
while(!k1);
ENA=1;
IN1=0; //IN1 管脚为低电平
IN2=1; //IN2 管脚为高电平
}
else if(k2==0)//加速
{
delay(100);
while(!k2);
Compare=Compare+20; //占空比加 20%
}
else if(k3==0)//减速
{
delay(100);
while(!k3);
Compare=Compare-20; //占空比减 20%
}
if(k4==0)//停止
{
delay(100);
while(!k4);
ENA=0; //关闭电机使能
TR0=0; //关闭定时器
IN1=0; //IN1管脚为低电平
IN2=0; //IN2管脚为低电平
}
}
}
//定时器中断函数,每 100 微秒触发一次中断,更新计数器的值,根据计数器和占空比的大小关系控制 IN1 管脚的电平状态。当计数器小于占空比时,IN1 管脚为高电平,反之为低电平
void Timer0() interrupt 1
{
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++; //计数器自增
Counter%=100; //计数器取模,最大值为 99
if(Counter<Compare) //如果小于占空比,IN1 管脚为高电平
{
IN1=1;
}
else
{
IN1=0;
}
}
六、汇编语言代码:
PWMH DATA 30H ; 声明变量 PWMH,高电平脉冲的个数 ,存储在地址 30H
PWM DATA 31H ; 声明变量 PWM周期,存储在地址 31H
COUNTER DATA 32H ; 声明变量 COUNTER
TEMP DATA 33H ; 声明变量 TEMP
ORG 0000H
AJMP MAIN ; 跳转到 MAIN 标签
ORG 000BH
AJMP INTT0 ; 跳转到 INTT0 标签
ORG 0100H ; 设置程序代码的起始地址为 0100H
MAIN:
MOV SP,#60H ; 设置堆栈指针 SP 的初始值为 60H
MOV PWMH,#02H ; 将变量 PWMH 的值设置为 02H
MOV COUNTER,#01H ; 将变量 COUNTER 的值设置为 01H
MOV PWM,#15H ; 将变量 PWM 的值设置为 15H
MOV TMOD,#02H ; 将计时器模式寄存器 TMOD 的值设置为 02H,表示定时器 0 工作在方式 2(8 位自动重载)下
MOV TL0,#38H ; 将计时器 0 的低 8 位初值设置为 38H,表示计时器 0 的周期为 1ms
MOV TH0,#38H ; 将计时器 0 的高 8 位初值设置为 38H
SETB ET0 ; 使能定时器 0 中断
SETB EA ; 全局使能中断
SETB TR0 ; 启动定时器 0
KSCAN: ; 标签 KSCAN,用于轮询按键状态
JNB P2.2,K1CHECK ; 如果按键 K1 没有按下,则跳转到 K1CHECK
JNB P2.3,K2CHECK ; 如果按键 K2 没有按下,则跳转到 K2CHECK
JNB P2.1,K3CHECK ; 如果按键 K3 没有按下,则跳转到 K3CHECK
JNB P2.0,K4CHECK ; 如果按键 K4 没有按下,则跳转到 K4CHECK
JNB P2.4,K0CHECK ; 如果按键 K0 没有按下,则跳转到 K0CHECK
SJMP KSCAN ; 如果所有按键都没有按下,则继续轮询
K3CHECK: ; 标签 K3CHECK,用于检测按键 K3 是否按下
JB P2.1,K3HANDLE ; 如果按键 K3 没有按下,则跳转到 K3HANDLE
SJMP K3CHECK ; 如果按键 K3 没有按下,则继续检测
K3HANDLE: ; 标签 K3HANDLE,用于处理按键 K3 的按下
MOV P1, #01H ; 将 P1 端口的值设置为 01H,点亮 LED1
SJMP KSCAN ; 处理完成后,继续轮询
K4CHECK: ; 标签 K4CHECK,用于检测按键 K4 是否按下
JB P2.0,K4HANDLE ; 如果按键 K4 没有按下,则跳转到 K4HANDLE
SJMP K4CHECK ; 如果按键 K4 没有按下,则继续检测
K4HANDLE: ; 标签 K4HANDLE,用于处理按键 K4 的按下
MOV P1, #02H ; 将 P1 端口的值设置为 02H,点亮 LED2
SJMP KSCAN ; 处理完成后,继续轮询
K0CHECK: ; 标签 K0CHECK,用于检测按键 K0 是否按下
JB P2.4,K0HANDLE ; 如果按键 K0 没有按下,则跳转到 K0HANDLE
SJMP K0CHECK ; 如果按键 K0 没有按下,则继续检测
K0HANDLE: ; 标签 K0HANDLE,用于处理按键 K0 的按下
MOV P1, #03H ; 将 P1 端口的值设置为 03H,点亮 LED1 和 LED2
SJMP KSCAN ; 处理完成后,继续轮询
K1CHECK: ; 标签 K1CHECK,用于检测按键 K1 是否按下
JB P2.2,K1HANDLE ; 如果按键 K1 没有按下,则跳转到 K1HANDLE
SJMP K1CHECK ; 如果按键 K1 没有按下,则继续检测
K1HANDLE: ; 标签 K1HANDLE,用于处理按键 K1 的按下
MOV A,PWMH ; 将变量 PWMH 的值加载到累加器 A 中
CJNE A,PWM,K1H0 ; 如果累加器 A 的值等于变量 PWM 的值,则跳转到 K1H0
SJMP KSCAN ; 如果累加器 A 的值不等于变量 PWM 的值,则继续检测
K1H0: ; 标签 K1H0,用于处理按键 K1
MOV A,PWMH ; 将变量 PWMH 的值加载到累加器 A 中
INC A ; 将累加器 A 的值加 1
CJNE A,PWM,K1H1 ; 如果累加器 A 的值等于变量 PWM 的值,则跳转到 K1H1
CLR TR0 ; 停止定时器 0
SETB P2.7 ; 设置 P2.7 为高电平,关闭 PWM 输出
SJMP K1H2 ; 跳转到 K1H2 标签
K1H1: ; 标签 K1H1,用于处理按键 K1
CJNE A,#02H,K1H2 ; 如果累加器 A 的值不等于 02H,则跳转到 K1H2
SETB TR0 ; 启动定时器 0
K1H2: ; 标签 K1H2,用于更新 PWM 输出的占空比
INC PWMH ; 将变量 PWMH 的值加 1
SJMP KSCAN ; 处理完成后,继续轮询
K2CHECK: ; 标签 K2CHECK,用于检测按键 K2 是否按下
JB P2.3,K2HANDLE ; 如果按键 K2 没有按下,则跳转到 K2HANDLE
SJMP K2CHECK ; 如果按键 K2 没有按下,则继续检测
K2HANDLE: ; 标签 K2HANDLE,用于处理按键 K2 的按下
MOV A,PWMH ; 将变量 PWMH 的值加载到累加器 A 中
CJNE A,#01H,K2H0 ; 如果累加器 A 的值不等于 01H,则跳转到 K2H0
SJMP KSCAN ; 如果累加器 A 的值等于 01H,则继续检测
K2H0: ; 标签 K2H0,用于处理按键 K2
MOV A,PWMH ; 将变量 PWMH 的值加载到累加器 A 中
MOV TEMP,PWM ; 将变量 PWM 的值加载到变量 TEMP 中
DEC A ; 将累加器 A 的值减 1
CJNE A,#00H,K2H1 ; 如果累加器 A 的值不等于 00H,则跳转到 K2H1
MOV PWM,A ; 将累加器 A 的值存储到变量 PWM 中
MOV PWMH,#01H ; 将变量 PWMH 的值设置为 01H
CLR TR0 ; 停止定时器 0
SETB P2.7 ; 设置 P2.7 为高电平,关闭 PWM 输出
MOV TL0,#38H ; 将计时器 0 的低 8 位初值设置为 38H,表示计时器 0 的周期为 1ms
MOV TH0,#38H ; 将计时器 0 的高 8 位初值设置为 38H
SJMP K2H2 ; 跳转到 K2H2 标签
K2H1: ; 标签 K2H1,用于处理按键 K2
MOV PWM,TEMP ; 将变量 TEMP 的值存储到变量 PWM 中
MOV PWMH,#00H ; 将变量 PWMH 的值设置为 00H
K2H2: ; 标签 K2H2,用于更新 PWM 输出的占空比
SJMP KSCAN ; 处理完成后,继续轮询
INTT0: ; 标签 INTT0,用于处理定时器 0 中断
CPL P2.7 ; 反转 P2.7 的值,实现 PWM 输出的占空比控制
MOV TH0,#38H ; 重新加载计时器 0 的初值,以实现定时 1ms 的周期
INC COUNTER ; 将变量 COUNTER 的值加 1
CJNE COUNTER,#100,KSCAN ; 如果变量 COUNTER 的值不等于 100,则跳转到 KSCAN ,继续轮询按键状态
MOV COUNTER,#01H ; 如果变量 COUNTER 的值等于 100,则将其重置为 01H,并继续查询按键状态
RETI ; 返回中断结束
END ; 程序结束