×
单片机 > 单片机程序设计 > 详情

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

发布时间:2021-12-22 发布时间:
|

一、搭建流水灯电路

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

二、流水灯程序

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

程序如下:


#include

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

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:因为该延时函数不需要返回值,所以写为void

delay1s:该函数的函数名,命名需要符合C语言的标识符命名规则。

(): 不需要传入参数,所以括号中为空

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

#include


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;


//延时1s

void 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;


//延时1s

delay1s();


//点亮第二个灯

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


//延时1s

void delay1s()

{

int i ,j;

for(i = 0;i<110; ++i){

for(j = 0;j<1000;++j){

;

}

}

}


void main()

{

unsigned char a1 = 0x01 ; // 0000 0001

unsigned char a2 = 0x02; // 0000 0010

//点亮第一个灯

P2 = a1;


//延时1s

delay1s();


//点亮第二个灯

P2 = a2;

//点亮剩余的灯

//省略……

while(1);

}


2.4 逻辑移位

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

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

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


unsigned char a = 0x01; //a = 0000 0001

unsigned char b = a<<1; // b = 0000 0010

usingned char c = a<<3; //c = 0000 1000


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


#include

//延时1s

void 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


//延时1s

void 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();

}

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
AVR熔丝位操作时的要点和需要注意的相关事项