单片机综合实验报告

单片机综合实验报告

题 目: 秒 表

班 级:

姓 名:

学 号:

指导老师:

时 间: 20xx-12-14

1、实验内容:

应用AT89C51的定时器设计一个3位的LED数码显示作为“秒表”:显示时间为00~99s,能显示到0.1秒。

二、实验电路及功能说明

设计了一个具有“开始计时/停止计时/计时清零”三功能合一体的按键K,由单片机的P3.7引出,初始时按下该键则秒表从0开始计时,再按一下则停止计时,第三次按则相当于复位,计数值清零,如此循环。

三、实验程序流程图:

单片机综合实验报告

4、实验结果分析

程序中设置定时器每0.1秒产生一次中断,即到0.1秒后第三位数码管加1,则计满10次后进位到秒的个位数码管加1,同理,秒的个位数码管计满后则秒的的十位数码管加1。直到三个数码管都显示999,再过0.1秒则数码管全部清零,重新开始计数。初始时按下键K则秒表从0开始计时,再按一下则停止计时,第三次按则相当于复位,计数值清零,如此循环。

5、心得体会

通过这次设计,让我进一步掌握了单片机的应用。包括定时器、按键的设置、中断子程序的写法以及数码管的显示。因为设计该秒表的时候,除了一个按键占用了一个I/O口,其它I/O口无需作逼得用途,所以在设计中我没有用锁存器来分时复用I/O口,而是直接将3位数码管接到了单片机的P0、P1、P2口上,但这样很浪费单片机的引脚资源,这种接法只是基于本设计,而如果是其它稍复杂一点的设计则不可用此接法。

六、程序清单

#include<reg51.h>

#define uchar unsigned char

#define uint unsigned int

#define ulint unsigned long int

sbit K=P3^7;

uchar i,Key;

ulint Second;

bit Key_State;

uchar DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

void DelayMS(uint ms)

{

uchar t;

while(ms--)

for(t=0;t<120;t++);

}

//处理按键程序

void Key_P()

{

if(Key_State==0)

{

Key=(Key+1)%3;

switch(Key)

{

case 1: EA=1;ET0=1;TR0=1;break;

case 2: EA=0;ET0=0;TR0=0;break;

case 0: P0=0x3f;

P1=0x3f;

P2=0x3f;

i=0;Second=0;

}

}

}

void main()

{

P0=0x3f;

P1=0x3f; //显示000

P2=0x3f;

i=0;

Second=0;

Key=0; //按键次数(取值0,1,2,3)

Key_State=1; //初始按键状态

TMOD=0x01; //定时器0方式1

TH0=(65536-50000)/256; //定时器0:50ms

TL0=(65536-50000)%256;

while(1)

{

if(Key_State!=K) //按键被按下

{

DelayMS(10);

Key_State=K;

Key_P();

}

}

}

void T0_() interrupt 1

{

TH0=(65536-50000)/256; //装初值

TL0=(65536-50000)%256;

if(++i==2) //0.1s定时到

{

i=0;

Second++;

P0=DSY_CODE[Second/100];

P2=DSY_CODE[Second%100/10];

P1=DSY_CODE[Second%10];

if(Second==1000)

{

P0=0x3f; //若没有此句,秒十位在计满数归0时会闪烁,求解???

Second=0;

}

}

}

 

第二篇:单片机综合实验报告格式

一、实验内容:

设计一个数字时钟,显示范围为00:00:00~23:59:59。通过5个开关进行控制,其中开关K1用于切换时间设置(调节时钟)和时钟运行(正常运行)状态;开关K2用于切换修改时、分、秒数值;开关K3用于使相应数值加1调节;开关K4用于减1调节;开关K5用于设定闹钟,闹钟同样可以设定初值,并且设定好后到时间通过实验箱音频放出一段乐曲作为闹铃。

选做增加项目:还可增加秒表功能(精确到0.01s)或年月日设定功能。电路:(只连粗实线部分)

二、实验电路及功能说明

数码LED显示器电路(不需接线)

