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

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

3天内不再提示

51单片机LED流水灯多种驱动方式

华仔的编程随笔 来源:华仔stm32 作者:华仔stm32 2023-04-24 15:29 次阅读

前言

开发者在入门点亮第一盏灯后,再深入一点就会用到流水灯。而如何实现流水灯又有好几种方式,我查询了一网上大神们的作品,无非有三种方式即查询法、位移法。这篇文章,我就如何实现流水灯开展讨论。

硬件

我以新定义TBK-RD8T3x_v1.0开发板,为实验条件。

image.png

板载了8个流水灯。原理图如下:

image.png

实现方式之一

从原理图上看,这8个灯不是接在1个P口上,分别接到了P3的第1-4,与P4的0-3端口之,按网上的教材位移方法都是不适用的。

于是我写下了第一种方法那就是直接对每一个灯进行写来实现:

#include "rd8.h"


#define ON 1
#define OFF 0

sbit LED0 = P4^0;
sbit LED1 = P4^1;
sbit LED2 = P4^2;
sbit LED3 = P4^3;
sbit LED4 = P3^1;
sbit LED5 = P3^2;
sbit LED6 = P3^3;
sbit LED7 = P3^4;

void  delay(uint32_t xms)   //延时约xms毫秒
{
    uint32_t  i,j;
    for(i=xms*2;i >0;i--)
    for(j=112;j >0;j--);    //分号代表跑空,for语句不需要分号,112次表示一毫秒
}

void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}



void main(void)
{
	LED_Init();
	while(1)
	{
		LED0 = ON;
		delay(500);
		
		LED0 = OFF;
		LED1 = ON;
		delay(500);
		
		LED1 = OFF;
		LED2 = ON;
		delay(500);
		
		LED2 = OFF;
		LED3 = ON;
		delay(500);
		
		LED3 = OFF;
		LED4 = ON;
		delay(500);
		
		LED4 = OFF;
		LED5 = ON;
		delay(500);
		
		LED5 = OFF;
		LED6 = ON;
		delay(500);
		
		LED6 = OFF;
		LED7 = ON;
		delay(500);
		
		LED7 = OFF;
		delay(500);
	}
}

这样的编程实现了流水灯,优点是直观,缺点是编写起来麻烦,代码比较长。经查看map文件编译结果为:Program Size: data=21.0 xdata=28 const=0 code=418

实现方式之二

用数组法来实现,我们用数据来定义了P4,P3两组显示状态,共组组了9对分别表示8个灯的显示状态:

#include "rd8.h"

//P40 P41 P42 P43 
//P31 P32 P33 P34  
//定义LED 状态数组 

static uint8_t LEDs[]={0x00,0x00,0x01,0x00, 0x02,0x00,0x04,0x00,0x08,0x00, 0x00,0x02, 0x00,0x04, 0x00,0x08,0x00,0x10};  


void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}


void delay(uint32_t xms)   //延时约xms毫秒
{
    uint32_t  i,j;
    for(i=xms*2;i >0;i--)
    for(j=112;j >0;j--);    //分号代表跑空,for语句不需要分号,112次表示一毫秒
}

void LED_Flash(void)
{
	static uint8_t ledIndex = 0;
	if(ledIndex == 9)
		ledIndex = 0;
	P4 = LEDs[ledIndex*2];
	P3 = LEDs[ledIndex*2+1];
	ledIndex ++;
	
}


void main(void)
{
	LED_Init();

	while(1)
	{
		LED_Flash();
		delay(500);
	}
}

这样用查表法整理出来的的代码相对于第一种实现方式,代码行有所减短,编译后,查看.map结果为:Program Size: data=40.0 xdata=0 const=0 code=454

实现方式之三

实现方式2,主要是查表的数组还是比较点内存,这里优化一下。

#include "rd8.h"

//P40 P41 P42 P43 
//P31 P32 P33 P34  
//定义LED 状态数组 

