失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 51单片机入门教程(2)——实现流水灯

51单片机入门教程(2)——实现流水灯

时间:2022-09-11 00:01:47

相关推荐

51单片机入门教程(2)——实现流水灯

51单片机入门教程(2)——实现流水灯

一、搭建流水灯电路二、流水灯程序2.1 延时程序2.2 延时函数2.3 按字节寻址2.4 逻辑移位2.5 条件判断

一、搭建流水灯电路

在Proteus中搭建流水灯电路如图

二、流水灯程序

我们可以把流水灯看作依次点亮若干个灯。

程序如下:

#include <reg52.h>sbit led1 = P2^0;sbit led2 = P2^1;sbit led3 = P2^2;sbit led4 = P2^3;sbit led5 = P2^4;sbit led6 = P2^5;sbit led7 = P2^6;sbit led8 = P2^7;void main(){//点亮第一个灯led1 = 1;led2 = 0;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0;//点亮第二个灯led1 = 0;led2 = 1;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0; //点亮剩余的灯//省略……while(1);}

编译并下载程序到仿真中,观察现象发现只有第二个灯是亮的???

什么鬼???

2.1 延时程序

单片机的执行指令速度非常快,一个晶振是12MHz的单片机执行一条指令的速度是微秒级的,所以点亮第一个灯的时间太短了,以至于我们根本没有察觉。

因此我们需要一个延时的语句。

实现延时的方法就是循环执行很多次空指令。程序如下:

//延时一秒的程序int i,j;for(i = 0;i < 110; ++i){for(j = 0; j < 1000; ++j){;//什么也不做}}

然后我们就可以把流水灯的程序改成这样的:

#include <reg52.h>sbit led1 = P2^0;sbit led2 = P2^1;sbit led3 = P2^2;sbit led4 = P2^3;sbit led5 = P2^4;sbit led6 = P2^5;sbit led7 = P2^6;sbit led8 = P2^7;void main(){int i,j;//点亮第一个灯led1 = 1;led2 = 0;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0;//延时1秒 for(i = 0;i < 110; ++i){for(j = 0; j < 1000; ++j){;//什么也不做}}//点亮第二个灯led1 = 0;led2 = 1;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0; //点亮剩余的灯//省略……while(1);}

编译并下载程序到仿真中,观察现象发现首先第一个灯亮,过了一会儿第二个灯亮。

2.2 延时函数

我们剩下的任务就是依次点亮每个灯,但是每次点亮一个灯就需要写一段延时程序,很麻烦!

为了程序的可读性(toulan),可以把延时程序写成一个子函数,随时供我们使用。

C语言中子函数的定义方式如下

返回值类型 函数名 (参数1,参数2,……){函数体;}

这样我们就可以把延时函数写成这样:

void delay1s(){int i,j;for(i = 0; i<110;++i){for(j = 0; j<1000;++j){//什么也不做}}}

几点说明:

void:因为该延时函数不需要返回值,所以写为voiddelay1s:该函数的函数名,命名需要符合C语言的标识符命名规则。(): 不需要传入参数,所以括号中为空

至此我们可以把流水灯程序写为以下形式:

#include <reg52.h>sbit led1 = P2^0;sbit led2 = P2^1;sbit led3 = P2^2;sbit led4 = P2^3;sbit led5 = P2^4;sbit led6 = P2^5;sbit led7 = P2^6;sbit led8 = P2^7;//延时1svoid delay1s(){int i ,j;for(i = 0;i<110; ++i){for(j = 0;j<1000;++j){;}}}void main(){//点亮第一个灯led1 = 1;led2 = 0;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0;//延时1sdelay1s();//点亮第二个灯led1 = 0;led2 = 1;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0; //点亮剩余的灯//省略……while(1);}

2.3 按字节寻址

我们可以看到,上面的代码十分冗长,每次点亮一个灯需要8条语句,那么如何简化?

比如把

led1 = 1;led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0;

这8条语句替代为P2 = 0000 0001???

答案是可以的。代码如下

unsigned char a = 0x01; //0x01是0000 0001的16进制形式P2 = a;//相当于led1 = 1;led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0;

至此,我们可以把流水的代码优化为如下形式:

#include <reg52.h>//延时1svoid delay1s(){int i ,j;for(i = 0;i<110; ++i){for(j = 0;j<1000;++j){;}}}void main(){unsigned char a1 = 0x01 ; // 0000 0001unsigned char a2 = 0x02; // 0000 0010//点亮第一个灯P2 = a1;//延时1sdelay1s();//点亮第二个灯P2 = a2; //点亮剩余的灯//省略……while(1);}

2.4 逻辑移位

依次点亮8个灯,每点亮一个灯都需要一句赋值语句还是很麻烦 。

所以可以使用逻辑移位语句,每次赋值后,将数值左移一位。

C语言逻辑左移代码如下:

unsigned char a = 0x01; //a = 0000 0001unsigned char b = a<<1; // b = 0000 0010usingned char c = a<<3; //c = 0000 1000

至此,我们可以把流水灯的代码优化如下:

#include <reg52.h>//延时1svoid delay1s(){int i ,j;for(i = 0;i<110; ++i){for(j = 0;j<1000;++j){;}}}void main(){//初始化unsigned char a = 0x01;while(1){//循环点亮流水灯P2 = a; a = a<<1;delay1s();}}

编译并下载程序到仿真中,观察现象发现8个灯依次亮过之后不再亮了。

2.5 条件判断

因为在移位操作中,当变量a的值为1000 0000时,再次执行左移操作,a中的1就溢出了,因此a的值变为0000 0000,此时我们需要加一个判断,使a再次恢复为0000 0001

C语言中,if条件判断使用方式如下

if(判断条件){//语句}

当判断条件为真时,执行{ }中的语句。

至此,流水灯代码可改成如下形式:

#include <reg52.h>//延时1svoid delay1s(){int i ,j;for(i = 0;i<110; ++i){for(j = 0;j<1000;++j){;}}}void main(){unsigned char a = 0x01;while(1){if(a == 0x00) //如果高位溢出{a = 0x01;//则恢复}//循环点亮led灯P2 = a;a = a<<1;delay1s();}}

如果觉得《51单片机入门教程(2)——实现流水灯》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。