电子音响电路

按键说明:

单片机综合实验报告格式

三、实验程序流程图:

本实验设计了基于单片机的多功能数字钟的总体方案,对装置软、硬件的设计作了详细研究,并进行了相应的软件和硬件调试。该数字钟采用AT89C51单片机作为核心控制芯片,完成整点报时、显示、定时功能。整个系统分为几个小的电路,分别实现各自的功能。晶振电路,12MHZ晶振和两个30pF电容构成并连谐振接到X1和X2口。复位电路,在RST复位输入引脚上接一10uF电容至VCC端,下接一个51K电阻到地。控制电路,4个按键控制,进行调时,定时,复位操作。显示电路,用6位7段数码管进行时,分,秒的显示。 装置中软件设计部分包括一个主程序、四个模块程序和二个子程序,各自执行自己的功能,完成定时,调时等设操作。本文从整体到部分详细介绍了数字钟的设计,在比较重要的部分进行了详细的论述,并且给出了程序框图及说明。

软件程序整个流程图如下:

四、实验结果分析

定时程序设计:

单片机的定时功能也是通过计数器的计数来实现的,此时的计数脉冲来自单片机的内部,即每个机器周期产生一个计数脉冲,也就是每经过1个机器周期的时间,计数器加1。如果MCS-51采用的12MHz晶体,则计数频率为1MHz,即每过1us的时间计数器加1。这样可以根据计数值计算出定时时间,也可以根据定时时间的要求计算出计数器的初值。MCS-51单片机的定时器/计数器具有4种工作方式,其控制字均在相应的特殊功能寄存器中,通过对特殊功能寄存器的编程,可以方便的选择定时器/计数器两种工作模式和4种工作方式。

定时器/计数器工作在方式0时,为13位的计数器,由TLX(X=0、1)的低5位和THX的高8位所构成。TLX低5位溢出则向THX进位,THX计数溢出则置位TCON中的溢出标志位TFX.

当定时器/计数器工作于方式1,为16位的计数器。本设计师单片机多功能定时器,所以MCS-51内部的定时器/计数器被选定为定时器工作模式,计数输入信号是内部时钟脉冲,每个机器周期产生一个脉冲使计数器增1。

实时时钟实现的基本方法:

时钟的最小计时单位是秒,但使用定时器的方式1,最大的定时时间也只能达到131ms。我们可把定时器的定时时间定为50ms。这样,计数溢出20次即可得到时钟的最小计时单位:秒。而计数20次可以用软件实现。

秒计时是采用中断方式进行溢出次数的累积,计满20次,即得到秒计时。从秒到分,从分到时是通过软件累加并进行比较的方法来实现的。要求每满1秒,则“秒”单元中的内容加1;“秒”单元满60,则“分”单元中的内容加1;“分”单元满60,则“时”单元中的内容加1;“时”单元满24,则将时、分、秒的内容全部清零。

实时时钟程序设计步骤:

(1)选择工作方式,计算初值;

(2)采用中断方式进行溢出次数累计;

(3)从秒——分——时的计时是通过累加和数值比较实现的;

(4)时钟显示缓冲区:时钟时间在方位数码管上进行显示,为此在内部RAM中要设置显示缓冲

区,共6个地址单元。显示缓冲区从左到右依次存放时、分、秒数值;

(5)主程序:主要进行定时器/计数器的初始化编程,然后反复调用显示子程序的方法等待中断

的到来;

(6)中断服务程序:进行计时操作;

(7)加1子程序:用于完成对时、分、秒的加操作,中断服务程序在秒、分、时加1时共有三种

条调用加1子程序,包括三项内容:合字、加1并进行十进制调整、分字。

程序说明:

在整个系统中,在单片机的30H、31H和32H中存储当前时间的小时、分钟和秒。由于要用数码管显示当前的时间,必须用到分字和合字,因此在33H、34H、35H、36H、37H和38H中存储当前时间的时十位、时个位、分十位、分个位、秒十位和秒个位,方便显示。

