LED流水燈
前言:
前幾篇學(xué)會(huì)了LED驅(qū)動(dòng)原理,并且成功點(diǎn)亮了一顆LED和實(shí)現(xiàn)了LED的閃爍,那么這篇緊接著就來解鎖LED的新功能,LED流水燈。當(dāng)然這里前提是基于肉眼余暉可見光達(dá)成的效果。
1、硬件電路設(shè)計(jì)和原理分析
開發(fā)板上 LED 模塊電路原理圖如下圖所示:
看上圖中 LED 采用共陽接法,D1-D8 連接到單片機(jī)的 P20-P27 口,即所有LED 陽極管腳接電源 VCC,陰極管腳通過一個(gè) 470 歐的限流電阻接到 P2 口上。
原理分析:
根據(jù)前面篇章 點(diǎn)亮一顆LED 的介紹我們知道,要讓 LED 發(fā)光即對(duì)應(yīng)的陰極管腳應(yīng)該為低電平,若為高電平則熄滅。
根據(jù)前面篇章 LED閃爍 的介紹我們知道,要讓 LED 閃爍,主要引用延時(shí)函數(shù)。
所以如果要想 51 單片機(jī)控制 LED實(shí)現(xiàn)流水燈的效果,就必須通過單片機(jī)管腳在 P2 口上反復(fù)循環(huán)的調(diào)用寄存器控制對(duì)應(yīng)D1~D8引腳的高低電平,當(dāng)?shù)谝活wLED點(diǎn)亮,則其它LED處于熄滅狀態(tài),當(dāng)?shù)诙wLED點(diǎn)亮?xí)r,其它LED處于熄滅狀態(tài),同理,其余的LED都是這個(gè)邏輯,其次MCU執(zhí)行程序語句都會(huì)有一定的時(shí)間,為了達(dá)到人肉眼的余暉效應(yīng),因此只需編寫一個(gè)循環(huán)函數(shù),讓CPU 不干其它事,專門在那循環(huán)運(yùn)行即可實(shí)現(xiàn)延時(shí)功能。
2、軟件設(shè)計(jì)
程序這邊主要介紹兩種思路的寫法:
(1)、利用循環(huán)和移位操作符,實(shí)現(xiàn)反復(fù)改寫對(duì)應(yīng)LED端口高低電平的改寫。實(shí)驗(yàn)效果:?jiǎn)蜗蛄魉疅?br> (2)、利用封裝好的庫函數(shù):左移_crol_、右移_cror_函數(shù)實(shí)現(xiàn)流水燈效果。實(shí)驗(yàn)效果:雙向流水燈
2.1、利用循環(huán)和移位操作符功能實(shí)現(xiàn):LED流水燈
//1.利用循環(huán)和移位操作符<< >>
/**/
#include <reg52.h>
#define LED_PORT P2//使用宏定義--- P2端口
typedef unsigned int u16;
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void main()
{
int i = 0;
//LED_PORT = 0xfe;
//LED_PORT = 0x01;
while(1)
{
for(i=0;i<8;i++)
{
LED_PORT = ~(0x01<<i);//i=0時(shí),D1燈亮,i++依次點(diǎn)亮
//移位后自動(dòng)補(bǔ)0,當(dāng)7次移位后,高位的1被移走,低位就自動(dòng)補(bǔ)0
//導(dǎo)致同時(shí)會(huì)亮兩個(gè)燈,那么就采取取反操作符。以移動(dòng)1然后取反來解決移位補(bǔ)0的這個(gè)問題
delay_10us(50000);
}
}
}
解釋說明:
前面章節(jié)已經(jīng)介紹了的內(nèi)容,這里的 delay_10us延時(shí)函數(shù) 和 typedef 類型重命名,就一筆帶過了。具體參考:前面篇章 點(diǎn)亮一顆LED 的介紹
然后這里簡(jiǎn)單說一下,#define關(guān)鍵字,是C語言中的一個(gè)宏定義預(yù)處理指令(“#”開頭的均為預(yù)處理命令)命令,它用來將一個(gè)標(biāo)識(shí)符定義為一個(gè)字符串,語法格式如:#define LED_PORT P2,該LED_PORT標(biāo)識(shí)符被稱為宏名,被定義的字符串P2稱為替換文本。
大概描述一下,主要的作用就是,在遇見大量重復(fù)又需要經(jīng)常改變的參數(shù),常常用宏定義一個(gè)新的字符串替換標(biāo)識(shí)符,從而實(shí)現(xiàn)便捷的更換程序參數(shù)。
最后,主函數(shù)main:進(jìn)入 main 函數(shù)后首先定義一個(gè)變量 i,然后進(jìn)入 while 循環(huán),由于要實(shí)現(xiàn) 8個(gè) LED 從 D1->D8 循環(huán)點(diǎn)亮,因此可以使用 for 循環(huán)語句循環(huán) 8 次,每循環(huán)一次,點(diǎn)亮的小燈向右移動(dòng)一個(gè),而 D1-D8 是連接到 P2.0-P2.7 的,因此輸出的低電平要左移一位,因此可以使用 LED_PORT=~(0x01<<i);語句實(shí)現(xiàn)。
主要解釋一下,~(0X01<<i):
表示 i 循環(huán) 1 次,則0x01 中的 1 就移動(dòng)多少位。另外,因?yàn)?1(高電平)不會(huì)讓 LED 點(diǎn)亮,需要取反后變?yōu)榈碗娖?0 才能點(diǎn)亮,所以最后的結(jié)果需要取反后給 LED_PORT 口,并且每次循環(huán)都要延時(shí)一段時(shí)間,這樣才能分辨出來 LED 在流水形式顯示。
如果不取反這里以二進(jìn)制表示就是:
0000 0001 << 1 得到 0000 0010 左移1位后最低位自動(dòng)補(bǔ)0,當(dāng)7次移位后1000 0000,第八次最高位的1被移走,最低位就自動(dòng)補(bǔ)0,則為0000 0000,又根據(jù)開發(fā)板的LED硬件原理圖,LED 采用共陽接法,給0為亮,所以最后的移位后的值,需要取反使得對(duì)應(yīng)的燈亮,其它燈滅。
2.2、利用利用封裝好的庫函數(shù)功能實(shí)現(xiàn):LED流水燈
//2.利用_crol_庫函數(shù)
/**/
#include <reg52.h>
#include <intrins.h>
//當(dāng)調(diào)用_cror_右移庫函數(shù)和_crol_左移庫函數(shù)時(shí),需調(diào)用頭文件<intrins.h>
//注意:庫函數(shù)的移位不會(huì)自動(dòng)補(bǔ)0,是最高位向最低位,進(jìn)行移位的
//了解函數(shù)的參數(shù):extern unsigned char _crol_ (unsigned char, unsigned char);
//第一個(gè)參數(shù)是移動(dòng)的值,第二個(gè)參數(shù)是移動(dòng)的位數(shù)
#define LED_PORT P2
typedef unsigned int u16;
typedef unsigned char u8;
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void main()
{
u8 i = 0;
LED_PORT = 0xfe;//1111 1110
delay_10us(50000);
//LED_PORT = ~0x01;//等價(jià)
while(1)
{
for(i=0;i<7;i++)//當(dāng)我們給LED_PORT賦初值,0xfe時(shí),只需要循環(huán)7次即可
{
LED_PORT = _crol_(LED_PORT,1);
delay_10us(50000);
}
//右移同理
for(i=0;i<7;i++)//當(dāng)我們給LED_PORT賦初值,0xfe時(shí),只需要循環(huán)7次即可
{
LED_PORT = _cror_(LED_PORT,1);
delay_10us(50000);
}
}
解釋說明:
以庫函數(shù)的寫法就相對(duì)更簡(jiǎn)單了,因?yàn)橹恍枰獣?huì)用就行,直接調(diào)用已經(jīng)封裝好的左移_crol_、右移_cror_函數(shù),然后查閱對(duì)應(yīng)的用法和參數(shù),以及對(duì)應(yīng)的頭文件即可。
以左移_crol_函數(shù)為例,其主要作用就是:
實(shí)現(xiàn)的移位功能就相當(dāng)于一個(gè)隊(duì)列內(nèi)循環(huán)移動(dòng),如果是左移,那么最高位就被移到最低位了,次高位變?yōu)樽罡呶唬来晤愅频难h(huán)排列。
最后,主函數(shù)main:進(jìn)入 main 函數(shù)后首先定義一個(gè)變量 i,LED_PORT=~0x01,因?yàn)?LED 是低電平
點(diǎn)亮,所以 0X01 取反后的結(jié)果是 0XFE,對(duì)應(yīng)二進(jìn)制數(shù)為 1111 1110,即最低位為 0,因此最開始的 D1 指示燈會(huì)點(diǎn)亮,然后進(jìn)入 while 循環(huán),使用 for 循環(huán)_crol_和_cror_移位函數(shù)實(shí)現(xiàn) LED 左右流水顯示。
注意到的是:此處每個(gè) for 循環(huán)只有 7 次,為什么不是 8 次呢,這是因?yàn)樵谶M(jìn)入 main 開始,就已經(jīng)將 LED_PORT 端口設(shè)置了一次狀態(tài),即讓 D1 點(diǎn)亮,并且我們是想讓 LED 從左至右依次點(diǎn)亮,然后繼續(xù)又從右至左依次點(diǎn)亮,這樣形成左右流水效果。
假如將循環(huán)次數(shù)改為 8 次,我們列舉下第一個(gè) for 循環(huán)的LED_PORT 端口狀態(tài)值,如下所示:
初始狀態(tài):LED_PORT=1111 1110
i=0:LED_PORT=1111 1101
i=1:LED_PORT=1111 1011
i=2:LED_PORT=1111 0111
i=3:LED_PORT=1110 1111
i=4:LED_PORT=1101 1111
i=5:LED_PORT=1011 1111
i=6:LED_PORT=0111 1111
i=7:LED_PORT=1111 1110
可以很直觀的查看到,當(dāng)i = 7時(shí),再次回到了初始狀態(tài)的顯示,可這里我們是想實(shí)現(xiàn)的是:LED從左流動(dòng)過來,又從右流動(dòng)回去的流水燈效果。所以,i = 6只需要for循環(huán)7次即可。
3、編譯結(jié)果
至此,兩個(gè)程序就編寫完成,我們編譯一下,如下圖所示:
從上圖編譯信息可以看出,我們的代碼占用FLASH 大小為:code = 65 字節(jié),所用的 SRAM 大小為:data = 9 個(gè)字節(jié)(9.0),xdata指是擴(kuò)展的外部存儲(chǔ)XSRAM所占的大小,并沒有使用XSRAM所以為0。
從上圖編譯信息可以看出,我們的代碼占用FLASH 大小為:code = 98 字節(jié),所用的 SRAM 大小為:data = 9 個(gè)字節(jié)(9.0),xdata指是擴(kuò)展的外部存儲(chǔ)XSRAM所占的大小,并沒有使用XSRAM所以為0。
硬件實(shí)驗(yàn)效果如圖所示:
C51基礎(chǔ)實(shí)驗(yàn) LED流水燈實(shí)驗(yàn)效果展示1
C51基礎(chǔ)實(shí)驗(yàn) LED流水燈實(shí)驗(yàn)效果展示2文章來源:http://www.zghlxwxcb.cn/news/detail-688185.html
4、結(jié)束語
寫這篇文章記錄作為自己學(xué)習(xí)的筆記,筆者水平有限,希望有錯(cuò)誤的地方還請(qǐng)多多指教,各抒己見交流學(xué)習(xí),同時(shí)希望筆者的內(nèi)容有幫助到你。如果有所幫助還請(qǐng)點(diǎn)點(diǎn)贊,表示支持哦。最后感謝各位的閱讀(不喜勿噴)。文章來源地址http://www.zghlxwxcb.cn/news/detail-688185.html
到了這里,關(guān)于【C51基礎(chǔ)實(shí)驗(yàn) LED流水燈】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!