//static uint8_t LEDs[]={0x00,0x00,0x01,0x00, 0x02,0x00,0x04,0x00,0x08,0x00, 0x00,0x02, 0x00,0x04, 0x00,0x08,0x00,0x10};  
//                            高四位代表P4 低四位代表P3 由于P3 为1-4,我们右移了一位,在显示时,我们需要左移一位
static uint8_t LEDs[]={0x00,// 0b 0000 00000
											 0x10,// 0b 0001 00000 
                       0x20,
                       0x40,
                       0x80,
                       0x01,//0b 0000 0001 
                       0x02, 0x04,0x08,}; 
void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}


void delay(uint32_t xms)   //延时约xms毫秒
{
    uint32_t  i,j;
    for(i=xms*2;i >0;i--)
    for(j=112;j >0;j--);    //分号代表跑空,for语句不需要分号,112次表示一毫秒
}

void LED_Flash(void)
{
	static uint8_t ledIndex = 0;
	if(ledIndex == 9)
		ledIndex = 0;
	P4 = (LEDs[ledIndex] & 0xF0) >>4;
	P3 = (LEDs[ledIndex] & 0x0F)< < 1;
	ledIndex ++;
	
}


void main(void)
{
	LED_Init();

	while(1)
	{
		LED_Flash();
		delay(500);
	}
}

这样优化后,点用内存有所减少:Program Size: data=31.0 xdata=0 const=0 code=446

实现方式之四

在方式2、方式3,我们定义了数组,利用查表法来实现流水灯。这一节我用利用位移来实现。

#include "rd8.h"

void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}


void delay(uint32_t xms)   //延时约xms毫秒
{
    uint32_t  i,j;
    for(i=xms*2;i >0;i--)
    for(j=112;j >0;j--);    //分号代表跑空,for语句不需要分号,112次表示一毫秒
}

void LED_Flash(uint8_t led_data)
{
	P3 = (led_data & 0xF0) >>3;  //由于P3从1开始,所以只右移3位
	P4 = (led_data & 0x0F);
}


void main(void)
{
	uint8_t LED_DATA;
	uint8_t i;
	LED_Init();
	
	while(1)
	{
		LED_DATA = 0x00;
		LED_Flash(LED_DATA); // 这里开始是熄灭所有的灯
		delay(500);
		LED_DATA = 0x01;      //初始值
		for(i=0;i< 9;i++)
		{
			LED_Flash(LED_DATA);
			LED_DATA = LED_DATA < < 1;
			delay(500);		
		}
	}
}

这样我也实现了流水灯,这次位移的实现,我们的代码量变化为:Program Size: data=23.0 xdata=0 const=0 code=325

实现方式之五

上面所有的流水灯是阻塞式的,我们如果需要处理其的事任,那就得修改为非阻塞式,这里我们增加了定时器来实现,代码如下:

#include "rd8.h"

uint8_t sta;  
uint32_t count = 0;

void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}

void Timer0Iint(void)
{
	TMOD |= 0x01;  // 配置定时器0为 16位定时器,  TH0、TL0全用 
	TH0 =(65536-1000)/256;   //1000us定时,即1毫秒溢出产生中断
	TL0 =(65536-1000)%256;  //1000us定时,即1毫秒溢出产生中断
	ET0 = 1;									//开启定时器0中断
	EA = 1;										//开启全局中断
	TR0 = 1;									//定时器0开始计数;
}

void LED_Flash(void)
{
	static uint8_t led_data = 0x00;

	P3 = (led_data & 0xF0) >>3;  //由于P3从1开始,所以只右移3位
	P4 = (led_data & 0x0F);
	led_data = led_data< < 1;
	if (led_data == 0x00)
		led_data = led_data |= 0x01;
}


void main(void)
{
	Timer0Iint();
	LED_Init();
	
	while(1)
	{
		if(sta == 1)
		{
			sta = 0;
			LED_Flash();		
		}
	}
}

