一、本表应当使用中文填写,字迹为黑色,文字应当打字或印刷,提交一式一份。
二、本表第①栏所填内容应当与该专利申请请求书中内容一致。其中,申请人应为第一署名申请人。如果该申请办理过著录项目变更手续,应当按照国家知识产权局批准变更后的内容填写。
三、本表第②、④栏中的方格供填表人选择使用,若有方格后所述情况的,应当在方格内作标记。
四、“发文序号”位于国家知识产权局发出的通知书地址栏下方。
五、发明专利申请人在提出实质审查请求时以及在收到国家知识产权局发出的发明专利申请进入实质审查阶段通知书之日起3个月内,可以对发明专利申请主动提出修改。实用新型或者外观设计专利申请人自申请日起2个月内,可以对实用新型或者外观设计专利申请主动提出修改。
六、本表第④栏,涉及核苷酸或者氨基酸序列的发明专利申请,对于未提交纸页序列表的申请,如果提交的计算机可读形式的序列表无法读取或者请求书中注明提交了序列表但是实际未提交,申请人补交序列表的,以向国家知识产权局提交符合规定的序列表之日为申请日。
七、本表第④栏,外观设计专利申请的图片或者照片的修改,申请人以图为单位进行补正。同时申请人在本表第③栏“文件中的位置”栏中填写图片或者照片的视图名称。
八、本表第⑤栏,委托专利代理机构的,应当由专利代理机构加盖公章。未委托专利代理机构的,申请人为个人的应当由本人签字或者盖章;申请人为单位的应当加盖单位公章;有多个申请人的由代表人签字或者盖章。
九、申请文件修改替换的格式要求:
对权利要求修改的应当提交相应的权利要求替换项,涉及权利要求引用关系时,则需要将相应权项一起替换。如果申请人需要删除部分权项,申请人应该提交整理后连续编号的部分权利要求书。
对说明书修改的应当提交相应的说明书替换段,不得增加和删除段号,仅只能对有修改部分段进行整段替换。如果要增加内容,则只能增加在某一段中;如果需要删除一个整段内容,应该保留该段号,并在此段号后注明:“此段删除”字样。段号以国家知识产权局回传的或公布/授权公告的说明书段号为准。
对说明书附图修改的应当以图为单位提交相应的替换附图。
对说明书摘要、摘要附图修改的应当提交相应的说明书摘要、摘要附图替换页。
同时,申请人应当在补正书第③栏中的“文件中的位置”中标明修改涉及的权项、段号、图、页。
第二篇:单片机实验指导书
MCS-51/MCS-52单片机实验教材
本章针对目前国内学生在MCS-51/MCS-52单片机实验课程中使用各种实验箱,这种实验箱做实验虽然快捷简单,但往往学生对电路的硬件连接没有亲手去做,诸如接口的设置,地址的分配印象不深,导致学生在软件设计中只能按照老师指定的端口地址进行编程,但为什么要按这样的端口地址编程,怎样做到硬软件设计有机结合,学生没有深刻理解。一旦出现故障,如何从硬件和软件上分析问题,排除故障,没有清晰的认识。为此,我们在实验中一改过去的传统做法,采用硬件电路的焊接搭建和软件的设计调试,下载,均由学生自己动手,使学生对硬件系统了如指掌,软件编程也就能得心应手,使学生作到了软硬兼施。
在实验方法上,采用控制领域最常用的键盘控制,直流电机和步进电机的调速控制,速度测量控制,跑马灯控制为主要内容。
在具体的实验方法和步骤上,采用先易后难,层层递进,搭积木式的累进方式,使学生能在老师的指导下,最后完成一个整体系统,整体实验过程是学生逐步提高分析问题和解决问题能力的过程。
1-1 MCS-51/MCS-52单片机的跑马灯的硬软件设计
1 MCS-51/MCS-52单片机跑马灯的硬件电路的设计。
图 1-1
如图1-1是一个利用51单片机设计的跑马灯电路,51单片机的第9引脚为复位电路,单片机上电之初,使用C-R充电过程使得第9脚保持10ms以上的高电位,使机器复位。复位开关K可使之做到随机复位。
51单片机的第18,19引脚为外接晶振,接一个12M的晶振,同51单片机内部电路配合,上电后产生12兆的晶振频率和1兆的机器周期频率。
因为89S52机片内含8K程序存储器,机器运行程序将下载其中,故89S51的引脚EA接电源VCC。
51单片机第32—39引脚为P0口,分别对应P0.7—P0.0,P0口外接10KΩ的上拉排阻。P0口的P0.0—P0.7与74HC573的D0—D7一一对应相连,74HC573的Q0—Q7为输出,分别经220Ω电阻后接于发光二极管(跑马灯)的D0—D7上。
74HC573为8位锁存器,其1脚为输出使能端,低电平有效。本电路将其接地,所以74HC573的8位Q端为直通输出。
74HC573的第11引脚LE为输入使能端,高电平有效。本电路中或非门的输出与其相连,而或非门的两个输入端分别连接于51机的和P2.7引脚上。将P0口的数据写入,74HC573的输入条件是在写入的瞬间必须使P2.7端为低电平,写入有效时,也同时为低电平。这就构成,74HC573(跑马灯)的写入地址为0X7FFF,此电路中的或非门在此时从低电平观点视为低与非门。
2 MCS-51/MCS-52单片机跑马灯的软件设计
/********************************************/
/* 51单片机学习板主程序,12MHz晶振 */
/********************************************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#include "scan_key.h"
#include "timer0srv.h"
#include "spd.h"
void Initial() //初始化函数
{
TMOD=0x11;
IT0 = 1; //键盘中断初始化
EX0 = 1;
PX0 = 0;
IT1 = 1; //直流电机转速计数初始化
EX1 = 1;
PX1 = 0;
ET1 = 1; //直流电机转速定时初始化
PT1 = 1;
TL1 = 0x00;
TH1 = 0x00;
TR1 = 1;
PT0 = 0; //步进电机调速和直流电机自动调速初始
ET0 = 1;
TL0 = 0x00;
TH0 = 0x00;
TR0 = 1;
EA = 1;
P1 = 0xf0;
DAC_ADDR = 0x7f;
}
void main()
{
unsigned char LEDval = 0x0f,i = 0,j=0;
unsigned int temp,step_delay=0;
Initial();
while(1)
{
P1 = 0xf0; //键盘初始化
/*/////// 跑马灯程序 ////////////////////////*/
for(i=1;i<10;i++)
{
for(temp=0;temp<256;temp+=i)
{
LED_ADDR = temp;
delay_nms(80);
}
}
for(i=0,j=0x01;i<10;)
{
LED_ADDR = j;
delay_nms(100);
j = j<<1;
if(j==0)
{
i++;
j++;
}
}
for(i=0,j=0x80;i<10;)
{
LED_ADDR = j;
delay_nms(60);
j = j>>1;
if(j==0)
{
i++;
j=0x80;
}
}
}
}
在以上的程序中:
#include <AT89X52.H>为51单片机中定义的特殊功能寄存器功能头文件。
#include <absacc.h>为C语言头文件。
#include "delay.h"为延时函数。
#include "scan_key.h"为键盘控制函数。
initial()函数为预置函数,为后续键盘控制程序,定时器中断程序,直流电机,步进电机驱动程序预置特殊功能寄存器。
在main()函数中先对变量temp进行加i计数,采用双重循环方式,第一遍i=1,temp计数,每次加1,计数范围从0——255,达到256归零。每计数一次,将结果送LED_ADDER。LED_ADDR地址定义为0X7FFF,即将temp结果经P0口送锁存器74HC573,然后经发光二极管显示。第二遍i=i+1=2,temp=temp+i,即temp每次加2,直到temp<256再对temp归零。这一循环过程直到i=9,在每次送LED_ADDER地址(P0口)显示后,调延时程序延时200ms左右,以便让学生看清楚显示过程。然后进入跑马灯左移位程序。先将j=1,LED_ADDR=j,delay_nms(100);j=j<<1,(左移一位)。再将LED_ADDR=j……直到j=0,再将j=1……这样循环左移10遍。再进入循环右移过程:先将j=0x80(即最左位置1), LED_ADDR=j;延时,j=j>>1(右移1位),LED_ADDR=j;直到j=0(右移8位后)再将经=0x80……如此循环10遍,再返回程序初始位置。
由于51机指令系统多数为单机器周期指令,运行速度是μs级,肉眼无法鉴别temp的计数过程,故在每次执行LED_ADDR=temp指令后,要调用延时函数delay_nms(80)使temp的值经P0口送74HC573锁存器后,保存显示在发光二极管400ms左右。
1-2.MCS-51/MCS-52单片机键盘控制及键号显示电路的软硬件设计。
1 MCS-51/MCS-52单片机键盘控制及键号显示电路的硬件设计。
图 1-2
51单片机键盘控制及键号数码显示硬件电路如图1-2,51单片机的P1口控制键盘,其中P1.0,P1.1,P1.2,P1.3为列线,P1.4,P1.5,P1.6,P1.7为行线。四根行线各接1只5.1K电阻,再与电源VCC(+5V)相连。四根行线同时也与74HC21(四输入与门)的输入端口相连,其输出端与51单片机的外中断0输入端P3.2相连。因为P1口通过指令设置为0xF0,即“11110000”,四列线均为“0”,如果没有键按下,则四个行线均为高电平。74HC21输出为高电平。当有任意一个键被按下,则如图1-2所示,则74HC21的四个输入端总有一个输入为低电平。此时的74HC21的功能为:只要有一个输入端为低电平,则其输出端为低电平。此下降沿触发51单片机的外中断0而引发中断服务(搜索中断键号),所以对键盘控制方式采用的是中断搜索方式。
键号的数码显示方式仍采用P0口输出给两片4511译码器,如图1-4。DC4511为四位BCD码输入,译码后产生7段数码管显示信号驱动数码管进行键号显示。
图1-44511的6脚,2脚,1脚,7脚为8421BCD码的输入端,引脚为输入使能端,低电平有效。B1为工作使能端,高电平有效。其控制功能见表1-1。
表1-1
当控制地址为0xBFFF时,(即P2状态为10111111),与配合,驱动74HC02至4511的第5脚LE端,打开4511的锁存器,键号的显示由P0口输出。见图1-2。P0口的P0.3,P0.2,P0.1,P0.0与4511-1的D、C、B、A相连,再经译码后驱动数码管Ⅰ,显示键号的个位。而P0的P0.7,P0.6,P0.5,P0.4与4511-2的D、C、B、A相连,经译码后驱动数码管Ⅱ,显示键盘号的十位数。
2 MCS-51/MCS/52单片机键盘控制及键号显示电路的软件设计。
键盘控制程序采用外中断的方式进入,即有人按下任意一个键,则外中断0启动,外中断0的中断服务程序主要采用两级循环程序嵌套的方式。键盘号码变量为一个无符号的8位nkeynumber。外循环中首先将P1.3设置为0,P1其它端口设置为1,再读入P1口状态,进入内循环程序。第一步测试P1.4是否为0,(见图1-2及扫描键盘子程序scan_key.h)。若是,则是0号键被按下,将键号0送nkeynumber,退出。若不是,则检查P1.5是否为0,若是,是4号键被按下,则将键号4送nkeynumber,退出。若不是,则检查P1.6是否为0………一直检查到P1.7。若没查到键号,则退出内循环,进入外循环,再将P1.2置0,P1其它端口置1,再读入P1口状态,又进入内循环,再分别查1,5,9,13号键。若是其中某键,则将键号送nkeynumber,若没查到键号,则退出内循环,进入外循环,将P1.1置0, P1其它端口置1,读入P1口状态,又进入内循环,再分别查2,6,10,14号键。若是其中某键,则将键号送nkeynumber,若没查到键号,则退出内循环,进入外循环,最后将P1.0置0,查找最后的四个键号。
当查找到键号后,对nkeynumber进行2-10进制数的处理,过程是:nkeynumber/10<<4,即取得nkeynumber除以10后取整再左移4位,由P1.7—P1.4输出键盘号码的十位给4511-Ⅱ,将nkeynumber%10取余数,即键盘号码的个位由P1.3—P1.0输出给4511-Ⅰ。键盘中断及控制,键号显示子程序如下:
/****************扫描矩阵键盘子程序scan_key.h******************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#ifndef _SCAN_KEY
#define _SCAN_KEY
#define SEG_ADDR XBYTE[0xbfff]
#define LED_ADDR XBYTE[0x7fff]
unsigned char nKeyNumber;
void int0() interrupt 0
{
int i,j;
int Pin1;
EX0 = 0;
delay_nms(20);
// if(P3_2==0)
// {
for(i=0;i<4;i++) //i代表行,j代表列,每列逐行扫描
{
P1=0xff&(~(0x01<<3-i));
Pin1=P1;
for(j=0;j<4;j++)
{
if(((Pin1>>(4+j))&0x01)==0)
{
nKeyNumber=i+j*4;
i = 4;
j = 4;
P1 = 0xf0;
SEG_ADDR = (nKeyNumber/10 <<4)+ nKeyNumber%10;
delay_nms(20);
EX0 = 1;
return;
}
}
}
// }
P1 = 0xf0;
EX0 = 1;
}
#endif
1-3 MCS-51/MCS/52单片机控制直流电机转速电路的软硬件设计。
1 MCS-51/MCS/52单片机控制直流电机转速电路的硬件设计。
如图1-5所示,将P0口的P0.0-P0.7与A/D转换器0832的D0-D7相连,单片机的待转换数据由P0口输出给8位D/A转换器0832的输入寄存器,写入地址为0xDFFF,即89S51的P2.5=0与同时为低,经74HC02反向后,则8位输入寄存器的输入使能端ILE为高,将D0—D7的8位转换数据送入0832寄存器,DAC0832内部两级寄存器接成直通状态,即0832的,,,XFER均接低电平,所以DAC0832的D/A转换器对输入的数据信号实时进行转换输出。输出端口为IOUT1和IOUT2。输出的模拟信号由两级运放LM324放大馈送至直流电机。LM324均由负极端口输入而正极端口接地,构成两极反向放大电路。故最终给电机的直流电流信号与DAC0832的输出端口的电流电压信号为同相信号,运算放大器的供电电压为±9V。
图 1-5
直流电机一端接LM324的输出,另一端接地。由于LM324用±9V供电,则LM324的输出电压则会以0V为中心点,对DAC0832的输出端的输出信号进行电流电压放大,使LM324的输出在+8V—-8V之间成比例地浮动,从而驱动直流电机以不同速度正转和反转。
2 MCS-51/MCS/52单片机控制直流电机转速电路的软件设计。
如下程序所示,用多分支语句SWITCH语句对不同按键下对0832数模转换器赋给不同的转换值。当键值变量nkeynumber的值为0时,给数模转换器0832赋值7F,其十进制值为127。经模数转换后,在LM324输出给直流电机的电压为0V,使得直流电机停转。同时,经步进电机控制端口赋值为SEG_ADDR=0x00,所以步进电机停转。
当键值变量nkeynumber的值为1时,给数模转换器0832的数值量为0x00,经模数转换LM324比例放大后,赋给直流电机电压为-8V,直流电机以反向最快速度转动,转速达到48转/S。
当键值变量nkeynumber的值为2时,给数模转换器0832的数值量为25,经模数转换LM324比例放大后,赋给直流电机电压为-6.8V,直流电机以39转/S左右反向转动。
键值由1逐步增加到6,数模转换值逐次递增至25,LM324输出电压,以每次递增1.3V左右。当键值为6时,赋给模数转换器的数值为127,此时LM324输出值为0V,直流电机停止转动。当键值nkeynumber=7时,模数转换赋值为150,经过模数转换器后由LM324比例放大输出电压为+1.2V,直流电机以2转/S左右的速度正向转动。
当键值变量nkeynumber的值为8时,给数模转换器0832的数值量为175,经模数转换LM324比例放大后,赋给直流电机电压为+2.5V,直流电机以10转/S正向转动。
当键值逐次增大,赋给数模转换器的数值以25的速度递增,LM324则以每次1.3V逐次递增。当键值变量nkeynumber的值为12时,LM324赋给直流电机电压为+8V,直流电机正向运动,速度为48转/S。
/***********************************/
/* 键盘中断及直流电机手动变速速控制*/
/**********************************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#ifndef _SCAN_KEY
#define _SCAN_KEY
#define SEG_ADDR XBYTE[0xbfff] //数码管地址
#define LED_ADDR XBYTE[0x7fff] //跑马灯地址
#define DAC_ADDR XBYTE[0xdfff] //直流电机地址
#define STEP_ADDR XBYTE[0xefff] //步进电机地址
unsigned char nKeyNumber;
void int0() interrupt 0
{
int i,j;
int Pin1;
EX0 = 0;
delay_nms(20);
for(i=0;i<4;i++) //i代表行,j代表列,每列逐行扫描
{
P1=0xff&(~(0x01<<3-i));
Pin1=P1;
for(j=0;j<4;j++)
{
if(((Pin1>>(4+j))&0x01)==0)
{
nKeyNumber=i+j*4;
i = 4;
j = 4;
P1 = 0xf0;
SEG_ADDR = nKeyNumber/10 + (nKeyNumber%10<<4);//交换键值位置并赋键值
//////////*根据键盘键值,调整直流电机转速*///////////////////////
switch(nKeyNumber)
{
case 0:
DAC_ADDR = 0x7f;
SEG_ADDR = 0x00;
break;
case 1:
DAC_ADDR = 0x00;
break;
case 2:
DAC_ADDR = 25;
break;
case 3:
DAC_ADDR = 50;
break;
case 4:
DAC_ADDR = 75;
break;
case 5:
DAC_ADDR = 100;
break;
case 6:
DAC_ADDR = 127;
break;
case 7:
DAC_ADDR = 150;
break;
case 8:
DAC_ADDR = 175;
break;
case 9:
DAC_ADDR = 200;
break;
case 10:
DAC_ADDR = 225;
break;
case 11:
DAC_ADDR = 240;
break;
case 12:
DAC_ADDR = 255;
break;
default:
break;
}
EX0 = 1;
return;
}
}
}
P1 = 0xf0;
EX0 = 1;
}
#endif
1-4 MCS-51/MCS-52单片机转速计数控制电路的软硬件设计
图 1-6
1 MCS-51/MCS-52单片机转速计数控制电路的硬件电路设计
如图1-6所示,由红外发射管D和红外接收管T组成的转速检测电路中,当D和T之间没有遮挡物时,红外光由D照向T,红外接收管T受光后饱和导通,A点电位为0.3V,经或非门输出高电平。P3.3端因高电平无中断触发;当转动轴上的叶片经过D-T之间划过瞬间,T管因叶片遮挡不受光而截止,A点呈高电平。在P3.3端口接收到一个由高电平至低电平的下降沿,导致外中断1被触发而引起中断请求。转动轴上的叶片每转动一周,划过D-T一次,红外光被遮一次而中断一次。如果在单位时间(秒)内D-T间被遮挡n次,则被中断n次,直流电机的转速便是n。
2 MCS-51/MCS-52单片机转速计数控制电路的软件设计
在头文件中设外中断1为0级中断,定时器1为1级中断,开外中断0,开定时器1中断,开定时器1。在直流电机测速程序中,ft为转轴转速次数变量,外中断1每中断一次,则对ft进行加1操作。
Pt为定时器1的中断次数,定时器1工作于方式1,即十六位计数。每中断一次pt+1,若中断15次,总时间为65535μs*15=983ms。外加每中断一次,所占用的时间,总时间约1秒钟。计时1秒后,先将转动圈数变量修正(因为用频率计检测后,51单片机所计转速与频率计计数略有误差,所以需要修正。)51单片机每秒测得转速为大于45转时,ft减4与频率计计数相当,51单片机每秒测得转速大于40转时,ft减3与频率计计数相当;当转速大于35转时,ft减2合适。修正后将ft的值送数码管显示。Ft清零后重新计数。
/******************************************/
/* 直流电机测速程序 */
/* pt:T1中断次数,ft:直流电机旋转圈数变量 */
/******************************************/
#include <AT89x52.h>
#include <absacc.h>
#include "delay.h"
#ifndef _SPD_H
#define _SPD_H
unsigned int pt=0;
unsigned char ft=0;
void int1( ) interrupt 2
{
ft = ft + 1;
}
void timer1_isr( ) interrupt 3
{
unsigned char pp;
if(pt>=15)
{
pt = 0;
if(ft!=0)
{
if(ft>45)
ft = ft - 4;
else if(ft>40)
ft = ft - 3;
else if(ft<35)
ft = ft - 3;
}
pp = ft/10 + (ft%10<<4);
SEG_ADDR = pp;
ft = 0;
}
else
pt=pt+1;
}
#endif
1-5 MCS-51/MCS-52单片机控制步进电机转速的硬软件设计
如图1-7所示,步进电机的驱动数码信号经P0.3,P0.2,P0.1,P0.0传送至HC573的D3,D2,D1,D0和D7,D6,D5,D4,传送到D7,D6,D5,D4的数码信号由HC573的Q7,Q6,Q5,Q4输出,再驱动四只发光二极管,显示驱动步进电机的数码及转速频率,而另外一路经过Q3,Q2,Q1,Q0传送至LM2003电流放大,LM2003的最大驱动电流可以达到0.5A。
图 1-7
1 MCS-51/MCS-52单片机控制步进电机转速的硬件电路设计
由LM2003去驱动步进电机正向或者反向转动。由于步进电机为感性负载,当驱动器LM2003输出端关断时,势必引起电机与LM2003D端口较大的反向电动势,危及LM2003输出端口的安全。因此电路中在LM2003与步进电机的输入端并接四只二极管D0,D1,D2,D3及四只4.7K的电阻,称之为续流二极管和续流电阻。当LM2003输出端口截止时,步进电机电感线圈产生的续流电动势大于+5.7V时,二极管导通,限制LM2003的输出端口电压不大于+5.7V,以确保LM2003输出端的安全。
2 MCS-51/MCS-52单片机控制步进电机转速和直流电机自动加速运转的软件设计
在步进电机运转速率的控制中,以T0为定时器,以变量loop_temp为计数基准,T0设置为工作方式1,即开中断ET0后,TH0,TL0进行16位计数,TF0每中断一次为65.5ms,将loop_temp+1,当(loop_temp+1)%5取余后loop_temp=0时,步进电机动作一次,即65.5ms*5=330ms=0.33s,步进电机步进一次。
另外,程序中设步进电机基数表达式为temp,初始值为0,每步进之前判断基数temp=(temp+1)%4,如果键号nkeynumber=13时:
若temp=2,则temp=(temp+1)%4为3,P0口输出为0x02;
若temp=1,则temp=(temp+1)%4为2,P0口输出为0x04;
若temp=0,则temp=(temp+1)%4为1,P0口输出为0x08;
若temp=3,则temp=(temp+1)%4为0,P0口输出为0x01;
如此周而复始的循环,在switch语句中,表达式temp在case中的值总是在0,1,2,3中循环,MCS51单片机P0口输出给步进电机的代码始终在0x01,0x02,0x04,0x08周而复始的循环,,驱动步进电机正向转动。
如果键号nkeynumber=14时,基数temp=(temp+1)%4分别为如下结果:
若temp=2,则temp=(temp+1)%4为3,P0口输出为0x06;
若temp=1,则temp=(temp+1)%4为2,P0口输出为0x0c;
若temp=0,则temp=(temp+1)%4为1,P0口输出为0x09;
若temp=3,则temp=(temp+1)%4为0,P0口输出为0x03;
在switch语句中,步进电机运转代码的地址为:STEP_ADDR的值在0x03,0x09,0x0c,0x06中循环。即MCS51单片机P0口输出给步进电机的代码则在0x03,0x09,0x0c,0x06周而复始的循环,,驱动步进电机反向转动。
要注意的是,nkeynumber为13和14时由于没有涉及更改直流电机的D/A转换值,D/A转换器0832内有输入寄存器,所以直流电机保持原转速不变,此时步进电机与直流电机同时转动。
当键号nkeynumber为15时,步进电机的转动速率及转动方向与键值键号nkeynumber为13或14时相同,但此时对直流电机驱动模数转换端口变量moto_val以每330ms增加1的速率变化。
moto_val=moto_val+1
如果直流电机此时正在正向运转,则会越转越快,直到moto_val的值为最大255,此时正向转速最高,达到48转/S左右。
因为moto_val为8位无符号数,当它达到最大值255后,若再加1,则moto_val=0,由1-3节直流电机转速控制硬软件分析所得,此时运放LM324的输出电压将由+8V突然跳转到-8V,此时直流电机将在正向最高速度运转下向反向最高速度跳转。(注:工业控制中较大功率电机的驱动中绝对不可用此方法)。
/*****************************************************/
/* 定时器0中断函数
/* loop_temp:T0中断次数,temp:步进电机的驱动值 */
/* motor_val:直流电机的驱动值 */
/*****************************************************/
#include <AT89X52.H>
#ifndef _TIMER0_SRV
#define _TIMER0_SRV
static unsigned char loop_temp = 0,temp = 0;
unsigned char motor_val = 0x00;
void timer0_srv() interrupt 1
{
TL0 = 0x00;
TH0 = 0x00;
loop_temp=(loop_temp+1)%5; //定时器0扩展4倍
if(loop_temp==0)
{
temp = (temp+1)%4; //步进电机四相
if(nKeyNumber==13)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x01;
break;
case 1:
STEP_ADDR = 0x02;
break;
case 2:
STEP_ADDR = 0x04;
break;
case 3:
STEP_ADDR = 0x08;
break;
}
}
else if(nKeyNumber==14)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x03;
break;
case 1:
STEP_ADDR = 0x09;
break;
case 2:
STEP_ADDR = 0x0c;
break;
case 3:
STEP_ADDR = 0x06;
break;
}
}
else if(nKeyNumber == 15)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x01;
break;
case 1:
STEP_ADDR = 0x02;
break;
case 2:
STEP_ADDR = 0x04;
break;
case 3:
STEP_ADDR = 0x08;
break;
}
motor_val = motor_val + 1;
DAC_ADDR = motor_val;
}
}
return;
}
#endif
/********************************************/
/* 51单片机学习板主程序,12MHz晶振 */
/********************************************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#include "scan_key.h"
#include "timer0srv.h"
#include "spd.h"
void Initial() //初始化函数
{
TMOD=0x11;
IT0 = 1; //键盘中断初始化
EX0 = 1;
PX0 = 0;
IT1 = 1; //直流电机转速计数初始化
EX1 = 1;
PX1 = 0;
ET1 = 1; //直流电机转速定时初始化
PT1 = 1;
TL1 = 0x00;
TH1 = 0x00;
TR1 = 1;
PT0 = 0; //步进电机调速和直流电机自动调速初始
ET0 = 1;
TL0 = 0x00;
TH0 = 0x00;
TR0 = 1;
EA = 1;
P1 = 0xf0;
DAC_ADDR = 0x7f;
}
void main()
{
unsigned char LEDval = 0x0f,i = 0,j=0;
unsigned int temp,step_delay=0;
Initial();
while(1)
{
P1 = 0xf0; //键盘初始化
/*/////// 跑马灯程序 ////////////////////////*/
for(i=1;i<10;i++)
{
for(temp=0;temp<256;temp+=i)
{
LED_ADDR = temp;
delay_nms(80);
}
}
for(i=0,j=0x01;i<10;)
{
LED_ADDR = j;
delay_nms(100);
j = j<<1;
if(j==0)
{
i++;
j++;
}
}
for(i=0,j=0x80;i<10;)
{
LED_ADDR = j;
delay_nms(60);
j = j>>1;
if(j==0)
{
i++;
j=0x80;
}
}
}
}
/****************扫描矩阵键盘子程序scan_key.h******************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#ifndef _SCAN_KEY
#define _SCAN_KEY
#define SEG_ADDR XBYTE[0xbfff]
#define LED_ADDR XBYTE[0x7fff]
unsigned char nKeyNumber;
void int0() interrupt 0
{
int i,j;
int Pin1;
EX0 = 0;
delay_nms(20);
// if(P3_2==0)
// {
for(i=0;i<4;i++) //i代表行,j代表列,每列逐行扫描
{
P1=0xff&(~(0x01<<3-i));
Pin1=P1;
for(j=0;j<4;j++)
{
if(((Pin1>>(4+j))&0x01)==0)
{
nKeyNumber=i+j*4;
i = 4;
j = 4;
P1 = 0xf0;
SEG_ADDR = (nKeyNumber/10 <<4)+ nKeyNumber%10;
delay_nms(20);
EX0 = 1;
return;
}
}
}
// }
P1 = 0xf0;
EX0 = 1;
}
#endif
/***********************************/
/* 键盘中断及直流电机手动变速速控制*/
/**********************************/
#include <AT89X52.H>
#include <absacc.h>
#include "delay.h"
#ifndef _SCAN_KEY
#define _SCAN_KEY
#define SEG_ADDR XBYTE[0xbfff] //数码管地址
#define LED_ADDR XBYTE[0x7fff] //跑马灯地址
#define DAC_ADDR XBYTE[0xdfff] //直流电机地址
#define STEP_ADDR XBYTE[0xefff] //步进电机地址
unsigned char nKeyNumber;
void int0() interrupt 0
{
int i,j;
int Pin1;
EX0 = 0;
delay_nms(20);
for(i=0;i<4;i++) //i代表行,j代表列,每列逐行扫描
{
P1=0xff&(~(0x01<<3-i));
Pin1=P1;
for(j=0;j<4;j++)
{
if(((Pin1>>(4+j))&0x01)==0)
{
nKeyNumber=i+j*4;
i = 4;
j = 4;
P1 = 0xf0;
SEG_ADDR = nKeyNumber/10 + (nKeyNumber%10<<4);//交换键值位置并赋键值
//////////*根据键盘键值,调整直流电机转速*///////////////////////
switch(nKeyNumber)
{
case 0:
DAC_ADDR = 0x7f;
SEG_ADDR = 0x00;
break;
case 1:
DAC_ADDR = 0x00;
break;
case 2:
DAC_ADDR = 25;
break;
case 3:
DAC_ADDR = 50;
break;
case 4:
DAC_ADDR = 75;
break;
case 5:
DAC_ADDR = 100;
break;
case 6:
DAC_ADDR = 127;
break;
case 7:
DAC_ADDR = 150;
break;
case 8:
DAC_ADDR = 175;
break;
case 9:
DAC_ADDR = 200;
break;
case 10:
DAC_ADDR = 225;
break;
case 11:
DAC_ADDR = 240;
break;
case 12:
DAC_ADDR = 255;
break;
default:
break;
}
EX0 = 1;
return;
}
}
}
P1 = 0xf0;
EX0 = 1;
}
#endif
/******************************************/
/* 直流电机测速程序 */
/* pt:T1中断次数,ft:直流电机旋转圈数变量 */
/******************************************/
#include <AT89x52.h>
#include <absacc.h>
#include "delay.h"
#ifndef _SPD_H
#define _SPD_H
unsigned int pt=0;
unsigned char ft=0;
void int1( ) interrupt 2
{
ft = ft + 1;
}
void timer1_isr( ) interrupt 3
{
unsigned char pp;
if(pt>=15)
{
pt = 0;
if(ft!=0)
{
if(ft>45)
ft = ft - 4;
else if(ft>40)
ft = ft - 3;
else if(ft<35)
ft = ft - 3;
}
pp = ft/10 + (ft%10<<4);
SEG_ADDR = pp;
ft = 0;
}
else
pt=pt+1;
}
#endif
/*****************************************************/
/* 定时器0中断函数
/* loop_temp:T0中断次数,temp:步进电机的驱动值 */
/* motor_val:直流电机的驱动值 */
/*****************************************************/
#include <AT89X52.H>
#ifndef _TIMER0_SRV
#define _TIMER0_SRV
static unsigned char loop_temp = 0,temp = 0;
unsigned char motor_val = 0x00;
void timer0_srv() interrupt 1
{
TL0 = 0x00;
TH0 = 0x00;
loop_temp=(loop_temp+1)%5; //定时器0扩展4倍
if(loop_temp==0)
{
temp = (temp+1)%4; //步进电机四相
if(nKeyNumber==13)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x01;
break;
case 1:
STEP_ADDR = 0x02;
break;
case 2:
STEP_ADDR = 0x04;
break;
case 3:
STEP_ADDR = 0x08;
break;
}
}
else if(nKeyNumber==14)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x03;
break;
case 1:
STEP_ADDR = 0x09;
break;
case 2:
STEP_ADDR = 0x0c;
break;
case 3:
STEP_ADDR = 0x06;
break;
}
}
else if(nKeyNumber == 15)
{
switch(temp)
{
case 0:
STEP_ADDR = 0x01;
break;
case 1:
STEP_ADDR = 0x02;
break;
case 2:
STEP_ADDR = 0x04;
break;
case 3:
STEP_ADDR = 0x08;
break;
}
motor_val = motor_val + 1;
DAC_ADDR = motor_val;
}
}
return;
}
#endif