找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5824|回复: 0
打印 上一主题 下一主题
收起左侧

单片机原理与应用实验报告下载,欢迎参考

[复制链接]
跳转到指定楼层
楼主
ID:421903 发表于 2018-11-6 18:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

单片机原理与应用实验报告

姓名xxx

学号xxxxxxxx

实验时间5月28日~6月11日

2.2 汇编程序实验2

一、实验要求

片内RAM 30H开始的32个单元中分布着随机的有符号8位二进制数,按从小到大的顺序进行排序,排序后的数据仍然保存到30H开始的32个单元中(低地址存放小数据)

  • 实验过程及结果记录

步骤:

  • 编写汇编语言并加上相应注释(注意扩展名为“*.asm”),将其保存。
  • 运行Keil u Vision2,建立工程“simlab2.uV2,CPUAT89C51,不用包含启动文件“STARTUP.A51”。
  • 将编写好的程序加入工程“simlab2.uV2,并设置工程“simlab2.uV2”的属性,将其晶振频率设置为12MHz,选择输出的可执行文件,仿真方式为“Use Simulator”。
  • 构造(Build)工程“simlab2.uV2”。如果输入有误,则进行修改,直至构造正确,生成可执行程序“simlab2.hex”为止。
  • 运行程序,并用存储器观察窗口观察内部RAM30H~4FH单元排序前后的数值。

结果:

由上图可知,32个数从30H开始由小到大排列

三、实验源程序


  1. ORG 0000H
  2. AJMP MAIN
  3. ORG 0030H
  4. MAIN:
  5.    MOV R0,#20H         ;R0用于存放数据时计数
  6.    MOV R1,#30H         ;R1指向30H地址单元
  7.    MOV DPTR,#TABLE     ;使DPTR指向表首
  8.    MOV R2,#00H        
  9.    MOV A,R2            ;给偏移地址赋初值,为0
  10. LOOP1:
  11.    MOVC A,@A+DPTR      ;取出表中的数据
  12.    MOV @R1,A           ;将表中的数据存入30H单元
  13.    INC R1              ;R1自增1,指向下一个单元
  14.    INC R2            
  15.    MOV A,R2            ;R2自增1,从而使偏移量增1
  16.    DJNZ R0,LOOP1       ;R0=R0-1,如果R0不为0,则再次从LOOP1处执行,将表中数据存入对应的单元;如果R0=0,则表示表中数据已经全部存入30H~4FH单元中
  17.    MOV R7,#1FH         ;将遍历次数31送入R7中
  18. LOOP2:
  19.    MOV A,R7           
  20.    MOV R6,A          ;将比较次数寄存器R6的值设定为R7的值
  21.    ADD A,#30H
  22.    MOV R0,A      ;将最大值为位置寄存器R0的值设定为#30H+R7
  23.    MOV R1,#30H         ;将R1指向30H单元
  24.    MOV B,@R1          ;取R1指向的单元的值到最大值寄存器B
  25. LOOP3:
  26.    CLR C              ;将C清零
  27.    INC R1             ;R1自增1        
  28.    MOV A,@R1         ;将R1所指向单元中的值赋给A
  29.    MOV R5,A          ;将A中的值赋给R5,作为备份
  30.    SUBB A,B           ;A=A-B
  31.    JC LOOP4         ;如果存在借位,即A<B,则跳转至LOOP4
  32.    MOV A,R1
  33.    MOV R0,A          ;如果A>B,将R1中的值赋给R0,使其始终保持最大值
  34.    MOV A,R5          ;恢复A的值
  35.    MOV B,A          ;使最大值寄存器B的值为A中的值
  36. LOOP4:
  37.    DJNZ R6,LOOP3     ;R6=R6-1,如果R6为0,表示这一轮的比较已经完成,否则再次执行LOOP3,继续进行比较
  38.    MOV A,B            ;如果这一轮比较完成,则将最大值寄存器B的值赋给A
  39.    XCH A,@R1        ;交换A和R1中的值,即将最大值存放到这一轮比较的最后的位置
  40.    MOV @R0,A       ;将A中的值赋给R0所指的单元,以上两步完成将最大值存到最后一位,最后一位的值存到原本最大值所在的位置
  41.    DJNZ R7,LOOP2    ;判断外循环是否完成,若未完成跳转至LOOP2,继续执行外循环      
  42. TABLE:
  43.    DB 1,3,9,2,17,4,11,6
  44.    DB 5,20,100,64,21,14,79,35
  45.    DB 92,7,91,23,65,16,13,18
  46.    DB 18,73,65,101,27,19,62,69
  47. SJMP $
  48. 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由小到大排列

三、实验源程序


  1. <font color="rgb(0, 0, 0)"><font face="Calibri"><font style="font-size: 14pt">#include <reg51.h>
  2. #include<stdio.h>
  3. #define uchar unsigned char
  4. #define uint unsigned int   //头文件
  5. uchar data a[32] _at_ 0x30;  //设定数组a的起始地址为30H
  6. uint i _at_ 0x55;
  7. uint j _at_ 0x56;
  8. uint t _at_ 0x57;           //以上三句表示将变量i,j,t分别放入地址55H,56H,57H
  9. void main()
  10. {
  11. char i,j,t;                //定义变量i,j,t
  12. 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};        //定义数组,并对其赋值
  13. for(i=0;i<32;i++)
  14. {a[i]=b[i];                //将数组b中的值赋给数组a,即将要比较的32个数,存放到相应的地址
  15. }
  16. for(i=0;i<32;i++)
  17. {for(j=0;j<31-i;j++)
  18. {if(a[j]>a[j+1])
  19.   {t=a[j];
  20.    a[j]=a[j+1];
  21.    a[j+1]=t;             //先让a[0]与a[1]比较,然后将较大的数存到a[1]中,接着让a[1]与a[2]比较,较大的存到a[2]中,以此类推,比较结束,将32个数中最大的存到地址最高位,完成第一轮的比较,相似地,比较其余31个数,将其中最大的放到地址的第二高位
  22. }
  23. }
  24. }
  25. while(1);
  26. }</font></font></font>
复制代码


3.1基本并行I/O口实验

  • 实验要求

当按键SW1被按下后,D1~D8轮流点亮,点亮的时间为100ms;当按键停下后,停止轮换;再次按下后继续轮换

  • 实验过程及结果记录