void Timer0() interrupt 1
{
	//每次产生中断后初始化定时器初值, 1ms秒产生1次中断
	TH0=(65536-1000)/256;
	TL0=(65536-1000)%256;
	//500毫秒执行次LED1反转
	count ++;
	if(count == 500)
	{
		sta =1;
		count = 0;
	}
	
}

经过修改,这一版是基于非阻塞式的实现。编译后的.map,代码尺寸如下:Program Size: data=15.0 xdata=0 const=0 code=364

实现方式之六

这里再增加一种位移的方面代码如下,这种方式更加简洁:

#include "rd8.h"
#include 
uint8_t sta;  
uint32_t count = 0;

void LED_Init(void)
{
	P3CON |= 0x1E; //P3 0b0001 1110 输出
	P4CON |= 0x0F; //P4 0b0000 1111
}

void Timer0Iint(void)
{
	TMOD |= 0x01;  // 配置定时器0为 16位定时器,  TH0、TL0全用 
	TH0 =(65536-1000)/256;   //1000us定时,即1毫秒溢出产生中断
	TL0 =(65536-1000)%256;  //1000us定时,即1毫秒溢出产生中断
	ET0 = 1;									//开启定时器0中断
	EA = 1;										//开启全局中断
	TR0 = 1;									//定时器0开始计数;
}

void LED_Flash(void)
{
	static uint8_t led_data = 0x01;
	led_data = _crol_(led_data,1);
	P3 = (led_data & 0xF0) >>3;  //由于P3从1开始,所以只右移3位
	P4 = (led_data & 0x0F);
//	led_data = led_data< < 1;
//	if (led_data == 0x00)
//		led_data = led_data |= 0x01;
}


void main(void)
{
	Timer0Iint();
	LED_Init();
	
	while(1)
	{
		if(sta == 1)
		{
			sta = 0;
			LED_Flash();		
		}
	}
}

void Timer0() interrupt 1
{
	//每次产生中断后初始化定时器初值, 1ms秒产生1次中断
	TH0=(65536-1000)/256;
	TL0=(65536-1000)%256;
	//500毫秒执行次LED1反转
	count ++;
	if(count == 500)
	{
		sta =1;
		count = 0;
	}
	
}

此次修改后的.map文件显示为:Program Size: data=15.0 xdata=0 const=0 code=359

总结

总结一下这几种编程方式点用的空间:

序号dataxdataconstcode优点缺点
定义端口法21.0280418代码可读性高,直观代码行数多,如何需要修改比较麻烦
数组查表法40.000454代码较第一种整洁,容易修改占用内存大
查表法优化31.000446相比上一种减少了内存的占用占用内存大
位移法之一23.000325相比上面的数组查询占用内存小实现代码复杂
非阻塞式位移15.000364相比上面的,实现非阻塞式位移代码理解需要一定基础
非阻塞进式位移二15.000359代码更整法,占用空间小,后期实现功能简单方便阅读理解代码,需要位移的基础知识

