单片机实验报告.docx
《单片机实验报告.docx》由会员分享,可在线阅读,更多相关《单片机实验报告.docx(43页珍藏版)》请在冰点文库上搜索。
单片机实验报告
单片机实验报告
单片机实验报告
一、实验目的:
1.掌握51单片机的内部结构和基本应用和工作原理。
2.掌握C51或汇编语言的语法及编程应用。
二、实验基本原理论述:
1.LED显示:
在静态显示中,各个字段连续通过电流,而动态显示的字段是断续通过电流的。
在动态显示中,逐次把所需显示的字符显示出来;在每点亮一个数码显示器之后,必须持续通电一段时间,使之发光稳定,然后再点亮另一个显示器,如此巡回扫描所有的显示器。
虽然在同一时刻只有一个显示器通电,但人的视觉为每个显示器都在稳定地显示。
当电源电压为5V时,选择的限流电阻的范围为200~510Ω。
2.计时实现:
利用定时器功能,在产生1s的时间后相应的秒加一,从而产生时钟功能。
具体有如下推导:
实验中我们选用11.0592M的晶振作为时钟产生中断源。
所谓机器周期就是访问一次存储器的时间。
而1个机器周期包括12个时钟周期。
因此欲产生1s的时间,我们需要机器周期数为:
而我们定时器满值为65536,因此有:
次
所以我们可以每次记满46080个,当定时器反复工作20次后即产生了1s的时间。
同样的,我们在秒表中要求10ms的计时单位,则其执行次数为9216次,我们可以让计数器记满4608,此时定时器反复2次即产生了10ms的基本时间单位。
3.键盘扫描:
矩阵式键盘,它的按键位于行、列的交叉点上。
按键的作用只是使相应接通或断开,被按按键在行列中所在的接点配合相应程序可产生键码。
按键属于电平开关,在按按键时总会有抖动。
因此,在硬件上可在按键两端加滤波电容或选用逻辑开关;在软件上可设置一定的延时。
4.音乐播放:
利用产生的不同占空比的方波作为不同的音调,然后根据其乐谱驱动蜂鸣器发声,从而实现了音乐播放功能。
5.PWM实现:
通过利用单片机的中断产生特定要求的占空比的方波,具体做法有:
我们可以设定一个计数值,到计数器未达到该值时显示高电平,若超过这个值,则置低电平,并当计数到一定值时对计数值清零。
为了满足占空比可调,我们可以通过按键去修改计数值从而实现其高低电平时间的相对变化,从而实现实验所要求的功能。
3、实验器材:
计算机(win7),单片机仿真学习板,KEILμVISION3,导线两根,示波器(1个)。
四、实验内容:
在实验板上编程实现2015年日历和实时时钟:
1.时-分-秒(2位-2位-2位)显示
可通过键盘置入时间值(参照电子表设置时间工作模式)。
2.可通过按键控制在LED上从右向左滚动显示年_月_日3次,如:
2015_01_20空空2015_01_20
3.实现每日闹铃提醒功能,闹铃时间可用按键设置。
闹铃采用提示音表示。
4.实现秒表功能(具有start/stop、pause/restart/clear键,参见秒表操作。
)。
5.实现定时器功能(预置定时5s,可通过+、-按键修改时间,按启动键倒计时,计到0时响定时结束提示音。
)。
6.设计实现音乐提示音。
7.设计PWM电压调节器(外加R:
1kW,C:
1mF滤波,输出:
0~3V,0.1V步进可调)
五、系统设计方案
本实验可以划分为时钟、日历,秒表,定时器和音乐播放五大模块。
基本设计框架为:
根据不同的按键选择相应的功能,若无按键,则默认选择时间显示,并不断检测闹钟是否来到。
当有按键按下是执行相应函数模块功能。
在函数功能完成后或者按键KEY=12则退回到时间显示主模块。
具体设计参看下面的程序框图。
六、程序框图:
七、调试与运行:
在单片机的调试过程中,遇到的第一个问题就是显示比较闪烁,通过查看相关的文章发现其主要是动态LED显示延时太长,导致了这个结果。
在对其LED显示延时做了相应修改后,时间显示明显效果变好。
遇到的第二个问题是,在做秒表是一直没能想到如何实现其计时暂停功能。
经过反复思考后利用了库函数里面的取反函数实现了秒表计时状态的反转,从而实现了计时和暂停功能的一键切换。
在这个问题调试中,有时暂停键不怎么有效,通过理论分析可能是按键延时不够,被误认为是二次操作。
通过修改键值延时按键效果明显变好。
遇到的第三个问题是闹钟音乐播放时时间显示熄灭。
为了让在音乐播放时显示时间,我将显示时间加入了音乐播放延时的,基本可以实现在播放音乐的同时显示时间,但冲突较大。
第四个问题是闰年2月份显示有误,仅有28天,为此,我在中断添加了闰年判别语句,对于闰年在2月达到30号是月份加一,日期置1,从而实现了这个问题的解决。
在实验验收过程中,老师要求从新做一个整点滚动显示学号的功能。
和日历滚动函数类似,我建立了一个滚动显示的字码表,然后利用对其循环赋值和滚动显示从而实现了上述功能,本次验收基本没有遇到太多问题。
运行结果如下图:
8、讨论与结论:
本次实验在做的过程中明显发现的问题有:
对C51语言的编程能力相对较弱,有待在以后的实践中再予以加强;对单片机工作原理理解不够透彻,需要加强动手实践,更多的去理解和运用所学习的单片机知识。
通过本次实验,基本对单片机结构及其内部的有了一个了解,也对外设如何驱动和设计有了一个初步的认识。
通过自己动手让单片机时钟正常工作,极大的感受了单片机的奥秘,也激发了对单片机学习的积极性和乐趣,为以后的工作和更进一步的学习打下了一定的基础。
总体而言,通过本次实验,比较好的完成了老师布置的单片机作业,也通过作业对单片机有了更为详尽和全面的了解。
9、致谢:
在本次实验过程中,邓建国、张鹏辉老师给予了很大的帮助,在此表示衷心的感谢。
10、参考文献:
[1]陈志旺,李亮.51单片机快速上手.北京:
机械工业出版社,2009
[2]薛钧义,张彦斌.MCS51单片微型计算机及其应用.西安:
西安交通大学出版社,1997
附录(实验代码)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include"reg52.h"
#include"intrins.h"
#defineucharunsignedchar
#defineuintunsignedint
//位定义
sbitbeep=P1^6;
sbita12=P2^4;
sbita13=P2^5;
sbita14=P2^6;
//编码表1(倒数第二个是中横杠,最后一个是下横杠)
unsignedcharcodetable1[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x08,0x5e,0x39,0x79};
//编码表2(用于日期的向左滚动显示)
unsignedcharcodetable2[]={0x5b,0x3f,0,0,0x08,0,0,0x08,0,0,0,0,0,0,0,0,0};
unsignedcharcodetable6[]={0x5b,0x06,0x5b,0x3f,0x6d,0x3f,0,0,0,0,0,0,0,0,0};
//编码表3(用于日期的向右滚动显示)
unsignedcharcodetable3[]={0,0,0x08,0,0,0x08,0x66,0x06,0x3f,0x5b,0,0,0,0,0,0,0};
//编码表4(用于提醒时间到时日期与时间的一起左滚显示)
unsignedcharcodetable4[]={0x5b,0x3f,0x06,0x66,0x08,0,0,0x08,0,0,0,0,0,0x40,0,0,0x40,0,0,0,0,0,0,0,0,0};
unsignedcharwatchdata[3]={0,0,0};
unsignedcharwatch[3]={0,5,0};
ucharcodeSONG_TONE[]=
{
212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,129,169,190,119,119,126,159,142,159,0
};
ucharcodeSONG_LONG[]=
{
9,3,12,12,12,24,9,3,12,12,12,24,9,3,12,12,12,12,12,9,3,12,12,12,24,0
};
//全局变量定义
unsignedcharyear,mon,day,hou,min,sec;//月、日、时、分、秒
unsignedcharxdata*ptr;
unsignedinti;
unsignedcharTimCou1,TimCou2,Key,KeyFlag;
unsignedcharAlarmHou,AlarmMin;//闹钟的小时,分钟
unsignedcharFlagST,Flagsec,Flagds,FLAG,FlagAm,FlagNe,Flagbeep;
//函数声明
voidInit();
voiddelay(unsignedchartt);
voidDisplayTime(bitflag,unsignedcharConBit);
voidDisplayDate(bitflag,unsignedcharConBit);
voidLSroDisplayDate();
voidRSroDisplayDate();
voidLSroDisplayzhunshi();
voidDisplayAlarm(bitflag,unsignedcharConBit);
voidStopwatchstart(bitflag,unsignedcharConBit);
voidDingshi(bitflag,unsignedcharConBit);
voidunsignedcharKeyScan();
voidSetTime();
voidSetDingshi(bitflag,unsignedcharConBit);
voidSetDate();
voidSetAlarm();
voiddelay60ms(void);
voidPlayMusic();
voidDelayMS(uintms);
//主函数
voidmain(){
Init();
while
(1){if(AlarmHou==hou&&AlarmMin==min&&sec<15)
{PlayMusic();}
f(min==0&&sec<7)
{LSroDisplayzhunshi();}
Key=KeyScan();
if(Key!
=0){
if(Key==1)SetTime();
if(Key==2)SetDate();
if(Key==3)SetAlarm();
if(Key==4)DisplayTime(0,1);
if(Key==5)DisplayTime(0,1);
if(Key==6)Stopwatchstart(0,1);
if(Key==7)Stopwatchstart(0,1);
if(Key==9)Dingshi(0,1);
if(Key==10)SetDingshi(0,1);
if(Key==11)PlayMusic();
if(Key==12)DisplayTime(0,1);
if(Key==13)LSroDisplayzhunshi();
if(Key==14)LSroDisplayDate();
if(Key==15)DisplayAlarm(0,1);
if(Key==16)DisplayDate(0,1);
}
elseDisplayTime(0,1);
}
}
voiddelay60ms(void)
{
unsignedchari,j;
for(i=0;i<200;i++)
for(j=0;j<100;j++)
;
}
voidDelayMS(uintms)
{
uchart;
while(ms--)
{DisplayTime(0,1);
for(t=0;t<120;t++);
}
}
voidPlayMusic()
{
uinti=0,j,k;
while((SONG_LONG[i]!
=0||SONG_TONE[i]!
=0)&&FLAG==0)
{Key=KeyScan();
if(Key==0)
{
for(j=0;j{
beep=~beep;
for(k=0;k}
DisplayTime(0,1);
i++;
}
else{break;};
}
}
voidDingshi(bitflag,unsignedcharConBit)
{unsignedcharcs[8];
unsignedcharwei,i;
while
(1)
{Key=KeyScan();
Flagds=0;
if(Key==3)
{
break;
}
if(Key==12||watch[1]==0)
{
Flagds=1;
Flagbeep=0;
return;
}
WR=0;//打开锁存器的必要条件
cs[7]=12;
cs[6]=5;
cs[5]=cs[2]=10;
cs[4]=watch[2]/10;
cs[3]=watch[2]%10;
cs[1]=watch[1]/10;
cs[0]=watch[1]%10;
wei=0x01;//从最右边开始显示
for(i=0;i<8;i++){
if(flag==1&&i==ConBit&&TimCou1>10){//闪烁控制
wei=_crol_(wei,1);
continue;
}
P0=0x00;//消隐
a12=a13=a14=0;//打开位选通端
P0=wei;//置数
a12=a13=a14=1;//关闭位选通端
wei=_crol_(wei,1);//位选通端左移一位
delay
(1);
P0=0x00;//消隐
a13=a14=0;//打开段选通端
P0=table1[cs[i]];//置数
a13=a14=1;//关闭段选通端
delay
(1);
}
P0=0x00;
WR=1;//关闭WR
}
}
voidStopwatchstart(bitflag,unsignedcharConBit)
{unsignedcharcs[8];
unsignedcharwei,i;
while
(1)
{
Key=KeyScan();
if(Key==2)
{watchdata[2]=0;
watchdata[0]=0;
watchdata[1]=0;
}
if(Key==4)
{Flagsec=~Flagsec;
}
if(Key==12)
{Flagsec=1;
return;
}
if(Key==3)
{//没有按键,秒表计
Flagsec=0;//没有按键,秒表计时
}
WR=0;//打开锁存器的必要条件
cs[7]=5;
cs[6]=13;
cs[5]=cs[2]=10;
cs[4]=watchdata[2]/10;
cs[3]=watchdata[2]%10;
cs[1]=watchdata[1]/10;
cs[0]=watchdata[1]%10;
wei=0x01;//从最右边开始显示
for(i=0;i<8;i++){
if(flag==1&&i==ConBit&&TimCou1>10){//闪烁控制
wei=_crol_(wei,1);
continue;
}
P0=0x00;//消隐
a12=a13=a14=0;//打开位选通端
P0=wei;//置数
a12=a13=a14=1;//关闭位选通端
wei=_crol_(wei,1);//位选通端左移一位
delay
(1);
P0=0x00;//消隐
a13=a14=0;//打开段选通端
P0=table1[cs[i]];//置数
a13=a14=1;//关闭段选通端
delay
(1);
}
P0=0x00;
WR=1;//关闭WR
}
//刷新显示页面
}
//初始化函数
voidInit(){
year=0;
mon=11;//初始月日时分秒的设定
day=9;//初始月日时分秒的设定
hou=10;
min=sec=0;
AlarmHou=AlarmMin=12;//闹钟初始时间
TimCou1=TimCou2=0;//定时器的计数初始为0
beep=1;//蜂鸣器不响
TMOD=0x11;//定时器0为方式1
TH0=(65526-46080)/256;
TH1=(65536-4608)/256;//重装初值
TL1=(65536-4608)%256;
TL0=(65526-46080)%256;
EA=ET0=ET1=1;//打开中断
TR0=1;//开始计时
TR1=1;//定时器1初始为关闭状态
Key=0;//键盘检测,初始为没有键按下
KeyFlag=13;//初始设置为13,为的是主函数刚进入时显示时间
FlagST=0;//判断是不是在设定时间,初始值为0,即不是设定时间状态
FlagAm=FlagNe=FlagBp=0;FlagDNT=0;//任意,为0表示显示日期
FlagBFAoN=0;//为0表示响声是闹钟的
Flagsec=1;
Flagds=1;
Flagbeep=1;
FLAG=0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//延时函数(tt=1时为延时1ms,但不精确)
voiddelay(unsignedchartt){
unsignedcharx,y;
for(x=0;x
for(y=0;y<100;y++){}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//显示时间的函数(动态扫描显示)
//传入的参数为了控制正常显示与设置时间状态下的闪烁显示:
flag为0时为正常显示,为1时则第ConBit位闪烁
voidDisplayTime(bitflag,unsignedcharConBit){
unsignedcharcs[8];
unsignedcharwei,i;
WR=0;//打开锁存器的必要条件
cs[7]=hou/10;
cs[6]=hou%10;
cs[5]=cs[2]=10;
cs[4]=min/10;
cs[3]=min%10;
cs[1]=sec/10;
cs[0]=sec%10;
wei=0x01;//从最右边开始显示
for(i=0;i<8;i++){
if(flag==1&&i==ConBit&&TimCou1>10){//闪烁控制
wei=_crol_(wei,1);
continue;
}
P0=0x00;//消隐
a12=a13=a14=0;//打开位选通端
P0=wei;//置数
a12=a13=a14=1;//关闭位选通端
wei=_crol_(wei,1);//位选通端左移一位
delay(3);
P0=0x00;//消隐
a13=a14=0;//打开段选通端
P0=table1[cs[i]];//置数
a13=a14=1;//关闭段选通端
delay(3);
}
P0=0x00;
WR=1;//关闭WR
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//滚动显示日期函数,从右向左滚动3次
//现在下面这个是不滚动的
//后面的函数LSroDisplayDate()是滚动显示的,用了那个后,这个只用于设置时显示
voidDisplayDate(bitflag,unsignedcharConBit){
unsignedcharcs[8];
unsignedcharwei,i;
WR=0;//打开锁存器的必要条件
cs[7]=year/10;
cs[6]=year%10;
cs[5]=cs[2]=10;
cs[4]=mon/10;
cs[3]=mon%10;
cs[1]=day/10;
cs[0]=day%10;
wei=0x01;//从最右边开始显示
for(i=0;i<8;i++){
if(flag==1&&i==ConBit&&TimCou1>10){//闪烁控制
wei=_crol_(wei,1);
continue;
}
P0=0x00;//消隐
a12=a13=a14=0;//打开位选通端
P0=wei;//置数
a12=a13=a14=1;//关闭位选通端
wei=_crol_(wei,1);//位选通端左移一位
delay
(1);
P0=0x00;//消隐
a13=a14=0;//打开段选通端
P0=table1[cs[i]];//置数
a13=a14=1;//关闭段选通端
delay
(1);
}
P0=0x00;
WR=1;//关闭WR
}
//////////////////////////////////////