0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

聊聊流水灯的写法

单片机技术宅 来源:单片机技术宅 作者:单片机技术宅 2021-03-02 15:52 次阅读

流水灯,学单片机时,编程第一课的内容,多少小伙伴的单片机之路都是从流水灯开始的。那有没有想过,我们能用几种方式来写流水灯,各有什么优缺点呢?今天小代就来聊聊流水灯的写法。

硬件介绍:小代采用自己画的STC15开发板,8位LED接P0口,阳极驱动,共阴连接方式,就这么多。

(实际测试时用的数码管模拟,昨天刚接了线,懒得再次重新接线,直接用数码管来代替LED,原理都一样,能验证就好)

1.初学者入门法

直接上代码看后再说

#include"STC15.h"#defineu8unsignedchar#defineu16unsignedintvoid delay_ms(u16x);//ms延时函数void main(){u8led=0x01;u8i=0;P0M1=0x00;//STC15单片机把IO设为推挽输出P0M0=0xff;P2M1=0x00;P2M0=0xff;P2=0xff;//数码管位选驱动,硬件介绍上已经说明原因while(1){//①初学者常见delay延时方式流水灯led=0x01;for(i=0;i<8;i++){            P0=led;            delay_ms(1000);            led=led<<1;        }     }      //while(1) 结束}//main结束 //************************************//功能:ms延时函数 //参数:x--延时的时间长短,x=1000约为1s 24M晶振//作者:小代//微信关注:单片机技术宅//************************************void delay_ms(u16 x){    u16 i,j,k;    for(k=0;k

一看代码37行,太多了,仔细一看,注释和空行占据了一大半,这样一想就开心多了。这个代码没有更多需要解释的,采用最常见的,初学者最喜欢的方式,delay延时方式实现,下面聊优缺点。

优点:简单粗暴好理解,能看懂文字(字母)的都知道

缺点:代码执行效率太低,太低,太低

程序流程图如下图所示,CPU更多的时间是花在“等待1s”上,效率太低,单纯的这样演示流水灯,那这个程序没有任何问题,当在这个程序中再加入其它的程序,必然会出问题,第一流水灯会被执行慢了,第二,新加入的功能反应会很慢,特别是一些实时性有要求的代码。加到这里就会有问题了。为了解决这些问题,我们引出了第二种方式的流水灯。

2.记录主程序执行次数方式

还是先上代码再聊

#include "STC15.h"

#define u8 unsigned char

#define u16 unsigned int

//************************************

//功能:主函数入口 main

//参数:无

//作者:小代

//微信关注:单片机技术宅

//************************************

voidmain(){

u8 led=0x01;

u16main_cnt=0;

P0M1=0x00; //STC15单片机把IO设为推挽输出

P0M0=0xff;

P2M1=0x00;

P2M0=0xff;

P2=0xff; //数码管位选驱动,硬件介绍上已经说明原因

while(1){

//②主程序循环次数实现延时方式流水灯

main_cnt++; //主程序每运行一次,main_cnt将会被加1

//通过if语句实现内部代码块的运行速率降低

//只有主程序循环60000此后,if语句内的代码块才被执行一次

//如若需要更低的执行速率,可以采用两层变量嵌套计数

P0=led;

if(main_cnt>60000){

main_cnt=0; //次数记录清零,为下一次记录准备

if(led==0x80){

led=0x01;

}

else{

led=led<<1;

}

}

} //while(1) 结束

}

//main结束

还是40+行代码,还是注释+空行占据了一半左右。以上代码最大的特点就是没有之前执行效率很低的delay函数,也算是升级了吧。没了delay延时,那如何实现等待的呢?小代慢慢聊。

在while(1)循环里的第21行,只要主程序每运行一次,21行就会对变量main_cnt加1,这个变量定义为16位无符号类型,最大可以到65535,在此,小代记录60000此后就去点亮下一个流水灯的LED,显示效果比方法1的略快,以上注释也说了,如果单一变量记录次数没法满足需要的等待时间,可以采用两个变量嵌套记录的方式。

通过这种方式点亮LED灯,真正的点灯程序段只有在主程序运行60000后才会被运行到一次。仔细看主程序里面,其实就只有一条语句,那就是对main_cnt做加1处理,完了每次都去判断一下main_cnt有没有到60000了,到了后才去处理LED点灯。下面聊聊优缺点。

优点:程序简单,效率高

缺点:点灯的速度会随着主程序内循环语句的增多而降低。

也就是说如果主程序里增加了其他的运行语句,那这里控制点灯的记录次数值就不再是60000,需要减小,或者说60000得到的效果就会让流水灯变慢。程序流程图如下图

