资源描述
单片机创新设计报告
设计题目: 基于单片机的电机测速及显示
学 院: 机电工程学院
专 业: 测控技术与仪器
班级学号: 071
姓 名: 董新彬
同组人员: 李爽、朱浩波
指导教师: 王军 冯梅林
设计时间: 2023、10、10--2023、10、30
单片机简介 2
1.1单片机历史 2
1.2 AT89C51的重要特性 3
1.3管脚说明 4
1.4振荡器特性 7
1.5芯片擦除 7
二、硬件电路的设计 8
2.1 AT89C51下载器部分 8
2.2电机驱动部分 11
三、程序设计 16
3.1 下载器程序 16
3.2电机测速程序 24
四、总结 37
五、参考文献 38
单片机简介
单片机又称单片微控制器,它不是完毕某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。概括的讲:一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、为学习、应用和开发提供了便利条件。同时,学习使用单片机了解计算机原理与结构的最佳选择。
1.1单片机历史
1)第一阶段(1976-1978):单片机的控索阶段。以Intel公司的MCS – 48为代表。MCS – 48的推出是在工控领域的控索,参与这一控索的公司尚有Motorola 、Zilog等,都取得了满意的效果。这就是SCM的诞生年代,“单机片”一词即由此而来。
2)第二阶段(1978-1982)单片机的完善阶段。Intel公司在MCS – 48 基础上推出了完善的、典型的单片机系列MCS –51。它在以下几个方面奠定了典型的通用总线型单片机体系结构。
①完善的外部总线。MCS-51设立了经典的8位单片机的总线结构,涉及8位数据总线、16位地址总线、控制总线及具有很多机通信功能的串行通信接口。
②CPU外围功能单元的集中管理模式。
③体现工控特性的位地址空间及位操作方式。
④指令系统趋于丰富和完善,并且增长了许多突出控制功能的指令。
3)第三阶段(1982-1990):8位单片机的巩固发展及16位单片机的推出阶段,也是单片机向微控制器发展的阶段。Intel公司推出的MCS – 96系列单片机,将一些用于测控系统的模数转换器、程序运营监视器、脉宽调制器等纳入片中,体现了单片机的微控制器特性。随着MCS – 51系列的广应用,许多电气厂商竞相使用80C51为内核,将许多测控系统中使用的电路技术、接口技术、多通道A/D转换部件、可靠性技术等应用到单片机中,增强了外围电路路功能,强化了智能控制的特性。
4)第四阶段(1990—):微控制器的全面发展阶段。随着单片机在各个领域全面进一步地发展和应用,出现了高速、大寻址范围、强运算能力的8位/16位/32位通用型单片机,以及小型便宜的专用型单片机
1.2 AT89C51的重要特性
·与MCS-51 兼容
·4K字节可编程闪烁存储器
·寿命:1000写/擦循环
·数据保存时间:2023
·全静态工作:0Hz-24Hz
·三级程序存储器锁定
·128*8位内部RAM
·32可编程I/O线
·两个16位定期器/计数器
·5个中断源
·可编程串行通道
·低功耗的闲置和掉电模式
·片内振荡器和时钟电路
1.3管脚说明
VCC:供电电压。
GND:接地。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸取8TTL门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0可以用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接受输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接受。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接受,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它运用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接受高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接受输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
P3口也可作为AT89C51的一些特殊功能口,如下表所示:
P3.0 RXD(串行输入口)
P3.1 TXD(串行输出口)
P3.2 /INT0(外部中断0)
P3.3 /INT1(外部中断1)
P3.4 T0(记时器0外部输入)
P3.5 T1(记时器1外部输入)
P3.6 /WR(外部数据存储器写选通)
P3.7 /RD(外部数据存储器读选通)
P3口同时为闪烁编程和编程校验接受一些控制信号。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定期目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想严禁ALE的输出可在SFR8EH地址上置0。此时, ALE只有在执行MOVX,MOVC指令是ALE才起作用。此外,该引脚被略微拉高。假如微解决器在外部执行状态ALE严禁,置位无效。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
1.4振荡器特性
XTAL1和XTAL2分别为反向放大器的输入和输出。该反向放大器可以配置为片内振荡器。石晶振荡和陶瓷振荡均可采用。如采用外部时钟源驱动器件,XTAL2应不接。有余输入至内部时钟信号要通过一个二分频触发器,因此对外部时钟信号的脉宽无任何规定,但必须保证脉冲的高低电平规定的宽度。
1.5芯片擦除
整个PEROM阵列和三个锁定位的电擦除可通过对的的控制信号组合,并保持ALE管脚处在低电平10ms 来完毕。在芯片擦操作中,代码阵列全被写“1”且在任何非空存储字节被反复编程以前,该操作必须被执行。
此外,AT89C51设有稳态逻辑,可以在低到零频率的条件下静态逻辑,支持两种软件可选的掉电模式。在闲置模式下,CPU停止工作。但RAM,定期器,计数器,串口和中断系统仍在工作。在掉电模式下,保存RAM的内容并且冻结振荡器,严禁所用其他芯片功能,直到下一个硬件复位为止。
二、硬件电路的设计
2.1 AT89C51下载器部分
SP-51Pro(即Easy51pro)编程器可以烧录Atmel公司系列单片机芯片,具有性能稳定,烧录速度快,性价比高等优点。产品性能介绍如下:
⑴支持的芯片
支持目前最为经典和市场占有量最大的ATMEL公司生产的AT89C51、C52、C55和最新的S51、S52;AT89C1051、2051、4051等芯片。
⑵产品特点
1.使用串口通讯,芯片自动判别,编程过程中的擦除、烧写、校验各种操作完全由编程器上的监控芯片89C51控制,不受PC配置及其主频的影响,因此烧写成功率高可以达成100%,烧写速度不久并且烧写速度和微机的档次无关。
2.采用57600高速波特率进行数据传送,编程速度可以和一般并行编程器相媲美,经测试,烧写一片4K ROM的AT89C51仅需要9.5S,而读取和校验仅需要3.5S。
3.体积小巧,省去笨重的外接电源适配器,直接使用USB端口5V电源, 携带方便,非常初学者学习51单片机的规定。
4.软件界面和谐,菜单、工具栏、快捷键齐全,全中文操作,提供加密功能,可以保护您的创作产权。可以说是麻雀虽小,五脏俱全!
5.功能完善,具有编程、读取、校验、空检查、擦除、加密等系列功能;
6.40pin和20pin锁紧插座,所有器件所有以第一脚对齐,无附加跳线,对于DIP封装芯片无需任何适配器;
7.采用优质万用锁紧插座,和接触不良等问题彻底说再见,可烧写40脚单片机芯片和20脚单片机芯片
8.改善的烧写深度保证每一片C51系列芯片的反复烧写次数都能达成1000以上!内部数据至少保存2023。
9.由于采用了9针传口通讯,这样一来就不会再和打印机抢一个打印口,随时随地想烧就烧,让芯片编程成为一种快乐!
(3)硬件连接
1.通讯电缆与编程器连接好,
2.将串口插头插入电脑串口,
3.USB插头插入电脑任一个USB口,此时编程器上LED点亮,表白电源接通。
4.接着安装软件,本软件支持Win9x/me/2023/NT,标准Window操作界面。本软件属于绿色软件,不需要安装,直接把相关的软件拷贝到硬盘中,运营其中的Easy 51Pro 2_0程序即可。
⑷ 软件使用
程序启动后,会自动检测硬件及连接,状态框中显示“就绪”字样,表达编程器连接和设立均正常。否则请检查硬件连接和端口设立。
把单片机芯片对的地放到编程器的相应插座上,注意,芯片的缺口要朝向插座的把手方向。
芯片放好后,就可以对芯片进行读写操作了,读写操作按下面的环节进行:
1、程序运营,请先选择器件(点下选框)
2、用“打开文献”选择打开要编写的.HEX 和 .BIN 文献
3、用“保存文献”可以保存读出来的文献
4、用“擦除器件”擦除芯片
5、用“写器件”编程
6、用“读器件”读取芯片中的程序,加密的读不出来
7、用“校验数据”检查编程的对的与否
8、用“自动完毕”自动执行以上各环节
9、用“加密”选择加密的级数2.12电机驱动部分
2.2电机驱动部分
图4-3中所示为一个典型的直流电机控制电路。电路得名于“H桥驱动电路”是由于它的形状酷似字母H。4个三极管组成H的4条垂直腿,而电机就是H中的横杠(注意:图4.12及随后的两个图都只是示意图,而不是完整的电路图,其中三极管的驱动电路没有画出来)。
如图所示,H桥式电机驱动电路涉及4个三极管和一个电机。要使电机运转,必须导通对角线上的一对三极管。根据不同三极管对的导通情况,电流也许会从左至右或从右至左流过电机,从而控制电机的转向。
图4-3 H桥简易驱动电路
要使电机运转,必须使对角线上的一对三极管导通。例如,如图4-4所示,当Q1管和Q4管导通时,电流就从电源正极经Q1从左至右穿过电机,然后再经Q4回到电源负极。按图中电流箭头所示,该流向的电流将驱动电机顺时针转动。当三极管Q1和Q4导通时,电流将从左至右流过电机,从而驱动电机按特定方向转动(电机周边的箭头指示为顺时针方向)。
图4-4 H桥电路驱动电机顺时针转动
图4-5所示为另一对三极管Q2和Q3导通的情况,电流将从右至左流过电机。当三极管Q2和Q3导通时,电流将从右至左流过电机,从而驱动电机沿另一方向转动(电机周边的箭头表达为逆时针方向)。
图4-5 H桥驱动电机逆时针转动
驱动电机时,保证H桥上两个同侧的三极管不会同时导通非常重要。假如三极管Q1和Q2同时导通,那么电流就会从正极穿过两个三极管直接回到负极。此时,电路中除了三极管外没有其他任何负载,因此电路上的电流就也许达成最大值(该电流仅受电源性能限制),甚至烧坏三极管。基于上述因素,在实际驱动电路中通常要用硬件电路方便地控制三极管的开关。
图4-6 所示就是基于这种考虑的改善电路,它在基本H桥电路的基础上增长了4个与门和2个非门。4个与门同一个“使能”导通信号相接,这样,用这一个信号就能控制整个电路的开关。而2个非门通过提供一种方向输人,可以保证任何时候在H桥的同侧腿上都只有一个三极管能导通。(与本节前面的示意图同样,图4.15所示也不是一个完整的电路图,特别是图中与门和三极管直接连接是不能正常工作的。)
图4-6 具有使能控制和方向逻辑的H桥电路
采用以上方法,电机的运转就只需要用三个信号控制:两个方向信号和一个使能信号。假如DIR-L信号为0,DIR-R信号为1,并且使能信号是1,那么三极管Q1和Q4导通,电流从左至右流经电机(如图4.-7所示);假如DIR-L信号变为1,而DIR-R信号变为0,那么Q2和Q3将导通,电流则反向流过电机。
图4-7 使能信号与方向信号的使用
实际使用的时候,用分立元件制作H桥是很麻烦的,好在现在市面上有很多封装好的H桥集成电路,接上电源、电机和控制信号就可以使用了,在额定的电压和电流内使用非常方便可靠。比如常用的L293D、L298N、TA7257P、SN754410等。
三、程序设计
3.1 下载器程序
#include <E51Pro.h>
BYTE ComBuf[18];//串口通讯数据缓存,发送和接受都使用
UINT nAddress;//ROM中地址计数
UINT nTimeOut;//超时计数
ProWork pw;//编程器一般操作
void Delay_us(BYTE nUs)//微秒级延时<255us
{
TH0=0;
TL0=0;
TR0=1;
while(TL0<nUs)//运用T0做定期计数器,循环采样,直到达成定期值
{
}
TR0=0;
}void Delay_ms(UINT nMs)//豪秒级的延时<65535ms
{
UINT n=0;
TR0=1;
while(n<nMs)////运用T0做定期计数器,循环采样,直到达成定期值
{
TH0=0;
TL0=20;
while(TH0<4)
{
}
n++;
}
TR0=0;
}
BOOL WaitComm()//等待上位机的命令,18字节
{
BYTE n=0;
RI=0;
while(!RI){}//等待第一个字节
ComBuf[n]=SBUF;
RI=0;
n++;
for(n;n<=17;n++)
{
nTimeOut=0;
while(!RI)
{
nTimeOut++;
if(nTimeOut>10000)//后17个字节都有超时限制
return 0;
}
ComBuf[n]=SBUF;
RI=0;
}
return 1;
}
BOOL WaitResp()//等待上位机回应,1字节,有超时限制
{
nTimeOut=0;
RI=0;
while(!RI)
{
nTimeOut++;
if(nTimeOut>50000)
{
return 0;
}
}
RI=0;
ComBuf[0]=SBUF;
return 1;
}
BOOL WaitData()//写器件时等待上位机数据,18字节,有超时限制
{
BYTE n;
RI=0;
for(n=0;n<=17;n++)
{
nTimeOut=0;
while(!RI)
{
nTimeOut++;
if(nTimeOut>10000)
{
return 0;
}
}
RI=0;
ComBuf[n]=SBUF;
}
return 1;
}
void SendData()//发送数据或回应操作完毕,18字节
{
BYTE n=0;
for(n;n<=17;n++)
{
TI=0;
SBUF=ComBuf[n];
while(!TI){}
TI=0;
}
}
void SendResp()//回应上位机1个字节,在写器件函数中使用
{
TI=0;
SBUF=ComBuf[0];
while(!TI){}
TI=0;
}
void SetVpp5V()//设立Vpp为5v
{
P3_4=0;
P3_3=0;
}
void SetVpp0V()//设立Vpp为0v
{
P3_3=0;
P3_4=1;
}
void SetVpp12V()//设立Vpp为12v
{
P3_4=0;
P3_3=1;
}
void RstPro()//编程器复位
{
pw.fpProOver();//直接编程结束
SendData();//告知上位机,表达编程器就绪,可以直接用此函数由于协议号(ComBuf[0])还没被修改,下同
}
void ReadSign()//读特性字
{
pw.fpReadSign();
SendData();//告知上位机,送出读出器件特性字
}
void Erase()//擦除器件
{
pw.fpErase();
SendData();//告知上位机,擦除了器件
}
void Write()//写器件
{
BYTE n;
pw.fpInitPro();//编程前的准备工作
SendData();//回应上位机表达进入写器件状态,可以发来数据
while(1)
{
if(WaitData())//假如等待数据成功
{
if(ComBuf[0]==0x07)//判断是否继续写
{
for(n=2;n<=17;n++)//ComBuf[2~17]为待写入数据块
{
if(!pw.fpWrite(ComBuf[n]))//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数
{
pw.fpProOver();//犯错了就结束编程
ComBuf[0]=0xff;
SendResp();//回应上位机一个字节,表达写数据犯错了
WaitData();//等待上位机的回应后就结束
return;
}
nAddress++;//下一个单元
}
ComBuf[0]=1;//回应上位机一个字节,表达数据块顺利完毕,请求继续
SendResp();
}
else if(ComBuf[0]==0x00)//写器件结束
break;
else//也许是通讯犯错了
{
pw.fpProOver();
return;
}
}
else//等待数据失败
{
pw.fpProOver();
return;
}
}
pw.fpProOver();//编程结束后的工作
Delay_ms(50);//延时等待上位机写线程结束
ComBuf[0]=0;//告知上位机编程器进入就绪状态
SendData();
}
void Read()//读器件
{
BYTE n;
pw.fpInitPro();//先设立成编程状态
SendData();//回应上位机表达进入读状态
while(1)
{
if(WaitResp())//等待上位机回应1个字节
{
if(ComBuf[0]==0)//ComBuf[0]==0表达读结束
{
break;
}
else if(ComBuf[0]==0xff)//0xff表达重发
{
nAddress=nAddress-0x0010;
}
for(n=2;n<=17;n++)//ComBuf[2~17]保存读出的数据块
{
ComBuf[n]=pw.fpRead();//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数
nAddress++;//下一个单元
}
ComBuf[0]=6;//向上位机发送读出的数据块
SendData();
}
else
break;//等待回应失败
}
pw.fpProOver();//操作结束设立为运营状态
ComBuf[0]=0;//告知上位机编程器进入就绪状态
SendData();
}
void Lock()//写锁定位
{
pw.fpLock();
SendData();
}
所支持的FID,请在这里继续添加
extern void PreparePro00();//FID=00:AT89C51编程器
extern void PreparePro01();//FID=01:AT89C2051编程器
extern void PreparePro02();//FID=02:AT89S51编程器
void main()
{
SP=0x60;
SetVpp5V();//先初始化Vpp为5v
SCON=0x00;
TCON=0x00;
//PCON=0x00;//波特率*2
IE=0x00;
//TMOD: GATE|C/!T|M1|M0|GATE|C/!T|M1|M0
// 0 0 1 0 0 0 0 1
TMOD=0x21;//T0用于延时程序
TH1=0xff;
TL1=0xff;//波特率28800*2,注意PCON
//SCON: SM0|SM1|SM2|REN|TB8|RB8|TI|RI
// 0 1 0 1 0 0 0 0
SCON=0x50;
TR1=1;
Delay_ms(1000);//延时1秒后编程器自举
ComBuf[0]=0;
SendData();
while(1)//串口通讯采用查询方式
{
if(!WaitComm())//假如超时,通讯犯错
{
Delay_ms(500);
ComBuf[0]=0;//让编程器复位,使编程器就绪
}
switch(ComBuf[1])//根据FID设立(ProWork)pw中的函数指针
{
case 0://at89c51编程器
PreparePro00();
break;
case 1://at89c2051编程器
PreparePro01();
break;
case 2://at89s51编程器
PreparePro02();
break;
//case 3:支持新器件时,请继续向下添加
// break;
//case 4:
// break;
default:
ComBuf[0]=0xff;
ComBuf[1]=0xff;//表达无效的操作
break;
}
switch(ComBuf[0])//根据操作ID跳到不同的操作函数
{
case 0x00:
RstPro();//编程器复位
break;
case 0x01:
ReadSign();//读特性字
break;
case 0x02:
Erase();//擦除器件
break;
case 0x03:
Write();//写器件
break;
case 0x04:
Read();//读器件
break;
case 0x05:
Lock();//写锁定位
break;
default:
SendData();
break;
}
}
}
3.2电机测速程序
/*
LED.C
128×64 LED驱动程序头文献
*/
#ifndef LED_H_
#define LED_H_
#include<REG51.H>
//定义背光控制信号
sbit LED_BL=P1^4;
//点亮背光灯
void LEDLightOn();
//熄灭背光灯
void LEDLightOff();
//清屏
void LEDClear();
//初始化
void LEDInit();
//显示ASCⅡ码
void LEDPutChar(unsigned char c);
//显示字符串
void LEDPuts(unsigned char*s);
#endif //LED_H_
/*
LED.C
128×64 LED驱动程序
*/
#include <INTRINS.H>
#include <ABSACC.H>
//#include "LED.H"
//定义屏幕光标(取值0~63,光标自身不可见)
unsigned char LEDCursor;
int i,j;
/*
函数:LEDLightOn()
功能:点亮背光灯
*/
void LEDLightOn()
{
LED_BL = 1;
}
/*
函数:LEDLightOff()
功能:熄灭背光灯
*/
void LEDLightOff()
{
LED_BL = 0;
}
/*
函数:LEDGetBF()
功能:读出状态位BF
返回:
BF=1,表达忙,不可进行任何操作
BF=0,表达不忙,可以进行正常操作
*/
bit LEDGetBF()
{
unsigned char dat;
dat = XBYTE[0xD002]; //XBYTE的定义见<ABSACC.H>
return (bit)(dat & 0x80);
}
/*
函数:LEDWriteCmd()
功能:向LED发送命令
参数:
cmd:命令字,详见器件的数据手册
*/
void LEDWriteCmd(unsigned char cmd)
{
while ( LEDGetBF() );
XBYTE[0xD000] = cmd;
}
/*
函数:LEDWriteDat()
功能:向LED写入数据
参数:dat,要写入的数据
说明:目的地址由地址计数器AC隐含指定,写完后AC自动加1
*/
void LEDWriteDat(unsigned char dat)
{
while ( LEDGetBF() );
XBYTE[0xD001] = dat;
}
/*
函数:LEDReadDat()
功能:从LED读出数据
返回:读出的数据
*/
/*
unsigned char LEDReadDat()
{
volatile unsigned char dat;
while ( LEDGetBF() );
dat = XBYTE[0xD003];
dat = XBYTE[0xD003]; //需要连续执行两次才可以读出真正的数据
return dat;
}
*/
/*
函数:LEDSetAC()
功能:设立DDRAM(显示数据RAM)的AC(地址计数器)值
参数:
ac:地址计数器值,范围0~63
*/
void LEDSetAC(unsigned char ac)
{
ac &= 0x3F;
ac |= 0x80;
LEDWriteCmd(ac);
}
/*
函数:LEDClear()
功能:LED清屏,并使光标回到0
*/
void LEDClear()
{
LEDWriteCmd(0x01); //清屏命令
LEDCursor = 0;
}
/*
函数:LEDDelay()
功能:延时(t*100)个机器周期
*/
void LEDDelay(unsigned char t)
{
unsigned char n;
do
{
n = 49;
while ( --n != 0 );
} while ( --t != 0 );
}
/*
函数:LEDInit()
功能:LED初始化
*/
void LEDInit()
{
LEDWriteCmd(0x30); //设立基本指令集
LEDDelay(3);
LEDWriteCmd(0x30); //设立基本指令集(需要再执行一次)
LEDDelay(1);
LEDWriteCmd(0x0C); //启动显示
LEDDelay(3);
LEDClear(); //清屏
LEDDelay(250);
LEDWriteCmd(0x06); //设立进入点
LEDDelay(10);
}
/*
函数:LEDCheckAC()
功能:根据光标位置调整AC
*/
void LEDCheckAC()
{
switch ( LEDCursor )
{
case 16:
LEDSetAC(16);
break;
case 32:
LEDSetAC(8);
break;
case 48:
LEDSetAC(24);
break;
case 64:
LEDCursor = 0;
LEDSetAC(0);
break;
default:
break;
}
}
/*
函数:LEDPutChar()
功能:显示ASCII码
参数:
c为可显示的ASCII码(0x20~0x7F)
*/
void LEDPutChar(unsigned char c)
{
LEDWriteDat(c);
LEDCursor++;
LEDCheckAC();
}
/*
函数:LEDPutHZ()
功能:显示汉字
参数:
ch,cl:汉字编码
*/
void LEDPutHZ(unsigned char ch, unsigned char cl)
{
if ( LEDCursor & 0x01 )
{//显示汉字时,必须偶地址对准,即光标位置不能是奇数
LEDPutChar(' '); //额外输出一个空格
}
LEDWriteDat(ch);
LEDWriteDat(cl);
LEDCursor += 2;
LEDCheckAC();
}
/*
函数:LEDPuts()
功能:显示字符串
参数:
*s:要显示的字符串(可同时包含ASCII码和汉字)
*/
void LEDPuts(unsigned char *s)
{
unsigned char ch, cl;
for (;;)
{
ch = *s++;
if ( ch == '\0' ) break;
if ( ch < 0x80 )
{
LEDPutChar(ch);
}
else
{
cl = *s++;
LEDPutHZ(ch,cl);
}
}
}
/*
显示主程序
*/
//#include"LED.H"
#include<REG51.H>
//#include "DELAY.H" /* 包含延时函数的头部文献delay_us();delay_ms(); */
/*
函数:Delay()
延时1ms 65.53s
t>0时,延时(t*0.001)s
t=0时。延时65.53s
*/
/********************************************************/
unsigned char SD[4]={'1','2','3','4'};//速度设定
unsigned char FK[4]={'2','2','3','4'};//速度反馈
int D=0;//方向控制中间变量
unsigned int Pwm=0;//速度产生中间变量
unsigned int p=0;
unsigned int Value=0;
unsigned int Pwm_Value=0;
unsigned int m;
//unsigned int a,b,c,d;
sbit KEY1=P2^0;
sbit KEY2=P2^1;
sbit KEY3=P2^2;
sbit MotorA=P1^6;
sbit MotorB=P1^7;
bit SWTR;
bit SWTF;
unsigned int SWTV;
#define Pwm_MAX 255
void Delay(unsigned int T)
{
SWTV=T;
SWTR=1;
while(!SWTF);
SWTR=0;
SWTF=0;
}
void KEY()
{
if(KEY1==0)
{
Value=Value+1;
}
if(KEY2==0)
{
Value=Value-1;
}
if(Value>255) Value=255;
if(Value<0) Value=0;
if(KEY3==0)
{
if(D==0)
{
D=1;
}
else
{
D=0;
}
}
}
v
展开阅读全文