步骤:

  • Proteus环境下建立如图的原理图,并将其保存为“basicIO_self.DSN”文件。
  • 编写控制源程序,将其保存为“basicIO_self.asm”。
  • 将源程序添加到U1中,并构造该程序。
  • 执行仿真过程,观察的D1~D8的指示,查看程序功能是否正确。
  • 修改延时程序延时参数,重新执行该程序。

结果:

三、实验源程序


  1. ORG 0000H
  2. SJMP MAIN
  3. ORG 0030H
  4. MAIN:
  5. MOV SP,#60H        ;使SP指向地址单元60H
  6. MOV P2,#0FFH       ;将P2口所有位设置为1,使P2口所接发光二极管全部熄灭
  7. MOV 20H,#0FEH      ;使显示缓冲单元的值为11111110
  8. LOOP1:
  9. MOV A,P1           ;将P1的值存到寄存器A中
  10. RRC A              ;A的带进位循环右移,即将A的最低位放入进位标志位中,标志位中的值放入A的最高位,实现查看P1.0位的功能
  11. JC LOOP1             ;如果进位不为0,则跳转至LOOP1
  12. MOV P2,20H         ;如果进位不为0,则将显示缓冲单元20H中的值送给P2
  13. LOOP2:MOV R7,#200   ;令R7中的值为200
  14. LOOP3:MOV R6,#250  ;令R6中的值为250
  15. DJNZ R6,[        DISCUZ_CODE_9        ]nbsp;           ;R6=R6-1,如果R6不为0,则执行$(原地踏步),如果为0,则顺序执行,以上两步维持时间为250*2*1us+1us
  16. DJNZ R7,LOOP3      ;R7=R7-1,如果R7不为0,则执行LOOP3,否则顺序执行,以上四步一共维持时间为(1us+250*2*1us+1us+2us)*200,约为100ms
  17. MOV A,20H          ;将显示缓冲单元中的值存到寄存器A中
  18. RL A                ;将A进行循环左移,即实现显示缓冲单元的值循环左移1位,
  19. MOV 20H,A          ;将A中的值再送回至显示缓冲单元中
  20. JMP LOOP1           ;无条件跳转至LOOP1
  21. END
复制代码

3.2 扩展并行I/O口实验

一、实验要求

仿真实现交通信号灯控制功能。控制顺序如下:南北绿灯亮,同时东西红灯亮10s;南北黄灯亮,同时东西红灯亮2s;南北红灯亮,同时东西绿灯亮10s;东西黄灯亮,同时南北红灯亮2s;重复上述四种状态。

  • 实验过程及结果记录

步骤:

(1)在Proteus环境下建立如图的原理图,并将其保存为“expandIO_self.DSN”文件。

(2)编写控制源程序,将其保存为“expandIO_self.asm”。

(3)将源程序添加到U1中,并构造该程序。

(4)执行仿真过程,观察各个方向上的交通信号灯指示,查看程序功能是否正确。

结果:

三、实验源程序


  1. <font style="font-size: 14pt">ORG 0000H
  2. SJMP MAIN
  3. ORG 0030H
  4. MAIN:
  5. MOV SP,#60H ;让SP指向地址单元60H
  6. MOV P0,#0FFH;令P0为11111111
  7. MOV P3,#40H;令P3为01000000
  8. MOV P2,#03H;令P2为00000011,以上三步使两个74LS373的输出端口所有位均为1,使所有发光二极管全部熄灭
  9. STAT1:
  10. MOV P3,#00H ; 令P3为00000000   
  11. MOV P2,#02H ;   令P2为0000010,使U4工作,U5不工作
  12. MOV P0,#0F3H;  令P0为11110011 ,使东西红灯亮  
  13. MOV P2,#01H ; 令P1为00000001 ,使U4不工作,U5工作
  14. MOV P0,#0CH ;  令P0为00001100 ,使南北绿灯亮  
  15. MOV P2,#03H ;  令P2为00000011   
  16. MOV P3,#40H ; 令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
  17. MOV R4,#10  ;  令R4的值为10     
  18. DELAY1:MOV R7,#10;令R7的值为10
  19. LOOP11:MOV R6,#200;令R6的值为200
  20. LOOP12:MOV R5,#250;令R5的值为250
  21. DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
  22. DJNZ R6,LOOP12;R6=R6-1,如果R6不为0,则执行LOOP12,否则执行下面的程序
  23. DJNZ R7,LOOP11;R7=R7-1,如果R7不为0,则执行LOOP11,否则执行下面的程序
  24. DJNZ R4,DELAY1;R4=R4-1,如果R4不为0,则执行DELAY1,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*10,大约为10s
  25. STAT2:
  26. MOV P3,#00H; 令P3为00000000
  27. MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
  28. MOV P0,#0C3H;令P0为11000011 ,使东西红灯亮 ,南北黄灯亮
  29. MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
  30. MOV P0,#0FH;令P0为00001111 ,使东西南北绿灯灭
  31. MOV P2,#03H;令P2为00000011
  32. MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
  33. MOV R4,#2; 令R4的值为2
  34. DELAY2:MOV R7,#10;令R7的值为10
  35. LOOP21:MOV R6,#200;令R6的值为200
  36. LOOP22:MOV R5,#250;令R5的值为250
  37. DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
  38. DJNZ R6,LOOP22;R6=R6-1,如果R6不为0,则执行LOOP22,否则执行下面的程序
  39. DJNZ R7,LOOP21;R7=R7-1,如果R7不为0,则执行LOOP21,否则执行下面的程序
  40. DJNZ R4,DELAY2;R4=R4-1,如果R4不为0,则执行DELAY2,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*2,大约为2s
  41. STAT3:
  42. MOV P3,#00H;令P3为00000000
  43. MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
  44. MOV P0,#0FCH;令P0为11111100 ,使南北红灯亮
  45. MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
  46. MOV P0,#03H;令P0为00000011 ,使东西绿灯亮
  47. MOV P2,#03H;令P2为00000011
  48. MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
  49. MOV R4,#10;令R4的值为10
  50. DELAY3:MOV R7,#10;令R7的值为10
  51. LOOP31:MOV R6,#200;令R6的值为200
  52. LOOP32:MOV R5,#250;令R5的值为250
  53. DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
  54. DJNZ R6,LOOP32;R6=R6-1,如果R6不为0,则执行LOOP32,否则执行下面的程序
  55. DJNZ R7,LOOP31;R7=R7-1,如果R7不为0,则执行LOOP31,否则执行下面的程序
  56. DJNZ R4,DELAY3;R4=R4-1,如果R4不为0,则执行DELAY3,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*10,大约为10s
  57. STAT4:
  58. MOV P3,#00H;令P3为00000000
  59. MOV P2,#02H;令P2为0000010,使U4工作,U5不工作
  60. MOV P0,#3CH;令P0为00111100 ,使东西黄灯亮,南北红灯亮
  61. MOV P2,#01H;令P1为00000001 ,使U4不工作,U5工作
  62. MOV P0,#0FH;令P0为00001111 ,使东西绿灯灭
  63. MOV P2,#03H;令P2为00000011
  64. MOV P3,#40H;令P3为01000000 ,以上两步实现所有的发光二极管均熄灭 的功能 ,变为初始状态
  65. MOV R4,#2;令R4的值为2
  66. DELAY4:MOV R7,#10;令R7的值为10
  67. LOOP41:MOV R6,#200;令R6的值为200
  68. LOOP42:MOV R5,#250;令R5的值为250
  69. DJNZ R5,$;R5=R5-1,如果R5不为0,则执行$即原地踏步,否则执行下面的程序
  70. DJNZ R6,LOOP42;R6=R6-1,如果R6不为0,则执行LOOP42,否则执行下面的程序
  71. DJNZ R7,LOOP41;R7=R7-1,如果R7不为0,则执行LOOP41,否则执行下面的程序
  72. DJNZ R4,DELAY4;R4=R4-1,如果R4不为0,则执行DELAY4,否则执行下面的程序,以上八步完成延时,(((1+250*2+2)*200+2)*10+2)*2,大约为2s
  73. JMP STAT1;无条件跳转至STAT1
  74. 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加载倒计时初值。

  • 再按下KEY_START开始倒计时

