51单片机学习简难(共6篇)
在一片集成电路芯片上集成微处理器、存储器、I/O接口电路,从而构成了单芯片微型计算机,即单片机。Intel公司推出了MCS-51系列单片机:集成 8位CPU、4K字节ROM、128字节RAM、4个8位并口、1个全双工串行口、2个16位定时/计数器。寻址范围64K,并有控制功能较强的布尔处理器。
2、单片机的作用
用到单片机的项目经验介绍
手持粮库温度寻检设备
毕设答辩打分器
电话台灯
自动感应水龙头
凡是与控制或简单计算有关的电子设备都可以用单片机来实现,再根据具体实际情况选择不同性能的单片机,如:atmel,stc,pic,avr,凌阳,80C51,arm等
工业自动化:数据采集、测控技术。
智能仪器仪表:数字示波器、数字信号源、数字万用表、感应电流表等。
消费类电子产品:洗衣机、电冰箱、空调机、电视机、微波炉、手机、IC卡、汽车电子设备等。
通讯方面:调制解调器、程控交换技术、手机、小灵通等。
武器装备:飞机、军舰、坦克、导弹、航天飞机、鱼雷制导、智能武器等。
等等…..3、学习单片机之前预备知识
(1)数字电路中只有两种电平:高和低
定义单片机为TTL电平:
高 +5V低 0V
(2)RS232电平:计算机的串口
高-12V低+12V
所以计算机与单片机之间通讯时需要加电平转换芯片
(3)进制转换与逻辑、算术运算
(4)C语言基础
(5)80C51了解
80C51是MCS-51系列中的一个典型品种;其它厂商以8051为基核开发出的 CMOS工艺单片机产品统称为80C51系列。
(6)
总线(BUS)是计算机各部件之间传送信息的公共通道。微机中有内部总线和 外部总线两类。内部总线是CPU内部之间的连线。外部总线是指CPU与其它部件之间 的连线。外部总线有三种: 数据总线DB(DataBus), 地址总线AB(AddressBus)和控制总线 CBControlBus)。
(7)
CPU:由运算和控制逻辑组成,同时还包括中断系统和部分外部特殊功能寄存器; RAM:用以存放可以读写的数据,如运算的中间结果、最终结果以及欲显示的数据; ROM:用以存放程序、一些原始数据和表格;
I/O口:四个8位并行I/O口,既可用作输入,也可用作输出;
T/C:两个定时/记数器,既可以工作在定时模式,也可以工作在记数模式;
五个中断源的中断控制系统;
一个全双工UART(通用异步接收发送器)的串行I/O口,用于实现单片机之间或单片机与微机之间的串行通信;
片内振荡器和时钟产生电路,石英晶体和微调电容需要外接。最高振荡频率取决于单片机型号及性能。
(8)
C51数据存储类型
例:
数据类型变量名
charvar1;
bitflags;
unsigned charvextor[10];
intwwww;
注意:变量名不能用C语言中的关键字表示。
(9)
包含的头文件(可以在安装目录下INC目录下查看)
通常有:reg51.h reg52.h math.hctype.hstdio.hstdlib.habsacc.h
常用有:reg51.h reg52.h
(定义特殊功能寄存器和位寄存器);
math.h(定义常用数学运算);
(10)中断服务程序的格式
函数名()interrupt n using m
{
函数内部实现 ….}
(11)I/O口定义
sbit beep=P2^3;
(12)单片机的基本时序
机器周期和指令周期
(1)振荡周期: 也称时钟周期, 是指为单片机提供时钟脉冲信号的振荡源的 周期,TX实验板上为11.0592MHZ。
(2)状态周期: 每个状态周期为时钟周期的 2 倍, 是振荡周期经二分频后 得到的。
(3)机器周期: 一个机器周期包含 6 个状态周期S1~S6, 也就是 12 个时 钟周期。在一个机器周期内, CPU可以完成一个独立的操作。
(4)指令周期: 它是指CPU完成一条操作所需的全部时间。每条指令执行时间都是有一个或几个机器周期组成。MCS-51系统中, 有单周期指令、双周期指令和四周期指令。
4、学习单片机目标
最小系统能够运行起来的必要条件。
1.电源 2.晶振3.复位电路
对单片机任意IO口的随意操作
1.输出控制电平高低2.输入检测电平高低。定时器:重点掌握最常用的方式
1 硬件理解
电子技术有硬件、软件之分。单片机的硬件即指:从外形上看, 它也是一个集成块。但是, 单片机这种集成块实质上是一台微型电脑, 或者是一台微型计算机, 也可以称之为微型控制器, 就像同一个人学习不同的知识会有不同的技能一样, 使同一台单片机“学习 (输入) ”不同的软件程序, 它也能实现不同的功能, 这也就是单片机应用特别广泛的原因。对于一个不是单片机的普通集成块来说, 是不能输入软件程序的。
以40脚双列直插51系列单片机为例, 学习各引脚的作用或功能[1]。一是所有单片机都必须具有且实现任何功能都必须用到的引脚, 包括:供电电源引脚 (20脚和40脚) ;时钟引脚 (18脚和19脚) , 即在18、19脚之间接一个晶振 (一般为6MHz或12MHz) , 各脚对“地”再各接一个20PF的电容;复位引脚 (第9脚) 。所谓复位就是单片机内部所有的工作部件都回到规定的状态, 程序也复位到头一条上开始逐条运行, 复位电路[1]非常简单, 不再赘述。二是I/O口引脚。40脚51系列单片机共有P0、P1、P2、P3共4个I/O口, 每个I/O口都有8个引脚, 所以共有32个I/O引脚。所谓I/O口, 即单片机信号的输入/输出口, 比如用按键控制LED灯的亮和灭, 那么按键接在I/O口上就起输入信号的作用, LED灯也接在I/O口上, 但相应的I/O口就起输出信号的作用。每个I/O口都有8个引脚, 说明40脚双列直插封装的51系列单片机是8位单片机。实际上, 每个I/O口就对应单片机内部的一个存储器 (或寄存器) , 只不过每个存储器都是2进制8位数, 每位又引出一个脚而已。三是其它特殊功能引脚。如需要“定时”功能时, 就要用14、15脚, 需要“中断”功能时, 就用12、13脚。
2 编制软件
编制单片机的软件程序, 简称编程。软件程序是由编程人员编写的、单片机按照人的意图去工作的文字性的资料, 将这种资料拷进单片机后, 单片机才能按照这些资料的要求有规律的工作。编制软件是单片机应用的核心内容。当然, 在学习单片机之初, 不要总想把各种单片机及其编程方法学全、学完, 即使是所谓的单片机专家, 也不能达到这种状态。为了入门较快, 对于编程的学习方法, 应按以下步骤进行:
1) 软件基础。建议先用汇编语言编制软件程序。51系列单片机汇编语言共有111条指令, 看似难于记忆, 但初学时不要求全, 应深入理解几个简单概念, 这样对学习有较大帮助: (1) 2进制、16进制及其相互转换。所有的单片机 (包括电脑) 都是用2进制进行存储、计算数据的, 在程序中要用到16进制数, 所以要想编制软件, 必须先熟悉2进制、16进制及它们之间的相互换算方法; (2) “位”的概念。前面已经谈到51系列单片机是8位的单片机, 所谓8位即指51系列单片机内部都是8位的2进制数存储器 (寄存器) 。所谓编制软件程序, 实质上就是用文字性的资料编制8位存储器中的每1位反复存储数字1、0的过程; (3) 寻址方式。“址”即是存放2进制数据的存储器的编号地址, 这就如同宾馆设置的房间号。只不过单片机中存储器的地址号都是用2进制或16进制数字编号的, 这就需要在理解、编制程序时注意存储器的地址号和存储器中存储的数据的本质上的不同。所以, 寻址方式实际上就是向某个存储器存储数据或数字时, 寻找数据在几号存储器存放的方法。位寻址, 即存储或改变8位存储器其中的1位数字。
2) 入门捷径。数模电基础较好的人员可直接从网上下载一些现成的软件及相应的硬件电路, 直接进入第3步、第4步的实际应用过程 (先购买一个几十元钱的编程器) , 在制作产品的过程中, 激发自己的学习兴趣, 结合有关指令逐步理解所软件的意义及编制方法。练习越多, 理解越深。数模电基础较差的人员, 也可购买一些单片机类的实验器材及编程器 (网上很多) , 这些器材会给你很多现成的硬件电路及相应的软件, 利用这些器材练习、理解单片机产品的制作过程。
3) 努力方向。在理解了位、址、存储器等概念后, 就可以学习、编制常用的软件程序, 在此过程中, 要注意学习一般的单片机编程思想: (1) MOV指令使用最多, 也最简单, 从MOV指令开始学习编程; (2) 在编制软件程序, 实现单片机的某个功能时, 必须对控制该功能的寄存器进行初始化设置。如若要编制定时/计数器程序, 则需要对其工作方式寄存器TMOD和控制寄存器TCON进行设置, 亦即将这些8位寄存器中的某些“位”置“0”或置“1”, 通过这些设置才能确定是要实现定时功能, 还是要实现计数功能;是用定时/计数器T0, 还是用定时/计数器T1; (3) 熟练掌握常用子程序[2,3], 如代码转换类子程序、查表子程序、运算子程序等; (4) 逐渐掌握常用程序[1], 如数字I/O程序、定时/计数器程序、中断程序、键盘接口程序、A/D、D/A转换程序、I2C总线接口技术、液晶显示器接口程序[5]; (5) 掌握进行程序设计的思路和步骤[4]:分析题意;确定算法;绘制流程图;编写程序;上机调试;程序优化。
3 编程器的使用
现在的编程器一般都和电脑相连, 只要具备基本电脑知识都能很快掌握操作步骤。在用编程器烧写程序过程中, 一般分两步进行 (多数教材没有介绍[1,2,3,4]) :首先用Keil uvision2.0 (或Keil c51) 编译软件将编制好的汇编程序编译, 生成Hex文件。之后用RF-810[5]或Easy51proV2.0烧写软件 (有些教材称之为编程软件[5]) 将Hex文件下载 (烧写) 到单片机。对于这些软件的使用方法, 互联网上有教程, 有的教材上也有详细的介绍[5]。
4 单片机电路的制作及运行
编制、烧写单片机程序的最终目的是让单片机及其外围电路联合实现一定的功能, 这就要制作成固定的电路板电路。市面上的各种单片机实验板就是为初学者设计的电路板电路。数模电基础较好的单片机初学者可以自己动手制作电路板, 不必购买实验板。
现行很多教材及有关单片机学习的各种资料中, 把单片机的仿真练习、用单片机实验板练习等也作为单片机学习的步骤, 给初学者增加了负担, 造成了混乱。严格说来, 这些练习是为文章介绍的“四个步骤”服务的。建议初学者, 特别是电子技术基础较好者不要理会这些步骤。现在的单片机价格便宜、可以烧写数千次, 不必担心多次烧写造成单片机的损坏, 只要认准编制、烧写单片机程序的最终目的, 严格按照单片机的”四步学习法”进行学习和练习, 就能事半功倍, 提高学习效率。
参考文献
[1]匡忠辉, 任富民, 杨旭方.单片机原理及应用[M].北京:机械工业出版社, 2007:8-155.
[2]胡汉才.单片机原理极其接口技术[M].北京:清华大学出版社, 2004:126-166.
[3]胡辉, 李叶紫, 胡力平.单片机原理与应用[M].北京:中国水利水电出版社, 2007:79-96.
[4]马淑兰, 王菲, 李加升.单片机应用技术与实训[M].济南:山东科学技术出版社, 2008:73-94.
1、定时器中断
{TMOD=0X01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1;} void time()interrupt 1
{
TMOD=0X01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0++;
}
2、延时子程序
void delay(int z);
void delay(int z)
{
int x,y;
for(x=z;x>0;x--)
for(y=100;y>0;y--);
}
3、数码管显示数字表
[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77};
4、数码管位选兼&LED左至右
[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
显示子程序
4位数
void dispaly(ints);
{从
for(shu=9999;shu>0;shu--){{qian=shu/1000;bai=shu%1000/100;shi=shu%100/10;ge=shu%10;}for(i=0;i<278;i++)
}
{}} duan=1;P0=duanxuan[qian];duan=0;P0=0xff;wei=1;P0=0xef;wei=0;delay(1);duan=1;P0=duanxuan[bai];duan=0;P0=0xff;wei=1;P0=0xdf;wei=0;delay(1);duan=1;P0=duanxuan[shi];duan=0;P0=0xff;wei=1;P0=0xbf;wei=0;delay(1);duan=1;P0=duanxuan[ge];duan=0;P0=0xff;wei=1;P0=0x7f;wei=0;delay(1);
八位数
void display(long s)
{
for(shu=s;shu>0;shu--)
{
{qianwan=shu/10000000;baiwan=shu%10000000/1000000;shiwan=shu%1000000/100000;wan=shu%100000/10000;qian=shu%10000/1000;bai=shu%1000/100;shi=shu%100/10;ge=shu%10;}
for(i=0;i<10;i++){duan=1;P0=duanxuan[qianwan];duan=0;P0=0xff;wei=1;P0=0xfe;wei=0;delay(1);duan=1;P0=duanxuan[baiwan];duan=0;P0=0xff;wei=1;P0=0xfd;wei=0;delay(1);duan=1;P0=duanxuan[shiwan];duan=0;P0=0xff;wei=1;P0=0xfb;wei=0;delay(1);duan=1;P0=duanxuan[wan];duan=0;P0=0xff;wei=1;
为期一周的单片机实习已经结束了。通过此次实训,让我们掌握了单片机基本原理的基础、单片机的编程知识以及初步掌握单片机应用系统开发实用技术,了解“51”单片机精简开发板的焊接方法。同时培养我们理论与实践相结合的能力,提高分析问题和解决问题的能力,增强学生独立工作能力;培养了我们团结合作、共同探讨、共同前进的精神与严谨的科学作风。
此次实训主要有以下几个方面:
一、实训目的
1.了解“51”精简开发板的工作原理及其结构。2.了解复杂电子产品生产制造的全过程。
3.熟练掌握电子元器件的焊接方法及技巧,训练动手能力,培养工程实践概念。4.能运用51单片机进行简单的单片机应用系统的硬件设计。5.掌握单片机应用系统的硬件、软件调试方法
二、实验原理
流水灯实际上就是一个带有八个发光二极管的单片机最小应用系统,即为由发光二极管、晶振、复位、电源等电路和必要的硬件组成的单个单片机。
它的电气性能指标:输入电压:DC4.5~6V,典型值为5V。可用干电池组供电,也可用直流稳压电源供电。如图所示:
本流水灯实际上就是一个带有八个发光二极管的单片机最小应用系统,即为由发光二极管、晶振、复位、电源等电路和必要的硬件组成的单个单片机。
三、硬件组成
1、晶振电路部分
单片机系统正常工作的保证,如果振荡器不起振,系统将会不能工作;假如振荡器运行不规律,系统执行程序的时候就会出现时间上的误差,这在通信中会体现的很明显:电路将无法通信。他是由一个晶振和两个瓷片电容组成的,x1和x2分别接单片机的x1和x2,晶振的瓷片电容是没有正负的,注意两个瓷片电容相连的那端一定要接地。
2、复位端、复位电路
给单片机一个复位信号(一个一定时间的低电平)使程序从头开始执行;一般有两中复位方式:上电复位,在系统一上电时利用电容两端电压不能突变的原理给系统一个短时的低电平;手动复位,同过按钮接通低电平给系统复位,时如果手按着一直不放,系统将一直复位,不能正常。当要对晶体重置时,只要对此引脚电平提升至高电平并保持两个及其周期以上的时间便能完成系统重置的各项动作,使得内部特殊功能寄存器内容均被设成已知状态。
如图所示,只要按此开关就能完成LED和开关的重置。
3、发光二极管电路
LED发光二极管依次接P1口,利用共阳极接线,只要P1口由高电平变为低电平LED灯即点亮。
四、安装、焊接及调试 ⑴安装步骤
1.检查元器件的数量、质量和规格,详细阅读硬件说明部分,并将元件对号入座,对于有极性的元器件要注意安装方向,确保一次性焊接成功。
2.先焊接低矮、耐热的元件,比如电阻,再对高一些的元件进行焊接,比如芯片座、排阻等,以此类推,最后焊接高大的元件。⑵焊接部分
1.检查印刷电路裸板电源正负端、各相邻焊点是否短路。
2.检测元器件质量,电容、接插件是否短路,按键通断状态是否正确。3.集成电路一定焊接插座,确定好插座空间安装位置。4.焊接时特别要注意锡不能太多,否则易发生焊点短路。5.电烙铁焊接时间不要过长,以免烫坏焊点。⑶调试部分 1.硬件调试
拿到电路板后,首先要检查加工质量,并确保没有任何方面的错误,如短路和断路,尤其要避免电源短路;元器件在安装前要逐一检查,用万用表测其数值,看是否与所用相同;完成焊接后,应先空载上电(芯片座上不插芯片),并检查各引脚的电位是否正确。若一切正常,方可在断电的情况下将芯片插入,再次检查各引脚的电位及其逻辑关系。将万用表的探针放到单片机接电源的引脚上检测一下,看是否符合要求。
进行串口测试。接上单片机电源和串口线,打开电源开关,电源指示灯D0亮,使用STC89C系列单片机,其本身自带了一个测试程序,上电之后D1~D8便会两个两个的灯亮的闪烁。或者自己下载一个程序,如果串口正常,如不成功,就应该好好检查焊点及串口线。2.流水灯程序调试
将电路板串口连接电脑,把程序烧入STC89C52系统。用USB接口连接电脑,为单片机提供电源。电源接入口,程序开始运行。LED灯开始轮流闪烁,闪烁间隔大概为0.5S。点击复位电路,单片机复位,LED灯从第一盏灯开始又循环亮起。3.C语言程序 #include
1.接好电池盒,电源这是灯不亮。这些是因为电源插座存在虚焊现象,接触不良。遇到这种情况的时候应该及时检查和修复虚焊点。
2.出现不能正常下载程序。这是因为电路板电源没有正常接通或者下载线焊接组装有误、电池电压低、芯片MAX232不正常工作或管脚虚焊。应该去检查电源是否正常接通,并且更正正确。
3.下载程序不能正常完成流水灯功能。这是因为电池电压低或者发光二极管损坏或者管脚虚焊、电阻R1开路或管脚虚焊。解决这样的方法是更换电池或者修复焊点。
五、结论
通过这次实习让我们可以在实践中检验我们所学的单片机知识,更好的融会贯通,并在实践中发现问题,解决问题。这次设计的流水灯由于比较简单,遇到的问题都不是很困难,我们通过互相之间的交流、查阅书籍以及通过互联网所搜所需的资料都能够比较好的解决。
这次所调试的流水灯系统缺点是程序输入采用串口输入,烧入程序比较复杂。电路比较简单,所实现的功能只有流水灯,时间闪烁的控制需要修改程序才能实现。如果需要改进的,可以增加一个时间设置来设这流水灯的闪烁时间,或者通过流水灯排列的形状不同可以做成花样流水灯。
下图为本次实训结果展示图:
电路板焊接图
电路板实现流水灯图
单片机课程设计
题目:用51单片机实现电子时钟
院 部 物理与电子信息工程学院 专 业 名 称 电子信息科学与技术 班 级 1111 姓 名 杨庆月 学 号 2011111136 指 导 教 师 李刚
2013年12月09日
目录
摘要------------------------------1 1 单片机的相关知识------------1 1.1 单片机的简介--------------------1 1.2 单片机的特点--------------------1 1.3 89C52单片机的基本特点------------2 2 电子时钟--------------------3 2.1电子时钟的基本特点----------------3 2.2电子时钟的原理-------------------4 控制系统的硬件设计---------4 3.1单片机型号的选择-----------------4 3.2 lcd1602工作的原理---------------4 3.3 键盘电路的设计------------------6 3.4 复位电路设计-------------------------6
3.5 时钟电路设计-------------------7 3.6 整体电路原理图-----------------7 控制系统的软件的设计------8 4.1程序的设计----------------------8 4.2程序源代码----------------------8 5 仿真结果和实物图---------------19 5.1仿真结果------------------------------19 5.2实物图-19 6 总结--20
参考文献------------------------21
摘要:单片计算机即单片微型计算机。由 RAM ,ROM,CPU构成,定时,计数和多种接口于一体的微控制器。它体积小,成本低,功能强,广泛应用于智能产业和工业自动化上。而 51系列单片机是各单片机中最为典型和最有代表性的一种。这次课程设计通过对它的学习,应用,从而达到学习、设计、开发软、硬的能力。
本设计主要设计了一个基于 AT89C52单片机的电子时钟。并在 1602上显示相应的时间。并通过一个控制键用来实现时间的调节和是否进入省电模式的转换。
具有时钟和日历的功能,年限显示范围是2013-2099(可修改),且具有闰年自动修正功能
关键字:单片机;子时钟;键盘控制;LCD1602。单片机识的相关知识 1.1 单片机简介
MCS-51是 INTEL公司在成功推广的 MCS-48单片机基础上加以改进而成的 8位单片机。
这种单片机大约是上世纪 70年代末推出的,内部程序可重写的为 8751,外扩程序的是 8031,一次性生产,不可改变程序的是 8051。外形一般为 DIP40封装。不久又推出了增强型的 8052,其资源更加丰富。以后又采用 CHMOS技术推出了 80c51,耗电大大降低。到了 90年代,INTEL公司把精力放到更赚钱的计算机上,将 51单片机技术转让给了一此其它公司,如 ATMEL Philips等半导体制造公司,使 51系列单片机的市场份额不断扩大。
尽管十多年前就有人认为 51单片机会很快淘汰,但事实证明 51单片机经过不断的改进后,由于技术成熟,使用方便,至今在 8位单片机市场仍然拥有庞大的用户。特别是 MCS-51技术的 20年专利期限到期后,大量的兼容型号不断推出。从上世纪 90年代后期开始,美国 ATMEL公司在掌握快速擦写的存储器后,推出了 AT89C系列,此系列在中国获得了广泛的应用。
在此之前,由于可擦写的 8751价格昂贵,国内长时间采用 8031+27C64这样的外扩存程序储器方式。
51单片机最初只有 DIP40这种很古老的封装,后来推出了 CHMOS工艺的80C51后开始有了 PLCC44这种相对较小的方形封装。AT89C系列中开始有 20脚的 DIP20的精简型封装,这极大方便了在一些相对简单的单片机应用,缩小了 PCB的体积。20脚的有 AT89C1051、AT89C1051、AT89C1051,对应程序存储器分别为 1K、2K、4K。
标准的 51为 4K程序空间,128字节的 RAM,32条端口,5个中断,2个定时/计数器,12个时钟周期执行一条基本指令,最长的除法为 48个周期。52为 8K程序空间,256字节的 RAM,32条端口,6个中断,3个定时/计数器。AT89S51是可在板上直接下载程序的改进型号,并增加了看门狗功能,AT89C51只能在编程器下写入程序,所以经常会有人在 PCB上安装 IC插座,以便取下来编程更新程序。
AT的 51系列后来也推出了单周期的 51,但价格没什么优势,国内很少使用。最近几年宏晶在国内大量推广 STC51系列单片机,最近又推出不少所谓 1T的单
片机,价格较低
STC采用串口直接下载程序,写入程序很方便。
1.2 单片机的特点.单片机的存储器ROM 和RAM 时严格区分的。ROM 称为程序存储器,只存放 程序,固定常数,及数据表格。RAM 则为数据存储器,用作工作区及存放用户数 据。2.采用面向控制的指令系统。为满足控制需要,单片机有更强的逻辑控制能力,特别是单片机具有很强的位处理能力。.单片机的I/O 口通常时多功能的。由于单片机芯片上引脚数目有限,为了 解决实际引脚数和需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于 何种功能,可由指令来设置或由机器状态来区分。.单片机的外部扩展能力很强。在内部的各种功能部件不能满足应用的需求 时,均可在外部进行扩展,与许多通用的微机接口芯片兼容,给应用系统设计带 来了很大的方便。
1.3 89C52单片机介绍
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 口也可作为AT89C52 的一些特殊功能口,如下表所示: 口管脚备选功能
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)。电子时钟
2.1 电子时钟的基本特点
现在高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟、石英 钟、石英表都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要 经常调试,数字式电子钟用集成电路计时时,译码代替机械式传动,用用液晶显 示器代替指针显示进而显示时间,减小了计时误差,这种表具有时、分、秒显示 时间的功能,还可以进行时和分的校对,片选的灵活性好。
2.2 电子时钟的原理
该电子时钟由89C52,1602 液晶等构成,采用晶振电路作为驱动电路,由延时程序和循环程序达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天。而电路中有四个控制按键,一个是选择,一个进行加数,一个进行减数,还有一个保存。例如按下选择键,然后1602显示光标,此时可以用加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行调节,最后待日期时间调节好后,按下保存键,时钟开始计时。控制系统的硬件设计 3.1 单片机型号的选择
通过对51单片机的学习,认为STC89C52 是最理想的电子时钟开发芯片。STC89C52,最终认为89C52是一种带8K 字节闪烁可编程可擦除只读存储器的低电压,高性能CMOS8位微处理器,器件采用高密度非易失存储器制造技术制造,与工业标准的MCS-52指令集和输出引脚相兼容。还有一点重要原因,就是采用AT89C52时不能用开发板进行程序的下载,所以最终选用STC89C52进行设计。
3.2 1602 工作原理及显示电路
字符型LCD 通常有14 条引脚线或16 条引脚线的LCD,多出来的2 条线是背 光电源线VCC(15 脚)和地线GND(16 脚),其控制原理与14 脚的LCD 完全一样 1602液晶的基本的操作分为以下四种:
状态字读操作:输入RS=低、RW=高、EP=高; 输出:DB0~7 读出为状态字; 数据读出操作:输入RS=高、RW=高、EP=高; 输出:DB0~7 读出为数据; 指令写入操作:输入RS=低、RW=低、EP=上升沿; 输出:无; 数据写入操作:输入RS=高、RW=低、EP=上升沿; 输出:无。
如图 1602模块的引脚
LCD1602正面
LCD1602背面
1602与单片机连接图 3.3 键盘电路设计
本时钟采用四个按键控制,一个(实物图蓝色线24号引脚)是选择,一个进行加数(实物图紫色线25号引脚),一个进行减数(实物图灰色线26号引脚),还有一个保存(实物图白色线27号引脚)。例如按下选择键,然后1602显示光标,此时可以用加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行调节,最后待日期时间调节好后,按下保存键,时钟开始计时。
3.4 复位电路设计
单片机复位有上电复位和手动复位两种方式,上电复位是接通电源后利用RC充电来实现复位。手动复位是通过人为干预,强制系统复位。
连接至9号复位引脚
复位电路如图所示,可以实现上电复位和手动复位功能。
3.5 时钟电路设计
系统时钟源由内部时钟方式产生,时钟电路由12MH晶振和两个30PF瓷片电容组成,构成自激振荡,形成振荡源提供给单片机。电容可在5PF到30PF之间选择,电容的大小对振荡频率有微小影响,可起频率微调作用。
3.6整体电路原理图 控制系统的软件设计 4.1 程序设计
由于C 语言程序设计较汇编可读性强,可移植性,且可以大大降低编程的难 度和缩短开发周期,本系统程序采用c 语言设计。
4.2 程序源代码
#include
//包含单片机寄存器的头文件 #include
#define uchar unsigned char #define uint unsigned int
sbit RS=P2^0;
//寄存器选择位,将RS位定义为P2.0引脚 sbit RW=P2^1;
//读写选择位,将RW位定义为P2.1引脚 sbit E=P2^2;
//使能信号位,将E位定义为P2.2引脚 sbit BF=P0^7;
//忙碌标志位,将BF位定义为P0.7引脚
uchar code table[]=“2013-12-07 WEEK6”;
//初始化液晶显示 16 uchar code table1[]=“TIME: 19-27-50”;
//14
uchar count,s1num;char second,minute,hour,day,month,year,week;
sbit s1=P2^3;
//功能键
sbit s2=P2^4;
//加键 sbit s3=P2^5;
//减键
sbit s4=P2^6;
//保存并退出
/*
延时若干毫秒
*/ void delay(uchar n){ uchar i,a,b;for(i=0;i for(b=199;b>0;b--) for(a=1;a>0;a--);} /*********************************************** 函数功能:判断液晶模块的忙碌状态 返回值:result。result=1,忙碌;result=0,不忙 ************************************************/ uchar BusyTest(void){ bit result;RS=0;//根据规定,RS为低电平,RW为高电平时,可以读状态 RW=1;E=1; //E=1,才允许读写 _nop_(); //空操作 _nop_();_nop_();_nop_(); //空操作四个机器周期,给硬件反应时间 result=BF;//将忙碌标志电平赋给result E=0; //将E恢复低电平 return result;} /******************************************** 函数功能:写指令 入口参数:dictate *********************************************/ void WriteInstruction(uchar dictate){ while(BusyTest()==1); //如果忙就等待 RS=0;//根据规定,RS和R/W同时为低电平时,可以写入指令 RW=0;E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置“0” _nop_(); _nop_(); //空操作两个机器周期,给硬件反应时间 P0=dictate; //将数据送入P0口,即写入指令或地址 _nop_();_nop_();_nop_();_nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_();_nop_();_nop_();_nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /********************************************* 函数功能:写数据 入口参数:y(为字符常量)**********************************************/ void WriteData(uchar y){ while(BusyTest()==1);RS=1; //RS为高电平,RW为低电平时,可以写入数据 RW=0;E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置“0” P0=y;//将数据送入P0口,即将数据写入液晶模块 _nop_();_nop_();_nop_();_nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_();_nop_();_nop_();_nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 } /****************************************** 函数功能:对LCD的显示模式进行初始化设置 *******************************************/ void LcdInitiate(void){ uchar num; second=50;minute=27;hour=19;week=6;day=7;month=12;year=13;count=0;s1num=0;E=0;delay(15);//延时15ms,首次写指令时应给LCD一段较长的反应时间 WriteInstruction(0x38);//显示模式设置:16×2显示,//5×7点阵,8位数据接口 delay(5);//延时5ms?,给硬件一点反应时间 WriteInstruction(0x38);delay(5);WriteInstruction(0x38);//连续三次,确保初始化成功 delay(5);WriteInstruction(0x0c);//显示模式设置:显示开,无光标,//光标不闪烁 delay(5);WriteInstruction(0x06);//显示模式设置:光标右移,字符不移 delay(5);WriteInstruction(0x01);//清屏幕指令,将以前的显示内容清除 delay(5);WriteInstruction(0x80);for(num=0;num<16;num++)//让液晶显示日期 { WriteData(table[num]);delay(5);} WriteInstruction(0x80+0x40);for(num=0;num<14;num++)//让液晶显示时间 { WriteData(table1[num]);delay(5);} TMOD=0x01; //定时器中断初始化 TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1; ET0=1;TR0=1;} //-------写年月日---------------void write_nyr(uchar add,uchar date){ uchar i,j;i=date/10;j=date%10;WriteInstruction(0x80+add);WriteData(0x30+i);WriteData(0x30+j);} //--------写时分秒---------------void write_sfm(uchar add,uchar date){ uchar i,j;i=date/10;j=date%10;WriteInstruction(0x80+0x40+add);WriteData(0x30+i);WriteData(0x30+j);} //-------------写星期-------------void write_week(uchar add,uchar date){ WriteInstruction(0x80+add);WriteData(0x30+date);} //---------该年是否是闰年-------------bit leap_year(){ int leap;if((year%4==0&&year%100!=0)||year%400==0) leap=1; //是闰年 else leap=0; //非闰年 return leap;} //----------键盘扫描--------------------void keyscan(){ if(s1==0) //第一个键是否按下 { delay(5); if(s1==0) { while(!s1); s1num++; if(s1num>7) s1num=1; if(s1num==1) //第一个键被按一次 { TR0=0; WriteInstruction(0x80+0x40+13); WriteInstruction(0x0f); } if(s1num==2) { WriteInstruction(0x80+0x40+10); } if(s1num==3) { WriteInstruction(0x80+0x40+7); } if(s1num==4) { WriteInstruction(0x80+9); } if(s1num==5) { WriteInstruction(0x80+6); } if(s1num==6) { WriteInstruction(0x80+3); } if(s1num==7) { WriteInstruction(0x80+15); } } } if(s1num!=0) //如果功能键被按下 { if(s2==0)//第二个按下 { delay(5); if(s2==0) { while(!s2); if(s1num==1) //第一个键被按一次,秒钟加一 { second++; if(second==60) second=0; write_sfm(12,second); WriteInstruction(0x80+0x40+13); } if(s1num==2) //第一个键被按二次,分钟加一 { minute++; if(minute==60) minute=0; write_sfm(9,minute); WriteInstruction(0x80+0x40+10); } if(s1num==3) //第一个键被按三次,时钟加一 { hour++; if(hour==24) hour=0; write_sfm(6,hour); WriteInstruction(0x80+0x40+7); } if(s1num==4) //日期加一 { day++; if(day==32) day=1; write_nyr(8,day); WriteInstruction(0x80+9); } if(s1num==5) //月加一 { month++; if(month==13) month=1; write_nyr(5,month); WriteInstruction(0x80+6); } if(s1num==6) //年加一 { year++; if(year==99) year=0; write_nyr(2,year); WriteInstruction(0x80+3); } if(s1num==7) //星期加一 { week++; if(week==8) week=1; write_week(15,week); WriteInstruction(0x80+15); } } } if(s3==0) //第三个键被按下 { delay(5);if(s3==0){ while(!s3); if(s1num==1) //秒减一 { second--; if(second==-1) second=59; write_sfm(12,second); WriteInstruction(0x80+0x40+13); } if(s1num==2) //分减一 { minute--; if(minute==-1) minute=59; write_sfm(9,minute); WriteInstruction(0x80+0x40+10); } if(s1num==3) //时减一 { hour--; if(hour==-1) hour=23; write_sfm(6,hour); WriteInstruction(0x80+0x40+7);} if(s1num==4) //日减一 { day--; if(day==0) day=31; write_nyr(8,day); WriteInstruction(0x80+9);} if(s1num==5) //月减一 { month--; if(month==0) month=12; write_nyr(5,month); WriteInstruction(0x80+6);} if(s1num==6) //年减一 { year--; if(year==-1) year=99; write_nyr(2,year); WriteInstruction(0x80+3);} if(s1num==7) //日期减一 { week--; if(week==0) week=7; write_week(15,week); WriteInstruction(0x80+15); } } } if(s4==0) //保存并退出 { s1num=0; WriteInstruction(0x0c); TR0=1; } } } /****************************************** main function *******************************************/ void main(void){ uchar k=0;LcdInitiate(); //调用LCD初始化函数 while(1){ keyscan(); k=1;} } /***************************************** 函数功能:定时器T0的中断服务函数 ******************************************/ void timer0()interrupt 1 { count++;if(count==13){ count=0; second++; if(second==60) //秒计满60,秒归0,分+1 { second=0; minute++; if(minute==60)//分计满60,分归0,时+1 { minute=0; hour++; if(hour==24)//时计满24,时归0,星期+1,日+1 { hour=0; week++; day++; if(week==8) week=1;//星期计满7,星期归1 if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)//大月三十一天 { if(day==32) //大月天数计满31,日归1,月+1 { day=1; month++; } } if(month==4||month==6||month==9||month==11)//小月三十天 { if(day==31) { //小月天数计满30,日归1,月+1 day=1; month++; } } if(month==2) { if(leap_year()) { if(day==30)//闰年二月29天??计满,日归1,月+1 { day=1; month++; } } else { if(day==29)//非闰年二月28天 计满,日归1,月+1 { day=1; month++; } } } if(month==13)//月计满12,月归1,年+1 { month=1; year++; } if(year==99)//年计满99,年归0 { year=0; } write_nyr(2,year); } write_nyr(5,month); } write_nyr(8,day); write_week(15,week); } write_sfm(6,hour); } write_sfm(9,minute);} write_sfm(12,second);5 仿真结果和实物图 5.1 仿真结果 5.2 实物图 总结: 说句实话,这个时钟在硬件上没有什么太多的技术含量,只有一个单片机的最小系统和一个显示电路,其实它们可以结合在一起,但是为了以后的方便,我还是将它们设计了两个部分,方便以后最小系统的其他方面的应用。还有就是程序,这个时钟程序如果让我自己写的话那我肯定不能再规定时间内完成,所以还是靠外界力量的帮忙。也正是如此,我找到我学习单片机的弱点,那就是程序的编写,记得室友百度开玩笑说:“程序是单片机的灵魂”,想想当时很搞笑,但仔 细一想,那还真是个恰当的比喻,如果说单片机没有程序的输入,那么它不能完成任何事情。虽然本学期的单片机课程即将结束,但是我学习单片机的过程还没有结束,以后还是要在程序的编写上多多下工夫。 此次的电子时钟设计给我奠定了一个实践基础,我会在以后的学习、生活中磨练自己,使自己适应于以后的竞争。当遇到不会或是设计不出来的地方,我们就会在QQ 群里讨论或者是同学之间相互帮助。团结就是力量,无论在现在的学习中还是在以后的工作中,团结都是至关重要的,有了团结会有更多的理念、更多的思维、更多的情感。 参考文献 在各种单片机控制程序中,常用到定时程序,单片机定时一是用定时器中断,二是用软件延时。一般来讲,定时器中断作定时相对是较为精确的,这一方面提高定时精度的研究也有许多[1],当然,绝对精确是不存在的,在一般常规控制领域,很高精度意义上的精确也是没有必要的,能满足应用系统需求即可。因为单片机的中断源数量有限,所以软件延时方法也很常用。 在很多应用场合,延时精确到ms级已足够,但也有一些地方如串行扩展系统中的时序控制,需要精确到μs级,不论精确到哪一级,用汇编语言设计延时程序都是比较容易的[2],而用C语言设计则较难,所以我们提议用C语言设计应用系统时,采用C语言和汇编语言混合编程的方法,应用系统中的延时程序用汇编语言设计。 很多人认为,编写延时程序是一项很麻烦的任务,需要多次修改才能满足要求,之所以如此,是因为很多人编写延时程序时往往先写出一个粗略的框架,然后去计算程序的延时时间,不满足要求时再修改循环次数,如此反复,直到满足要求,可以说是“凑”出来的延时程序。这是一种无计划的随机设计方式,没有统一的计算方法,每设计一个延时程序都要反复测试多次。在这一方面虽有许多研究,但因为没有规范的计算方法,有时设计的延时程序误差很大[3]。在这里提出一种规范的计算方法,由要求的延时时间计算出延时程序的循环次数并保证误差最小。 2 汇编语言设计延时程序 2.1 使用的符号和基本公式 f0:单片机晶振频率; tm:单片机机器周期,tm=12/f0; dt:要求的延时时间; m:延时时间需要的机器周期数。 m=dt/tm=dtf0/12;(1) (1)式即延时计算的基本公式,在公式中,如果f0以MHz为单位,则dt以μs为单位。根据需要的延时时间dt计算出延时所需的机器周期数m后,设计延时时间为dt的延时程序就变成了设计延时m个机器周期的程序。 2.2 延时程序的一般形式 把延时程序分成短暂延时、中等延时和长延时3种,形式不同,计算方法也不相同。 (1)短暂延时程序:短暂延时程序的延时时间在几十μs以下,常用于时序控制,如I2C接口时序需要5μs的延时,1-WIRE器件温度传感器DS18B20需要15μs和60μs的延时,这种延时只使用NOP指令即可,一个NOP指令执行时间为一个机器周期。例如:对11.0592MHz的晶振,设计15μs的延时程序,根据(1)式,计算得所需机器周期数为: m=15*11.0592/12=13.824=14 因为调用延时程序时的一条LCALL或ACALL指令用2个机器周期,延时程序结束时的RET指令用1个机器周期,所以延时程序要用14-3=11个NOP指令,程序形式如下: Delay:NOP;共11个NOP指令 … NOP RET 60μs的延时程序可调用4次15μs的延时程序。这种看似很笨的方法其实是既简单又精确的方法,完全可以满足各种时序的要求。 (2)中等延时程序:中等延时程序是指可以用一个8位寄存器构造的一重循环实现的程序,一般形式为: delay:mov r7,#n;1个机器周期 dlp: NOP;k个NOP,k个机器周期 … NOP djnz r7,dlp;2个机器周期 ret 延时的机器周期数m为(下式最后加3是调用和返回指令的机器周期数): m=1+n(k+2)+3=4+n(k+2)(2) 在不加NOP指令时(k=0),(2)式变为: m=4+2n(3) 取n=255,由(3)式得最大延时的机器周期数为:514,对11.0592MHz的晶振,由(1)式得最大延时时间为:557.726μs。如果延时时间不超过557.726μs,根据(1)、(3)式由延时时间计算出n值即可。例如,对11.0592MHz的晶振需要延时480μs的延时程序,计算得所需机器周期数:m=442.368,n=220,误差为-0.3993μs。延时程序为: delay:mov r7,#220 djnz r7,$ ret 在内层循环中加若干条NOP指令可以很方便地扩展延时时间,例如加8条NOP指令(k=8),由(2)式得最大延时的机器周期数为:2554,对11.0592MHz的晶振,由(1)式得最大延时时间为:2771.27μs。当k≠0时,对给定的延时时间,先取n=255,由(1)、(2)式初步估算一个k值,将其进位取整,再将取整后的k代回(2)式重算n值,这样作的目的是在能保证延时时间的条件下尽可能减少内层循环的指令,从而减少误差。例如,对11.0592MHz的晶振需要延时约2000μs的延时程序,计算得所需机器周期数:m=1843.2,k=6,n=230,误差为+0.8681μs。延时程序为: delay:mov r7,#230 dlp:NOP;6个NOP … djnz r7,dlp ret (3)中延时程序:中延时程序是指用两个8位寄存器构造的两重循环实现的程序,一般形式为: delay:mov r7,#n1;1个机器周期 dlp1:mov r5,#n2;1个机器周期 dlp2:;加k个NOP NOP;1个机器周期 … NOP;1个机器周期 djnz r5,dlp2;2个机器周期 djnz r7,dlp1;2个机器周期 ret 延时的机器周期数m为: m=1+n1(1+n2(k+2)+2)+3=4+n1(3+n2(k+2))(4) 在不加NOP指令时(k=0),(4)式变为: m=4+n1(3+2n2)(5) 取n1=n2=255,由(5)式得最大延时的机器周期数为:130819,对11.0592MHz的晶振,由(1)式得最大延时时间为:141948μs。当k=0时,对给定的延时时间,先取n1=255,由(1)、(5)式初步估算一个n2值,将其进位取整,再将取整后的n2代回(5)式重算n1值,这样作的目的是在能保证延时时间的条件下尽可能减少内层循环的指令,从而减少误差。例如,对11.0592MHz的晶振需要延时约10ms的延时程序,计算得所需机器周期数:m=9216,n2=17,n1=249,误差为+1.0851μs。延时程序为: delay:mov r7,#249 dlp1:mov r5,#17 djnz r5,$ djnz r7,dlp1 ret 同样,在内层循环中加若干条NOP指令可以很方便地扩展延时时间,例如加8条NOP指令(k=8),由(4)式得最大延时的机器周期数为:651019,对11.0592MHz的晶振,由(1)式得最大延时时间为:706401μs。当k≠0时,对给定的延时时间,先取n1=n2=255,由(1)、(4)式初步估算一个k值,将其进位取整,再将取整后的k代回(2)式并取n1=255重新估算一个n2值,将其进位取整,再将取整后的k和n2代回(2)式重新计算n1,这样做的目的也是在能保证延时时间的条件下尽可能减少内层循环的指令,从而减少误差。例如,对11.0592MHz的晶振需要延时约500ms的延时程序,计算得所需机器周期数:m=460800,k=6,n2=226,n1=254,误差为-870.226μs。延时程序为: delay:mov r7,#254 dlp1:mov r5,#226 dlp2:NOP;6个NOP … djnz r5,dlp2 djnz r7,dlp1 ret 3 C51语言设计延时程序 直接用C51语言设计较准确的延时程序是比较困难的,人们提出的方法主要有软件仿真(4)和反汇编分析两种(5),其实这两种方法也都是无计划的随机设计方式,每设计一个延时程序要反复测试多次,严格地讲基本上不具备实用价值。实际上,C51语言可以非常方便地调用汇编语言程序,这样,在C51程序中用汇编语言设计延时程序即可。 3.1 C51程序中另一种短暂延时函数的设计 C51程序中的短暂延时除了调用汇编语言程序外,还有另一种更简单的方法,就是使用INTRINS.H头文件,这个文件主要包含了51单片机的空操作和循环移位等几条汇编指令的C语言调用接口。C51程序包含了INTRINS.H头文件后,可以用:_nop_();形式直接调用汇编语言的空操作指令,这样,C51程序中短暂延时函数形式为: delay() {_nop_(); … _nop_(); } 同汇编语言程序一样,调用此函数要执行一条LCALL和一条RET指令,它们占用3个机器周期,要考虑到延时时间内。 3.2 C51程序调用汇编语言程序 在C51中使用汇编语言有内嵌和调用两种方式(6),对延时程序来讲,C51程序调用汇编语言程序比较合适,既可以无参调用也可以有参调用,编程方法如下: (1)在工程中建立一个C程序文件(*.c)和一个汇编语言程序文件(*.asm); (2)在C程序文件中声明汇编语言函数为外部函数,例如声明以下两个延时函数,一个无参,一个有参: extern delay(),delay1(uchar,uchar); 在以后的程序中可随时调用这两个函数; (3)在汇编语言程序文件中用汇编语言设计两个延时函数: ;无参函数delay ?PR?delay SEGMENT CODE;放在代码段 PUBLIC delay;声明为公共函数 RSEG?PR?delay;函数放代码段任意位置 delay:mov r7,#200 d1:mov r6,#250 d2:nop nop djnz r6,d2 djnz r7,d1 ret ;有参函数delay1,特别注意:函数名前加下划线(_delay1),两个参数由r7和r5传递 ?PR?_delay1?DELAY1 SEGMENT CODE PUBLIC_delay1 RSEG?PR?_delay1?DELAY1 _delay1:mov a,r5;保存r5 dlp1:mov r5,a djnz r5,$ djnz r7,dlp1 ret end 4 结语 介绍的方法是非常规范、实用的计算方法,在设计各种单片机应用系统中都可以直接使用。如果延时时间很长,加NOP指令的二重循环仍不能胜任,可用三重循环实现,计算方法完全类似,不难导出。 参考文献 [1]蹇兴亮.单片机定时中断的精确定时编程方法种种[J].单片机与嵌入式系统应用,2004,(8):70-71. [2]沈舷.延时程序延时时间的精确计算[J].机械制造与自动化,2005,(6):152-153. [3]彭志刚.51系列单片机延时程序运行时间的计算[J].仪器仪表用户,2008,(5):102-103. [4]段向东,等.Keil C51程序设计中几种精确延时方法[J].单片机与嵌入式系统应用,2007,(12):33-35. [5]薛小玲,等.C8051F单片机C程序精确延时的方法[J].单片机与嵌入式系统应用,2008,(9):77-79.51系列单片机软件延时计算方法 篇6