《单片机原理与应用》实验报告 姓名:xxx 学号:xxxxxxxx 实验时间:5月28日~6月11日 2.2 汇编程序实验2 一、实验要求 片内RAM 30H开始的32个单元中分布着随机的有符号8位二进制数,按从小到大的顺序进行排序,排序后的数据仍然保存到30H开始的32个单元中(低地址存放小数据) 步骤: - 编写汇编语言并加上相应注释(注意扩展名为“*.asm”),将其保存。
- 运行Keil u Vision2,建立工程“simlab2.uV2”,CPU为AT89C51,不用包含启动文件“STARTUP.A51”。
- 将编写好的程序加入工程“simlab2.uV2”,并设置工程“simlab2.uV2”的属性,将其晶振频率设置为12MHz,选择输出的可执行文件,仿真方式为“Use Simulator”。
- 构造(Build)工程“simlab2.uV2”。如果输入有误,则进行修改,直至构造正确,生成可执行程序“simlab2.hex”为止。
- 运行程序,并用存储器观察窗口观察内部RAM30H~4FH单元排序前后的数值。
结果: 由上图可知,32个数从30H开始由小到大排列 三、实验源程序
- ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV R0,#20H ;R0用于存放数据时计数
- MOV R1,#30H ;R1指向30H地址单元
- MOV DPTR,#TABLE ;使DPTR指向表首
- MOV R2,#00H
- MOV A,R2 ;给偏移地址赋初值,为0
- LOOP1:
- MOVC A,@A+DPTR ;取出表中的数据
- MOV @R1,A ;将表中的数据存入30H单元
- INC R1 ;R1自增1,指向下一个单元
- INC R2
- MOV A,R2 ;R2自增1,从而使偏移量增1
- DJNZ R0,LOOP1 ;R0=R0-1,如果R0不为0,则再次从LOOP1处执行,将表中数据存入对应的单元;如果R0=0,则表示表中数据已经全部存入30H~4FH单元中
- MOV R7,#1FH ;将遍历次数31送入R7中
- LOOP2:
- MOV A,R7
- MOV R6,A ;将比较次数寄存器R6的值设定为R7的值
- ADD A,#30H
- MOV R0,A ;将最大值为位置寄存器R0的值设定为#30H+R7
- MOV R1,#30H ;将R1指向30H单元
- MOV B,@R1 ;取R1指向的单元的值到最大值寄存器B
- LOOP3:
- CLR C ;将C清零
- INC R1 ;R1自增1
- MOV A,@R1 ;将R1所指向单元中的值赋给A
- MOV R5,A ;将A中的值赋给R5,作为备份
- SUBB A,B ;A=A-B
- JC LOOP4 ;如果存在借位,即A<B,则跳转至LOOP4
- MOV A,R1
- MOV R0,A ;如果A>B,将R1中的值赋给R0,使其始终保持最大值
- MOV A,R5 ;恢复A的值
- MOV B,A ;使最大值寄存器B的值为A中的值
- LOOP4:
- DJNZ R6,LOOP3 ;R6=R6-1,如果R6为0,表示这一轮的比较已经完成,否则再次执行LOOP3,继续进行比较
- MOV A,B ;如果这一轮比较完成,则将最大值寄存器B的值赋给A
- XCH A,@R1 ;交换A和R1中的值,即将最大值存放到这一轮比较的最后的位置
- MOV @R0,A ;将A中的值赋给R0所指的单元,以上两步完成将最大值存到最后一位,最后一位的值存到原本最大值所在的位置
- DJNZ R7,LOOP2 ;判断外循环是否完成,若未完成跳转至LOOP2,继续执行外循环
- TABLE:
- DB 1,3,9,2,17,4,11,6
- DB 5,20,100,64,21,14,79,35
- DB 92,7,91,23,65,16,13,18
- DB 18,73,65,101,27,19,62,69
- SJMP $
- END
复制代码
2.3 C语言程序实验 一、实验要求 片内RAM 30H开始的32个单元中分布着随机的有符号8位二进制数,按从小到大的顺序进行排序,排序后的数据仍然保存到30H开始的32个单元中(低地址存放小数据) 步骤: (1)编写C语言源程序,并加上相应注释(注意扩展名为“*.c”),将其保存。 (2)运行Keil u Vision2,建立工程“simlab3.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (3)将编写好的程序加入工程“simlab3.uV2”,并设置工程“simlab3.uV2”的属性,将其晶振频率设置为12MHz,选择输出的可执行文件,仿真方式为“Use Simulator”。 (4)构造(Build)工程“simlab3.uV2”。如果输入有误,则进行修改,直至构造正确,生成可执行程序“simlab3.hex”为止。 (5)运行程序,并用存储器观察窗口观察内部RAM30H~4FH单元排序前后的数值。 结果: 由上图可知,32个数从30H到4FH由小到大排列 三、实验源程序
- <font color="rgb(0, 0, 0)"><font face="Calibri"><font style="font-size: 14pt">#include <reg51.h>
- #include<stdio.h>
- #define uchar unsigned char
- #define uint unsigned int //头文件
- uchar data a[32] _at_ 0x30; //设定数组a的起始地址为30H
- uint i _at_ 0x55;
- uint j _at_ 0x56;
- uint t _at_ 0x57; //以上三句表示将变量i,j,t分别放入地址55H,56H,57H
- void main()
- {
- char i,j,t; //定义变量i,j,t
- char b[]={1,3,9,2,17,4,11,6,5,20,100,64,21,14,79,35,92,7,91,23,65,16,13,18,18,73,65,101,27,19,62,69}; //定义数组,并对其赋值
- for(i=0;i<32;i++)
- {a[i]=b[i]; //将数组b中的值赋给数组a,即将要比较的32个数,存放到相应的地址
- }
- for(i=0;i<32;i++)
- {for(j=0;j<31-i;j++)
- {if(a[j]>a[j+1])
- {t=a[j];
- a[j]=a[j+1];
- a[j+1]=t; //先让a[0]与a[1]比较,然后将较大的数存到a[1]中,接着让a[1]与a[2]比较,较大的存到a[2]中,以此类推,比较结束,将32个数中最大的存到地址最高位,完成第一轮的比较,相似地,比较其余31个数,将其中最大的放到地址的第二高位
- }
- }
- }
- while(1);
- }</font></font></font>
复制代码
3.1基本并行I/O口实验 当按键SW1被按下后,D1~D8轮流点亮,点亮的时间为100ms;当按键停下后,停止轮换;再次按下后继续轮换 步骤: - 在Proteus环境下建立如图的原理图,并将其保存为“basicIO_self.DSN”文件。
- 编写控制源程序,将其保存为“basicIO_self.asm”。
- 将源程序添加到U1中,并构造该程序。
- 执行仿真过程,观察的D1~D8的指示,查看程序功能是否正确。
- 修改延时程序延时参数,重新执行该程序。
结果: 三、实验源程序
- ORG 0000H
- SJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H ;使SP指向地址单元60H
- MOV P2,#0FFH ;将P2口所有位设置为1,使P2口所接发光二极管全部熄灭
- MOV 20H,#0FEH ;使显示缓冲单元的值为11111110
- LOOP1:
- MOV A,P1 ;将P1的值存到寄存器A中
- RRC A ;A的带进位循环右移,即将A的最低位放入进位标志位中,标志位中的值放入A的最高位,实现查看P1.0位的功能
- JC LOOP1 ;如果进位不为0,则跳转至LOOP1
- MOV P2,20H ;如果进位不为0,则将显示缓冲单元20H中的值送给P2
- LOOP2:MOV R7,#200 ;令R7中的值为200
- LOOP3:MOV R6,#250 ;令R6中的值为250
- DJNZ R6,[ DISCUZ_CODE_9 ]nbsp; ;R6=R6-1,如果R6不为0,则执行$(原地踏步),如果为0,则顺序执行,以上两步维持时间为250*2*1us+1us
- DJNZ R7,LOOP3 ;R7=R7-1,如果R7不为0,则执行LOOP3,否则顺序执行,以上四步一共维持时间为(1us+250*2*1us+1us+2us)*200,约为100ms
- MOV A,20H ;将显示缓冲单元中的值存到寄存器A中
- RL A ;将A进行循环左移,即实现显示缓冲单元的值循环左移1位,
- MOV 20H,A ;将A中的值再送回至显示缓冲单元中
- JMP LOOP1 ;无条件跳转至LOOP1
- END
复制代码
3.2 扩展并行I/O口实验 一、实验要求 仿真实现交通信号灯控制功能。控制顺序如下:南北绿灯亮,同时东西红灯亮10s;南北黄灯亮,同时东西红灯亮2s;南北红灯亮,同时东西绿灯亮10s;东西黄灯亮,同时南北红灯亮2s;重复上述四种状态。 步骤: (1)在Proteus环境下建立如图的原理图,并将其保存为“expandIO_self.DSN”文件。 (2)编写控制源程序,将其保存为“expandIO_self.asm”。 (3)将源程序添加到U1中,并构造该程序。 (4)执行仿真过程,观察各个方向上的交通信号灯指示,查看程序功能是否正确。 结果: 三、实验源程序
- <font style="font-size: 14pt">ORG 0000H
- SJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H ;让SP指向地址单元60H
- MOV P0,#0FFH;令P0为11111111
- MOV P3,#40H;令P3为01000000
- MOV P2,#03H;令P2为00000011,以上三步使两个74LS373的输出端口所有位均为1,使所有发光二极管全部熄灭
- STAT1:
- MOV P3,#00H ; 令P3为00000000
- MOV P2,#02H ; 令P2为0000010,使U4工作,U5不工作
- MOV P0,#0F3H; 令P0为11110011 ,使东西红灯亮
- MOV P2,#01H ; 令P1为00000001 ,使U4不工作,U5工作
- MOV P0,#0CH ; 令P0为00001100 ,使南北绿灯亮
- MOV P2,#03H ; 令P2为00000011
- MOV P3,#40H ; 令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
- MOV R4,#10 ; 令R4的值为10
- DELAY1:MOV R7,#10;令R7的值为10
- LOOP11:MOV R6,#200;令R6的值为200
- LOOP12:MOV R5,#250;令R5的值为250
- DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
- DJNZ R6,LOOP12;R6=R6-1,如果R6不为0,则执行LOOP12,否则执行下面的程序
- DJNZ R7,LOOP11;R7=R7-1,如果R7不为0,则执行LOOP11,否则执行下面的程序
- DJNZ R4,DELAY1;R4=R4-1,如果R4不为0,则执行DELAY1,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*10,大约为10s
- STAT2:
- MOV P3,#00H; 令P3为00000000
- MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
- MOV P0,#0C3H;令P0为11000011 ,使东西红灯亮 ,南北黄灯亮
- MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
- MOV P0,#0FH;令P0为00001111 ,使东西南北绿灯灭
- MOV P2,#03H;令P2为00000011
- MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
- MOV R4,#2; 令R4的值为2
- DELAY2:MOV R7,#10;令R7的值为10
- LOOP21:MOV R6,#200;令R6的值为200
- LOOP22:MOV R5,#250;令R5的值为250
- DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
- DJNZ R6,LOOP22;R6=R6-1,如果R6不为0,则执行LOOP22,否则执行下面的程序
- DJNZ R7,LOOP21;R7=R7-1,如果R7不为0,则执行LOOP21,否则执行下面的程序
- DJNZ R4,DELAY2;R4=R4-1,如果R4不为0,则执行DELAY2,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*2,大约为2s
- STAT3:
- MOV P3,#00H;令P3为00000000
- MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
- MOV P0,#0FCH;令P0为11111100 ,使南北红灯亮
- MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
- MOV P0,#03H;令P0为00000011 ,使东西绿灯亮
- MOV P2,#03H;令P2为00000011
- MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
- MOV R4,#10;令R4的值为10
- DELAY3:MOV R7,#10;令R7的值为10
- LOOP31:MOV R6,#200;令R6的值为200
- LOOP32:MOV R5,#250;令R5的值为250
- DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
- DJNZ R6,LOOP32;R6=R6-1,如果R6不为0,则执行LOOP32,否则执行下面的程序
- DJNZ R7,LOOP31;R7=R7-1,如果R7不为0,则执行LOOP31,否则执行下面的程序
- DJNZ R4,DELAY3;R4=R4-1,如果R4不为0,则执行DELAY3,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*10,大约为10s
- STAT4:
- MOV P3,#00H;令P3为00000000
- MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
- MOV P0,#3CH;令P0为00111100 ,使东西黄灯亮,南北红灯亮
- MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
- MOV P0,#0FH;令P0为00001111 ,使东西绿灯灭
- MOV P2,#03H;令P2为00000011
- MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
- MOV R4,#2;令R4的值为2
- DELAY4:MOV R7,#10;令R7的值为10
- LOOP41:MOV R6,#200;令R6的值为200
- LOOP42:MOV R5,#250;令R5的值为250
- DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
- DJNZ R6,LOOP42;R6=R6-1,如果R6不为0,则执行LOOP42,否则执行下面的程序
- DJNZ R7,LOOP41;R7=R7-1,如果R7不为0,则执行LOOP41,否则执行下面的程序
- DJNZ R4,DELAY4;R4=R4-1,如果R4不为0,则执行DELAY4,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*2,大约为2s
- JMP STAT1;无条件跳转至STAT1
- END</font>
复制代码
3.3静态LED显示实验 7SEG2为十位显示数码管,7SEG1为个位显示数码管,KEY_LOAD为“倒计时初值”按钮,KEY_START为“倒计时启动”按钮。要实现的功能:当KEY_LOAD按钮被按下时,加载倒计时初值(如10s);当按下KEY_START按钮时,开始倒计时,每过1s,计时减1,直到减到“00”为止。减到“00”时,时P3.0引脚上的LED按10Hz频率闪烁,直到再次按下KEY_LOAD按钮,才重新加载初值,并熄灭LED。再次按下KEY_START按钮又一次开始倒计时,如此反复。 步骤: (1)在Proteus环境下建立如图的原理图,并将其保存为“staticLED_self.DSN”文件。 (2)编写控制源程序,将其保存为“staticLED_self.asm”。 (3)将源程序添加到U1中,并构造该程序。 (4)执行仿真过程,观察秒表程序功能是否正确。 结果: (1)按下KEY_LOAD加载倒计时初值。 三、实验源程序
- <font style="font-size: 14pt">ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H; 堆栈初始化
- MOV R0,#0 ;将0赋给R0,即表示初始值的个位
- MOV R1,#1; 将1赋给R1,即表示初始值的十位
- SETB P3.0; 关掉 LED1
- CLR F0 ;对标志位清零
- LOOP:
- JB P1.1,LOOP2; 如果 P1.1=1, 跳转到 LOOP2 ,
- LOOP1:
- CLR F0 ;对标志位清零
- MOV 30H,R0 ;将个位放在地址单元30H中
- MOV 31H,R1; 将十位放在地址单元31H中,以上两步实现装载初值的功能
- SETB P3.0; 关闭 LED1
- LCALL DISPLAY; 显示
- LOOP2:
- JB P1.0,LOOP; 如果 P1.0=1 ,跳回 LOOP ,否则继续执行
- LOOP3:
- LCALL DISPLAY; 刷新显示,显示就是将数字呈现在数码管上
- LCALL DELAY1S; 延时 1s
- LCALL ADJUST2; 调整计时器寄存器
- JB F0,LOOP4 ;计时器寄存器如果为1,则跳转至LOOP4
- LJMP LOOP3 ;否则长跳转至LOOP3
- LOOP4: ;LED闪烁子程序
- CLR P3.0 ;将P3.0清零,即LED 亮
- LCALL DELAY100MS;调用子程序DELAY100MS
- SETB P3.0; 关掉LED
- LCALL DELAY100MS;调用子程序DELAY100MS
- JB P1.1,LOOP4;如果P1.1为1,则跳转至LOOP4
- LJMP LOOP1
- DISPLAY: ; 显示子程序
- MOV A,30H ;将个位送至A中
- MOV DPTR,#TABLE
- MOVC A,@A+DPTR ;通过查表获得对应的数据
- MOV DPTR,#0FE00H ;将其数据送到U2的锁存地址中
- MOVX @DPTR,A ;把A的内容送到DPTR所指的外部地址
- MOV A,31H
- MOV DPTR,#TABLE
- MOVC A,@A+DPTR
- MOV DPTR,#0FD00H
- MOVX @DPTR,A ;同上,将对应数据送到U3的锁存地址中
- RET
- ADJUST2:
- DEC 30H ;将地址单元30H中的值自减1
- MOV A,30H ;将地址单元30H中的值送入寄存器A中
- CJNE A,#-1,GOTORET ;如果A中的值不为-1,则跳转至GOTORET,即返回主程序
- MOV 30H,#9 ;将9送入地址单元30H中
- DEC 31H ;将地址单元31H中的值自减1
- MOV A,31H ;将地址单元31H中的值送入寄存器A中
- CJNE A,#-1,GOTORET ;如果A中的值不为-1,则跳转至GOTORET,即返回主程序
- SETB F0; 将用户标志位置1
- RET
- GOTORET:
- RET
- DELAY1S:MOV R7,#10
- DL2:MOV R6,#200
- DL1:MOV R5,#250
- DJNZ R5,$
- DJNZ R6,DL1
- DJNZ R7,DL2 ;实现延时,延时时间为((1+2*250+2)*200+2)*10,大约为1s
- RET
- DELAY100MS:MOV R7,#200
- DL:MOV R6,#250
- DJNZ R6,$
- DJNZ R7,DL;实现延时,延时时间为((1+250*2)+2)*200,大约为0.1s,即使P3.0引脚上的LED按10Hz频率闪烁
- RET
- TABLE: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
- END</font>
复制代码
3.4矩阵键盘扫描实验 D1~D8八个发光二极管构成彩色旋灯,D9~D13为挡位指示灯,1挡旋转速度最慢(周期为1s,D13亮),2挡较快(周期为0.8s,D12亮),3挡更快(周期为0.6s,D11亮),4挡较快(周期为0.4s,D10亮),5挡较快(周期为0.2s,D9亮)。按键KEY_0~KEY1用于设定旋转方向为顺时针或者逆时针旋转,KEY_2~KEY_3用于加快或者减慢旋转速度。 步骤: (1)在Proteus环境下建立如图的原理图,并将其保存为“keyscan_self.DSN”文件。 (2)编写控制源程序,将其保存为“keyscan_self.asm”。 (3)将源程序添加到U1中,并构造该程序。 (4)执行仿真过程,观察程序功能是否正确。 结果: 按下按键KEY_0时,D1~D8顺时针旋转,按下按键KEY1时,D1~D8逆时针旋转,按下按键KEY_2或KEY_3,分别是加速与减速。 三、实验源程序
- <font style="font-size: 14pt">ORG 0000H
- AJMP MAIN
- ORG 0030H
- MAIN:
- MOV SP,#60H;使SP指向地址单元60H
- MOV P0,#0FFH;使P0为11111111,即所有的彩色旋转灯都不亮
- MOV P1,#0FFH;使P1为11111111,即所有的挡位灯都不亮
- MOV R7,#10;令R7的值为10
- MOV R4,#0EFH;令R4的值为0EFH
- LCALL LOOP;调用子程序SCAN
- JMP MAIN;无条件跳转至MAIN
- BUTTON0:
- MOV 30H,#0H;将0放入地址单元30H
- MOV P1,#0FEH;令P1为11111110,即让D1亮
- JMP ZHUAN1;无条件跳转至ZHUAN1,来实现彩色旋转灯的顺时针旋转
- BUTTON1:
- MOV 30H,#1H;将1放入地址单元30H
- MOV P1,#0FEH;令P1为11111110,即让D1亮
- JMP ZHUAN2;无条件跳转至ZHUAN2,来实现彩色旋转灯的逆时针旋转
- BUTTON2:
- DEC R7;R7自减1
- DEC R7;R7自减1
- MOV A,R4;将R4的值存到寄存器A中
- RR A;将A中的值进行不带进位的循环右移
- MOV R4,A;将A中的值送回R4中
- MOV A,30H;将地址单元30H中的值赋给A
- JZ ZHUAN1;如果ZF=1(即A中的值为0),则跳转至ZHUAN1
- JMP ZHUAN2;否则跳转至ZHUAN2
- BUTTON3:
- INC R7;R7自增1
- INC R7;R7自增1
- MOV A,R4;将R4中的值存到A中
- RL A;将A中的值进行不带进位的循环左移
- MOV R4,A;将A中的值送回至R4中
- MOV A,30H;将地址单元30H中的值存到A中
- JZ ZHUAN1;如果ZF=1(即A中的值为0),则跳转至ZHUAN1
- JMP ZHUAN2;否则跳转至ZHUAN1
- ZHUAN1:
- MOV P0,R4;将R4中的值送到P0,用来变换挡位指示灯
- LCALL DLS;长调用DLS
- MOV A,P1;将P1中的值存到A中
- RL A;将A进行不带进位的循环左移
- MOV P1,A;将A中的值送回至P1中
- LCALL SCAN;长调用子程序SCAN
- JMP ZHUAN1;无条件跳转至ZHUAN1
- ZHUAN2:
- MOV P0,R4;将R4中的值送到P0,用来变换挡位指示灯
- LCALL DLS;长调用DLS
- MOV A,P1;将P1中的值存到A中
- RR A;将A进行不带进位的循环左移
- MOV P1,A;将A中的值送回至P1中
- LCALL LOOP;长调用子程序SCAN
- JMP ZHUAN2;无条件跳转至ZHUAN2
- DLS:
- MOV A,R7;将R7中的值存到寄存器A中
- DL2:MOV R6,#200;令R6的值为200
- DL1:MOV R5,#250;令R5的值为250
- DL0:
- DJNZ R5,DL0;R5=R5-1,如果R5不为0,则跳转至DL0,否则顺序执行
- DJNZ R6,DL1;R6=R6-1,如果R6不为0,则跳转至DL1,否则顺序执行
- DJNZ R7,DL2;R7=R7-1,如果R7不为0,则跳转至DL2,否则顺序执行,实现延时,延时时间为((1+250*2+2)*200+2)*R7
- MOV R7,A;将A中的值送回至R7
- RET;
- LOOP:
- MOV P3,#030H;令P3为00110000,使开关闭合时能实现对应的功能
- JNB P3.4,NEXT1;如果P3.4为低电平(KEY0或KEY2闭合),则跳转至NEXT1,否则顺序执行
- JNB P3.5,NEXT2;如果P3.5为低电平(KEY1或KEY3闭合),则跳转至NEXT2,否则顺序执行
- JMP TORET;无条件跳转至TORET,即返回源程序
- NEXT1:
- MOV P3,#3H;令P3为00000011
- JNB P3.0,BUTTON0;如果P3.0为低电平(KEY0闭合),则跳转至BUTTON0,否则顺序执行
- JNB P3.1,BUTTON2;如果P3.1为低电平(KEY2闭合),则跳转至BUTTON2,否则顺序执行
- JMP TORET;无条件跳转至TORET,即返回源程序
- NEXT2:
- MOV P3,#3H;令P3为00000011
- JNB P3.0,BUTTON1;如果P3.0为低电平(KEY1闭合),则跳转至BUTTON1,否则顺序执行
- JNB P3.1,BUTTON3;如果P3.1为低电平(KEY3闭合),则跳转至BUTTON3,否则顺序执行
- TORET:
- RET
- END</font>
复制代码
3.7 LCD 1602显示实验 一、实验要求 利用LCD 1602和16个按键实现简单的十进制的加减乘除四则混合运算。其中按键KEY_0~KEY_9分别代表数字0~9;按键KEY_10~KEY_13分别代表运算符“+”“-”“*”“/”;按键KEY15代表“=”;按键KEY_14代表清楚命令,以便进行下一次的输入和计算。不管什么时候按下“清除”按键,计算过程均将停止,两个输入变量都将清0,屏幕将清屏。LCD 1602的第一行用于显示所输入的两个计算数以及计算符,第二行用于显示计算结果。结果允许为负数,但输入的两个输入数都必须是双字节正整数范围内的数,即0~32767。除数必须保证不为0,否则将报错。在有余数除法中,必须能同时显示商与余数。 步骤: (1)在Proteus环境下建立如图的原理图,并将其保存为“LCD1602_self.DSN”文件。 (2)编写控制源程序,将其保存为“LCD1602_self.c”。 (3)运行Keil u Vision2,建立工程“LCD1602_self.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (4)将编写好的程序加入工程“LCD1602_self.uV2”,并设置工程“LCD1602.uV2”的属性,将其晶振频率设置为12MHz,选择输出的可执行文件,仿真方式为“选择硬仿真”,并选择其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)构造(Build)工程“LCD1602_self.uV2”。如果输入有误,则进行修改,直至构造正确,生成可执行程序“LCD1602_self.hex”为止。 - 为AT89C51设置可执行程序“LCD1602_self.hex”。
- 运行程序,单击按键输入数据与运算符,计算,观察计算结果,并验证其是否正确。
- 输入过程中,按“清除”按键观察结果,重新输入数据计算并验证。
结果: (1)加法 (2)减法 (3)乘法 (4)除法 (5)报错 三、实验源程序
- <font style="font-size: 14pt">#include<reg51.h>
- #define uint unsigned int
- #define uchar unsigned char
-
- sbit lcden=P1^5;//使能信号
- sbit rs=P1^7;//数据命令选择
- sbit rw=P1^6;//读写选择
- sbit busy=P2^7;
-
- char i,j,temp,num;
- long a,b,c,d;
- float a_c,b_c;
- uchar flag,fuhao;//flag
-
- uchar code table[]={
- 0,1,2,3,
- 4,5,6,7,
- 8,9,0,0,
- 0,0,0,0};
- uchar code table1[]={
- 0,1,2,3,
- 4,5,6,7,
- 8,9,0x2b-0x30,0x2d-0x30,
- 0x2a-0x30,0x2f-0x30,0x01-0x30,0x3d-0x30};//按键对应的符号
- uchar code table2[]="!rorrE";
-
- void delay(uchar z) // 延迟函数
- {
- uchar i,t;
- for(i=0;i<z;i++)
- for(t=0;t<120;t++);
- }
-
- void check() // 判断忙或空闲
- {
- do
- {
- P2=0xFF;
- rs=0; //指令
- rw=1; //读
- lcden=0; //禁止读写n
- delay(1); //等待,液晶显示器处理数据
- lcden=1; //允许读写
- }
- while(busy==1); //判断是否为空闲,1为忙,0为空闲
- }
-
- void write_com(uchar com) // 写指令函数
- {
- P2=com; //com指令付给P0口
- rs=0;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void write_date(uchar date) // 写数据函数
- {
- P2=date;
- rs=1;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void init() //初始化
- {
- num=-1;
- lcden=1; //使能信号为高电平
- write_com(0x38); //8位,2行
- write_com(0x0c); //显示开,光标关,不闪烁*/
- write_com(0x06); //增量方式不移位
- write_com(0x80); //检测忙信号
- write_com(0x01); //清屏指令
- i=0;
- j=0;
- a=0; //第一个参与运算的数
- b=0; //第二个参与运算的数
- c=0;
- d=0;
- flag=0; //flag表示是否有符号键按下,
- fuhao=0; // fuhao表征按下的是哪个符号
- }
-
- void keyscan() // 键盘扫描程序
- {
- P3=0xfe;
- if(P3!=0xfe)
- {
- delay(20);
- if(P3!=0xfe)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=0;
- break;
- case 0xd0:num=1;
- break;
- case 0xb0:num=2;
- break;
- case 0x70:num=3;
- break;
- }
- }
- while(P3!=0xfe);
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- i=table1[num];
- write_date(0x30+i);//写入按键对应的 符号
- }
-
- P3=0xfd;
- if(P3!=0xfd)
- {
- delay(5);
- if(P3!=0xfd)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=4;
- break;
-
- case 0xd0:num=5;
- break;
-
- case 0xb0:num=6;
- break;
-
- case 0x70:num=7;
- break;
- }
- }
- while(P3!=0xfd);
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfb;
- if(P3!=0xfb)
- {
- delay(5);
- if(P3!=0xfb)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=8;
- break;
-
- case 0xd0:num=9;
- break;
-
- case 0xb0:num=10;
- break;
-
- case 0x70:num=11;
- break;
- }
- }
- while(P3!=0xfb);
- if(num==8||num==9)//如果按下的是'8','9'
- {
- if(flag==0)//没有按过符号键
- {
- a=a*10+table[num];
- }
- else//如果按过符号键
- {
- b=b*10+table[num];
- }
- }
- else if(num==10)//如果按下的是'+'
- {
- flag=1;
- fuhao=1;//1表示加号已按
- }
- else if(num==11)//如果按下的是'-'
- {
- flag=1;
- fuhao=2;//2表示减号已按6
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xf7;
- if(P3!=0xf7)
- {
- delay(5);
- if(P3!=0xf7)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=12;
- break;
-
- case 0xd0:num=13;
- break;
-
- case 0xb0:num=14;
- break;
-
- case 0x70:num=15;
- break;
- }
- }
- while(P3!=0xf7);
- switch(num)
- {
- case 12:{write_date(0x30+table1[num]); flag=1;fuhao=3;}
- break;
- case 13:{write_date(0x30+table1[num]); flag=1;fuhao=4;}
- break;
- case 14:{write_com(0x01);i=0;j=0;a=0;b=0;c=0;d=0;flag=0;fuhao=0;}//按下的是"清零"
- break;
- case 15:{
- j=1;
-
- if(fuhao==1){write_com(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处
- write_com(0x04); //写入数据后地址加1 ,从右向左写入数据
- c=a+b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d); //再写"="
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==2){write_com(0x80+0x4f);//光标前进至第二行最后一个显示处
- write_com(0x04); //设置从后住前写数据,每写完一个数据,光标后退一格)
- if(a-b>0)
- c=a-b;
- else
- c=b-a;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a-b<0)
- write_date(0x2d); //写’-‘
- write_date(0x3d); //再写"="
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==3)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
-
- else if(fuhao==4)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- if(b==0)
- {
- i=0;
- while(table2[i]!='\0')
- {
- write_date(table2[i]);
- i++;
- }//若除数为0,输出Error!
- a=0;b=0;flag=0;fuhao=0;
- }
- else if((a%b==0)&&(b!=0))
- {
- c=a/b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- else if((a%b!=0)&&(b!=0))
- {
- d=a%b;
- while(d!=0)
- {
- write_date(0x30+d%10);
- d=d/10;
- }//若不能整除,输出余数
- write_date(0x2e);
- write_date(0x2e);
- write_date(0x2e);//输出“...“
- c=a/b;//输出整除结果
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- }
- }
- break;
- }
- }
- }
-
- main()
- {
- init();//初始化
- while(1)
- {
- keyscan();//键盘扫描
- }
- }</font>
复制代码
3.8 ADC0808/9信号采集实验 一、实验要求 利用LCD1602和AD0808实现简单的交流信号过零检测与频率分析。要求信号幅度变化时,比影响检测结果。频率检测的结果通过LCD1602的第1行显示出来,信号过零时,能够通过P2.6输出一个脉冲宽度为5us的脉冲信号。电位器RV1用于改变交流信号的幅值。交流信号通过单击窗口左侧绘图工具窗口中的“虚拟信号发生器”按钮,然后在器件窗口中选择正弦信号(SINE)实现。 二、实验过程及结果记录 步骤: (1)在Proteus环境下建立如图的原理图,并将其保存为“ADC0808_self.DSN”文件。 (2)编写控制源程序,将其保存为“ADC0808_self.c”。 (3)运行Keil u Vision2,建立工程“ADC0808_self.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (4)将编写好的程序加入工程“ADC0808_self.uV2”,并设置工程“ADC0808.uV2”的属性,将其晶振频率设置为12MHz,选择输出的可执行文件,仿真方式为“选择硬仿真”,并选择其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)构造(Build)工程“ADC0808_self.uV2”。如果输入有误,则进行修改,直至构造正确,生成可执行程序“ADC0808_self.hex”为止。 (6)为AT89C51设置可执行程序“ADC0808_self.hex”。 (7)运行程序,观察计算结果,并验证其是否正确。 (8)改变RV1的抽头位置,从而改变输入信号的幅值,观察计算结果是否正确。 (9)更改信号发射器的频率,再次验证其功能是否正确。 结果: 三、实验源程序
4.1 按键声光报警实验 一、实验要求 利用外部硬件中断,按下一次按键产生一次外部中断,在中断服务程序中计数器加1,同时通过发光二极管的闪烁和蜂鸣器响的次数,指示计数器的当前值。当计数到10时,再次按键将重新从1开始计。 二、实验过程及结果记录 步骤: - 关掉实验箱电源,将MCU板插接在母版上,将硬件连接好
- 在仿真器断电情况下将仿真器的仿真头插在MCU板的CPU插座上。将仿真器与PC机的通信口连接好,打开实验箱及仿真器的电源。
(3)运行Keil u Vision2,建立工程“int0_c.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (4)将编写好的程序加入工程“int0_c.uV2”,并设置工程“int0_c.uV2”的属性,将其晶振频率设置为11.0592MHz,选择输出的可执行文件,仿真方式为“选择硬仿真”,并选择其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)构造(Build)工程“int0_c.uV2”。如果输入有误,则进行修改,直至构造正确。 (6)运行程序,按下MCU板上的KEY0按键,观察每次按键按下时主板上的发光二极管的闪烁和蜂鸣器响的次数,是否符合程序要求,分析出错原因,继续执行(4)(5),直至结果正确。 结果: 老师实验室验证 三、实验源程序
- <font style="font-size: 14pt">#include<reg52.h>
- #define uint unsigned int
- #define uchar unsigned char
- sbit bell=P3^1; // 用 p3.1 口控制 bell
- sbit led=P3^0; // 用 P3^0 来控制 led
- sbit key0=P3^2; // 报警的键
- uint count; // 定义一个无符号整形数 ,
- 用来计数
- /******************************************************************/
- void delay(uint count) // 延时 1ms
- {
- uint x,y;
- for(x=count;x>0;x--)
- for(y=110;y>0;y--);
- }
- /******************************************************************/
- void show(uint count) // 使铃铛响,使灯亮的
- 函数
- { uint i;
- for(i=0;i<=count;i++) // 函数循环 i 次
- led=0;bell=0; // 灯亮,铃响
- delay(500); // 延时 0.5s
- led=1;bell=1; // 灯灭,铃停
- delay(500); // 延时 500ms
- }
- }
- /***********************************************************/
- Void s_timer0() interrupt 0 using 0 // 中断 0
- {
- EA=0; // 屏蔽其他中断请求
- show(count); // 调用子程序
- count++;
- delay(50);
- if(count>=10) // 若 count 为十则结
- 束
- count=0;
- EA=1; // 开放中断
- }
- /************************** 主程序 **********************************/
- void main()
- { EA=1; // 开放中断
- EX0=1; // 允许外部中断 0 中断
- IT0=0; // 外部中断 0 为电平触发方式
- while(1); // 循环执行,等待循环
- }</font>
复制代码
4.5 8255并行I/O扩展及交通信号灯控制实验 一、实验要求 利用8255实现可编程的并行I/O扩展功能,并完成交通灯控制。实验要求每个方向红灯亮30s,然后绿灯亮25s,再闪烁绿灯5s。使用静态数码管显示绿灯亮倒计时。 二、实验过程及结果记录 步骤: (1)关掉实验箱电源,将MCU板、PIO板、KEY&LED板插接在母版上,将硬件连接好 (2)在仿真器断电情况下将仿真器的仿真头插在MCU板的CPU插座上。将仿真器与PC机的通信口连接好,打开实验箱及仿真器的电源。 (3)运行Keil u Vision2,建立工程“PIO8255_traffic_c.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (4)将编写好的程序加入工程“PIO8255_traffic_c.uV2”,并设置工程“PIO8255_traffic_c.uV2”的属性,将其晶振频率设置为11.0592MHz,选择输出的可执行文件,仿真方式为“选择硬仿真”,并选择其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)构造(Build)工程“PIO8255_traffic_c.uV2”。如果输入有误,则进行修改,直至构造正确。 (6)运行程序,观察交通灯的状态转换以及倒计时器的显示是否符合程序要求。若不符合,分析出错原因,继续执行(4)(5),直至结果正确。 结果: 老师实验室验证 三、实验源程序
- <font style="font-size: 14pt">#include <reg52.h>
- #include <absacc.h>
- #define PA XBYTE[0x7FFC] //CS--A15
- #define COM XBYTE[0x7FFF]
- /***************************************************************************/
- void init_8255(void)
- {
- COM=0x80; // c = out, a = out,b = out
- }
- /***************************************************************************/
- void Uart_Init(void)
- {
- SCON = 0x10; //SCON:工作模式 0
- PCON = 0x00;
- TI = RI = 0;
- IE = 0x90;
- EA = 0;
- }
- ***********************************************************
- void Uart_Out(unsigned char DA T) //74LS164 的串转并
- {
- TI = 0;
- SBUF = ~DAT; }
- ***************************************************************************
- void delay_ms(unsigned int ms) //延时 1ms 程序
- {
- int j;
- for(;ms!=0; ms--)
- for (j=0;j<125;j++)
- {
- }
- }
- ********************************************************
- int main(void)
- {
- signed char i;
- init_8255();
- Uart_Init();
- while(1)
- {
- PA = 0x96; //东西绿灯亮
- for(i = 25;i >= 0;i--) // 延时 25s
- {
- Uart_Out(~(((i/10)<<4) | (i%10)));
- delay_ms(1000);
- }
- for(i = 5;i > 0;i--) //5s
- {
- PA = 0xBE;
- delay_ms(500);
- PA = 0x96;
- delay_ms(500);
- }
- PA = 0x69; //南北绿灯亮
- for(i = 25;i >= 0;i--) // 延时 25s
- {
- Uart_Out(~(((i/10)<<4) | (i%10)));
- delay_ms(1000);
- }
- for(i = 5;i > 0;i--) //5s
- {
- PA = 0xEB;
- delay_ms(500);
- PA = 0x69;
- delay_ms(500);
- }
- }
- }</font>
复制代码
4.7 7279键盘/动态LED显示实验 一、实验要求 利用7279进行键盘扫描及动态LED数码管的显示控制。当按下某个键时,所按按键对应的字符显示在最右端LED数码管上;再次按下一个按键,则原来显示的内容往左移1位,新按下的字符显示在最右端;当6位LED均显示已满时,再次按下新的按键,则原来显示的内容同样都左移1位,最后1位显示新按按键的字符。 二、实验过程及结果记录 步骤: (1)关掉实验箱电源,将MCU板、KEY&LED板插接在母版上,将硬件连接好 (2)在仿真器断电情况下将仿真器的仿真头插在MCU板的CPU插座上。将仿真器与PC机的通信口连接好,打开实验箱及仿真器的电源。 (3)运行Keil u Vision2,建立工程“HD7279_c.uV2”,CPU为AT89C51,包含启动文件“STARTUP.A51”。 (4)将编写好的程序加入工程“HD7279_c.uV2”,并设置工程“HD7279_c.uV2”的属性,将其晶振频率设置为11.0592MHz,选择输出的可执行文件,仿真方式为“选择硬仿真”,并选择其中的“PROTEUS VSM MONITOR 51 DEIVER”仿真器。 (5)构造(Build)工程“HD7279_c.uV2”。如果输入有误,则进行修改,直至构造正确。 (6)运行程序,观察结果是否符合程序要求。若不符合,分析出错原因,继续执行(4)(5),直至结果正确。 结果: 老师实验室验证 三、实验源程序
- <font style="font-size: 14pt">#include <reg51.h>
- //*** 函数定义 ***
- void long_delay(void); // 长延时
- void short_delay(void); // 短暂延时
- void delay10ms(unsigned char); // 延时 10MS
- void write7279(unsigned char, unsigned char); // 写入到 HD7279
- unsigned char read7279(unsigned char); // 从 HD7279 读出
- void send_byte(unsigned char); // 发送一个字节
- #define uchar unsigned char
- #define uint unsigned int
- uchar
- bianma[]={0x1b,0x13,0x0b,0x03,0x1a,0x12,0x0a,0x02,0x19,0x11,0x09,0x01,0x18,0x10,0x08,0x00};
- unsigned char receive_byte(void); // 接收一个字节
- //*** 变量及 I/O 口定义 ***
- unsigned char digit[5];
- unsigned char key_number, j, k,mk; //mk 为按键次数计数值
- unsigned int tmr;
- unsigned long wait_cnter;
- sbit cs=P1^0; // cs at P1.0
- sbit clk=P1^1; // clk 连接于 P1.1
- sbit dat=P1^2; // dat 连接于 P1.2
- sbit key=P1^3; // key 连接于 P1.3
- void write7279(unsigned char cmd, unsigned char dta)
- {
- send_byte (cmd);
- send_byte (dta);
- }
- unsigned char read7279(unsigned char command)
- {
- send_byte(command);
- return(receive_byte());
- }
- void send_byte( unsigned char out_byte)
- {
- unsigned char i;
- cs=0;//芯片使能
- long_delay();
- for (i=0;i<8;i++) // 分 8 次移入数据
- {
- if (out_byte&0x80)// 先传高位
- {
- dat=1;
- }
- else
- {
- dat=0;
- }
- clk=1;
- short_delay();
- clk=0;
- short_delay();
- out_byte=out_byte*2;// 数据左移
- }
- dat=0;
- }
- unsigned char receive_byte(void)
- {
- unsigned char i, in_byte;
- dat=1; // set to input mode
- long_delay();
- for (i=0;i<8;i++)// 分 8 次读入数据高位在前
- {
- clk=1;
- short_delay();
- in_byte=in_byte*2; // 数据左移
- if (dat)
- {
- in_byte=in_byte|0x01;
- }
- clk=0;
- short_delay();
- }
- dat=0;
- return (in_byte);
- 12
- }
- void long_delay(void)
- {
- unsigned char i;
- for (i=0;i<0x30;i++);
- }
- void short_delay(void)
- {
- unsigned char i;
- for (i=0;i<8;i++);
- }
- void main(){
- uchar jianpan,i,num;
- send_byte(0xa4); //全部复位指令
- while(1){
- if(key==0){ //如果按键按下
- send_byte(0x15); //读键盘指令
- jianpan=receive_byte(); //接收键盘数据
- // P0=num;
- for(i=0;i<16;i++){
- if(jianpan==bianma[i]){ // 等于判断一定是双等于号
- num=i;
- break;
- }
- }
- send_byte(0xa1);
- write7279(0xc8,num);
- while(key==0);
- }
- } }</font>
复制代码
完整的Word格式文档51黑下载地址:
单片机实验报告.docx
(325.27 KB, 下载次数: 9)
|