最新版单片机实验报告2814596.docx
《最新版单片机实验报告2814596.docx》由会员分享,可在线阅读,更多相关《最新版单片机实验报告2814596.docx(22页珍藏版)》请在冰豆网上搜索。
![最新版单片机实验报告2814596.docx](https://file1.bdocx.com/fileroot1/2023-1/7/1be945d8-fb8b-4fb2-9c1c-2777b98e1875/1be945d8-fb8b-4fb2-9c1c-2777b98e18751.gif)
最新版单片机实验报告2814596
单片机原理实验报告
学年:
______________
学期:
______________
专业:
09电子信息工程
班级:
______________
姓名:
____Pred______
学号:
______________
指导老师:
___________
日期:
年月日
目录contents
1.I/O输入、输出实验…………………………………………………………………3
2.数码管动态扫描显示实验……………….….………………………………………6
3.键盘输入实验………………….……………………………………….……………9
4.定时/计数器…………………………………………………………………………12
5.音频控制实验……………………………..…………………………………………16
6.串行口通信………………………………..…………………………………………22
说明:
1.6个实验程序均在伟纳电子ME830单片机实验板上调试成功。
Mcu是AT89S52。
2.音频控制实验源码来自网上,若想在晶振11.0592mhz上运行,只需更改输出频率表格的定时器初值即可。
同时,由于程序占用233字节data,写入普通51mcu是运行不了的,这里我是用ICE52仿真器运行。
3.串行口通信实验中上位机使用伟纳电子的串口调试软件,可以到其官方网站下载。
4.由于本次实验旨在达到实验目的,程序本身存在很多不完善的地方,如:
定时计数器实验中取位运算中耗费大量时间,导致显示过程出现闪烁现象。
5.电路原理图在prorel99se上画的,不能保证原理图的正确。
(我还没学呢….)
实验一:
I/O口输入/输出实验
1.实验任务
流水灯单循环,P0口接八个共阳发光二极管,分别为D0、D1……D7。
程序先点亮D0,延时一段时间(1秒钟),再顺序点亮D1……D7,然后又是D0。
同时只能有一个灯亮。
设晶振频率fosc=11.0592MHz,要求亮灯1秒后下一个灯点亮。
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)先计算好定时器初值,并载入TH0,TL0
2)等待定时器中断响应,响应后累次叠加到1s时,设置标志位
3)检测标志位,点灭上一个灯,点亮点一个灯
4)判断是否点亮第七个灯,是则下一个点亮第零个灯,否则跳过
5.程序框图
6.C语言源程序
#include
#defineucharunsignedchar
#defineLEDPORTP0
bitledturn=0;//设置亮灯标志
chari=0;
ucharcodeledlight[8]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};//led亮起顺序
voidmain()
{
RCAP2H=0x4C;//定时器2,晶振11.0592MHz,单次定时50ms
RCAP2L=0x00;
ET2=1;//定时器2中断允许
EA=1;//中断允许
TR2=1;//开始计时
while
(1)//进入死循环
{
if(ledturn)
{
ledturn=0;
LEDPORT=ledlight[i];
i++;
if(i==8)i=0;
}
}
}
timer2()interrupt5//定时器2终端服务程序
{
staticuchart;
TF2=0;//溢出清0
t++;
if(t==20)
{
t=0;//取消标志
ledturn=1;//设置亮灯标志
}
}
7.数据分析
这里实现流水灯单循环的方法是,依次灭掉前一个灯和点亮后一个灯,再延时一会,不断循
环,当点亮到D07时候,下一个是点亮D00。
如此,就可以看到流水灯单循环的效果了。
实验二:
数码管动态扫描显示实验
1.实验任务
在动态共阳数码管上显示89C51字样
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)先准备好要显示的数据,放入相应的显示存储单元中。
2)根据要使用的数码管的具体位置来确定扫描初值和扫描方向。
3)根据使用数码管的个数来确定扫描的位数。
4)查表将要显示的数据转换为能使数码管正确显示相对应的段码。
5)分时送段码和位码,数码管开始循环显示。
5.程序框图
6.C语言源程序
#include
#defineucharunsignedchar
ucharcodedig[]={0x10,0x08,0x04,0x02,0x01};//位码
ucharcodedisplay[]={0x80,0x90,0xC6,0x92,0xF9};//段码
uchari=0;
voiddelayms(unsignedintms)
{
unsignedchark;
while(ms--)
{
for(k=0;k<114;k++)
;
}
}
voidmain()
{
P2=0xFF;
P0=0xFF;
while
(1)
{
P2=0xff;
P0=display[i];
P2=~dig[i];
delayms
(1);
i++;
if(i==5)i=0;
}
}
7.数据分析
显示89C51字样主要依靠人的视觉停留效应,先选中第一个数码管,送入段码显示1,延迟一段时间后关闭段码,选中第二个数码管,送入段码显示2,再延迟一会儿,不断循环,直到显示到第五个数码管,再次选中第一个数码管….,这样就可以在数码管上看到89C51了。
实验三:
键盘输入实验
1.实验任务
在键盘上按K1、K2、K3、K4后分别在数码管上显示1、2、3、4。
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)先准备好要显示的数据,放入相应的显示存储单元中。
2)判断是否有按键按下,有则逐个检查那个按键。
3)根据按下的键值,送显示数据到数码管
5.程序框图
6.C语言源程序
#include
#defineucharunsignedchar
ucharcodedisplay[]={0xf9,0xa4,0xb0,0x99};
sbitk1=P1^4;
sbitk2=P1^5;
sbitk3=P1^6;
sbitk4=P1^7;
voiddelayms(ucharms)//延时子函数,ms
{
uchari;
while(ms--)
{
for(i=0;i<114;i++);
}
}
voidmain(void)
{
P2=0xFE;//数码管初始化
P0=~(0x40);
P1=0xFF;//按键初始化
while
(1)
{
if(P1!
=0xFF)
{
delayms(20);
if(P1!
=0xFF)
{
if(!
k1)P0=display[0];
elseif(!
k2)P0=display[1];
elseif(!
k3)P0=display[2];
elseP0=display[3];
while(P1!
=0xFF)
;
}
}
}
}
7.数据分析
程序判断是否有按键按下,有则延迟一段时间后重新判断,有按键按下进入键值判断,否则返回。
进入判断键值后,把相应的键值转为数值再转为段码送入数码管显示,进入一个“死循环”,直到按键松开后弹出。
实验四:
定时/计数器
1.实验任务
设置一个定时器/计数器,分辨率为0.1S,并在数码管上显示
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)先准备好要显示的数据,放入相应的显示存储单元中。
2)调整定时器初始值,每隔0.1S向时间累加器加一。
3)根据时间累加器的值分别取毫秒、秒、十秒等位并送入相应寄存器储存。
4)根据要使用的数码管的具体位置来确定扫描初值和扫描方向。
5)查表将要显示的数据转换为能使数码管正确显示相对应的段码。
6)分时送段码和位码,数码管开始循环显示。
5.程序框图
6.C语言源程序
#include
unsignedcharcodedisplay[]=
{
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90
};//设置位码
unsignedcharcodedig[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//设置段码
unsignedcharnum[9]={0,0};
unsignedchari,j,once=1;
voiddelayms(unsignedcharms)
{
chari;
while(ms--)
{
for(i=0;i<80;i++);
}
}
voidmain(void)
{
RCAP2H=0x4C;//定时器2载入初始值,时长50ms
RCAP2L=0x00;
TR2=1;
ET2=1;
EA=1;
P2=0xFF;//数码管初始化
P0=0xFF;
while
(1)
{
for(i=0;i<7;i++)
{
P0=0xFF;//关显示去除“鬼影”
P2=~(dig[(j)]);//送位码
P0=display[num[j]];送段码
delayms
(1);
j++;
if(j==8)j=0;
}
}
}
timer()interrupt5//中断服务
{
staticunsignedlongtimer=0;
TF2=0;
P2=0xFF;//关显示,消除显示抖动
if(once==2)//中断两次,累加一次
{
once=0;
timer++;
num[0]=timer%10;//个
num[1]=timer/10%10;//十
num[2]=timer/100%10;//百
num[3]=timer/1000%10;//千
num[4]=timer/10000%10;//万
num[5]=timer/100000%10;//十万
num[6]=timer/%10;//百万
num[7]=timer/%10;//千万
}
once++;
P2=~(dig[(j)]);//恢复显示
}
7.数据分析
上电复位后可以在数码管上看到程序从零开始计时,精度为0.1S。
这里显示数字的方法同实验二的数码管动态扫描显示实验的原理一样,所不同的是程序根据一定的时序改变送入数码管的段码。
程序每隔0.1S更新一次显示数据,即在循环显示的时候通过中断服务程序,累加时间,取各权值数值换成段码。
实验五:
音频控制实验
1.实验任务
上电复位后在蜂鸣器上响起音乐。
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)储存产生不同频率的中断初始值。
2)乐谱解释函数:
遇到拍子分隔符和空格跳过,判断是否高低音,读音符,调整为高低音音符,读音符后的升半个音符的“#”,读延长音“-”“.”,读缩短一半音长的“_”,字符串结束符“0x00”
3)音乐播放函数:
将音符频率的序号数组对应的频率送入定时器预置数中,再延时对应音符播放的时间。
4)乐谱书写规则:
1234567为7个基本音阶
前面加逗号','表示这是低音
前面加上点号'`'表示这是高音
后面加'#',表示这个音符升半个音阶
后面加'.',表示这个音符要再加长自身一半的延时
后面加一个或多个'-',每个表示延时一拍
后面加一个或多个'_',表示这个音符要缩短自身一半的时长,最多支持2个'_'。
5.程序框图
6.C语言源程序
#defineucharunsignedchar//定义一下方便使用
#defineuintunsignedint
#defineulongunsignedlong
#include//包括一个52标准内核的头文件
charcodedx516[3]_at_0x003b;//仿真头中断用
sbitBEEP=P1^7;//喇叭输出脚
ucharth0_f;//在中断中装载的T0的值高8位
uchartl0_f;//在中断中装载的T0的值低8位
//T0的值,及输出频率对照表
ucharcodefreq[36*2]={
0xA9,0xEF,//00220HZ,1//0
0x93,0xF0,//00233HZ,1#
0x73,0xF1,//00247HZ,2
0x49,0xF2,//00262HZ,2#
0x07,0xF3,//00277HZ,3
0xC8,0xF3,//00294HZ,4
0x73,0xF4,//00311HZ,4#
0x1E,0xF5,//00330HZ,5
0xB6,0xF5,//00349HZ,5#
0x4C,0xF6,//00370HZ,6
0xD7,0xF6,//00392HZ,6#
0x5A,0xF7,//00415HZ,7
0xD8,0xF7,//00440HZ1//12
0x4D,0xF8,//00466HZ1#//13
0xBD,0xF8,//00494HZ2//14
0x24,0xF9,//00523HZ2#//15
0x87,0xF9,//00554HZ3//16
0xE4,0xF9,//00587HZ4//17
0x3D,0xFA,//00622HZ4#//18
0x90,0xFA,//00659HZ5//19
0xDE,0xFA,//00698HZ5#//20
0x29,0xFB,//00740HZ6//21
0x6F,0xFB,//00784HZ6#//22
0xB1,0xFB,//00831HZ7//23
0xEF,0xFB,//00880HZ`1
0x2A,0xFC,//00932HZ`1#
0x62,0xFC,//00988HZ`2
0x95,0xFC,//01046HZ`2#
0xC7,0xFC,//01109HZ`3
0xF6,0xFC,//01175HZ`4
0x22,0xFD,//01244HZ`4#
0x4B,0xFD,//01318HZ`5
0x73,0xFD,//01397HZ`5#
0x98,0xFD,//01480HZ`6
0xBB,0xFD,//01568HZ`6#
0xDC,0xFD,//01661HZ`7//35
};
//定时中断0,用于产生唱歌频率
timer0()interrupt1
{
TL0=tl0_f;TH0=th0_f;//调入预定时值
BEEP=~BEEP;//取反音乐输出IO
}
//******************************
//音乐符号串解释函数
//入口:
要解释的音乐符号串,输出的音调串,输出的时长串
changedata(uchar*song,uchar*diao,uchar*jie)
{
uchari,i1,j;
chargaodi;//高低+/-12音阶
ucharbanyin;//有没有半个升音阶
ucharyinchang;//音长
ucharcodejie7[8]={};//C调的7个值
*diao=*song;
for(i=0,i1=0;;)
{
gaodi=0;//高低=0
banyin=0;//半音=0
yinchang=4;//音长1拍
if((*(song+i)=='|')||(*(song+i)==''))i++;
//拍子间隔和一个空格过滤
switch(*(song+i))
{
case',':
gaodi=-12;i++;//低音
break;
case'`':
gaodi=12;i++;//高音
break;
}
if(*(song+i)==0)//遇到0结束
{
*(diao+i1)=0;//加入结束标志0
*(jie+i1)=0;
return;
}
j=*(song+i)-0x30;i++;//取出基准音
j=jie7[j]+gaodi;//加上高低音
yinc:
switch(*(song+i))
{
case'#':
//有半音j加一个音阶
i++;j++;
gotoyinc;
case'-':
//有一个音节加长
yinchang+=4;
i++;
gotoyinc;
case'_':
//有一个音节缩短
yinchang/=2;
i++;
gotoyinc;
case'.':
//有一个加半拍
yinchang=yinchang+yinchang/2;
i++;
gotoyinc;
}
*(diao+i1)=j;//记录音符
*(jie+i1)=yinchang;//记录音长
i1++;
}
}
//******************************************
//奏乐函数
//入口:
要演奏的音乐符号串
voidplay(uchar*songdata)
{
uchari,c,j=0;
uintn;
ucharxdatadiaodata[112];//音调缓冲
ucharxdatajiedata[112];//音长缓冲
changedata(songdata,diaodata,jiedata);//解释音乐符号串
TR0=1;
for(i=0;diaodata[i]!
=0;i++)//逐个符号演奏
{
tl0_f=freq[diaodata[i]*2];//取出对应的定时值送给T0
th0_f=freq[diaodata[i]*2+1];
for(c=0;cfor(n=0;n<32000;n++);
TR0=0;
for(n=0;n<500;n++);//音符间延时
TR0=1;
}
TR0=0;
}
//仙剑乐谱
ucharcodexianjian[]={
"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|"
"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|"
"67_6_55_3_|5--3_5_|26_5_32_3_|3---|"
"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|"
"67_6_55_3_|5--3_5_|67_6_76_7_|3---|"
"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|"
};
//乐谱方式输入的音乐播放,仙剑奇侠传
voidmain(void)//主程序
{
TMOD=0x01;//使用定时器0的16位工作模
TR0=0;
ET0=1;
EA=1;
while
(1)
{
play(xianjian);
}
}
7.数据分析
实验中蜂鸣器响起的音乐是由单片机输出高、低电平上实现的。
其中音调是由改变中断响应时间控制的,节拍是由改变中断循环次数实现的。
实验前先在乐谱函数中保存所要播放的乐谱,编译运行后有乐谱解释函数逐字节解释乐谱的字符,音乐播放函数接受来自乐谱解释函数的值,控制循环中断次数、中断响应时间,中断响应后取反P3.7,进而实现蜂鸣器响起音乐。
本实验用仿真头ICE52接在系统板上仿真,晶振22.1184MHz。
实验六:
串行口通信
1.实验任务
接受来自上位机的单字节十六进制数据,并在LED上通过二进制表示出来。
2.实验原理图
3.系统板上硬件连接
4.程序设计内容
1)设置串口工作方式,使用定时器1作为波特率发生器。
2)载入定时器初值,开启中断允许,定时器1使能。
3)进入循环程序,从上位机读数据,取反后赋值给LED端口。
5.程序框图
6.C语言源程序
#include
voiddelayms(unsignedintms)
{
unsignedchark;
while(ms--)
{
for(k=0;k<114;k++);
}
}
unsignedcharrxdata()//从上位机读数据
{
unsignedchardat;
while(!
RI)//等待数据接收完
dat=SBUF;//接收数据
RI=0;//清中断标志
return(dat);
}
voidmain(void)
{
P2=0xff;//初始化led显示
SCON=0x50;//设定串口工作方式1,接收使能
PCON=0x00;//波特率不倍增
TMOD=0x20;//定时器1工作于8位自动重载模式,用于产生波特率
EA=1;
TL1=0xfd;
TH1=0xfd;//波特率9600
TR1=1;
delayms(100);
while
(1)
{
P2=~(rxdata());//接收数据,并赋值给P2
}
}
7.数据分析
在上位机打开串口调试工具,调整波特率为9600,发送格式设置为16进制模式。
输入4c,点击发送,可以在下位机系统板上看到P2口LED亮暗顺序为暗亮暗暗亮亮暗暗。
即表示所发送数据十六进制的二进制格式。