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