单片机实验报告山东大学.docx
《单片机实验报告山东大学.docx》由会员分享,可在线阅读,更多相关《单片机实验报告山东大学.docx(76页珍藏版)》请在冰豆网上搜索。
![单片机实验报告山东大学.docx](https://file1.bdocx.com/fileroot1/2022-11/26/35eee08b-369a-47ea-b735-dd6ccb4e339e/35eee08b-369a-47ea-b735-dd6ccb4e339e1.gif)
单片机实验报告山东大学
第三单元Proteus系统仿真实验
实验一基本并行口I/O口实验自我完成实验
1、实验要求
当按键SW1按下之后,D1-D8轮流点亮,点亮时间为100ms,当按键停下后,停止轮换,
再次按下后继续轮换。
2、编程思路
①进行初始化工作,包括设置堆栈指针SP,将P2口所有位设置为1,使P2口所接发光二
极管全部熄灭。
将显示缓冲单元(设为20H单元)初始化为FEH。
②从P1口读数据,查看P1.0位,如果P1.0位为0,则执行如下循环:
将显示缓冲单元
的值送给P2口,调用100ms延时程序,将显示缓冲单元的值循环左移1位,再送回显示缓
冲单元。
如果P1.0位不为0则不执行上述循环。
③重复上面的操作②
3、实验步骤
①根据上述实验内容,参考1.2.2,在Proteus环境下建立图3.5所示原理图,并将其保
存为basicIO_self.DSN文件。
②根据
(2)和(3)编写控制源程序,将其保存为basicIO_self.asm。
③将源程序添加到U1中,并构造(build)该程序。
④执行仿真过程观察D1-D8的指示,查看程序功能是否正确。
⑤修改延时程序延时参数,重新执行③和④。
4、源程序
ORG0000H
AJMPMAIN
ORG0030H
MAIN:
MOVSP,#60H
MOVP2,#0FFH
MOVA,#0FEH
MOV20H,A;缓冲单元
LOOP:
JNBP1.0,LOOP1;;如果P1.0=0,跳转
SJMPLOOP;否则循环不断检测
LOOP1:
MOVP2,20H;将缓冲单元内的值给P2口
LCALLDELAY100MS;延时100ms
;MOVA,20H
RLA;左移一位
MOV20H,A
JBP1.0,LOOP;如果P1.0=1,跳转到LOOP处
LJMPLOOP1;否则循环
DELAY100MS:
MOVR7,#200;1us
DL:
MOVR6,#248;1us
DJNZR6,$;248*2=496us
NOP;1us
DJNZR7,DL;2us
RET
;(496+1+1+2)*200+1=100.001ms
END
5、电路图
6、仿真结果
当按键SW1按下之后,D1-D8轮流点亮,点亮时间为100ms,当按键停下后,停止轮换,
再次按下后继续轮换。
实验二扩展并行I/O口实验自我完成实验
1、实验要求
仿真实现交通信号灯控制功能。
控制顺序为:
①南北绿灯亮,同时东西红灯亮10s;
②南北黄灯亮,同时东西红灯亮2s;
③南北红灯亮,同时东西绿灯亮10s;
④东西黄灯亮,同时南北红灯亮2s;
⑤重复①~④。
2、编程思路
①进行初始化工作,包括设置堆栈指针SP,将两个373的输出口所有位均设置为1,使所有发光二极管全部熄灭。
②分析两个373的地址:
假定所有无关地址均定义为1,那么U4的锁存地址为:
#0FE00H,U5的锁存地址为:
#0FD00H。
③分析4个状态下两个373的输出数据值:
假定“南北绿灯亮,同时东西红灯亮”为状态1,即:
Stat1;“南北黄灯亮,同时东西红灯亮”为状态2,即:
Stat2;
“南北红灯亮,同时东西绿灯亮”为状态3,即:
Stat3;
“东西黄灯亮,同时南北红灯亮”为状态4,即:
Stat4。
3、实验步骤
①根据上述实验内容,参考1.2.2,在Proteus环境下建立图3.7所示原理图,并将其保
存为expandIO_self.DSN文件。
②根据
(2)和(3)编写控制源程序,将其保存为expandIO_self.asm。
③将源程序添加到U1中,并构造(build)该程序。
④执行仿真过程观察各个方向的交通信号灯指示,查看程序功能是否正确。
4、源程序
ORG0000H
AJMPMAIN
ORG0030H
MAIN:
MOVSP,#60H
MOVA,#0FFH
MOVDPTR,#0FE00H
MOVX@DPTR,A
MOVDPTR,#0FD00H
MOVX@DPTR,A
STAT1:
MOVA,#0F3H
MOVDPTR,#0FE00H
MOVX@DPTR,A
MOVA,#0CH
MOVDPTR,#0FD00H
MOVX@DPTR,A
LCALLDELAY10S
STAT2:
MOVA,#0C3H
MOVDPTR,#0FE00H
MOVX@DPTR,A
MOVA,#0FH
MOVDPTR,#0FD00H
MOVX@DPTR,A
LCALLDELAY2S
STAT3:
MOVA,#0FCH
MOVDPTR,#0FE00H
MOVX@DPTR,A
MOVA,#03H
MOVDPTR,#0FD00H
MOVX@DPTR,A
LCALLDELAY10S
STAT4:
MOVA,#3CH
MOVDPTR,#0FE00H
MOVX@DPTR,A
MOVA,#0FH
MOVDPTR,#0FD00H
MOVX@DPTR,A
LCALLDELAY2S
LJMPSTAT1
DELAY2S:
MOVR7,#20
DL2:
MOVR6,#200
DL1:
MOVR5,#250
DJNZR5,$
DJNZR6,DL1
DJNZR7,DL2
RET
DELAY10S:
MOVR7,#100
DL3:
MOVR6,#200
DL4:
MOVR5,#250
DJNZR5,$
DJNZR6,DL4
DJNZR7,DL3
RET
END
5、电路图
6、实验结果
①南北绿灯亮,同时东西红灯亮10s;
②南北黄灯亮,同时东西红灯亮2s;
③南北红灯亮,同时东西绿灯亮10s;
④东西黄灯亮,同时南北红灯亮2s;
实验三静态LED显示实验自我完成实验
1、实验要求
图中7SEG2为十位显示数码管,7SEG1为个位显示数码管,KEY_LOAD为倒计时初
值按钮,KEY_START为倒计时启动按钮。
要求实现的功能是:
当KEY_LOAD按钮按下时加载倒计时初值(如:
10s),当按下KEY_START按钮时,开始倒计时,每过1s,计时器减1,直到减到“00”为止。
减到“00”时使P3.0引脚上的LED按10Hz频率进行闪烁,直到再次按下KEY_LOAD按钮才重新加载初值,并熄灭LED。
再次按下KEY_START按钮又一次开始倒计时,如此反复。
2、编程思路
①分析两个373的地址:
假定所有无关地址均定义为1,那么U2的锁存地址为:
#0FE00H,U3的锁存地址为:
#0FD00H。
②程序流程图:
3、实验步骤
①根据上述实验内容,参考1.2.2,在Proteus环境下建立图3.9所示原理图,并将其保
存为staticLED_self.DSN文件。
②根据
(2)和(3)编写控制源程序,将其保存为staticLED_self.asm。
③将源程序添加到U1中,并构造(build)该程序。
④执行仿真过程观察秒表程序功能是否正确。
4、源程序
ORG0000H
AJMPMAIN
ORG0030H
MAIN:
MOVSP,#60H;堆栈初始化
MOVR0,#0
;各位
MOVR1,#1;十位
SETBP3.0;关掉LED1
CLRF0
LOOP:
JBP1.1,LOOP2;如果P1.1=1,跳转到LOOP2,
LOOP1:
CLRF0
MOV30H,R0
MOV31H,R1;装载初值
SETBP3.0;关闭LED1
LCALLDISPLAY;显示
LOOP2:
JBP1.0,LOOP;如果P1.0=1,跳回LOOP,否则继续执行
LOOP3:
LCALLDISPLAY;刷新显示
LCALLDELAY1S;延时1s
LCALLADJUST2;调整计时器寄存器
JBF0,LOOP4
LJMPLOOP3
LOOP4:
CLRP3.0;LED闪烁程序
LCALLDELAY100MS
SETBP3.0
LCALLDELAY100MS
JBP1.1,LOOP4
LJMPLOOP1
DISPLAY:
;显示子程序
MOVA,30H
MOVDPTR,#TABLE
MOVCA,@A+DPTR
MOVDPTR,#D1ADD
MOVX@DPTR,A
MOVA,31H
MOVDPTR,#TABLE
MOVCA,@A+DPTR
MOVDPTR,#D10ADD
MOVX@DPTR,A
RET
ADJUST2:
DEC30H
MOVA,30H
CJNEA,#-1,GOTORET
MOV30H,#9
DEC31H
MOVA,31H
CJNEA,#-1,GOTORET
SETBF0
RET
GOTORET:
RET
DELAY1S:
MOVR7,#10
DL2:
MOVR6,#200
DL1:
MOVR5,#250
DJNZR5,$
DJNZR6,DL1
DJNZR7,DL2
RET
DELAY100MS:
MOVR7,#200
DL:
MOVR6,#248
DJNZR6,$
NOP
DJNZR7,DL
RET
TABLE:
DB0C0H,0f9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
D1ADDEQU0FE00H;U3的锁存地址
D10ADDEQU0FD00H
END
5、电路图
6、仿真结果
当KEY_LOAD按钮按下时加载
倒计时初值(如:
10s),当按下KEY_START按钮时,开始倒计时,每过1s,计时器减1,
直到减到“00”为止。
减到“00”时使P3.0引脚上的LED按10Hz频率进行闪烁,直到再次
按下KEY_LOAD按钮才重新加载初值,并熄灭LED。
再次按下KEY_START按钮又一次开始倒计时,如此反复。
实验四矩阵键盘扫描实验自我完成实验
1、实验要求
D1~D8八个发光二极管构成彩色旋转灯,D9~D13为档位指示灯,一档旋转速度最慢(周期1s,D13亮),二档较快(周期0.8s,D12亮),三档更快(周期0.6s,D11亮),四档再快(周期0.4s,D10亮),五档最快(周期0.2s,D10亮)。
四个按键KEY0-KEY1于设定旋转方向为顺时针旋转或者逆时针旋转,KEY2-KEY3用于增快或则减慢旋转速度。
2、编程思路
按键扫描的方式可以采用前面示例程序中的方法:
线反转法或行扫描法。
可以用汇编语言
实现,也可以用C语言实现。
建议如前面示例所示,汇编采用行扫描法,C语言用线反法。
程序控制流程是:
首先初始化设置默认运行参数,然后读取按键,识别键码,并根据键码
的不同执行运行参数调整,最后根据当前的运行参数执行发光二极管D1-D8的轮流旋转。
速度的控制通过控制调用延时程序的次数来决定,假设延时程序的延时长度为5ms。
延时
程序可以按如下方式实现(假设晶振频率为12MHz):
voiddelays()
{
uchart,ms;
ms=5;//延时5ms
while(ms--)for(t=0;t<120;t++);
}
或者采用内嵌汇编来实现:
voiddelays()
{
#pragmaasm
MOVR2,#50//;5ms延时程序
DL1:
MOVR1,#48
DL2:
DJNZR1,DL2//;内循环100us
NOP
DJNZR2,DL1//;中循环10ms
#pragmaendasm
}
旋转彩灯线反转法C语言程序控制流程图
(1)主控流程图
(2)键盘扫描子程序Keyscan流程图
旋转彩灯行扫描法汇编控制流程图
3、实验步骤
①根据上述实验内容,参考1.2.2,在Proteus环境下建立图3.11所示原理图,并将其
保存为keyscan_self.DSN文件。
②根据
(2)和(3)编写控制源程序,将其保存为keyscan_self.asm或keyscan_self.c。
③将源程序添加到U1中,并构造(build)该程序。
④执行仿真过程观察秒表程序功能是否正确。
4、源程序
#include"reg52.h"
#include"intrins.h"
#defineucharunsignedchar
#defineuintunsignedint
sbitg0=P0^4;
ucharcodeT_TABLE[]={200,160,120,80,40};//周期值表
ucharcodekey_code[]={0x22,0x12,0x21,0x11};
voiddelay()//延时5ms
{
uchart,ms;
ms=5;
while(ms--)
for(t=0;t<120;t++);
}
voidmain()
{
intaa=0xfe;
uintdir=1;
uintspeed=0;
inttemp,temp2,keycode;
intj,key;
g0=0;
while
(1)
{
P3=0x30;
temp=P3;
if((temp&0x30)!
=0x30)//按键检测
{
delay();
delay();
P3=0x30;
temp=P3;
if((temp&0x30)!
=0x30)
{
P3=0x03;
temp2=P3;
keycode=temp|temp2;
for(j=0;j<4;j++)
{
if(keycode==key_code[j])
{
key=j;
}
}
if(key==0)dir=1;//正转
if(key==1)dir=0;//反转
if(key==2)
{
speed++;
if(speed==5)speed=4;//换档
}
if(key==3)
{
if(speed==0)speed++;//换档
speed--;
}
switch(speed)
{
case0:
P0=0xef;break;
case1:
P0=0xf7;break;
case2:
P0=0xfb;break;
case3:
P0=0xfd;break;
case4:
P0=0xfe;break;
default:
break;
}
P3=0x03;
while(!
(P3==0x03));
}
}
if(dir==1)//正转时执行
{
P1=aa;
for(j=0;jdelay();
aa=_crol_(aa,1);//左移
}
if(dir==0)//反转时执行
{
P1=aa;
for(j=0;jdelay();
aa=_cror_(aa,1);//右移
}
}
}
5、电路图:
6、仿真结果:
D1~D8八个发光二极管构成彩色旋转灯,D9~D13为档位指示灯,一档旋转速度最慢,二档较快,三档更快,四档再快,五档最快。
四个按键KEY0-KEY1于设定旋转方向为顺时针旋转或者逆时针旋转,KEY2-KEY3用于增快或则减慢旋转速度。
实验五定时器计数器实验自我完成实验
1、实验要求
用NE555构成的脉冲信号发生器,右边是用定时/计数器0和定时/计数器1构成的频率计。
为了检验频率计量是否准确,用Proteus的虚拟频率计来进行测量脉冲信号频率进行比对。
7SEG1-7SEG6用于频率计百分位、十分位、个位、十位、百位、千位的显示,
单位为Hz。
要求单片机上电运行后作为频率计将一直运行,改变脉冲发生器所产生的脉冲
频率,则频率计的显示将跟随变化。
2、编程思路
定时/计数器0工作在定时器模式方式1(16位),定时/计数器1工作在计数器模式方
式2(8位自动重装初值)。
定时/计数器1计数200个脉冲后(每计数200个脉冲产生一次中断)统计这200个脉
冲总的时间长度,计算出平均每个周期的时间长度。
200个脉冲所用时间长度的测量是靠定时/计数器0来实现的,定时/计数器0的初值为
0。
当定时/计数器1产生中断时,读出定时/计数器0当前计数器值,再加上在定时/计数器0中断中累积的值即可得到。
3、实验步骤
①根据上述实验内容,参考1.2.2,在Proteus环境下建立图3.11所示原理图,并将其保存为frequencycounter.DSN文件。
②根据
(2)和(3)编写控制源程序,将其保存为frequencycounter.c。
③运行KeiluVision2开发环境,按照1.1.3节介绍的方法建立工程
frequencycounter.uV2,CPU为AT89C51,包含启动文件STARTUP.A51。
④按照1.2.2第(6)节介绍的方法将C语言源程序frequencycounter.c加入工程
frequencycounter.uV2,并设置工程frequencycounter.uV2属性,将其晶振频率设置
为12MHz,选择输出可执行文件,仿真方式为选择硬仿真,并选择其中的“PROTEUSVSM
MONITOR51DRIVER”仿真器。
⑤构造(Build)工程frequencycounter.uV2。
如果输入有误进行修改,直至构造正确,
生成可执行程序frequencycounter.hex为止。
⑥为AT89C51设置可执行程序frequencycounter.hex。
⑦运行程序,观察数码管的显示与虚拟频率计是否一致。
⑧改变RV2的值,继续观察频率测量结果,观察数码管的显示与虚拟频率计是否一致。
4、源程序
#include"reg52.h"
#defineucharunsignedchar
#defineuintunsignedint
ucharcodeled_table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
ucharxdatada001_at_0xfe00;
ucharxdatada01_at_0xfd00;
ucharxdatada1_at_0xfb00;
ucharxdatada10_at_0xf700;
ucharxdatada100_at_0xef00;
ucharxdatada1k_at_0xdf00;
uchardv001,dv01,dv1,dv10,dv100,dv1k;
longsumtime=0;//总时间
floatfrequency,ptime;//分别为频率,单周期时间
uinttimer0H;
uinttimer0L;
voids_timer0()interrupt1
{
EA=0;
sumtime=sumtime+65536;
TH0=timer0H;
TL0=timer0L;
EA=1;
}
voids_timer1()interrupt3
{
EA=0;
sumtime=sumtime+TH0*256+TL0;
TH0=timer0H;
TL0=timer0L;
ptime=(float)sumtime/200;
sumtime=0;
frequency=(float)1000000/ptime;
dv1k=(uchar)(frequency/1000);
frequency=frequency-dv1k*1000;
dv100=(uchar)(frequency/100);
frequency=frequency-dv100*100;
dv10=(uchar)(frequency/10);
frequency=frequency-dv10*10;
dv1=(uchar)frequency;
frequency=frequency-dv1;
frequency=frequency*10;
dv01=(uchar)frequency;
frequency=frequency-dv01;
frequency=frequency*10;
dv001=(uchar)frequency;
da001=led_table[dv001];
da01=led_table[dv01];
da1=led_table[dv1];
da10=led_table[dv10];
da100=led_table[dv100];
da1k=led_table[dv1k];
EA=1;
}
voidmain()
{
TMOD=0X61;//T1计数器,方式2,T0定时器,方式1
timer0H=0;//T0定时器初值
timer0L=0;
TH1=TL1=56;//T1计数器初值256-200=56
EA=1;//开总中断
ET0=1;//开定时器0中断
TR0=1;//启动定时器0
ET1=1;//开启T1中断
TR1=1;//开启T1
while
(1);
}
5、电路图
6、仿真结果
频率计显示的与脉冲发生器的频率基本一致。
实