TWAS手把手教你做呼吸燈-基于51單片機(jī)學(xué)習(xí)板 內(nèi)容比較簡(jiǎn)單,發(fā)這個(gè)貼主要是針對(duì)新手! 什么是呼吸燈?
顧名思義,燈光在微電腦控制之下完成由亮到暗的逐漸變化,感覺(jué)像是在呼吸。用專業(yè)的話來(lái)說(shuō)是通過(guò)控制PWM的占空比來(lái)完成對(duì)LED亮度的控制
什么是PWM和占空比?
脈沖寬度調(diào)制(Pulse Width Modulation,簡(jiǎn)稱PWM),是利用微處理器的數(shù)字輸出來(lái)對(duì)模擬電路進(jìn)行控制的一種技術(shù)。
占空比:高電平在一個(gè)周期之內(nèi)所占的時(shí)間比率。
呼吸燈原理
當(dāng)一顆LED在高速閃爍,閃爍的頻率已經(jīng)超過(guò)了人眼的感知的范圍,那么我們看到這顆LED就是一直亮的,也就是視覺(jué)暫留現(xiàn)象(余暉效應(yīng))。如果
我們控制一次閃爍中亮和滅的時(shí)間(修改占空比),就可以控制亮度。
代碼實(shí)現(xiàn):
/*******************************************************
* 程序名稱:main.c
* 程序功能:實(shí)現(xiàn)呼吸燈的主程序文件
* 程序作者:TWAS
* 創(chuàng)建時(shí)間:2015-1-22
* 修改時(shí)間:
* 程序版本:V0.1
*******************************************************/
/* 包含的頭文件 */
#include <reg52.h>
/* 尋址變量定義 */
sbit LED_Drive = P3^5; /* 定義驅(qū)動(dòng)LED的IO口,LED為共陽(yáng) */
/******************************************************
* 函數(shù)名稱:main
* 函數(shù)功能:主函數(shù)
* 入口參數(shù):NULL
* 出口參數(shù):NULL
*******************************************************/
int main()
{
unsigned char i;
/* 初始化 */
LED_Drive = 1;
/* 主循環(huán) */
while(1)
{
for(i = 0; i < 200; i++)
{
/* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
* 通過(guò)修改if后面的值,就可以改變占空比
*/
if(i < 10)
{
LED_Drive = 0;
}
else
{
LED_Drive = 1;
}
}
}
return 0;
}
/******************************************
* 程序結(jié)束
*****************************************/
可以明顯看出我們所控制的LED比電源燈暗許多,既然我們會(huì)控制亮度,想實(shí)現(xiàn)呼吸燈也就變的簡(jiǎn)單了
代碼實(shí)現(xiàn):(為了節(jié)約空間和界面簡(jiǎn)潔,只貼出主要實(shí)現(xiàn)的部分)
int main()
{
unsigned char i;
unsigned char ucNum = 0; /* 新增兩個(gè)變量,ucNum控制占空比*/
bit bAdd = 1; /* bAdd選擇是增大占空比還是減小占空比 */
/* 初始化 */
LED_Drive = 1;
/* 主循環(huán) */
while(1)
{
for(i = 0; i < 200; i++)
{
/* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
* 通過(guò)修改if后面的值,就可以改變占空比
*/
if(i < ucNum)
{
LED_Drive = 0;
}
else
{
LED_Drive = 1;
}
}
/* 選擇是增大占空比還是減小占空比 */
if (1 == bAdd)
{
ucNum++;
}
else
{
ucNum--;
}
/* 當(dāng)Num等于200也就是最大值時(shí),bAdd置0,Num開(kāi)始減小 */
if (200 == ucNum)
{
bAdd = 0;
}
/* 當(dāng)Num等于200也就是最大值時(shí),bAdd置1,Num開(kāi)始增大 */
else if (0 == ucNum)
{
bAdd = 1;
}
}
return 0;
}
由于圖片看不到效果,這個(gè)地方就不貼圖了,根據(jù)測(cè)試,我們的所需要的功能實(shí)現(xiàn)了!
但是這時(shí)候有的人就有疑問(wèn)了,這是很普通的LED,那如果是特殊一點(diǎn)的呢?比如我所用的
學(xué)習(xí)板上面,16顆LED是用595驅(qū)動(dòng)的,那呼吸燈又該如何實(shí)現(xiàn)呢?
其實(shí)很簡(jiǎn)單,我們把驅(qū)動(dòng)LED的函數(shù)封裝一下,直接替換,其它不變就行了!
代碼實(shí)現(xiàn):(為了節(jié)約空間和界面簡(jiǎn)潔,只貼出主要實(shí)現(xiàn)的部分)
for(i = 0; i < 200; i++)
{
/* 外邊的for循環(huán)共循環(huán)200次,前面10次點(diǎn)亮LED,后面180次熄滅LED
* 通過(guò)修改if后面的值,就可以改變占空比
*/
if(i < ucNum)
{
DriveLED(0x0003); /* LED驅(qū)動(dòng),點(diǎn)亮D1和D2 */
}
else
{
DriveLED(0x0002); /* LED驅(qū)動(dòng),熄滅D1點(diǎn)亮D2 */
}
}
當(dāng)我把程序改成這樣的時(shí)候,出了一點(diǎn)問(wèn)題,不能呼吸,變成閃爍了!等等,先把LED驅(qū)動(dòng)部分發(fā)一下:
/******************************************************
* 函數(shù)名稱:SendData
* 函數(shù)功能:74HC595數(shù)據(jù)的發(fā)送
* 入口參數(shù):unsigned int uiDataOne, unsigned int uiDataTwo
* 出口參數(shù):void
*******************************************************/
void SendData(unsigned char ucDataOne, unsigned char ucDataTwo)
{
unsigned int i = 0;
/* 將片選信號(hào)置為低電平 */
HC595RCK = 0;
/* 輸入第一個(gè)數(shù)據(jù):uiDataOne */
for (i = 0; i < 8; i++)
{
/* 給出脈沖信號(hào),首先將CLK置為0 */
HC595CLK = 0;
if (0 != (ucDataOne & 0x80))
{
HC595DATA = 1;
}
else
{
HC595DATA = 0;
}
/* 給出脈沖信號(hào),首先將CLK置為1 */
HC595CLK = 1;
/* 準(zhǔn)備第二個(gè)數(shù)據(jù) */
ucDataOne = ucDataOne << 1;
}
/* 輸入第二個(gè)數(shù)據(jù):uiDataTwo */
for (i = 0; i < 8; i++)
{
/* 給出脈沖信號(hào),首先將CLK置為0 */
HC595CLK = 0;
if (0 != (ucDataTwo & 0x80))
{
HC595DATA = 1;
}
else
{
HC595DATA = 0;
}
/* 給出脈沖信號(hào),首先將CLK置為1 */
HC595CLK = 1;
/* 準(zhǔn)備第二個(gè)數(shù)據(jù) */
ucDataTwo = ucDataTwo << 1;
}
/* 將片選信號(hào)置為高電平 */
HC595RCK = 1;
}
/********************************************************
* 函數(shù)名稱:DriveLED
* 函數(shù)功能:595驅(qū)動(dòng)程序是分兩個(gè)數(shù)據(jù)發(fā)的,
* 本函數(shù)把它合并成一個(gè)數(shù)據(jù)
* 入口參數(shù):uiData:16顆LED需要顯示的數(shù)據(jù)
* 出口參數(shù):NULL
*******************************************************/
void DriveLED(unsigned int uiData)
{
SendData(uiData >> 8,uiData);
}
繼續(xù)剛剛的問(wèn)題,呼吸燈變成閃爍了,怎么回事呢?在程序邏輯上是沒(méi)有問(wèn)題的,
我們只是更改了LED的驅(qū)動(dòng)部分,看來(lái)就是LED驅(qū)動(dòng)的問(wèn)題了!先來(lái)Debug看一下,執(zhí)行
DriveLED這個(gè)函數(shù),時(shí)間是接近400微妙,循環(huán)200次,就是差不多80毫秒,那么LED的
閃爍頻率為12.5HZ(都是大概的值,沒(méi)有精確計(jì)算),還不足以形成視覺(jué)暫留現(xiàn)象。
那怎么辦呢,減少循環(huán)次數(shù)為50,頻率增大到50HZ左右,像這樣:
for(i = 0; i < 50; i++)
{
/* 通過(guò)修改ucNum的值,就可以改變占空比 */
if(i < ucNum)
{
DriveLED(0x0003); /* LED驅(qū)動(dòng),點(diǎn)亮D1和D2 */
}
else
{
DriveLED(0x0002); /* LED驅(qū)動(dòng),熄滅D1點(diǎn)亮D2 */
}
}
經(jīng)過(guò)驗(yàn)證!成功了!
如有錯(cuò)誤的地方,希望大家批評(píng)指正!
|