到这里,程序执行效率问题我们已经解决了,在这程序基础上加入其它代码后,各个功能还是能运行起来,但是还是有问题,流水灯的速度会改变,为解决这个问题,小代引出了第三种方法。

3.定时器实现

说到定时器,首先还得知道中断的原理,但是,中断和定时器,学单片机连这两个知识点都没学会,那怎好意思说你学过单片机。也就是说中断和定时器就像单片机驱动IO口一样的普通,一样的简单,不要想的多复杂。还是先上代码再聊。

#include "STC15.h"

#define u8 unsigned char

#define u16 unsigned int

voiddelay_ms(u16 x); //ms延时函数

voidTimer0Init(void); //2毫秒@24.000MHz

u16 timer0_cnt=0;

bit timer0_1s_flag=0;

//************************************

//功能:主函数入口 main

//参数:无

//作者:小代

//微信关注:单片机技术宅

//************************************

voidmain(){

u8 led=0x01;

u16main_cnt=0;

P0M1=0x00; //STC15单片机把IO设为推挽输出

P0M0=0xff;

P2M1=0x00;

P2M0=0xff;

P2=0xff; //数码管位选驱动

Timer0Init(); //定时器初始化

while(1){

//③通过定时器中断控制流水灯效果

//主程序里只做LED的驱动

//如果任务少,判断标志位置位都可以放到定时器中断里

//这里统一放到了主循环里

P0=led;

if(timer0_1s_flag==1){

timer0_1s_flag=0; //清除标志位

if(led==0x80){ //是否移动了8次

led=0x01;

}

else{

led=led<<1;

}

}

}//while(1) 结束

}

//main结束

//************************************

//功能:定时器初始化函数

//参数:无

//作者:小代

//微信关注:单片机技术宅

//************************************

voidTimer0Init(void) //2毫秒@24.000MHz

{

AUXR|=0x80; //定时器时钟1T模式

TMOD&=0xF0; //设置定时器模式

TL0=0x80; //设置定时初值

TH0=0x44; //设置定时初值

TF0=0; //清除TF0标志

TR0=1; //定时器0开始计时

ET0=1; //开中断

EA=1;

}

//************************************

//功能:Timer0中断函数 2ms中断一次

//参数:无

//作者:小代

//微信关注:单片机技术宅

//************************************

voidtimer0_int (void) interrupt 1 {

TF0=0;

timer0_cnt++;

if(timer0_cnt==500){

timer0_1s_flag=1;

timer0_cnt=0;

}

}

看到这,一看代码量暴增,一下子就是原来的两倍,其实更多的也还是注释,代码量是有所增加,因为用到了定时器和中断,需要对定时器进行初始化,完了还需要一个中断函数。在这个程序,定时T0每2ms中断一次,进入中断后,中断处理函数直接对timer0_cnt变量加1记录,当记录500次后,说明1s时间到,此时置位1s时间标志位timer0_1s_flag=1。在主程序,只做点灯和判断1s时间到来没有,当1s时间到来后,主程序就去处理LED的移位操作。

优点:效率极高,实时性好,时间稳定

缺点:非要说,那就是用到了定时器和中断,初学者会觉得难

通过这种方式实现流水灯,还可以在主程序中加入其它的代码,并不会影响到流水灯的运行。其实这只是一个最简单的模型,在复杂项目中同样可以用这模型,比如,1s点亮一个LED灯,1ms刷新一次数码管,10ms读取一次按键,500ms读取一次ADC的值等等。这样很多的功能都可以采用这样的模型来实现,并且各个功能之间是互不干扰的。

到此,今天的内容聊完了,其实第三种方式就是“状态机”或者“分时处理”等等一些比较高级的名称就是这么一回事。下次再听到这些高大上的名称时,一定要知道,这并不是什么高深的东西。更重要的是在以后的复杂项目中要会用这样的方式去处理各个功能之间的切换。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6001

    文章

    43973

    浏览量

    620800
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59104
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66746

原文标题:你有几种方法写流水灯