三、实验源程序


  1. <font style="font-size: 14pt">ORG 0000H
  2. AJMP MAIN
  3. ORG 0030H
  4. MAIN:
  5. MOV SP,#60H; 堆栈初始化
  6. MOV R0,#0    ;将0赋给R0,即表示初始值的个位  
  7. MOV R1,#1; 将1赋给R1,即表示初始值的十位  
  8. SETB P3.0; 关掉 LED1
  9. CLR F0 ;对标志位清零
  10. LOOP:
  11. JB P1.1,LOOP2; 如果 P1.1=1, 跳转到 LOOP2 ,
  12. LOOP1:
  13. CLR F0 ;对标志位清零
  14. MOV 30H,R0 ;将个位放在地址单元30H中  
  15. MOV 31H,R1; 将十位放在地址单元31H中,以上两步实现装载初值的功能  
  16. SETB P3.0; 关闭 LED1   
  17. LCALL DISPLAY; 显示
  18. LOOP2:   
  19. JB P1.0,LOOP; 如果 P1.0=1 ,跳回 LOOP ,否则继续执行
  20. LOOP3:   
  21. LCALL DISPLAY; 刷新显示,显示就是将数字呈现在数码管上  
  22. LCALL DELAY1S; 延时 1s   
  23. LCALL ADJUST2; 调整计时器寄存器
  24. JB F0,LOOP4 ;计时器寄存器如果为1,则跳转至LOOP4
  25. LJMP LOOP3 ;否则长跳转至LOOP3
  26. LOOP4:    ;LED闪烁子程序
  27. CLR P3.0 ;将P3.0清零,即LED 亮
  28. LCALL DELAY100MS;调用子程序DELAY100MS
  29. SETB P3.0; 关掉LED
  30. LCALL DELAY100MS;调用子程序DELAY100MS
  31. JB P1.1,LOOP4;如果P1.1为1,则跳转至LOOP4
  32. LJMP LOOP1      
  33. DISPLAY:     ; 显示子程序
  34. MOV A,30H ;将个位送至A中
  35. MOV DPTR,#TABLE
  36. MOVC A,@A+DPTR ;通过查表获得对应的数据
  37. MOV DPTR,#0FE00H ;将其数据送到U2的锁存地址中
  38. MOVX @DPTR,A ;把A的内容送到DPTR所指的外部地址
  39. MOV A,31H
  40. MOV DPTR,#TABLE
  41. MOVC A,@A+DPTR
  42. MOV DPTR,#0FD00H
  43. MOVX @DPTR,A ;同上,将对应数据送到U3的锁存地址中
  44. RET
  45. ADJUST2:
  46. DEC 30H ;将地址单元30H中的值自减1
  47. MOV A,30H ;将地址单元30H中的值送入寄存器A中
  48. CJNE A,#-1,GOTORET ;如果A中的值不为-1,则跳转至GOTORET,即返回主程序
  49. MOV 30H,#9 ;将9送入地址单元30H中
  50. DEC 31H ;将地址单元31H中的值自减1
  51. MOV A,31H ;将地址单元31H中的值送入寄存器A中
  52. CJNE A,#-1,GOTORET ;如果A中的值不为-1,则跳转至GOTORET,即返回主程序
  53. SETB F0; 将用户标志位置1
  54. RET
  55. GOTORET:
  56. RET
  57. DELAY1S:MOV R7,#10
  58. DL2:MOV R6,#200
  59. DL1:MOV R5,#250
  60. DJNZ R5,$
  61. DJNZ R6,DL1
  62. DJNZ R7,DL2 ;实现延时,延时时间为((1+2*250+2)*200+2)*10,大约为1s
  63. RET
  64. DELAY100MS:MOV R7,#200
  65. DL:MOV R6,#250
  66. DJNZ R6,$
  67. DJNZ R7,DL;实现延时,延时时间为((1+250*2)+2)*200,大约为0.1s,即使P3.0引脚上的LED按10Hz频率闪烁
  68. RET
  69. TABLE: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H   
  70. 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,分别是加速与减速。

