基于51单片机的直流电机控制
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
51 单片机的直
流电机控制
一、试验器件选择
1、控制芯片的作用主要是与L289相连接驱动直流电机,以及与八位数码管相连显
示。
(1)、AT89C51是一种带4K自己FLASH存储器的低压、高性能CMOS8为微处理器。
单片机的可擦除只读存储器可以反复擦除1000次。
该器件采用ATMEL高密度非易失真存储制造技术制造,与工业标准的MCS-51指令集和输出关键相兼容。
由于将多功能8位CPU和闪存组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器。
AT89C51单片机为很多嵌入式控制系统提供了一种灵活性奥高且廉价的方案。
(2)、AT89C51引脚图如下:
2、电机驱动芯片
(1)、电机驱动芯片选择L298。
其主要功能是作为单片机与直流电机中间的过度链接,单片机输出的信号通过L298加载到直流电机上驱动直流电机运行。
(2)、主要工作原理:
1、15脚分别是两个H 桥的电流反馈脚,不用时可以直接接地;
2、3为一对输出端口, 1
3、14为一对输出端口; 4为驱动电压输入,最小值必须比输入的低电平高 2; 5、7一对输入端口,10、12 —对输入端口,TTL 电平兼容 6、11使能端,低电平禁止输出; 8、9分别为接地和逻辑电源
3、直流电机。
在protues 中选择motor-encoder 直流电机,引脚图如下:
上方左右的两个引脚在点击运转时输出频 率相同的方波,但是在相位上相差 90
,而且
在正转和反转是相反,因此可以根据这两个引 脚的输出情况判断点击的转向。
上方中间的引
脚每当电机转一圈就输出一个正脉冲, 可以据此册数点击的转速。
左 右两个引脚是电机的电压输入端。
4、74HC74 。
当D 触发器的D 和CLK 输入端分别接电机上方的左右两个输出
其引脚图如下:
U2
13
VS
0UT1 0UT2
OUT3 VCC IN1
IN2 IN3 IN4 ENA ENB 10 12
77
0UT4
GND
L298
SENSA SENSB
端口时可以根据D触发器的输出情况判断点击的转速。
5、八位数码管。
用以显示。
二、系统硬件设计连接
1、系统的器件连接图如下:
2、单片机与数码管通过P0 口和P2 口相连,其中P2 口选择点亮哪一个数码管,P0 口则控制被点亮的数码管显示的数据。
3、单片通过P1A0和P1A1和L298的第一对输入端IN1和IN2相连,然后又
L298的第一对输出端OUT1和OUT2与直流电机相连,已达到控制直流电机的目的。
4、从PW4到P1A7分别接一个Button按钮来实现PID控制,P3A6和P3A7 分别接Button按钮实现对电机的加速与减速控制。
5、双刀双掷开关SW1课实现点击的正转与反转,单刀双掷开关SW2可实现点
击的开启与停止
三、系统程序设计及功能实现
1、程序流程图:
通过按钮加减 改变当前值,
差值,将差值加到原值上, 通过PID 算法改变PWM 波
2、各部分实现程序: #include <delay.h>
输入一个值,点击 Enter 按 钮,通过PID 算法,改变 PWM 波输出让电机运行
循环
(1)、普通延时:
Enter 键确定
判断新的输入值与当前值的
输出控制电机运行
______ __ _____ J
{
unsigned char i ; while(x--)
for(i = 0 ; i < 120 ; i++) ;
}
2) 、数码管显示: #include <reg51.h> #include <display.h> #include <delay.h>
void display_lilun(double num)
{
char code table[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7d, 0x07, //0~7 对应数
码
0x7f, 0x6f, 0x77, 0x7c, 0x39,
0x5e, 0x79, 0x71}; //8~F 对应数码
long int n=num;
P0 = 0; P2 =0x7f; P0 =
table[n % 1000/100]; table[n %
100
delayms(2);// 十位
P0 = 0; P2 =0xdf; table[n
%
delayms(2);// 个位
P0 = 0; 二 aa 示器 }
void display(double num,int dir)
{
char code table[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66,
0x6d, 0x7d, 0x07, //0~7 对应数
码
0x7f, 0x6f, 0x77, 0x7c, 0x39,
0x5e, 0x79, 0x71}; //8~F 对应数码
long int n=num*10;
P0 = 0; P2 =0xf7; P0 = table[n
/ 1000]; delayms(2); // 百位
delayms(2);// 百位加小数点
void delayms(unsigned char x) P0 0; P2 =0xbf; P0
/
10];
P0 = 10];
// 关闭显
加小数点
table[n % 1000/100];
delayms(2); // 百位加小数点
P0 = 0; P2 =0xfd; P0 = table[n %
100
/
10]+128;
delayms(2);// 十位
P0 = 0; P2 =0xfe; P0 = table[n%
10];
delayms(2);// 个位
示器
if(dir==1)
{
P0=0;P2=0xef;P0=0x40;delay ms(2); } }
义全局变量 void keyscan() // 对各
{
if(jiashi==0) {
while(!jiashi); num_key[0]++ }
// 定 if(jianshi==0)
P0 0; P2 =0xfb; P0
P0 = 0; // 关闭显
3) 、按键扫描: #include <reg51.h> sbit jiashi=P1A 3; 个按钮进行位定义 sbit jianshi=P1A4; sbit jia=P1A5; sbit jian=P1A6; sbit enter=P1A7; extern int num_key[5];
{
while(!jianshi);
num_key[1]++;
}
if(jia==0)
{
while(!jia);
num_key[2]++;
}
if(jian==0)
{
while(!jian);
num_key[3]++;
}
if(enter==0)
{
while(!enter);
num_key[4]++;
}
}
4) 、PWM 波输出:#include <reg51.h> #include <delay.h> #include <PWM.h>
extern int PWM ; // 赋初值extern int start,sudu_lilun;
extern double dis_count;
sbit S2 =P3A6 ; //PWM 值减少键
sbit S3 =P3A7 ; //PWM
值增加键
void PWM_duty()
{
if(start>=1)
PWM=sudu_lilun;
do
{
if(PWM!=0xff)
{
PWM++ ;
delayms(10);
}
}
while(S3==0);
delayms(10);
{
if(PWM>=0x02)
{
PWM-- ;
}
}
while(S2==0); }
5) 、中断服务程序:
#include <reg51.h>
extern int PWM,count,count1,dir,count20
ms_flag;
extern double dis_count;
sbit PWM_OUT1=P1A1;
sbit PWM_OUT2=P1A0;
void timer0() interrupt 1
{
TL0=0x00;
TH0=0xd8; //10ms
TL0=0xf0;
TH1=PWM ;
TR1=1 ;
PWM_OUT1=0 ; // 启动输出
PWM_OUT2=0;
if(i++==492)
{
count20ms_flag=1;
long int i;
i=0;
TR1=0 ;
dir=0;
do
dis_count=(double)(count+co unt1)/2;
count=0;
count1=0;
}
}
void timer1() interrupt 3
{
TR1=0 ;
if(dir==0)
{
PWM_OUT1=1 ; //
结
束输出
PWM_OUT2=0;
}
else
{
PWM_OUT1=0;
PWM_OUT2=1;
}
} {
EX0=0;
count++;
EX0=1;
}
void EIRQ1(void) interrupt 2 {
EX1=0;
count1++;
EX1=1;
}
6) ) 、PID 控制:
#include <PID.h>
#include <PWM.h>
int P,I,D;
extern int sudu_lilun; typedef struct PID // 定义结构体
{
int SetPoint; // 目标
long SumError; // 误差
void EIRQ0(void) interrupt 0
double Proportion; // 比例系
数
double Integral; // 积分系数int IncPIDCalc(int NextPoint)
double Derivative; // 微分系数int LastError;
int PrevError;
}PID;
static PID sPID;
static PID *sptr = &sPID;
void IncPIDInit()
{
sptr->SumError = 0;
sptr->LastError =0; //Error[-1] sptr->PrevError =0; //Error[-2] sptr->Proportion =0.5; // 比例系数
sptr->Integral =0.3; // 积分系数sptr->Derivative = 0.3; // 微分系
数
sptr->SetPoint =sudu_lilun;
} {
register int iError, iIncpid; // 当
前的误差值
iError = sptr->SetPoint - NextPoint; // 计算增加量
iIncpid = sptr->Proportion * iError //E[k] 项
- sptr->Integral * sptr->LastError //E[k -1]项
+ sptr->Derivative * sptr->PrevError; //E[k -2]项
// 存储当前误差以便后面计算
sptr->PrevError = sptr->LastError;
sptr->LastError = iError;
// 返回增量值
return(iIncpid);
}
#include <intrins.h>
#include <reg51.h> #include <key.h> 7) 、main 函数:
#include <delay.h>
#include <display.h>
#include <PWM.h>
#include <PID.h>
sbit P10=P1A2; 〃确定电机转
向
int num_key[5];
int
PWM,PWM1,count,count1,dir,su du_lilun,start,count20ms_flag; double dis_count;
int PWM_PID;
void init();
void main()
{
init();
while(1)
{
PWM_duty();
if(P10==1)
dir=0;
keyscan();
sudu_lilun=num_key[0]*10- num_key[1]*10+num_key[2]- num_key[3];
display_lilun(sudu_lilun);
if(num_key[4]==1)
start=1;
display(dis_count,dir);
if(start>=1&&count20ms_flag ==1)
{
count20ms_flag=0;
IncPIDInit();
PWM_PID=IncPIDCalc(dis_cou nt);
PWM=PWM+PWM_PID*2;
else
dir=1;
IT1=1;
}
void init()
器、外部中断初始化{
TMOD=0x01 ; TH0=0xd8;
TL0=0xf0;
IT0=1;
EX0=1;
EX1=1;
〃定时TH1=PWM ;
TL1=0xff ;
EA=1;
ET0=1;
ET1=1;
TR0=1 ;
}
3、程序实现效果:。