审核编辑 黄宇

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

    关注

    6035

    文章

    44553

    浏览量

    634724
  • 编程
    +关注

    关注

    88

    文章

    3614

    浏览量

    93692
  • 定时器
    +关注

    关注

    23

    文章

    3246

    浏览量

    114733
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59697
收藏 人收藏

    评论

    相关推荐

    如何去点亮基于51单片机LED流水灯

    如何让8个小灯依次一个接一个的点亮?怎样去编写基于51单片机LED流水灯的程序?如何去点亮基于51单片
    发表于 08-11 08:49

    基于51单片机的心形流水灯原理图

    51单片机控制的心形流水灯原理图,通心形流水灯的制作熟悉单片机的接口
    发表于 11-23 11:03 72次下载

    51单片机流水灯程序

    51单片机流水灯程序 51单片机流水灯程序
    发表于 12-21 15:52 170次下载

    基于单片机流水灯介绍_51单片机流水灯的五种实现方法

    本文为大家带来五种51单片机流水灯的实现方法。
    发表于 01-06 10:23 5.1w次阅读
    基于<b class='flag-5'>单片机</b>的<b class='flag-5'>流水灯</b>介绍_<b class='flag-5'>51</b><b class='flag-5'>单片机</b><b class='flag-5'>流水灯</b>的五种实现方法

    使用51单片机控制的LED流水灯C语言程序免费下载

    本文档的主要内容详细介绍的是使用51单片机控制的LED流水灯C语言程序免费下载。
    发表于 03-25 18:19 17次下载
    使用<b class='flag-5'>51</b><b class='flag-5'>单片机</b>控制的<b class='flag-5'>LED</b>的<b class='flag-5'>流水灯</b>C语言程序免费下载

    使用51单片机实现LED流水灯的程序和仿真资料免费下载

    本文档的主要内容详细介绍的是使用51单片机实现LED流水灯的程序和仿真资料免费下载。
    发表于 12-07 08:00 38次下载
    使用<b class='flag-5'>51</b><b class='flag-5'>单片机</b>实现<b class='flag-5'>LED</b><b class='flag-5'>流水灯</b>的程序和仿真资料免费下载

    基于51单片机流水灯参考案例下载

    基于51单片机流水灯参考案例下载
    发表于 09-05 17:02 42次下载

    基于AT89C51单片机简易流水灯设计(C语言)

    ,区别于汇编语言。在进行单片机学习时,流水灯是基础的练习,了解单片机程序编程的基本语句。本文章的流水灯仅仅实现简单的单个LED依次亮灭。在后
    发表于 11-05 11:06 19次下载
    基于AT89C<b class='flag-5'>51</b>的<b class='flag-5'>单片机</b>简易<b class='flag-5'>流水灯</b>设计(C语言)

    51单片机实现流水灯

    文章目录51单片机实现流水灯一、点亮第一个LED灯二、流水灯1.总线型控制2.延时函数3._ crol _函数使用4. 实现
    发表于 11-05 13:36 24次下载
    <b class='flag-5'>51</b><b class='flag-5'>单片机</b>实现<b class='flag-5'>流水灯</b>

    C51单片机流水灯C代码

    C51单片机流水灯C代码
    发表于 11-05 15:20 34次下载
    C<b class='flag-5'>51</b><b class='flag-5'>单片机</b><b class='flag-5'>流水灯</b>C代码

    51单片机流水灯教程。

    51单片机流水灯教程。
    发表于 11-11 20:21 22次下载
    <b class='flag-5'>51</b><b class='flag-5'>单片机</b><b class='flag-5'>流水灯</b>教程。

    51单片机流水灯实验

    基于51单片机流水灯实验 我们知道通过编写程序对51单片机进行控制,完成流水灯实验的
    发表于 11-20 17:51 66次下载
    <b class='flag-5'>51</b><b class='flag-5'>单片机</b><b class='flag-5'>流水灯</b>实验

    单片机led灯闪烁实验总结_51单片机实现LED流水灯

    流水灯51单片机实现点亮1个2个3个……8个流水灯。我们选择P1口作为控制端口,输出0时LED灯点亮。
    发表于 11-23 16:19 26次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>led</b>灯闪烁实验总结_<b class='flag-5'>51</b><b class='flag-5'>单片机</b>实现<b class='flag-5'>LED</b><b class='flag-5'>流水灯</b>

    单片机51流水灯

    实验一 单片机流水灯【实验目的】1、熟练掌握AT89C51开发板的使用方法和注意事项。2、了解简单单片机应用系统的设计方法。3、掌握应用KEIL软件编辑、编译源程序的操作方法。4、掌握
    发表于 11-23 16:20 24次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>51</b>的<b class='flag-5'>流水灯</b>

    51单片机流水灯制作

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