一、实验任务
- 安装Proteus8软件,使用AT89C51单片机的外部引脚,点亮1个LED灯。采用汇编指令完成。
- 采用多个LED,设计一个LED流水灯电路,分别用51汇编语言和C语言编程,实现流水灯正常工作。
二、实验实现
2.1 实验前置
http://t.csdnimg.cn/MrPeg 参考这篇博客
参考上面这篇博客,画出如下电路原理图。
2.2点亮一个LED灯
2.2.1 汇编指令
http://t.csdnimg.cn/2f8Pn 参考这个博客
其中最重要的几条指令:
ORG XXXXH ;程序入口,其中xxxxH为程序起始地址
MOV XX,#NUM ;MOV为数据传送指令,其中NUM为传输值,XX为寄存器
CLR X ; 累加器X清零:
SJMP $ ;
SJMP短转移指令:
先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。
特例:SJMP $就是SJMP 0FEH,因为0FEH为-2补码,所以转移后地址为PC+2-2还是为0FEH,无限循环。
2.2.2 KEIL代码
ORG 0000H ;设置程序的起始地址
MOV P0,#0FFH ;将P0所有端口设为高电平,即关闭所有连接的LED灯
CLR P0.0 ;将P0端口第0位清除为低电平,即P0.0连接led灯点亮
SJMP $ ;短跳转指令,无限循环跳转到当前指令的地址,即LED长亮
END
2.2.3效果展示
2.3点亮流水灯
2.3.1 原理
在嵌入式开发过程中,流水灯的实现主要通过Delay函数实现。即P0~P7引脚对应的LED灯依次为低电平,然后加入延时函数,从而实现流水灯的效果。
因此,想要用汇编指令实现流水灯,则应该将寄存器中的值改变,把寄存器A中的值1000000(十进制的128)依次右移,即01000000、00100000…然后加入延时与循环,最终实现流水灯的效果。
2.3.2 汇编语言
LJMP长转移指令
如:在程序存储器中0000H单元存放一条指令:LJMP 3000H;程序就会转到3000H位置
LCALL长调用指令
RET 返回主程序
DJNZ*减 1 条件转移指令
2.3.3 KEIL代码
ORG 0000H
LJMP MAIN ;跳转到标签MAIN所在的地址
ORG 0100H
MAIN:
MOV A,#80H ;立即数80H(即十进制的128,二进制的1000 0000,除LED0.0其余都亮)移动到累加器A中
LOOP: ;循环标签
MOV P0,A ;将累加器A的内容移动到端口P0
LCALL DELAY ;长调用指令,它调用DELAY子程序
RR A ;将累加器A的内容右旋一位
LJMP LOOP
DELAY:
MOV R2,#255 ;分别将立即数255和250移动到寄存器R2和R3中
D1:MOV R3,#250
D2:DJNZ R3,D2
DJNZ R2,D1 ;这两个指令分别减少R3和R2的内容,并在不为0时跳回到对应的标签,形成延时
RET ;返回主程序
END
2.3.4 实现效果
2.3.5 反向流水灯
如果我们想实现以一个个LED灯逐个点亮形成流水的效果,我们还可以这么写。
此时以LED1举例,首先我们需要让LED1亮,其余都不亮,即0111 1111,对用十进制数127,十六进制数7F。此时我们只需在2.3.3的代码基础上改动一行代码:
MOV A,#7FH
2.3.5 C语言编程
同理,C语言实现反向流水灯,只需要将P0赋相对应的值:
如,当LED1亮,其余不亮时,即为1111 1110(十六进制FE)
当LED2亮,其余不亮时,即为1111 1101(十六进制FD)
当LED3亮,其余不亮时,即为1111 1011(十六进制FB)
当LED4亮,其余不亮时,即为1111 0111(十六进制FE)
当LED5亮,其余不亮时,即为1110 1111(十六进制EF)
当LED6亮,其余不亮时,即为1101 1111(十六进制FB)
当LED7亮,其余不亮时,即为1011 1111(十六进制FD)
当LED8亮,其余不亮时,即为0111 1111(十六进制FE)
如果看不懂怎么转换的,简单介绍一下
十六进制0、1、2、3、4…9、A、B、C、D、E、F
以1111 1110为例,前半部分1111转换为十进制为15,即十六进制的F
后半部分十进制是15,即十六进制的E,合起来就是FE
如果上面的也实在看不懂,可以打开微软自带的计算机
//51单片机编程常用的头文件
#include <reg51.h>
#include <intrins.h>
//延迟函数
void delay_ms(int a)
{
int i,j;
for(i=0;i<a;i++)
{
for(j=0;j<1000;j++) _nop_();
}
}
void main(void)
{
while(1)
{
P0=0xfe;
delay_ms(50);
P0=0xfd;
delay_ms(50);
P0=0xfb;
delay_ms(50);
P0=0xf7;
delay_ms(50);
P0=0xef;
delay_ms(50);
P0=0xdf;
delay_ms(50);
P0=0xbf;
delay_ms(50);
P0=0x7f;
delay_ms(50);
}
}
//https://blog.csdn.net/qq_43279579/article/details/108908566
三、实验总结
此次实验过程中我们分别了解了汇编语言与C语言如何操作单片机流水灯,其实本质都是通过将所需要的值写入寄存器,从而实现引脚高低电平开关。
读完本篇文章,或许你也可以尝试用汇编或者C语言写一个1000 0000类型的流水灯程序。
以上是我的实验内容与个人学习记录,欢迎各位大佬指正其中的错误‘