三、实验源程序


  1. <font style="font-size: 14pt">ORG 0000H
  2. AJMP MAIN
  3. ORG 0030H
  4. MAIN:
  5. MOV SP,#60H;使SP指向地址单元60H
  6. MOV P0,#0FFH;使P0为11111111,即所有的彩色旋转灯都不亮
  7. MOV P1,#0FFH;使P1为11111111,即所有的挡位灯都不亮
  8. MOV R7,#10;令R7的值为10
  9. MOV R4,#0EFH;令R4的值为0EFH
  10. LCALL LOOP;调用子程序SCAN
  11. JMP MAIN;无条件跳转至MAIN
  12. BUTTON0:
  13. MOV 30H,#0H;将0放入地址单元30H
  14. MOV P1,#0FEH;令P1为11111110,即让D1亮
  15. JMP ZHUAN1;无条件跳转至ZHUAN1,来实现彩色旋转灯的顺时针旋转
  16. BUTTON1:
  17. MOV 30H,#1H;将1放入地址单元30H
  18. MOV P1,#0FEH;令P1为11111110,即让D1亮
  19. JMP ZHUAN2;无条件跳转至ZHUAN2,来实现彩色旋转灯的逆时针旋转
  20. BUTTON2:
  21. DEC R7;R7自减1
  22. DEC R7;R7自减1
  23. MOV A,R4;将R4的值存到寄存器A中
  24. RR A;将A中的值进行不带进位的循环右移
  25. MOV R4,A;将A中的值送回R4中
  26. MOV A,30H;将地址单元30H中的值赋给A
  27. JZ ZHUAN1;如果ZF=1(即A中的值为0),则跳转至ZHUAN1
  28. JMP ZHUAN2;否则跳转至ZHUAN2
  29. BUTTON3:
  30. INC R7;R7自增1
  31. INC R7;R7自增1
  32. MOV A,R4;将R4中的值存到A中
  33. RL A;将A中的值进行不带进位的循环左移
  34. MOV R4,A;将A中的值送回至R4中
  35. MOV A,30H;将地址单元30H中的值存到A中
  36. JZ ZHUAN1;如果ZF=1(即A中的值为0),则跳转至ZHUAN1
  37. JMP ZHUAN2;否则跳转至ZHUAN1
  38. ZHUAN1:
  39. MOV P0,R4;将R4中的值送到P0,用来变换挡位指示灯
  40. LCALL DLS;长调用DLS
  41. MOV A,P1;将P1中的值存到A中
  42. RL A;将A进行不带进位的循环左移
  43. MOV P1,A;将A中的值送回至P1中
  44. LCALL SCAN;长调用子程序SCAN
  45. JMP ZHUAN1;无条件跳转至ZHUAN1
  46. ZHUAN2:
  47. MOV P0,R4;将R4中的值送到P0,用来变换挡位指示灯
  48. LCALL DLS;长调用DLS
  49. MOV A,P1;将P1中的值存到A中
  50. RR A;将A进行不带进位的循环左移
  51. MOV P1,A;将A中的值送回至P1中
  52. LCALL LOOP;长调用子程序SCAN
  53. JMP ZHUAN2;无条件跳转至ZHUAN2
  54. DLS:
  55. MOV A,R7;将R7中的值存到寄存器A中
  56. DL2:MOV R6,#200;令R6的值为200
  57. DL1:MOV R5,#250;令R5的值为250
  58. DL0:
  59. DJNZ R5,DL0;R5=R5-1,如果R5不为0,则跳转至DL0,否则顺序执行
  60. DJNZ R6,DL1;R6=R6-1,如果R6不为0,则跳转至DL1,否则顺序执行
  61. DJNZ R7,DL2;R7=R7-1,如果R7不为0,则跳转至DL2,否则顺序执行,实现延时,延时时间为((1+250*2+2)*200+2)*R7
  62. MOV R7,A;将A中的值送回至R7
  63. RET;
  64. LOOP:
  65. MOV P3,#030H;令P3为00110000,使开关闭合时能实现对应的功能
  66. JNB P3.4,NEXT1;如果P3.4为低电平(KEY0或KEY2闭合),则跳转至NEXT1,否则顺序执行
  67. JNB P3.5,NEXT2;如果P3.5为低电平(KEY1或KEY3闭合),则跳转至NEXT2,否则顺序执行
  68. JMP TORET;无条件跳转至TORET,即返回源程序
  69. NEXT1:
  70. MOV P3,#3H;令P3为00000011
  71. JNB P3.0,BUTTON0;如果P3.0为低电平(KEY0闭合),则跳转至BUTTON0,否则顺序执行
  72. JNB P3.1,BUTTON2;如果P3.1为低电平(KEY2闭合),则跳转至BUTTON2,否则顺序执行
  73. JMP TORET;无条件跳转至TORET,即返回源程序
  74. NEXT2:
  75. MOV P3,#3H;令P3为00000011
  76. JNB P3.0,BUTTON1;如果P3.0为低电平(KEY1闭合),则跳转至BUTTON1,否则顺序执行
  77. JNB P3.1,BUTTON3;如果P3.1为低电平(KEY3闭合),则跳转至BUTTON3,否则顺序执行
  78. TORET:
  79. RET
  80. 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)报错

