前言
開發(fā)者在入門點(diǎn)亮第一盞燈后,再深入一點(diǎn)就會(huì)用到流水燈。而如何實(shí)現(xiàn)流水燈又有好幾種方式,我查詢了一網(wǎng)上大神們的作品,無非有三種方式即查詢法、位移法。這篇文章,我就如何實(shí)現(xiàn)流水燈開展討論。
硬件
我以新定義TBK-RD8T3x_v1.0開發(fā)板,為實(shí)驗(yàn)條件。
板載了8個(gè)流水燈。原理圖如下:
實(shí)現(xiàn)方式之一
從原理圖上看,這8個(gè)燈不是接在1個(gè)P口上,分別接到了P3的第1-4,與P4的0-3端口之,按網(wǎng)上的教材位移方法都是不適用的。
于是我寫下了第一種方法那就是直接對(duì)每一個(gè)燈進(jìn)行寫來實(shí)現(xiàn):
#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) //延時(shí)約xms毫秒
{
uint32_t i,j;
for(i=xms*2;i >0;i--)
for(j=112;j >0;j--); //分號(hào)代表跑空,for語句不需要分號(hào),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);
}
}
這樣的編程實(shí)現(xiàn)了流水燈,優(yōu)點(diǎn)是直觀,缺點(diǎn)是編寫起來麻煩,代碼比較長。經(jīng)查看map文件編譯結(jié)果為:Program Size: data=21.0 xdata=28 const=0 code=418
實(shí)現(xiàn)方式之二
用數(shù)組法來實(shí)現(xiàn),我們用數(shù)據(jù)來定義了P4,P3兩組顯示狀態(tài),共組組了9對(duì)分別表示8個(gè)燈的顯示狀態(tài):
#include "rd8.h"
//P40 P41 P42 P43
//P31 P32 P33 P34
//定義LED 狀態(tài)數(shù)組
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) //延時(shí)約xms毫秒
{
uint32_t i,j;
for(i=xms*2;i >0;i--)
for(j=112;j >0;j--); //分號(hào)代表跑空,for語句不需要分號(hào),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);
}
}
這樣用查表法整理出來的的代碼相對(duì)于第一種實(shí)現(xiàn)方式,代碼行有所減短,編譯后,查看.map結(jié)果為:Program Size: data=40.0 xdata=0 const=0 code=454
實(shí)現(xiàn)方式之三
實(shí)現(xiàn)方式2,主要是查表的數(shù)組還是比較點(diǎn)內(nèi)存,這里優(yōu)化一下。
#include "rd8.h"
//P40 P41 P42 P43
//P31 P32 P33 P34
//定義LED 狀態(tài)數(shù)組
//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,我們右移了一位,在顯示時(shí),我們需要左移一位
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) //延時(shí)約xms毫秒
{
uint32_t i,j;
for(i=xms*2;i >0;i--)
for(j=112;j >0;j--); //分號(hào)代表跑空,for語句不需要分號(hào),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);
}
}
這樣優(yōu)化后,點(diǎn)用內(nèi)存有所減少:Program Size: data=31.0 xdata=0 const=0 code=446
實(shí)現(xiàn)方式之四
在方式2、方式3,我們定義了數(shù)組,利用查表法來實(shí)現(xiàn)流水燈。這一節(jié)我用利用位移來實(shí)現(xiàn)。
#include "rd8.h"
void LED_Init(void)
{
P3CON |= 0x1E; //P3 0b0001 1110 輸出
P4CON |= 0x0F; //P4 0b0000 1111
}
void delay(uint32_t xms) //延時(shí)約xms毫秒
{
uint32_t i,j;
for(i=xms*2;i >0;i--)
for(j=112;j >0;j--); //分號(hào)代表跑空,for語句不需要分號(hào),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);
}
}
}
這樣我也實(shí)現(xiàn)了流水燈,這次位移的實(shí)現(xiàn),我們的代碼量變化為:Program Size: data=23.0 xdata=0 const=0 code=325
實(shí)現(xiàn)方式之五
上面所有的流水燈是阻塞式的,我們?nèi)绻枰幚砥涞氖氯?,那就得修改為非阻塞式,這里我們?cè)黾恿?a href="http://www.www27dydycom.cn/tags/定時(shí)器/" target="_blank">定時(shí)器來實(shí)現(xiàn),代碼如下:
#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; // 配置定時(shí)器0為 16位定時(shí)器, TH0、TL0全用
TH0 =(65536-1000)/256; //1000us定時(shí),即1毫秒溢出產(chǎn)生中斷
TL0 =(65536-1000)%256; //1000us定時(shí),即1毫秒溢出產(chǎn)生中斷
ET0 = 1; //開啟定時(shí)器0中斷
EA = 1; //開啟全局中斷
TR0 = 1; //定時(shí)器0開始計(jì)數(shù);
}
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
{
//每次產(chǎn)生中斷后初始化定時(shí)器初值, 1ms秒產(chǎn)生1次中斷
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
//500毫秒執(zhí)行次LED1反轉(zhuǎn)
count ++;
if(count == 500)
{
sta =1;
count = 0;
}
}
經(jīng)過修改,這一版是基于非阻塞式的實(shí)現(xiàn)。編譯后的.map,代碼尺寸如下:Program Size: data=15.0 xdata=0 const=0 code=364
實(shí)現(xiàn)方式之六
這里再增加一種位移的方面代碼如下,這種方式更加簡潔:
#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; // 配置定時(shí)器0為 16位定時(shí)器, TH0、TL0全用
TH0 =(65536-1000)/256; //1000us定時(shí),即1毫秒溢出產(chǎn)生中斷
TL0 =(65536-1000)%256; //1000us定時(shí),即1毫秒溢出產(chǎn)生中斷
ET0 = 1; //開啟定時(shí)器0中斷
EA = 1; //開啟全局中斷
TR0 = 1; //定時(shí)器0開始計(jì)數(shù);
}
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
{
//每次產(chǎn)生中斷后初始化定時(shí)器初值, 1ms秒產(chǎn)生1次中斷
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
//500毫秒執(zhí)行次LED1反轉(zhuǎn)
count ++;
if(count == 500)
{
sta =1;
count = 0;
}
}
此次修改后的.map文件顯示為:Program Size: data=15.0 xdata=0 const=0 code=359
總結(jié)
總結(jié)一下這幾種編程方式點(diǎn)用的空間:
序號(hào) | data | xdata | const | code | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|---|---|---|---|
定義端口法 | 21.0 | 28 | 0 | 418 | 代碼可讀性高,直觀 | 代碼行數(shù)多,如何需要修改比較麻煩 |
數(shù)組查表法 | 40.0 | 0 | 0 | 454 | 代碼較第一種整潔,容易修改 | 占用內(nèi)存大 |
查表法優(yōu)化 | 31.0 | 0 | 0 | 446 | 相比上一種減少了內(nèi)存的占用 | 占用內(nèi)存大 |
位移法之一 | 23.0 | 0 | 0 | 325 | 相比上面的數(shù)組查詢占用內(nèi)存小 | 實(shí)現(xiàn)代碼復(fù)雜 |
非阻塞式位移 | 15.0 | 0 | 0 | 364 | 相比上面的,實(shí)現(xiàn)非阻塞式位移 | 代碼理解需要一定基礎(chǔ) |
非阻塞進(jìn)式位移二 | 15.0 | 0 | 0 | 359 | 代碼更整法,占用空間小,后期實(shí)現(xiàn)功能簡單方便 | 閱讀理解代碼,需要位移的基礎(chǔ)知識(shí) |
審核編輯 黃宇
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44960瀏覽量
648772 -
編程
+關(guān)注
關(guān)注
88文章
3686瀏覽量
95030 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3297瀏覽量
117573 -
流水燈
+關(guān)注
關(guān)注
21文章
433瀏覽量
60401
發(fā)布評(píng)論請(qǐng)先 登錄
如何去點(diǎn)亮基于51單片機(jī)的LED流水燈
基于單片機(jī)的流水燈介紹_51單片機(jī)流水燈的五種實(shí)現(xiàn)方法

使用51單片機(jī)控制的LED的流水燈C語言程序免費(fèi)下載

使用51單片機(jī)實(shí)現(xiàn)LED流水燈的程序和仿真資料免費(fèi)下載

基于AT89C51的單片機(jī)簡易流水燈設(shè)計(jì)(C語言)

51單片機(jī)實(shí)現(xiàn)流水燈

51單片機(jī)流水燈實(shí)驗(yàn)

單片機(jī)led燈閃爍實(shí)驗(yàn)總結(jié)_51單片機(jī)實(shí)現(xiàn)LED流水燈

單片機(jī)51的流水燈

51單片機(jī)流水燈制作

評(píng)論