本设计有由四个轻触按键组成的小键盘,这些按键可以任意改变当前的状态。按功能移位键一次,表示当前要校对小时的十位;按第二次,表示当前校对的是小时的个位;按第三次,则表示校对的是分钟的十位;第四次,表示的校对的是分钟的个位。按下数字“+” 键和数字“-”键可在当前校对的数字上相应加上1或者减去1。

本设计采用查表方式,在程序里预先存储两个表格,即日常作息时间表和考试时间表,可以通过手动按键来选择所要执行的时间表。并且用红、绿发光二极管来区别当前所执行的时间表。系统开机后,按功能移位键就可以调整当前的时间,整个系统操作简单,功能明确。

显示数据时,先把要显示的数据送到数据缓冲区SBUF中,再从SBUF中显示。串行口缓冲寄存器SBUF器是可直接寻址的专用寄存器。在物理上,它对应着两个寄存器,一个发送寄存器,一个接收寄存器。CPU写SBUF,就是修改发送寄存器;读SBUF,就是读接收寄存器。接收器是双缓冲的,以避免在接收下一帧数据之前,CPU未能及时响应接收器的中断,没有把上一帧数据读走,而产生两帧数据重叠的问题。对于发送器,为了保持最大的传输速率,一般不需要双缓冲,因为发送时CPU是主动的,不会产生写重叠的问题。

五、心得体会

通过本次多功能数字钟设计实验,真正的感受到了理论联系实际的重要性,以及这之间莫大区别,到最后看着自己的结果心里还是感到很欣慰的。

首先摆在我们面前的是要先弄懂所要设计实验的原理,于是最开始我在网上查找了大量的相关的资料,再结合课本的内容以及充分利用了网络资源和在图书馆借了相关的书籍资料,在仔细分析了本次实验所要达到的目的之后,我初步确定了思路。接下来的是进一步的分析其原理, 最后则编写出本次实验的程序。

在这次多功能数字钟设计实验过程中,我留下了很深的印象。由于以前都没有接触过,开始编写程序时很费力,但到后来就好了。在每次的实验中,遇到问题,最好的办法就是问别人,因为每个人掌握情况不一样,不可能做到处处都懂,发挥群众的力量,复杂的事情就会变得很简单。这一点我深有体会,在很多时候,我遇到的困难或许别人之前就已遇到,向他们请教远比自己在那冥思苦想来得快。

经过这些天的学习我深刻的体会到实际与理论有很大的区别。在我们学习的过程中不仅考验了我们对知识的吸收和掌握,而且也考验了我们的细心和耐心。特别是在编写程序过程中,我深有体会。所以,这次的实验不仅仅学习了程序的编写,还掌握了Proteus的一些功能,同时还提高了我们的专业素质。

总之,进过两次的实验心得体会,我总结了以下几条:首先,多动手写程序、调试,只有自己亲自动手编写了,才会让你印象深刻,收益更大。其次, 善于向别人学习,在你解决一个问题后,你可能会发现别人有更简便的方法解决,这时就是你向别人学习的时候。

六、程序清单

#include"reg51.h" //晶振为6MHZ

#include"absacc.h"

#define uchar unsigned char

#define uint unsigned int

#define DATA XBYTE[0XFFDC] //段选

#define SEL XBYTE[0XFFDD] //位选

sbit P1_0 = P1^0;

sbit P1_1 = P1^1;

sbit P1_2 = P1^2;

sbit Speak = P1^3;

uchar code table[2][13]={{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xf7},

{0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0xf7}};

int count=0; //定时器计数,以记到1S

uchar sec=0; //秒

uchar hou=0; //小时

uchar min=0; //分

uchar flag=0; //显示时间还是闹钟时间,为0时显示时间

uchar al_clk1=11; //显示闹钟小时

uchar al_clk2=11; //显示闹钟分

uchar al_clk3=0; //显示闹钟秒

uchar disp1; // 显示时间或者闹钟时间

uchar disp2;

uchar disp3;

uchar dot_sel=0; //小数点选择标准位