三、实验源程序


  1. <font style="font-size: 14pt">#include<reg51.h>  
  2. #define uint unsigned int
  3. #define uchar unsigned char

  4. sbit lcden=P1^5;//使能信号  
  5. sbit rs=P1^7;//数据命令选择
  6. sbit rw=P1^6;//读写选择   
  7. sbit busy=P2^7;

  8. char i,j,temp,num;
  9. long a,b,c,d;   
  10. float a_c,b_c;
  11. uchar flag,fuhao;//flag

  12. uchar code table[]={
  13. 0,1,2,3,
  14. 4,5,6,7,
  15. 8,9,0,0,
  16. 0,0,0,0};
  17. uchar code table1[]={
  18. 0,1,2,3,
  19. 4,5,6,7,
  20. 8,9,0x2b-0x30,0x2d-0x30,
  21. 0x2a-0x30,0x2f-0x30,0x01-0x30,0x3d-0x30};//按键对应的符号
  22. uchar code table2[]="!rorrE";

  23. void delay(uchar z) // 延迟函数
  24. {
  25.               uchar i,t;
  26.               for(i=0;i<z;i++)
  27.                   for(t=0;t<120;t++);
  28. }

  29. void check() // 判断忙或空闲
  30. {
  31.               do
  32.               {
  33.                   P2=0xFF;
  34.                   rs=0;     //指令     
  35.                   rw=1;     //读   
  36.                   lcden=0;     //禁止读写n   
  37.                   delay(1); //等待,液晶显示器处理数据     
  38.                   lcden=1;     //允许读写  
  39.               }
  40.               while(busy==1); //判断是否为空闲,1为忙,0为空闲
  41. }

  42. void write_com(uchar com) // 写指令函数   
  43. {
  44.               P2=com;    //com指令付给P0口   
  45.               rs=0;
  46.               rw=0;
  47.               lcden=0;
  48.               check();
  49.               lcden=1;
  50. }

  51. void write_date(uchar date) // 写数据函数     
  52. {
  53.     P2=date;
  54.               rs=1;
  55.               rw=0;
  56.               lcden=0;
  57.               check();
  58.               lcden=1;
  59. }

  60. void init() //初始化   
  61. {
  62.     num=-1;
  63.               lcden=1; //使能信号为高电平  
  64.               write_com(0x38); //8位,2行  
  65.               write_com(0x0c); //显示开,光标关,不闪烁*/   
  66.               write_com(0x06); //增量方式不移位      
  67.               write_com(0x80); //检测忙信号      
  68.               write_com(0x01); //清屏指令
  69.               i=0;
  70.               j=0;
  71.               a=0;     //第一个参与运算的数        
  72.               b=0;     //第二个参与运算的数      
  73.               c=0;
  74.     d=0;
  75.               flag=0; //flag表示是否有符号键按下,  
  76.               fuhao=0; // fuhao表征按下的是哪个符号   
  77. }

  78. void keyscan() // 键盘扫描程序   
  79. {
  80.               P3=0xfe;
  81.               if(P3!=0xfe)
  82.               {
  83.                                delay(20);
  84.                                if(P3!=0xfe)
  85.                                {
  86.                                 temp=P3&0xf0;
  87.                                 switch(temp)
  88.                                 {
  89.                                               case 0xe0:num=0;
  90.                                                  break;
  91.                                                case 0xd0:num=1;
  92.                                                  break;
  93.                                                case 0xb0:num=2;
  94.                                                 break;
  95.                                                 case 0x70:num=3;
  96.                                                 break;
  97.                                 }
  98.                                }
  99.                                while(P3!=0xfe);
  100.                                if(flag==0)//没有按过符号键
  101.                                {
  102.                                              a=a*10+table[num];
  103.                             }
  104.                             else//如果按过符号键
  105.                             {
  106.                                           b=b*10+table[num];
  107.                             }
  108.                                           i=table1[num];
  109.                                           write_date(0x30+i);//写入按键对应的 符号  
  110.               }

  111.               P3=0xfd;
  112.               if(P3!=0xfd)
  113.               {
  114.                  delay(5);
  115.                  if(P3!=0xfd)
  116.                  {
  117.                   temp=P3&0xf0;
  118.                   switch(temp)
  119.                   {
  120.                    case 0xe0:num=4;
  121.                        break;
  122.                   
  123.                    case 0xd0:num=5;
  124.                        break;
  125.                   
  126.                    case 0xb0:num=6;
  127.                        break;
  128.                   
  129.                    case 0x70:num=7;     
  130.                        break;
  131.                   }
  132.                  }
  133.                  while(P3!=0xfd);
  134.                  if(flag==0)//没有按过符号键
  135.                   {
  136.                    a=a*10+table[num];
  137.                   }
  138.                   else//如果按过符号键
  139.                   {
  140.                    b=b*10+table[num];
  141.                   }
  142.                  i=table1[num];
  143.                  write_date(0x30+i);
  144.               }
  145.             
  146.               P3=0xfb;
  147.               if(P3!=0xfb)
  148.               {
  149.                  delay(5);
  150.                  if(P3!=0xfb)
  151.                  {
  152.                   temp=P3&0xf0;
  153.                   switch(temp)
  154.                   {
  155.                    case 0xe0:num=8;
  156.                        break;
  157.                   
  158.                    case 0xd0:num=9;
  159.                        break;
  160.                   
  161.                    case 0xb0:num=10;
  162.                        break;
  163.                   
  164.                    case 0x70:num=11;
  165.                        break;
  166.                   }
  167.                  }
  168.                  while(P3!=0xfb);
  169.                  if(num==8||num==9)//如果按下的是'8','9'
  170.                  {
  171.                     if(flag==0)//没有按过符号键
  172.                   {
  173.                    a=a*10+table[num];
  174.                   }
  175.                   else//如果按过符号键
  176.                   {
  177.                    b=b*10+table[num];
  178.                   }
  179.                  }
  180.                  else if(num==10)//如果按下的是'+'
  181.                  {
  182.                   flag=1;
  183.                   fuhao=1;//1表示加号已按     
  184.                  }
  185.                  else if(num==11)//如果按下的是'-'
  186.                  {
  187.                   flag=1;
  188.                   fuhao=2;//2表示减号已按6
  189.                  }
  190.                  i=table1[num];
  191.                  write_date(0x30+i);
  192.               }
  193.             
  194.               P3=0xf7;
  195.               if(P3!=0xf7)
  196.               {
  197.                  delay(5);
  198.                  if(P3!=0xf7)
  199.                  {
  200.                   temp=P3&0xf0;
  201.                   switch(temp)
  202.                   {
  203.                    case 0xe0:num=12;
  204.                        break;
  205.                   
  206.                    case 0xd0:num=13;
  207.                        break;
  208.                   
  209.                    case 0xb0:num=14;
  210.                        break;
  211.                   
  212.                    case 0x70:num=15;
  213.                        break;
  214.                   }
  215.                  }
  216.                  while(P3!=0xf7);
  217.                  switch(num)
  218.                  {
  219.                   case 12:{write_date(0x30+table1[num]); flag=1;fuhao=3;}
  220.                    break;
  221.                   case 13:{write_date(0x30+table1[num]); flag=1;fuhao=4;}              
  222.                    break;
  223.                   case 14:{write_com(0x01);i=0;j=0;a=0;b=0;c=0;d=0;flag=0;fuhao=0;}//按下的是"清零"   
  224.                    break;
  225.                   case 15:{
  226.                                              j=1;

  227.                          if(fuhao==1){write_com(0x80+0x4f);//按下等于键,光标前进至第二行最后一个显示处        
  228.                          write_com(0x04);     //写入数据后地址加1 ,从右向左写入数据      
  229.                          c=a+b;
  230.                          while(c!=0)
  231.                          {
  232.                            write_date(0x30+c%10);
  233.                            c=c/10;
  234.                          }
  235.                          write_date(0x3d);     //再写"="
  236.                          a=0;b=0;flag=0;fuhao=0;
  237.                          }

  238.                     else if(fuhao==2){write_com(0x80+0x4f);//光标前进至第二行最后一个显示处      
  239.                           write_com(0x04);     //设置从后住前写数据,每写完一个数据,光标后退一格)
  240.                          if(a-b>0)
  241.                            c=a-b;
  242.                          else
  243.                            c=b-a;
  244.                          while(c!=0)
  245.                          {
  246.                            write_date(0x30+c%10);
  247.                            c=c/10;
  248.                          }
  249.                          if(a-b<0)
  250.                          write_date(0x2d);    //写’-‘
  251.                          write_date(0x3d);     //再写"="         
  252.                          a=0;b=0;flag=0;fuhao=0;
  253.                         }

  254.                     else if(fuhao==3)
  255.                               {
  256.                                                         write_com(0x80+0x4f);
  257.                           write_com(0x04);
  258.                           c=a*b;
  259.                           while(c!=0)
  260.                           {
  261.                                          write_date(0x30+c%10);
  262.                                          c=c/10;
  263.                           }
  264.                            write_date(0x3d);   
  265.                                       a=0;b=0;flag=0;fuhao=0;
  266.                            }

  267.                     else if(fuhao==4)
  268.                                                {
  269.                                                         write_com(0x80+0x4f);
  270.                           write_com(0x04);
  271.                                                         if(b==0)
  272.                                                         {
  273.                                                                       i=0;
  274.                                                                       while(table2[i]!='\0')
  275.                                                                       {
  276.                                                                                     write_date(table2[i]);
  277.                                                                                     i++;
  278.                                                                       }//若除数为0,输出Error!
  279.                                                                       a=0;b=0;flag=0;fuhao=0;
  280.                                                         }
  281.                                                         else if((a%b==0)&&(b!=0))
  282.                                                         {
  283.                                         c=a/b;
  284.                                         while(c!=0)
  285.                                          {
  286.                                                          write_date(0x30+c%10);
  287.                                                         c=c/10;
  288.                                          }
  289.                                                                       if(a/b<=0)
  290.                                          write_date(0x30);
  291.                                         write_date(0x3d);                             
  292.                                         a=0;b=0;flag=0;fuhao=0;
  293.                                                         }
  294.                                                         else if((a%b!=0)&&(b!=0))
  295.                                                         {
  296.                                                                       d=a%b;
  297.                                                             while(d!=0)
  298.                                          {
  299.                                                          write_date(0x30+d%10);
  300.                                                         d=d/10;
  301.                                          }//若不能整除,输出余数  
  302.                                            write_date(0x2e);
  303.                                                                       write_date(0x2e);
  304.                                                                       write_date(0x2e);//输出“...“
  305.                                                                       c=a/b;//输出整除结果
  306.                                                             while(c!=0)
  307.                                          {
  308.                                                          write_date(0x30+c%10);
  309.                                                         c=c/10;
  310.                                          }
  311.                                                                       if(a/b<=0)
  312.                                         write_date(0x30);
  313.                                         write_date(0x3d);                             
  314.                                         a=0;b=0;flag=0;fuhao=0;
  315.                                                         }
  316.                        }
  317.                     }
  318.                    break;
  319.                  }
  320.               }
  321. }

  322. main()
  323. {
  324.               init();//初始化
  325.               while(1)
  326.               {
  327.                                keyscan();//键盘扫描
  328.               }
  329. }</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)更改信号发射器的频率,再次验证其功能是否正确。

