有了之前的吊燈案例做打底,我們再來看一個小檯燈的案例,生活中的一個小電器,這個小檯燈價格也不貴,是一款光線可調節的,有三種亮度可以調節,只有一個按鍵,電池是可充電電池。
當這個小檯燈購買回來時,家人感覺很神奇,只需要觸摸就可以點亮,而且可以調節亮度,同時通過USB充電即可,很實用。作為我們電氣人來說,通過外觀和動作就可以大致解析出內部原理和組成,我不做這個,所以就不分析了,我們只是來看下,如果通過51單片機如何進行實現這個檯燈的功能。
每個程序都是建立在硬體的基礎上的,儘管我們不分析其結構,但是我們有必要對光線可調來進行簡單的分析,這樣有利於下一步的程序書寫。
我們可以觀察到有四種狀態,暗,一般,亮,關。
於是我們可以得出以下四種控制方式,也許有更多,我們只是以這四種為例。
1,通過調節電阻值得大小來調節亮度。
2,通過調節燈的數量來調節亮度。
3,通過調節電流的大小來調節亮度。
4,通過佔空比信號來調節亮度。
四種方法,第一和第二種最直觀,最好理解,第一是通過減小串入電路的電阻,進而減小電流的大小,然後就可以控制燈光的亮度了。第二種是通過增加燈泡的數量,也可以增加燈光的亮度。簡單,直接,好理解。
第三種其實是第一種的一種變形,此處是通過短路的方法來實現電阻的大小改變,進而同樣的改變電流的大小,也就實現了燈光亮度的調節。
第四種就是通過佔空比來調節燈泡的亮度,這種方法,我們之後在著重介紹,首先介紹下前三種。
為了便於理解,我們使用第一個電路來實現這個案例。
首先分析下輸入,只有一個可復位按鈕開關,輸出為一個總電源,三個控制線。當點擊第一下時,暗模式打開,點擊第二下時,一般模式打開,點擊第三下,亮模式打開,點擊第四下,關閉。
我們首先梳理下程序。
如果你看過了之前的那一篇關於《多彩的吊燈》的文章,你會發現,其實這裡的程序跟吊燈中的幾乎一樣,唯一不同的就是修改了switch函數中的輸出變量,因為這裡的內容對應的是開關的相應的動作。然後是把按鍵的功能由10個調整到了4個,所以對key進行了修改。之前一直沒有對程序進行講解,是因為,我們的教程也從第一期更新了50多期了,如果從第一期一直看過來的話,想必不會出現無法讀懂的情況,所以我們就只是把代碼貼出來,沒有講解,不直接複製代碼而採用圖片是因為,這樣可以讓大家有更多的機會去自己把代碼寫出來,一味地複製別人的代碼,一方面不利於理解,另一方面對自己打字的速度也沒有提升。如果有需要源碼的可以留言,我會私信提供。
這裡我就這個代碼進行簡單的說明,之後會依然是直接貼代碼,然後仿真。案例還會再說幾個,儘量把案例說的覆蓋面廣一些,之後就開始中斷和定時器了。
第五行是一個聲明,說明了我們所使用的這些簡寫,如P1,P2等等,在reg52.h中有定義,這裡使用時都可以直接調用,非常方便。
然後是輸入信號的定義,這裡使用key_Led來代替P1^0,不是說P1^0不能用,只是為了方便在程序中當我看到key_Led時,可以快速的知道這個埠指的是什麼含義,如果記憶力超群,也是可以直接使用P1^0的。
接下來是輸出埠的定義,同樣是為了方便自己識別。名稱的定義,可以自己按照自己的想法來,也可以多看看別人的代碼,然後對一些常用的功能使用通用名稱,其他的可以自己定義。例如delay就是一個延時函數,多數同學在書寫時,都會使用delay來代表延時函數,當然也有同學使用yanshi來直接用的,沒有問題,怎麼寫完全看自己。不過代碼如果還需要交到隊友手裡的話,最好還是約定好名稱的定義規則,以免造成代碼寫好了,卻讀起來很困難。
最後一行就是一個延時函數的聲明,記著,函數有返回值得需要在聲明中加上,不能省略。
這個是主函數,由於代碼量比較小,所以功能就都在主函數中進行書寫了。
P1=0xff是對P1埠的所有位置一,因為如果我們需要讀取埠上的數據,那麼就需要先將埠置一,這樣在程序中才會讀取到埠外電位的變化。這一步是不能省略的,儘管單片機上電就是高電位,我們也需要自己主動操作一次。
主要的邏輯功能就放在了循環函數中了,這樣可以保證,程序始終在程序中運行,不會跑飛。
第一個程序結構是消抖
if(key_Led==0)
{
keybuff=key_Led;
delay(6);
if(keybuff==key_Led)
{**執行文件**}
}
判斷按鍵是否按下,如果按下就把按鍵的值賦值給中間緩存變量,然後延時,我這裡的delay是2ms多一點,6次就是12ms,基本可以把抖動延時過去了。接著判斷中間緩存變量中保存的值與當前的按鍵狀態是否一致,如果一致,就執行接下來的動作,不一致,就跳出。
第二個結構是按鍵動作
switch(key)
{
case 0: P2=0xf1;break;//1111 0001
case 1: P2=0xf8;break;//1111 1000
case 2: P2=0xf4;break;//1111 0100
case 3: P2=0xf2;break;//1111 0010
}
while(key_Led==0);
這個也是一個判斷函數,不同與if,這個函數可以對函數中的語句進行依次判斷,一次執行多個動作,if只能執行一次,當然為了加快速度,我們在語句中添加了break,這個語句可以讓函數執行到這裡,直接跳出,不再執行接下來的語句,減少時間。
Switch中的key就是需要對比判斷的量,對比的數據是case後的0123這些數,這個可以自己規定,按程序要求來,不一定非要是0123,也可以是0xff這些,但有一點,需要是確定的數據,寫個變量a是不行的。
P2=0xf1就是需要執行的動作,這個要依據實際功能來說了,我們這裡的動作是關閉電源,所以,需要對P20輸出高電位,對P21、P22、P23輸出低電位。於是低四位就是0001.
最後一句的循環語句,是為了讓動作停止在開關按下的狀態,因為如果手指沒有抬起,按鍵就會一直保持等於零的狀態,程序如果有其他操作,那麼不添加這一句,程序就會反覆執行,造成程序異常,這一句也相當於在監測按鍵是否彈起,不彈起就不向下執行動作。
第三個結構是按鍵計數
key++;
if(key==4)
{
key=0;
}
這個是在按鍵彈起後,我們就對key加一,這個加一是在說明按鍵有了一次有效的按下動作,然後會判斷此時按鍵的按下次數有沒有超出規定的範圍,因為我們就只有四個動作,所以當key等於4的時候,我們之前的switch中沒有對應的語句,所以此時需要對key進行置零。
這樣在程序中走一圈之後,就會執行case 0 這一句,關掉所有埠。
延時函數,大同小異,每一個初學者都會經歷這個函數,他的主要作用就是在某些階段浪費程序的時間,達到延時目的。
While會循環判斷外部引入的t是否為真,也就是大於零。如果大於零就會反覆執行循環體中的語句。
而這個語句本身也是一個循環函數,for循環是先對變量i清零,然後判斷i是不是小於設定的數,這裡是200,如果小於200,就會執行加一操作,然後再次判斷是否小於200,知道i加到等於200,就會跳出循環。這樣while中的一個t減一就相當於程序跑了200次,於是就可以通過調節t的值來調整延時的時間。這個時間不是很精確,依據晶振頻率和程序的執行情況而定,與硬體也有關係,只能通過實際測試或者仿真得出一個大致的範圍,用在一些對時間要求比較松的場合還是可以的。有興趣也可以通過機器周期自己計算出來。
好了一個簡單的檯燈程序又寫了這麼長。仿真的話下篇說吧。
有問題或者疑問可以直接留言,我會回復或私信給你。