uchar dot_hou; //小时的小数点显示

uchar dot_min; //分钟的小数点显示

uchar clk_f=0; //闹钟标志位

void init()

{

TMOD = 0x02; //定时器0,方式2自动重装

TH0 = 0x06;

TL0 = 0x06;

EA = 1;

ET0 = 1;

TR0 = 1;

IT0 = 1; //外部中断0边沿触发

EX0 = 1; //外部中断0允许

IT1 = 1; //外部中断1边沿触发

EX1 = 1; //外部中断1允许

}

void Delay_1ms(uint i) //延时n*ms

{

uchar x,j;

for(j=0;j<i;j++)

for(x=0;x<=148;x++);

}

void dot_choice() //选择小数点显示的位置

{

if(!P1_1)

{

Delay_1ms(25);

if(!P1_1)

{

dot_sel = ~dot_sel;

if(dot_sel)

{

dot_hou=1;

dot_min=0;

}

else

{

dot_hou=0;

dot_min=1;

}

}

}

}

void al_clk_seting() //闹钟设定

{

if(clk_f)

{

if((al_clk1==hou)&(al_clk2==min))

{

Speak = ~Speak;

Delay_1ms(38);

}

}

}

void display() //显示程序

{

if(!P1_0)

{

Delay_1ms(19); //闹钟和时间切换

if(!P1_0) flag = ~flag;

}

if(flag) //显示时间或者闹钟时间

{

disp1 = al_clk1;

disp2 = al_clk2;

disp3 = al_clk3;

}

else

{

disp1 = hou;

disp2 = min;

disp3 = sec;

}

if(!P1_2)

{

Delay_1ms(25);

if(!P1_2)

{

dot_hou=0;

dot_min=0;

clk_f = !clk_f; //clk_f为1是闹钟为设定状态。

}

}

dot_choice(); //选择小数点显示的位置

SEL=0x80;

DATA=table[0][disp1/10] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x40;

DATA=table[dot_hou][disp1%10] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x20; //显示-

DATA=table[0][11] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x10;

DATA=table[0][disp2/10] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x08;

DATA=table[dot_min][disp2%10] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x04; //显示-

DATA=table[0][11] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x02;

DATA=table[0][disp3/10] ;

Delay_1ms(1);

DATA=table[0][10] ;

SEL=0x01;

DATA=table[clk_f][disp3%10] ; //clk_f为1是闹钟设定最后一位小数点显示

Delay_1ms(1);

DATA=table[0][10] ;

}

void time() //时间计数部分

{

if(sec==60)

{

min++;

sec=0;

if(min==60)

{

hou++;

min=0;

if(hou==24)

hou=0;

}

}

}

void main() //主函数

{

init();

while(1)

{

display(); //显示

time(); //时钟

al_clk_seting(); //闹钟设定

}

}

void timer_0() interrupt 1 //定时器0时钟计数单元

{

count++;

if(count==2000)

{

sec++;

count=0;

}

}

void inter_ex_0() interrupt 0 //外部中断0进行闹钟或者时间的加1

{

if(flag&dot_sel) al_clk1++;

if(flag&(~dot_sel)) al_clk2++;

if((~flag)&dot_sel) hou++;

if((~flag)&(~dot_sel)) min++;

if(min == 60) min = 0;

if(hou == 24) hou = 0;

if(al_clk2 == 60) al_clk2 = 0;

if(al_clk1 == 24) al_clk1 = 0;

}

void inter_ex_1() interrupt 2 //外部中断1进行闹钟或者时间的减1

{

if(flag&dot_sel)

{

if(al_clk1 == 0) al_clk1 =24;

al_clk1--;

}

if(flag&(~dot_sel))

{

if(al_clk2 == 0) al_clk2 =60;

al_clk2--;

}

if((~flag)&(~dot_sel))

{

if(min == 0) min = 60;

min--;

}

if((~flag)&dot_sel)

{

if(hou == 0) hou = 24;

hou--;

}

}

相关推荐