结果:

三、实验源程序

  1. <font style="font-size: 16pt"><b>#include<reg51.h>   
  2. #include<intrins.h>
  3. sbit RS=P2^0;   
  4. sbit RW=P2^1;   
  5. sbit E=P2^2;   
  6. sbit BF=P1^7;   
  7. sbit CLK=P2^3;
  8. sbit start=P2^4;
  9. sbit oe=P2^5;
  10. sbit eoc=P2^7;
  11. sbit out_pulse=P2^6;//5us脉冲  
  12. sbit p30=P3^0;
  13. #define uchar unsigned char
  14. #define uint unsigned int
  15. uchar n=0;
  16. uchar flag=0;//1s标志位  
  17. void delay1ms()
  18. {
  19. unsigned char i,j;            
  20. for(i=0;i<10;i++)
  21. for(j=0;j<33;j++)
  22.                  ;                           
  23. }
  24. void delay(unsigned int n)
  25. {
  26.                  unsigned int i;
  27.               for(i=0;i<n;i++)
  28.               delay1ms();
  29. }
  30. bit BusyTest(void)
  31.   {
  32.                   bit result;
  33.                             RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态     
  34.                   RW=1;
  35.                   E=1;        //E=1,才允许读写  
  36.                   _nop_();   //空操作     
  37.                   _nop_();
  38.                   _nop_();
  39.                                _nop_();   //空操作四个机器周期,给硬件反应时间                    
  40.                   result=BF;  //将忙碌标志电平赋给result   
  41.                             E=0;//关掉使能端  
  42.                   return result;
  43.   }
  44. void Write_com (unsigned char dictate)//将模式设置指令或显示地址写入液晶显示模块      
  45. {  
  46.     while(BusyTest()==1); //如果忙就等待
  47.               RS=0;                  //根据规定,RS和R/W同时为低电平时,可以写入指令      
  48.               RW=0;  
  49.               E=0; //写入指令或显示地址               

  50.               _nop_();
  51.               _nop_();            
  52.               P1=dictate;         
  53.               _nop_();
  54.               _nop_();
  55.               _nop_();
  56.               _nop_();            
  57.               E=1;                  
  58.               _nop_();
  59.               _nop_();
  60.               _nop_();
  61.               _nop_();              
  62.                 E=0;                 
  63. }
  64. void WriteAddress(unsigned char x)
  65. {
  66.      Write_com(x|0x80); //显示位置的确定方法规定为"80H+地址码x"            
  67. }
  68. void WriteData(unsigned char y)
  69. {
  70.     while(BusyTest()==1);
  71.                 RS=1;         
  72.                 RW=0;
  73.                 E=0;//写入数据                        
  74.                 P1=y;         
  75.                 _nop_();
  76.                 _nop_();
  77.                 _nop_();
  78.       _nop_();      
  79.                 E=1;        
  80.                 _nop_();
  81.                 _nop_();
  82.                 _nop_();
  83.                 _nop_();      
  84.                 E=0;           
  85. }
  86. void LcdInt(void)
  87. {
  88.                  delay(15);            
  89.                  Write_com(0x38);  //数据总线为8位 ,显示两行  
  90.               delay(5);  
  91.               Write_com(0x0c); //显示功能开,无光标,光标不闪烁   
  92.               delay(5);
  93.               Write_com(0x06);  //写入数据后  地址寄存器     AC的内容减一      
  94.               delay(5);                                                                                                                                                           
  95.               Write_com(0x01); //清屏
  96.               delay(5);
  97. }
  98. void sysinit()
  99. {
  100.                                              
  101.               TMOD = 0x21;//T1,T0同时使用,就设置  T1方式2,T0方式1    ,即TMOD=0x21   
  102.               TH1=0xff;
  103.               TL1=0xEC;//50khz
  104.               EA = 1; //开总中断
  105.               ET1=1;
  106.               TR1=1; //启动定时器T1  
  107.               TH0=0x3c;
  108.               TL0=0xb0;//50MS定时  
  109.               ET0=1;
  110.               TR0=1;
  111.               start=0;    // START: A/D转换启动信号,输入,高电平有效。
  112.               oe=0;  
  113. }
  114. void t0(void) interrupt 1
  115. {
  116.               ET0=0;
  117.               TH0=0X45;                       
  118.               TL0=0X00;//50MS定时
  119.               n++;
  120.               if(n==20) {flag=1;n=0;}//实现一秒的定时,来计算果过零次数出一
  121.               ET0=1;
  122. }
  123. void t1(void) interrupt 3
  124. {
  125.               ET1=0;
  126.               CLK=~CLK;//代表取反   
  127.               ET1=1;//T1中断允许  
  128. }
  129. //0808数据采集   
  130. unsigned char adc()
  131. {
  132.    unsigned  char  Temp;
  133.    start=1;
  134. //              delay(1);//do not delay  
  135.               start=0;  //启动信号 ,下降沿有效     
  136.    while (!eoc);// A/D转换结束信号  
  137.               P0=0xff;
  138. //              delay(1);
  139.    oe=1;//数据输出允许信号   
  140.    Temp=P0;//读取采集数据   
  141.    oe=0;
  142. //  delay(4);
  143.    return(Temp);//返回采集数据   
  144. }
  145. void display(uint a)//显示子函数  
  146. {
  147.               uint bai,shi,ge;
  148.               bai=a/100;
  149.               shi=(a-bai*100)/10;
  150.               ge=a%10;
  151.               WriteAddress(2);
  152.               WriteData(0x30+bai);//显示百位  
  153.               WriteData(0x30+shi);//显示十位  
  154.               WriteData(0x30+ge);//显示个位  
  155.             
  156. }
  157. void main()
  158. {
  159.               uint temp1,temp2;
  160.               uchar f=0;
  161.               LcdInt();
  162.               delay(5);
  163.               sysinit();
  164.               CLK=0;
  165.               WriteAddress(0);
  166.               WriteData('f');
  167.               WriteData(':');
  168.               WriteAddress(5);
  169.               WriteData('H');            
  170.               WriteData('z');
  171.               while(1)
  172.               {                           
  173.                             temp2=temp1;
  174.                             temp1=adc();//ad采集                               if(((temp1>=128)&&(temp2<=128))||((temp1<=128)&&(temp2>=128)))
  175.                             {
  176.                                           f++;//f是存放过零次数的  
  177.                                           out_pulse=1;
  178.                                           _nop_();
  179.                                           _nop_();
  180.                                           _nop_();
  181.                                           _nop_();
  182.                                           _nop_();
  183.                                           out_pulse=0;//产生5us的脉冲信号   
  184.                             }
  185.                             if(flag==1)//到达1s后计算频率   
  186.                             {
  187.                                           flag=0;
  188.                                           f=f/2;//信号频率为过零次数出除以二     
  189.                                           display(f);//显示频率
  190.                                           f=0;
  191.                             }            
  192.               }
  193. }</b></font>
