在今年春節的時候,在大街上看到很多的流行燈,非常的漂亮。
而今天在看單片機的書時,看到制作呼吸燈的例子,思索一下,發現者流星燈就是有很多的呼吸燈制作而成的。看了一下書上的源碼,感覺很有意思。
#include <REG51.h> //51頭文件 /********************************************************************************************* //《C_無級亮度閃爍》 #define DY_PORT P1 //設置LED連接的I/O組 #define DY_SPEED 1 //設置每一個明亮級的停留時間(值域:0~65535) #define DY_PWM 50 //設置明亮的總級數(級數過大會出現閃爍)(值域:0~65535) #define DY_MAX 50 //設置最大明亮(值域:小于明亮總級數) /*********************************************************************************************/ //《B_無級亮度變化》 #define DY_PORT P1 //設置LED連接的I/O組 #define DY_SPEED 1 //設置每一個明亮級的停留時間(值域:0~65535) #define DY_PWM 500 //設置明亮的總級數(級數過大會出現閃爍)(值域:0~65535) #define DY_MAX 500 //設置最大明亮(值域:小于明亮總級數) /********************************************************************************************* //《A_8級亮度變化》 #define DY_PORT P1 //設置LED連接的I/O組 #define DY_SPEED 100 //設置每一個明亮級的停留時間(值域:0~65535) #define DY_PWM 500 //設置明亮的總級數(級數過大會出現閃爍)(值域:0~65535) #define DY_MAX 8 //設置最大明亮(值域:小于明亮總級數) /********************************************************************************************* bit [自定義名] ; //定義一個位(位的值只能是0或1)例:bit LED #define [代替名] [原名] //用代替名代替原名(可以方便修改常改或調試的值)例:#define LED P1 sbit [自定義名] = [系統位名] ; //自定義系統位名。例:sbit Add_Key = P3 ^ 1; unsigned char [自定義名] ; //定義一個0~255的整數變量.例:unsigned char a; unsigned int [自定義名] ; //定義一個0~65535的整數變量 /*********************************************************************************************/ void delay (unsigned int a){ // 0.1ms延時程序(12MHz 10倍于51單片機速度時) unsigned char i; while( --a != 0){ for(i = 0; i < 12; i++); } } /*********************************************************************************************/ void display (unsigned int a){ //顯示程序(50ms的PWM寬度) DY_PORT = 0x00; //LED小燈亮 delay (a); //延時a的長度 DY_PORT = 0xff; //LED小燈滅 delay (DY_PWM-a);//延時總PWM長度減a } /*********************************************************************************************/ void main (void){ //主程序 unsigned int t=1; unsigned int i; bit LOOP=0; //LOOP是循環切換標志 while (1){ if(LOOP == 0){ //變亮循環 for(i = 0; i < DY_SPEED; i++){ display(t); } t++; if(t>(DY_MAX-2)){ LOOP = 1; } } if(LOOP == 1){ //變暗循環 for(i = 0; i < DY_SPEED; i++){ display(t); } t--; if(t<2){ LOOP = 0; } } } } /*********************************************************************************************/
從這里看起來就很有意思了。想漸明漸暗,用到的是PWM(脈沖寬度調制)。簡單的講,對于這個燈,就是調節暗和明的比例。
比如10為一個時間段的話,那么1/10為明,9/10為暗,這樣亮度就算是1了。因為機器的時間段非常的短到人們看到的一直是連續的。
另外想到一點,當時序短到一定的程度的時候,那么本來連續的程序,變成為了并行(這話說得不是很嚴密,要看什么樣的程序)。所以,我們能一邊上qq,一邊看網頁。
另外,面向過程符合機器的思維,面向對象符合人的思維。
學嵌入式很有意思的一點就是,你可以理解到程序運行的本質。有一種掌控感,而擁有掌控這項技能的,似乎只有神。。。
我一直想,學計算機應該從底層學起,雖然讓讓人很提不起興趣。
言歸正傳,說道這個程序,有個缺點,就是無法獨立控制很多的LED燈。我查了很多的資料。卻沒有得到很明確的結果。倒是發現了一點國內教材的通病---- 天下文章一大抄。我買的基本教材,竟然大部分一樣。更可恨的是,連圖也一樣。這讓我情何以堪。后來我發現圖的出處----單片機的使用說明書。感情這說明書就是最好的教材。其實不光我們技術比國外落后,教材也落后。就像大學里那些只會照著ppt讀的老師一樣惡心。
看了看單片機的說明書,發現上面有現成的PCA模塊。可惜我的這個型號只能同時控制兩路。在網上找到有控制16路的,目前還看不懂。
看來流星燈的制作,還是有點小困難的。還得繼續研究。
下面是兩路的程序
#include <reg52.h> //設置sfr sfr CCON = 0xD8; sfr CMOD = 0xD9; sfr CL = 0xE9; sfr CH = 0xF9; sfr CCAP0L = 0xEA; sfr CCAP0H = 0xFA; sfr CCAP1L = 0xFB; sfr CCAP1H = 0xFB; sfr CCAPM0 = 0xDA; sfr CCAPM1 = 0xDB; sbit CR = 0xDE; void PWM_init(void) { CMOD = 0x02;//設置PCA定時器 CL = 0x00; CH = 0x00; //PWM0的設置 CCAPM0 = 0x42; CCAP0L = 0x00; CCAP0H = 0x00; //PWM1的設置 CCAPM1 = 0x42; CCAP0L = 0x00; CCAP0H = 0x00; CR = 1;//啟動PCA定時器 } //設置PWM0的參數 void PWM0_set(unsigned char a) { CCAP0L = a; CCAP0H = a; } //設置PWM1的參數 void PWM1_set(unsigned char a) { CCAP1L = a; CCAP1H = a; } void delay (unsigned int a){ // 0.1ms延時程序(12MHz 10倍于51單片機速度時) unsigned char i; while( --a != 0){ for(i = 0; i < 12; i++); } } void main(void) { unsigned int i; PWM_init();//PWM初始化 PWM0_set(0x00);//設置PWM0占空比 PWM1_set(0x00);//設置PWM1占空比 while(1) { for(i = 0;i < 256;i++) { PWM0_set(i); PWM1_set(256 - i); delay(100); } for(i = 256;i > 0;i--) { PWM0_set(i); PWM1_set(256 - i); delay(100); } } }
效果如下:
OK,先到這里。