文章出处:【微信号:chuxue_MCU,微信公众号:单片机技术宅】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    51单片机流水灯制作

    流水灯是学习51单片机的一个基本项目,是我们对单片机IO口输出认识的基本项目。当然学会了花样流水灯也很好玩。 下面就分享一种51单片机流水灯制作的方法。 一、流水灯原理图 二、相关知
    的头像 发表于 02-26 10:06 445次阅读
    51单片机<b class='flag-5'>流水灯</b>制作

    利用SCR步进指令实现流水灯循环点亮

    在以往介绍西门子smart文章中,提到过流水灯写法,有用循环位移字[ROL(R)_B]节来实现,有利用定时器(TON)来实现。今天我们利用SCR步进指令来实现流水灯循环点亮,在作这个实验前提必须满足如下几个软硬件条件:
    的头像 发表于 12-04 09:15 756次阅读
    利用SCR步进指令实现<b class='flag-5'>流水灯</b>循环点亮

    如何利用SCR步进指令来实现流水灯循环点亮?

    在以往介绍西门子smart文章中,提到过流水灯写法,有用循环位移字[ROL(R)_B]节来实现,有利用定时器(TON)来实现。
    的头像 发表于 12-04 09:14 1054次阅读
    如何利用SCR步进指令来实现<b class='flag-5'>流水灯</b>循环点亮?

    分享花样流水灯源程序

    电子发烧友网站提供《分享花样流水灯源程序.doc》资料免费下载
    发表于 11-18 09:59 3次下载
    分享花样<b class='flag-5'>流水灯</b>源程序

    怎么设置让流水灯加速?

    流水灯需要可以加速四段
    发表于 10-30 06:05

    如何使用51单片机制作一个心形流水灯

    使用 51 单片机制作一个心形流水灯 心形流水灯,顾名思义,成品肯定是一个心形。随着程序的改变,通过单片机控制单个灯的亮灭达到不同的流动图案效果。 01 单片机,类似于电脑cpu,处理数据的芯片
    的头像 发表于 09-11 10:27 2516次阅读
    如何使用51单片机制作一个心形<b class='flag-5'>流水灯</b>

    9013三极管流水灯(含电路图 PCB图)

    9013三极管流水灯 含电路图 PCB图
    发表于 08-18 15:13 1次下载

    基于FPGA的流水灯设计

    依次点亮4个LED灯,实现流水灯的效果,两灯之间点亮间隔为0.5s,LED灯一次点亮持续时间0.5s。
    的头像 发表于 06-23 16:54 1295次阅读
    基于FPGA的<b class='flag-5'>流水灯</b>设计

    基于FPGA开发板流水灯的设计实现

    流水灯,有时候也叫跑马灯,是一个简单、有趣又经典的实验,基本所有单片机的玩家们在初期学习的阶段都做过。本次我们也来介绍一下如何通过小脚丫FPGA实现一个流水灯
    发表于 06-20 17:10 915次阅读
    基于FPGA开发板<b class='flag-5'>流水灯</b>的设计实现

    基于51单片机设计的花样流水灯设计

    花样流水灯是一种常见的LED灯效果,被广泛应用于舞台表演、节日庆典、晚会演出等场合。
    的头像 发表于 06-11 10:00 2576次阅读
    基于51单片机设计的花样<b class='flag-5'>流水灯</b>设计

    基于51单片机的查表法实现流水灯例程源代码

    基于51单片机的查表法实现流水灯例程源代码
    发表于 05-17 15:04 4次下载

    ARM Cortex-M学习笔记:GPIO流水灯的前世今生

    上一章通过控制GPIO的高低电平实现了流水灯,但只是告诉了大家怎么做,如何实现流水灯,本文将深入剖析的GPIO流水灯的前生今世,深入研究流水灯的调用逻辑和数据结构。
    的头像 发表于 05-15 14:44 1919次阅读
    ARM Cortex-M学习笔记:GPIO<b class='flag-5'>流水灯</b>的前世今生

    ARM Cortex-M学习笔记:初识GPIO流水灯

    熟悉单片机的朋友都知道,学习的第一个例程就是流水灯,要想实现流水灯,首先必须了解GPIO的工作原理。GPIO的基本结构如图1所示。
    的头像 发表于 05-15 11:31 2221次阅读
    ARM Cortex-M学习笔记:初识GPIO<b class='flag-5'>流水灯</b>

    GD32开发实战指南(基础篇) 第3章 GPIO流水灯的前世今生

    上一章通过控制GPIO的高低电平实现了流水灯,但只是告诉了大家怎么做,如何实现流水灯,本文将深入剖析的GPIO流水灯的前生今世,深入研究流水灯的调用逻辑和数据结构。
    的头像 发表于 05-10 08:58 4517次阅读
    GD32开发实战指南(基础篇) 第3章 GPIO<b class='flag-5'>流水灯</b>的前世今生

    GD32开发实战指南(基础篇) 第2章 初始GPIO流水灯

    熟悉单片机的朋友都知道,学习的第一个例程就是流水灯,要想实现流水灯,首先必须了解GPIO的工作原理。GPIO的基本结构如下图所示。
    的头像 发表于 05-08 09:03 6451次阅读
    GD32开发实战指南(基础篇) 第2章 初始GPIO<b class='flag-5'>流水灯</b>