复制代码

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),直至结果正确。

结果:

老师实验室验证

三、实验源程序


  1. <font style="font-size: 14pt">#include<reg52.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. sbit bell=P3^1; // 用 p3.1 口控制 bell
  5. sbit led=P3^0; // 用 P3^0 来控制 led
  6. sbit key0=P3^2; // 报警的键
  7. uint count; // 定义一个无符号整形数 ,
  8. 用来计数
  9. /******************************************************************/
  10. void delay(uint count) // 延时 1ms
  11. {
  12. uint x,y;
  13. for(x=count;x>0;x--)
  14. for(y=110;y>0;y--);
  15. }
  16. /******************************************************************/
  17. void show(uint count) // 使铃铛响,使灯亮的
  18. 函数
  19. { uint i;
  20. for(i=0;i<=count;i++) // 函数循环 i 次
  21. led=0;bell=0; // 灯亮,铃响
  22. delay(500); // 延时 0.5s
  23. led=1;bell=1; // 灯灭,铃停
  24. delay(500); // 延时 500ms
  25. }
  26. }
  27. /***********************************************************/
  28. Void s_timer0() interrupt 0 using 0 // 中断 0
  29. {
  30. EA=0; // 屏蔽其他中断请求
  31. show(count); // 调用子程序
  32. count++;
  33. delay(50);
  34. if(count>=10) // 若 count 为十则结

  35. count=0;
  36. EA=1; // 开放中断
  37. }
  38. /************************** 主程序 **********************************/
  39. void main()
  40. { EA=1; // 开放中断
  41. EX0=1; // 允许外部中断 0 中断
  42. IT0=0; // 外部中断 0 为电平触发方式
  43. while(1); // 循环执行,等待循环
  44. }</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),直至结果正确。

