分享

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

 幽州浅水 2021-03-18

一、搭建流水灯电路

在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); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

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

2.1 延时程序

单片机的执行指令速度非常快,一个晶振是12MHz的单片机执行一条指令的速度是微秒级的,所以点亮第一个灯的时间太短了,以至于我们根本没有察觉。
因此我们需要一个延时的语句。
实现延时的方法就是循环执行很多次空指令。程序如下:

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

#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); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

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

2.2 延时函数

我们剩下的任务就是依次点亮每个灯,但是每次点亮一个灯就需要写一段延时程序,很麻烦!
为了程序的可读性(toulan),可以把延时程序写成一个子函数,随时供我们使用。
C语言中子函数的定义方式如下

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

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

void delay1s() { int i,j; for(i = 0; i<110;++i) { for(j = 0; j<1000;++j) { //什么也不做 } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

几点说明:

  • void:因为该延时函数不需要返回值,所以写为void
  • delay1s:该函数的函数名,命名需要符合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;

//延时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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

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;
  • 1
  • 2
  • 1
  • 2

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

#include <reg52.h>

//延时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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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

#include <reg52.h>
//延时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();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

2.5 条件判断

因为在移位操作中,当变量a的值为1000 0000时,再次执行左移操作,a 中的1就溢出了,因此a的值变为0000 0000,此时我们需要加一个判断,使a再次恢复为0000 0001
C语言中,if条件判断使用方式如下

if(判断条件) { //语句 }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

当判断条件为真时,执行{ }中的语句。
至此,流水灯代码可改成如下形式:

#include <reg52.h>

//延时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();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多