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

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

发布时间:2020-08-21 发布时间:
|

一、搭建流水灯电路

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

}

}

关键字:51单片机  入门教程  流水灯

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

热门文章 更多
单片机中高阻态的实质及意义