结果:

老师实验室验证

三、实验源程序


  1. <font style="font-size: 14pt">#include <reg52.h>
  2. #include <absacc.h>
  3. #define PA XBYTE[0x7FFC] //CS--A15
  4. #define COM XBYTE[0x7FFF]
  5. /***************************************************************************/
  6. void init_8255(void)
  7. {
  8. COM=0x80; // c = out, a = out,b = out
  9. }
  10. /***************************************************************************/
  11. void Uart_Init(void)
  12. {
  13. SCON = 0x10; //SCON:工作模式 0
  14. PCON = 0x00;
  15. TI = RI = 0;
  16. IE = 0x90;
  17. EA = 0;
  18. }
  19. ***********************************************************
  20. void Uart_Out(unsigned char DA T) //74LS164 的串转并
  21. {
  22. TI = 0;
  23. SBUF = ~DAT; }
  24. ***************************************************************************
  25. void delay_ms(unsigned int ms) //延时 1ms 程序
  26. {
  27. int j;
  28. for(;ms!=0; ms--)
  29. for (j=0;j<125;j++)
  30. {
  31. }
  32. }
  33. ********************************************************
  34. int main(void)
  35. {
  36. signed char i;
  37. init_8255();
  38. Uart_Init();
  39. while(1)
  40. {
  41. PA = 0x96; //东西绿灯亮
  42. for(i = 25;i >= 0;i--) // 延时 25s
  43. {
  44. Uart_Out(~(((i/10)<<4) | (i%10)));
  45. delay_ms(1000);
  46. }
  47. for(i = 5;i > 0;i--) //5s
  48. {
  49. PA = 0xBE;
  50. delay_ms(500);
  51. PA = 0x96;
  52. delay_ms(500);
  53. }
  54. PA = 0x69; //南北绿灯亮
  55. for(i = 25;i >= 0;i--) // 延时 25s
  56. {
  57. Uart_Out(~(((i/10)<<4) | (i%10)));
  58. delay_ms(1000);
  59. }
  60. for(i = 5;i > 0;i--) //5s
  61. {
  62. PA = 0xEB;
  63. delay_ms(500);
  64. PA = 0x69;
  65. delay_ms(500);
  66. }
  67. }
  68. }</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),直至结果正确。

结果:

老师实验室验证

三、实验源程序


  1. <font style="font-size: 14pt">#include <reg51.h>
  2. //*** 函数定义 ***
  3. void long_delay(void); // 长延时
  4. void short_delay(void); // 短暂延时
  5. void delay10ms(unsigned char); // 延时 10MS
  6. void write7279(unsigned char, unsigned char); // 写入到 HD7279
  7. unsigned char read7279(unsigned char); // 从 HD7279 读出
  8. void send_byte(unsigned char); // 发送一个字节
  9. #define uchar unsigned char
  10. #define uint unsigned int
  11. uchar
  12. bianma[]={0x1b,0x13,0x0b,0x03,0x1a,0x12,0x0a,0x02,0x19,0x11,0x09,0x01,0x18,0x10,0x08,0x00};
  13. unsigned char receive_byte(void); // 接收一个字节
  14. //*** 变量及 I/O 口定义 ***
  15. unsigned char digit[5];
  16. unsigned char key_number, j, k,mk; //mk 为按键次数计数值
  17. unsigned int tmr;
  18. unsigned long wait_cnter;
  19. sbit cs=P1^0; // cs at P1.0
  20. sbit clk=P1^1; // clk 连接于 P1.1
  21. sbit dat=P1^2; // dat 连接于 P1.2
  22. sbit key=P1^3; // key 连接于 P1.3
  23. void write7279(unsigned char cmd, unsigned char dta)
  24. {
  25. send_byte (cmd);
  26. send_byte (dta);
  27. }
  28. unsigned char read7279(unsigned char command)
  29. {
  30. send_byte(command);
  31. return(receive_byte());
  32. }
  33. void send_byte( unsigned char out_byte)
  34. {
  35. unsigned char i;
  36. cs=0;//芯片使能
  37. long_delay();
  38. for (i=0;i<8;i++) // 分 8 次移入数据
  39. {
  40. if (out_byte&0x80)// 先传高位
  41. {
  42. dat=1;
  43. }
  44. else
  45. {
  46. dat=0;
  47. }
  48. clk=1;
  49. short_delay();
  50. clk=0;
  51. short_delay();
  52. out_byte=out_byte*2;// 数据左移
  53. }
  54. dat=0;
  55. }
  56. unsigned char receive_byte(void)
  57. {
  58. unsigned char i, in_byte;
  59. dat=1; // set to input mode
  60. long_delay();
  61. for (i=0;i<8;i++)// 分 8 次读入数据高位在前
  62. {
  63. clk=1;
  64. short_delay();
  65. in_byte=in_byte*2; // 数据左移
  66. if (dat)
  67. {
  68. in_byte=in_byte|0x01;
  69. }
  70. clk=0;
  71. short_delay();
  72. }
  73. dat=0;
  74. return (in_byte);
  75. 12
  76. }
  77. void long_delay(void)
  78. {
  79. unsigned char i;
  80. for (i=0;i<0x30;i++);
  81. }
  82. void short_delay(void)
  83. {
  84. unsigned char i;
  85. for (i=0;i<8;i++);
  86. }
  87. void main(){
  88. uchar jianpan,i,num;
  89. send_byte(0xa4); //全部复位指令
  90. while(1){
  91. if(key==0){ //如果按键按下
  92. send_byte(0x15); //读键盘指令
  93. jianpan=receive_byte(); //接收键盘数据
  94. // P0=num;
  95. for(i=0;i<16;i++){
  96. if(jianpan==bianma[i]){ // 等于判断一定是双等于号
  97. num=i;
  98. break;
  99. }
  100. }
  101. send_byte(0xa1);
  102. write7279(0xc8,num);
  103. while(key==0);
  104. }
  105. } }</font>
复制代码


完整的Word格式文档51黑下载地址:

单片机实验报告.docx (325.27 KB, 下载次数: 9)




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表