单片机控制直流电机.docx
《单片机控制直流电机.docx》由会员分享,可在线阅读,更多相关《单片机控制直流电机.docx(33页珍藏版)》请在冰豆网上搜索。
单片机控制直流电机
单片机课程设计
单片机控制直流电动机
:
xxx
学号:
xxx
专业:
xxx
指导老师:
xxx
组号:
第xxx组
单片机控制直流电机
摘要
随着时代的进步和科技的发展,电机调速系统在工农业生产、交通运输以及日常伤害中起着越来越重要的作用、由于直流电机剧院良好的起、制动性能,宜与在广泛围平滑调速。
在轧钢机、矿井卷机,挖掘机、金属切削机床、金属切削机床、造纸机高层电梯等领域中得到广泛应用。
长期以来,由于直流调速系统的性能指标优于交流调速系统。
PWM控制技术就是以该结论为理论基础,使输出端得到一系列幅值相等而宽度不相等的脉冲,用这些脉冲来代替正弦波或其他所需要的波形。
按一定的规则对各种脉冲的宽度进行调制,既可改变逆变电路输出电压大小,也可以改变输出频率。
PWM控制技术及其控制简单、灵活和动态响应好的优点而成为电子技术最广泛应用的控制方式,也是人们研究的热点。
由于必须在工作期间改变直流电机的速度,直流电机的控制是一个较困难的问题。
直流电机高效运行的最常见方法是施加一个PWM(脉宽调制)方波,其占空比对应于所需速度。
电机起到一个低通滤波器作用,将PWM信号转换为有效直流电平。
特别是对于微处理器驱动的直流电机,由于PWM信号相对容易产生,这种驱动方式使用的更为广泛。
设计要求
采用单片机设计一个控制直流电机并测量转速的装置。
单片机扩展有A/D转换芯片ADC0809和D/A转换芯片DAC0832。
(1)通过改变A/D输入端可变电阻来改变A/D的输入电压,D/A输入检测量大小,进而改变直流电机的转速。
(2)手动控制。
在键盘上设置两个按键—直流电动机加速键和直流电机减速键。
在手动状态下,每按一次键,电机的转速按照约定的速率改变。
(3)键盘列扫描(4 ⨯ 6)。
实验原理
与步进电机类似,直流电机也可精确地控制旋转速度或转矩。
直流电机是通过两个磁场的互作用产生旋转。
其结构如下页图所示,固定部分(定子)上,装设了一对直流励磁的静止的主磁极N和S,在旋转部分(转子)上装设电枢铁心。
定子与转子之间有一气隙。
在电枢铁心上放置了由A和X两根导体连成的电枢线圈,线圈的首端和末端分别连到两个圆弧形的铜片上,此铜片称为换向片。
直流电机的速度与施加的电压成正比,输出转矩则与电流成正比。
由于必须在工作期间改变直流电机的速度,直流电机的控制是一个较困难的问题。
直流电机高效运行的最常见方法是施加一个PWM(脉宽调制)方波,其占空比对应于所需速度。
电机起到一个低通滤波器作用,将PWM信号转换为有效直流电平。
特别是对于微处理器驱动的直流电机,由于PWM信号相对容易产生,这种驱动方式使用的更为广泛。
利用直流电机的速度与施加电压成正比的原理,通过滑动变阻器向ADC0809输入控制电压信号,经AD后,输入到AT89C51中,AT89C51将此信号转发给DAC0832,通过功放电路放大后,驱动直流电机。
设计方案
1.系统控制电路
采用STC89C52单片机由软件产生脉冲调制信号,来对直流电机进行控制。
2.电机控制电路
采用由三极管搭成的H型桥电路来控制电机的转动。
3.键盘电路
采用行式键盘实现电机转速的加速减速以及正反转的控制,在手动状态下,每按一次,其转速相应发生改变。
4.显示电路
采用LM016L对电机运动状态进行显示。
系统组成框图
系统总组成框图以STC89C52为主控芯片,采用桥式电路对直流电机驱动,如下所示:
硬件电路设计
1.键盘控制电路
按下DEC按钮,电机转速降低;按下INC按钮,电机转速增加。
2.单片机主控电路图
该部分电路主要由STC89C52主控芯片和晶振组成。
STC89C52芯片是低功耗8位CMOS微处理器,提供串口程序下载口。
它主要有以下几个特点:
256字节的RAM;4KB的ROM;32个通用I/O口线,为用户提供了丰富的I/O口资源;32个通用工作寄存器;2个定时器/计数器;具有6个中断源;4.0~5.5V的工作电压等。
晶振给单片机正常工作提供稳定的信号。
3.H型桥式电机驱动电路
H桥式电机驱动电路包括4个三极管和一个电机。
要使电机运转,只须导通对角线上的一对三极管。
在此设计中用到的完整的驱动电路如下:
主控程序
程序流程
总仿真电路图
程序清单
1.主程序
#include"AT89X51.h"
#include
#include
#include"led.h"
#include"uart.h"
#include"timer0.h"
#include"timer1.h"
#include"common.h"
#include"ADC0831.h"
#include"lcd1602.h"
#include"keyboard.h"
#include"ISR.h"
#include"DaType_Change.h"
#defineDcMotor_Direction_P
uChar8code*String1="DCMotorControl";
uChar8code*String2="pwm:
/100";
uChar8PWM_buff[3];
voidmain(void)
{
LCD_Init();
timer0_Init();
timer1_Init();
#ifdefDcMotor_Direction_P
Der1=0;
#elseDer1=1;
#endif
LED_Run_EN();
WrStrLCD(0,0,String1);
WrStrLCD(1,0,String2);
while
(1)
{
key_Process();//按键处理子程序
Char_To_Str(PWM_duty,&PWM_buff[0]);//液晶显示子程序
WrStrLCD(1,4,&PWM_buff[0]);
}
}
2.子程序
………………………………………………………………………………………………………………………………………………………
#include
unsignedcharvalue_converted=0x00;
unsignedcharvalue_AN6=0x00;
unsignedcharvalue_AN7=0x00;
bitend_of_convertion=0;
voidADC_Config(void)
{
ADCF=0xC0;
ADCLK=0x06;
ADCON=0x20;
EA=1;
EADC=1;
while
(1)
{
ADCON&=~0x07;
ADCON|=0x06;
ADCON&=~0x40;
ADCON|=0x08;
while(!
end_of_convertion);
end_of_convertion=0;
value_AN6=value_converted;
ADCON&=~0x07;
ADCON|=0x07;
ADCON&=~0x40;
ADCON|=0x08;
while(!
end_of_convertion);
end_of_convertion=0;
value_AN7=value_converted;
}
}
voidit_Adc(void)interrupt8
{
ADCON&=~0x10;
value_converted=ADDH;
end_of_convertion=1;
}
……………………………………………………………………………………………………………………………………………………..
#include"adc0831.h"
voidADC_CLK(void)
{
adcclk=1;
_nop_();
adcclk=0;
_nop_();
}
uChar8Read_ADC(void)
{
uChar8i;
bittemp=ADC_Val^0;
adccs=0;
ADC_CLK();
while(adcdo);
for(i=0;i<8;i++)
{
ADC_CLK();
ADC_Val=(ADC_Val<<1)|adcdo;
}
adccs=1;
return(ADC_Val);
}
voidIntToStr(uInt16t,uChar8*str,uChar8n)
{
uChar8a[5];
chari,j;
a[0]=(t/10000)%10;//取得整数值到数组
a[1]=(t/1000)%10;
a[2]=(t/100)%10;
a[3]=(t/10)%10;
a[4]=(t/1)%10;
for(i=0;i<5;i++)//转成ASCII码
a[i]=a[i]+'0';
for(i=0;a[i]=='0'&&i<=3;i++);//计算空格(0)数量
for(j=5-n;j
{*str='';str++;}
for(;i<5;i++)
{*str=a[i];str++;}//加入有效的数字
*str='\0';
}
…………………………………………………………………………………………………………………………………………………......
#include"beep.h"
sbitbeep=P1^4;
voidBeepRing(void)
{
beep=0;
DelayMS(100);
beep=1;
DelayMS(100);
}
………………………………………………………………………………………………………………………………………………………
#include"DaType_Change.h"
voidChar_To_Str(uChar8Data,uChar8*str)
{
uChar8a[4];
uChar8i,j;
a[0]=(Data/100)%10;
a[1]=(Data/10)%10;
a[2]=(Data/1)%10;
for(i=0;i<3;i++)//转成ASCII码
a[i]=a[i]+'0';
for(i=0;a[i]=='0'&&i<3;i++);
for(j=0;j
{*str='';str++;}
for(;i<3;i++)
{*str=a[i];str++;}//加入有效的数字
*str='\0';
}
………………………………………………………………………………………………………………………………………………………
#include"delay.h"
voidDelayUS(uChar8ValUS)//精确延时,18uS+(ValUS-1)*8us
{
for(;ValUS>0;ValUS--)
{;}
}
staticvoidDelay1MS(void)
{
uChar8i=2,j=199;
do
{
while(--j);
}
while(--i);
}
voidDelayMS(uInt16ValMS)
{
uInt16uiVal;
for(uiVal=0;uiVal{
Delay1MS();
}
}
………………………………………………………………………………………………………………………………………………………
#include"DS18B20.h"
sbitDQ=P1^0;
voidSendDS18B20(uChar8SendDat)
{
uChar8i;
for(i=0;i<8;i++)
{
DQ=0;
_nop_();_nop_();_nop_();_nop_();//延时4us
if((SendDat&0x01)==0)
DQ=0;
else
DQ=1;
SendDat=SendDat>>1;
DelayUS(5);
DQ=1;
}
}
uChar8Init_DS18B20(void)
{
uChar8i;
DQ=0;
DelayUS(61);
DQ=1;
DelayUS(8);
for(i=0;i<100;i++)
{
if(DQ)
break;
}
DQ=1;
DelayUS(11);
return0xff;
}
uChar8ReceiveDS18B20(void)
{
uChar8tmp=0;
uChar8i;
for(i=0;i<8;i++)
{
tmp=tmp>>1;
DQ=0;
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
DQ=1;
DelayUS
(1);
if(DQ)
tmp|=0x80;
DQ=1;
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
}
return(tmp);
}
uInt16ReadDS18B20(void)
{
union{
uInt16Data;
uChar8tmp[2];
}temp;
temp.tmp[1]=ReceiveDS18B20();
temp.tmp[0]=ReceiveDS18B20();
return(temp.Data);
}
uInt16GetTemper(void)
{
uInt16Temper;
DQ=1;
Init_DS18B20();
SendDS18B20(0xcc);
SendDS18B20(0xbe);
Temper=ReadDS18B20();
return(Temper);
}
……………………………………………………………………………………………………………………………………………………...
#include"ISR.h"
uInt16ms_Counter;
uChar8ucCounter;
uInt16key_l;//按键低电平计数器
uChar8key_h;//按键高电平计数器
uChar8key;
uChar8kpush;
bitUpdate_ADC_Flag=0;
voidISR_Ext0(void)interrupt0
voidISR_timer0(void)interrupt1
{
TH0=(65535-1000)/255;
TL0=(65535-1000)%255;
if(ms_Counter==PWM_duty)
{
Der2=0;
}
ms_Counter++;
if(ms_Counter==PWM_cycle)
{
ms_Counter=0;
if(PWM_duty)Der2=1;
}
}
voidISR_timer1(void)interrupt3
{
TH1=0xFB;
TL1=0x1E;
if((P0&0x0C)==0x0C){
if((key_l>30)&&(key_l<800)&&(key_h>30))//释放按键,如果之前按键的时间<1s,读出键值
{key=kpush;}
if((++key_h)>200)key_h=0;//记录高电平时间
key_l=0;
if(key>0x80)key=0;
}
else
{
kpush=P0&0x0C;
key_l++;
if((key_l>800)&&(key_h>30))
{
key=kpush|0x80;
key_h=0;
key_l=0;
}
}
}
………………………………………………………………………………………………………………………………………………………
#include"keyboard.h"
#include"ISR.h"
#include"LED.h"
uChar8PWM_duty=50;
uChar8PWM_cycle=100;#include"keyboard.h"
#include"ISR.h"
#include"LED.h"
uChar8PWM_duty=50;
uChar8PWM_cycle=100;
//4*4矩阵式键盘扫描
uChar8Key_Scan(void)
{
uChar8code_h,code_l;
P3=0xF0;
if((P3&0xF0)!
=0xF0)
{
DelayMS
(1);
if((P3&0xF0)!
=0xF0)
{
code_h=0xFE;
while((P3&0xF8)!
=0xF0)
{
P3=code_h;
if((P3&0xF0)!
=0xF0)
{
code_l=(P3&0xF0|0x0F);
return((~code_h)+(~code_l));
}
elsecode_h=(code_h<<1)|0x01;
}
}
}
return(0);
}
//4*4矩阵式键盘译码
uChar8Get_Key_Val(uChar8key_temp)
{
switch(key_temp)
{
case0x14:
return1;
case0x24:
return2;
case0x44:
return3;
case0x12:
return4;
case0x22:
return5;
case0x42:
return6;
case0x11:
return7;
case0x21:
return8;
case0x41:
return9;
default:
return0;
}
}
//按键处理函数
voidkey_Process(void)
{
switch(key)
{
case0x08:
//KB1键按下
{
if(PWM_duty==100)PWM_duty=100;
elsePWM_duty++;
break;
}
case0x88:
//KB1键按下
{
if(PWM_duty==100)PWM_duty=100;
elseif(PWM_duty<=90)PWM_duty=PWM_duty+10;
break;
}
case0x04:
//KB2键按下
{
if(PWM_duty==0x00)PWM_duty=0x00;
elsePWM_duty--;
break;
}
case0x84:
//KB2键按下
{
if(PWM_duty==0x00)PWM_duty=0x00;
elseif(PWM_duty>=10)PWM_duty=PWM_duty-10;
break;
}
default:
break;
}
key=0x1C;
}
uChar8Key_Scan(void)
{
uChar8code_h,code_l;
P3=0xF0;
if((P3&0xF0)!
=0xF0)
{
DelayMS
(1);
if((P3&0xF0)!
=0xF0)
{
code_h=0xFE;
while((P3&0xF8)!
=0xF0)
{
P3=code_h;
if((P3&0xF0)!
=0xF0)
{
code_l=(P3&0xF0|0x0F);
return((~code_h)+(~code_l));
}
elsecode_h=(code_h<<1)|0x01;
}
}
}
return(0);
}
//4*4矩阵式键盘译码
uChar8Get_Key_Val(uChar8key_temp)
{
switch(key_temp)
{
case0x14:
return1;
case0x24:
return2;
case0x44:
return3;
case0x12:
return4;
case0x22:
return5;
case0x42:
return6;
case0x11:
return7;
case0x21:
return8;
case0x41:
return9;
default:
return0;
}
}
//按键处理函数
voidkey_Process(void)
{
switch(key)
{
case0x08:
//KB1键按下
{
if(PWM_duty==100)PWM_duty=100;
elsePWM_duty++;
break;
}
case0x88:
//KB1键按下
{
if(PWM_duty==100)PWM_duty=100;
elseif(PWM_duty<=90)PWM_duty=PWM_duty+10;
break;
}
case0x04:
//KB2键按下
{
if(PWM_duty==0