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

51单片机入门教程(2)——实现流水灯51单片机入门教程(2)——实现流水灯一、搭建流水灯电路二、流水灯程序2.1延时程序2.2延时函数2.3按字节寻址2.4逻辑移位2.5条件判断一、搭建流水灯电路在Proteus中搭建流水灯电路如图二、流水灯程序我们可以把流水灯看作依次点亮若干个灯。程序如下:#include<reg52.h>sbitled1=P2^0;sbitled2=P2^1…

大家好,又见面了,我是你们的朋友全栈君。

一、搭建流水灯电路

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

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>

//延时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 <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();
	}
}

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

2.5 条件判断

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

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

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

#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();
	}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132711.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • C++ override使用详解

    C++ override使用详解C++override从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法。   公有继承包含两部分:一是“接口”(interface),二是”实现”

    2025年7月10日
    0
  • Java中数组的输入输出

    Java中数组的输入输出数组的输入首先声明一个int型数组int[]a或者inta[]给数组分配空间a=newint[10];和声明连起来就是int[]a=newint[10];或者是inta[]=newint[10];给数组赋值a[0]=1;//0代表的是数组的第1个元素,元素下标为0a[1]=1;//1代表的是数组的第2个元素,元素下标为0访问数组数据…

    2022年5月20日
    45
  • Java设置全局变量_java如何定义全局变量

    Java设置全局变量_java如何定义全局变量//思想是将全局变量X设置成SS类的属性,//再在SS中添加fuzhi方法,来改变X的值。

    2022年8月21日
    10
  • meanshift算法图解

    meanshift算法图解本博将对meanshift算法进行总结,包括meanshift算法原理以及公式推导,图解,图像聚类,目标跟踪中的应用及优缺点总结。算法原理meanshift算法其实通过名字就可以看到该算法的核心,mean(均值),shift(偏移),简单的说,也就是有一个点 ,它的周围有很多个点  我们计算点  移动到每个点  所需要的偏移量之和,求平均,就得到平均偏移量,(该偏移量的方向是周围点分布密集…

    2022年7月13日
    12
  • 抓包工具Charles使用技巧

    抓包工具Charles使用技巧抓包工具charles使用技巧抓取HTTPS从本地文件读取数据作为接口数据数据转发mapremote

    2022年5月22日
    47
  • office2007安装包下载,专业版&完整版&官方原版

    office2007安装包下载,专业版&完整版&官方原版网络上office的版本各异,各种修改版精简版也是比比皆是,,让用户无从选择。更有甚者夹带私货(流氓程序和木马病毒捆绑),破坏系统,导致各种异常。所以最好的办法是通过官方渠道下载完整版。分享的office安装包都是官方原版(完整版),大家可以放心下载安装。1.基本介绍office2007是office的经典版本之一,开发代号office12,在功能界面等方面和office2003有很大的区别…

    2022年7月19日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号