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

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

    关注

    6032

    文章

    44513

    浏览量

    632840
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59634
  • 代码
    +关注

    关注

    30

    文章

    4742

    浏览量

    68333

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

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

收藏 人收藏

    评论

    相关推荐

    基于51单片机的跑马灯/流水灯系统

    具体实现功能(1)9种LED流水灯模式通过按键进行切换,数码管显示流水灯模式。(2)通过加减按键可以切换每种LED流水灯的速度。仿真演示视频:设计介绍51单片机简介51单片是一种低功耗、高性能
    的头像 发表于 10-22 14:12 154次阅读
    基于51单片机的跑马灯/<b class='flag-5'>流水灯</b>系统

    FPGA 实验一:流水灯模块

    实验一:流水灯模块 对于发展商而言,动土仪式无疑是最重要的任务。为此,流水灯实验作为低级建模II的动土仪式再适合不过了。废话少说,我们还是开始实验吧。 图1.1 实验一建模图。 如图1.1 所示
    发表于 06-10 09:38

    单片机POV LED流水灯制作

    电子发烧友网站提供《单片机POV LED流水灯制作.docx》资料免费下载
    发表于 05-28 14:34 3次下载

    【紫光同创盘古PGX-Nano教程】——(盘古PGX-Nano开发板/PG2L50H_MBG324第三章)键控流水灯实验例程

    灯、按键、拨码开关等。 二:实验目的 由PB0(即开发板S0位置)按键输入,切换LED0~LED7的输出效果。 三:实验原理 实现框架如下: (1)顶层实现按键切换LED的流水灯状态
    发表于 04-29 16:06

    【紫光同创盘古PGX-MINI-4K教程】——(盘古PGX-MINI-4K开发板/PGC4KD-6ILPG144第二章)LED 流水灯实验例程

    载 jtag 调试接口, 预留两组 20PIN 扩展 IO、数码管、按键、led 灯等硬件资源,为用户提供基本的 开发环境。 二:实验目的掌握流水灯原理并实现流水灯 三:实验要求流水灯:8 个
    发表于 03-26 16:24

    51单片机流水灯制作

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

    【紫光同创国产FPGA教程】——(PGL22G第二章)键控流水灯实验例程

    ~ USER_LED8 的输出效果。 三:实验原理 实现框架如下: (1)顶层实现按键切换 LED 的流水灯状态; (2)需要设计一个输入控制模块及一个输出控制模块; 这个实验带大家将多个模块整合
    发表于 01-05 11:22

    PLC控制8盏流水灯电路原理图和实际接线图详解

    PLC控制8盏流水灯电路原理图和实际接线图
    的头像 发表于 12-27 11:47 6089次阅读
    PLC控制8盏<b class='flag-5'>流水灯</b>电路原理图和实际接线图详解

    【每周一练】盘古1K开发板 练习一:LED流水灯实验

    查看附件中的快速使用手册。 LED流水灯实验 本次实验实现LED流水灯,使用的到的硬件为LED灯,在【每周一练】小眼睛FPGA1K开发板硬件平台中使用的LED硬件和管脚分布进行了介绍。 实现流水灯效果
    发表于 12-21 00:20

    【每周一练】盘古1K开发板 练习一:LED流水灯

    实验目的 熟悉PDS开发流程,掌握流水灯原理并实现流水灯。 实验要求 设计8个LED以0.5s间隔接替点亮。 学习心得 实现了IO控制,点亮了LED。 实现了LED逆序点亮。LED8-->1点亮方式。
    发表于 12-10 16:39

    【每周一练】盘古1K开发板 练习一:LED流水灯实验学习

    实验目的 熟悉PDS开发流程,掌握流水灯原理并实现流水灯 实验要求 设计8个LED以0.5s间隔接替点亮 实现代码 `define UD #1 module led_light
    发表于 12-09 14:20

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

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

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

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

    使用74HC595驱动LED流水灯实验

    本次实验的simulink模型如图5.2所示,实验现象可以通过改变控制PC6引脚的“constant2”变量实现LED流水灯效果,如图5.1所示,本次实验电路原理如图5.3所示,STM32引脚
    的头像 发表于 11-29 16:20 1885次阅读
    使用74HC595驱动LED<b class='flag-5'>流水灯</b>实验

    【每周一练】+盘古1K开发板+环境建立与流水灯

    下载线,该下载线的连接请参考“小眼睛FPGA”微信视频号中的“#紫光同创盘古系列FPGA开发板@盘古1K2K开发板 烧录器下载器 连接教程”。 二、流水灯测试 要实现流水灯的效果,在FPGA中比
    发表于 11-27 21:57