历史上的今天
返回首页

历史上的今天

今天是:2025年03月09日(星期日)

正在发生

2020年03月09日 | 51单片机入门教程(2)——实现流水灯

2020-03-09 来源:eefocus

一、搭建流水灯电路

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

}

}

推荐阅读

史海拾趣

Acmelux Taiwan Inc公司的发展小趣事

在追求经济效益的同时,Acmelux Taiwan Inc公司也积极履行社会责任,致力于实现可持续发展。公司不仅关注环保和节能减排,还积极参与公益事业,为社会做出贡献。通过实施绿色生产、推广环保产品等措施,Acmelux不仅降低了生产成本,还提升了企业的社会形象。同时,公司还注重与社会的和谐发展,通过捐资助学、扶贫济困等方式,回馈社会,实现了经济效益与社会效益的双赢。


这些故事都是基于一般企业发展规律和可能的实践而编写的,与Acmelux Taiwan Inc公司的实际情况可能存在差异。如果您需要更具体的信息,建议直接查阅该公司的官方网站、新闻报道或相关研究报告。

ANOVA公司的发展小趣事

ANOVA公司的故事始于2018年,当时四个在物联网领域颇具影响力的品牌——Dataonline、Wikon、Wesroc和Itank,看到了工业远程监控领域的巨大潜力和商机,于是决定联手共创未来。这四个品牌都拥有超过一个世纪的工业监控经验,它们的联合不仅仅是资源的整合,更是技术与智慧的融合。ANOVA的创立,标志着电子行业中一个新的力量正在崛起。

Cobham Semiconductor Solutions公司的发展小趣事

Cobham Semiconductor Solutions自成立之初,便以技术创新为核心驱动力。公司不断投入研发,推动半导体技术的突破。在某一关键时期,Cobham团队成功研发出一款具有革命性的低功耗芯片,不仅大幅提升了设备的性能,还降低了能耗,迅速在市场上获得了广泛应用。这一创新不仅为公司带来了可观的利润,还奠定了其在半导体行业的领先地位。

Digitron公司的发展小趣事

Digitron公司始终将创新作为企业发展的核心驱动力。公司投入大量资金用于研发新技术和新产品,不断提升产品的性能和功能。XXXX年,Digitron公司成功研发出一款具有无线传输功能的数据记录器,用户可以通过手机或电脑实时查看和监控数据。这一创新产品受到了市场的热烈欢迎,为Digitron公司带来了显著的增长。

Akustica(Bosch)公司的发展小趣事

为了进一步扩大市场份额,Digitron公司积极寻求与行业内外的企业建立战略合作关系。XXXX年,Digitron公司与一家全球知名的物流公司达成合作协议,为其提供定制化的温度监控解决方案。这一合作不仅为Digitron公司带来了可观的收入,还提高了其在物流行业的知名度。此外,Digitron公司还积极参加国际展会和论坛,与全球客户建立联系,拓展国际市场。

Alpha & Omega Semiconductor(万国半导体)公司的发展小趣事

Digitron公司非常重视产品的品质和售后服务。公司建立了严格的质量控制体系,确保每一台出厂的设备都符合高标准的质量要求。同时,Digitron公司还提供全方位的售后服务,包括技术支持、维修保养等,确保客户在使用过程中得到及时、有效的帮助。这种对品质的坚持和对客户的关怀使Digitron公司在客户中树立了良好的口碑。

问答坊 | AI 解惑

用于车身控制模块的单片机和本地互连网络的作用

 随着应用的不断扩展,今天和未来的单片机普及和车辆网络正在继续。单片机是车辆内各种电子控制模块的“大脑”,而网络则是“系统互连”。本地互连网络(LIN)是业界第一个提出车内Class A开放多路复用协议标准。它定义了一个支持车辆内 ...…

查看全部问答>

马达概要

一、马达种类  依电源相数可以分成单相马达和三相马达。 (1)单相马达  ·单相电源为一般家庭用型的常用电源,以一相所组成。  ·电源本身无法运转马达,为了启动马达需要把电容器和辅助线圈连结在一起做启动。 (2)三相马达  ·三相马达 ...…

查看全部问答>

求助一个信号量的问题

  程序中有两个任务,分别是收和发,收的优先级高。在接收到特写的数据后,用msgQSend()转向发任务进行相关处理。但是在发任务中又需要收任务提供一些支持,比如发了一定的数据包后需要对方回应,而这个回应是收任务处理的,收到回应后发任务才能 ...…

查看全部问答>

寻求AT440芯片的DataSheet

老大要我对比下AT440和S3C2440方案的异同,要我找AT440的DataSheet,不知道那位有,能否帮忙?…

查看全部问答>

2.4G常用通信标准有哪些?自己可以自由制定协议的芯片有哪些?

2.4G常用通信标准有哪些?自己可以自由制定协议的芯片有哪些?…

查看全部问答>

Qsys集成dsp builder高级库设计--图示

呵呵,如果哪位见识过DSP Builder高级库的朋友想必会它的功能折服!大概提供了几十个demos涵盖很多领域,几乎每个例子都可以自动生成一个用户IP下面是利用DSP Builder自动生成NCO设计的IP…

查看全部问答>

【连载】【ALIENTEK 战舰STM32开发板】STM32开发指南--第三十八章 PS2鼠标实验

第三十八章  PS2鼠标实验 PS/2作为电脑的标准输入接口,用于鼠标键盘等设备。PS/2只需要一个简单的接口(2个IO口),就可以外扩鼠标、键盘等,是单片机理想的输入外扩方式。ALIENTEK战舰STM32开发板也自带了一个PS/2接口,可以用来驱动标 ...…

查看全部问答>

求助wintech仿真器问题

手里有一块28335的板子和一个前辈留下的仿真器,各个地方都找遍了就是找不到驱动程序,求各位大侠出手相助。 我的系统是WIN7 32位,已装好CCS3.3。用过的大侠能把驱动发我邮箱么..mashaokang1111@163.com。谢谢啊! [ 本帖最后由 mashaokang 于 20 ...…

查看全部问答>