【.NET 與樹莓派】PWM 調節LED小燈的亮度

東邪獨孤發表於2021-02-09

在開始本文內容之前,老周先糾正一個錯誤。在上一篇中,提到過 Arduino 開發板的 Vin 引腳,文中老周說這個供電口的輸入電壓不能高於 5.5V。這裡有錯,被賣家給的使用說明忽悠了,上 Arduino 官網看了一下說明和原理圖,Vin 引腳的有效電壓是 7 - 12V,和DC輸入口一樣;輸入電壓不能高於 5.5V 的是 5V 引腳。5V 引腳既可以為元器件供電(輸出),也可以向這個引腳輸入 5V 電壓為開發板供電。

=========================================================================================================

本篇文章最後會完成一個很簡單的實驗,這個實驗基本是電子實驗中最經典的,被許多教程重複了幾億次。儘管是個老掉牙的實驗,但該實驗簡單,而且有代表性。啥實驗?就是標題上寫著的,調節LED小燈的亮度。

當然了,不是你家裡裝的LED大燈泡,以開發板輸出的功率,是不能點亮那種大燈泡的。我們們實驗用的一般是發光二級管,如下面高清無碼大圖所示。

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

這個玩意兒很便宜,一兩塊錢能買到一堆,非常適合我們這種待脫貧人群的日常把玩。當你拿到這個玩意兒的時候,你可能會有一個疑問:這貨有兩個腳 ,沒有標註正負極,我怎麼區分呢?不知道你有沒有仔細看,這貨其實是國家三級殘疾的,一條腿長,一條腿短,醫學上叫啥來著,忘了。人家生產商是故意讓它殘疾,然後領養它的人就知道怎麼照顧它了——長的那條腿是正極(陽極),短的是負極(陰極)。現在明白乎?

還有一種是四條腿的,分為“三長一短”和“三短一長”,咋理解?先看圖。

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

這種叫 RGB 發光二極體,實際上和兩個腳的是一樣的,只是它分了藍、綠、紅三種顏色的光,然後三種光以不同亮度混合,可以組成各種顏色。“三長一短”就是 R G B 三個腳是正極,短的那個是負極,也就是說它們共一個負極,叫共陰;“三短一長”就是 R G B 三個腳是負極,長的那個是正極,即它們共用一個正極,叫共陽。

發燈二極體不同的顏色所需電壓有差異,一般是 2.0 - 2.2 V,電壓上下有波動沒關係,燒不了,但是過高了就會燒。經老周實測,二極體如果不接電阻直接供 5V 就很危險,發熱嚴重,3.3 V 情況相對好一點。但是,電阻肯定要加的,保險一點嘛,當然也不用加 1k 那麼恐怖,200 Ω 左右就可以了。

你可以選可調電阻,這樣比較靈活,就像這種,也很便宜。

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

這種電阻頂部有個螺絲,用“一”字螺絲刀旋轉可以調節電阻。這種便宜,所以沒有可視螢幕,可以用萬用表來測電阻。你會發現電阻上面有三個腳,老周畫了一個模擬圖。

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

中間的 C 點類似個滑塊,通過頂部的旋轉螺絲,AC,CB兩段的電阻會改變。假設這個電阻的最大阻值為 200 Ω,那麼:

1、A、B 兩端相接,其阻值就是固定的 200 Ω;

2、A、C 兩端相接,可旋轉螺絲來調節電阻大小,假如調節為 50 Ω;

3、B、C 兩端相接,也可以通過旋轉螺絲來調節阻值;

4、A-C 與 B-C 兩段的電阻之和等於最大阻值,所以:若 A-C為160Ω,那麼 B-C 段阻值為 200-160 = 40Ω。

以上計算為理論資料,使用萬用表檢測,會存在幾歐姆的誤差。

 

接下來我們們要了解一個概念—— PWM,全稱為 Pulse Width Modulation,可譯為“可調製脈衝”。在前面的爛文中,老周提過,GPIO 通訊時輸出兩個狀態訊號,還記得不?哦,猜對了,就是高電平和低電平。好,現在你想一下,如果一個 GPIO 介面以一定的頻率不斷地輸出電平訊號,會發生什麼?是不是會產生如下圖所示的波形?

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

其中,突起來的就是高電平,與橫軸重合的是低電平,由於通訊介面只使用兩個電平訊號,於是發生的波形就成了方波。

方波的週期,也就是一秒鐘內有多少個週期,就是我們常說的頻率,單位是 Hz。例如,某脈衝方波的頻率為 50 Hz,即一秒鐘內迴圈50次,那麼,每個週期的時長為 1 / 50 = 0.02 秒,合 20 毫秒。

既然脈衝中一個週期內可以輸出高電平或低電平,那麼,高電平與低電平兩者所佔用的時間,就形成另一個名詞——佔空比。用一句話解釋,就是:高電平持續的時間佔整個週期的百分比

沿用上文的舉例,若週期是 20 毫秒,如果高電平持續的時間為10毫秒,那麼佔空比 = 10/20 = 50%;如果高電平持續的時間為 15 毫秒,那麼佔空比 = 15/20 = 75%,低電平佔用的時間比就是 25%。但佔空比的定義是關注高電平的持續時間。

我們們這一次調節發光二極體亮度的實驗就是用到 PWM。當然,調節電壓或電阻也能改變亮度,不過開發板自身可不能改變電壓和電阻,可以用一些穩壓模組來調節。

為什麼脈衝可以改變燈的亮度呢?回想一下,前面我們們聊過,對開發板而言,高電平的電壓是 3.3V,低電平是 0V。接到二極體正、負兩腳上的電壓如果相等,由於沒有電勢差,不產生電流,燈就熄滅;反之,存在電勢差,有電流通過,燈就亮。

情形1:二極體的正極接 GPIO 口,負極接 GND (接地,始終是低電平,相對 0V 電勢)。此時,如果GPIO口輸出高電平,與 GND 之間存在對0V的電勢差,二極體發光;反過來,如果GPIO口輸出低電平,那麼,0V與GND的0V位於同一參考值上,沒有電勢差,二極體不亮。

情形2:二極體的正極接 3.3V(供電介面始終輸出高電平),負極接GPIO口。如果GPIO口輸出低電平,就相當於GND的作用了,有電流通過,燈亮;如果GPIO口輸出高電平,也是 3.3V,與供電口的相對電平相同,沒有電勢差,無電流通過,燈滅。

現在入重點了,高電平燈亮,低電平燈滅,那麼高、低電平交替輸出呢?也就是高 - 低 - 高 - 低 - 高 - 低……那燈就會一亮一滅,也就是在閃。但是,由於燈從亮到滅的過程會有很短的個延時,如果這延時足夠短,人的眼睛就看不到燈的閃爍(不知道貓眼能不能看到),視覺延遲導致反應不過來,就沒感覺了。所以,用PWM調亮度時,頻率不要太低,50 - 60 Hz 明顯看到閃爍;選 100-200 Hz 比較好,頻率太高了效果也不好,頻率高到比燈熄滅的延時還短的話,就等於燈是一直有充足的電流可用,這樣它就不會暗下來了,調節亮度就沒效果了。

 

上面說的都是基本理論,下面我們們動手幹活。

先要看看在樹莓派上怎麼配置 PWM 功能。配置檔案依然是 /boot 目錄下的那個 config.txt。下面是文件說明:Name: pwm

Info:   Configures a single PWM channel
        Legal pin,function combinations for each channel:
          PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
          PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
        N.B.:
          1) Pin 18 is the only one available on all platforms, and
             it is the one used by the I2S audio interface.
             Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
          2) The onboard analogue audio output uses both PWM channels.
          3) So be careful mixing audio and PWM.
          4) Currently the clock must have been enabled and configured
             by other means.
Load:   dtoverlay=pwm,<param>=<val>
Params: pin                     Output pin (default 18) - see table
        func                    Pin function (default 2 = Alt5) - see above
        clock                   PWM clock frequency (informational)

這些文件最大的缺點是說得不清不楚,讓你霧裡看花,水中撈月。不過,根據文件的描述,樹莓派有兩路 PWM 引腳,所以以下這段很關鍵。

        Legal pin,function combinations for each channel:
          PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
          PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)

樹莓派有 GPIO 0 到 GPIO 27,所以:

        Legal pin,function combinations for each channel:
          PWM0: 12,4(Alt0) 18,2(Alt5) 
          PWM1: 13,4(Alt0) 19,2(Alt5) 

第一路 PWM 是引腳 GPIO 12 和 GPIO 18,板上的序號是 32、12;

第二路 PWM 是引腳 GPIO 13 和 GPIO 19,板上的序號是 33、35。

【.NET 與樹莓派】PWM 調節LED小燈的亮度

 

此處只需要調節一個燈,所以開啟第一路 PWM 就可以。

說一下這些引數的含義,12,4(Alt0),表示使用 GPIO 12,後面的4要按說明來配置,此處就是數值 4 表示 Alt0。前面的文章中提過,為了擴充套件 GPIO 的功能,會定義引腳的重用(或叫複用),即你指定不同的 Alt 就會啟用對應的功能。

老周手上這塊 4B,用 GPIO 12 無法產生 PWM,串聯萬用表檢測不到電流,只有 GPIO 18 能用。其他版本不知,因為老周沒有買齊所有樹莓派版本。所以大家可以多試試,反正第一路 PWM 只有 GPIO 12 和 GPIO 18 兩個口,不行就換一個。

使用 Linux 自帶的 Nano 應用開啟 config.txt 檔案。

cd /boot
sudo nano config.txt

記得加 sudo ,作用就不說了。

然後加上:

dtoverlay=pwm,pin=18,func=2

GPIO 18 啟用 PWM 的 Alt 是 Alt5,所以 func 引數的值是2(參考剛剛上面說的),因為這個是所有樹莓派版本預設支援的配置,故可以省略引數。

dtoverlay=pwm

按 Ctrl + X,退出,nano 提示是否儲存,輸入 Y,搞定。

 

下一步看看.NET 相關 API。

名稱空間:System.Device.Pwm。

類:PwmChannel。

這是個抽象類,內部會根據平臺實現不同型別,為了統一呼叫,公開一個靜態方法——Create,定義如下:

static PwmChannel Create(int chip, int channel, int frequency = 400, double dutyCyclePercentage = 0.5);

chip 引數常為 0,即第一塊控制晶片,channel 是第幾路PWM通道,樹莓派有兩路,所以此引數可以用 0 或 1。本次我們們用的是第一路,所以值是 0。frequency 是頻率,預設400 Hz。dutyCyclePercentage 是佔空比,0.0 到 1.0,表示 0% 到 100%,預設 0.5(50%)。

呼叫這個靜態方法後,得到一個 PwmChannel 例項,呼叫例項物件的 Start 方法就可以開始發生脈衝方波了,呼叫 Stop 方法停止脈衝。另外,Frequency 屬性改變頻率,DutyCycle 屬性改變佔空比,這兩個屬性都可以在 PWM 運作期間直接修改,不必重新 Start。

而我們們這次的調光實驗就是通過改變佔空比來實現的。佔空比為 0%,始終是低電平,燈滅;佔空比是 100% ,始終輸出高電平,燈最亮;而亮度的改變就在 0% - 100% 之間的值。

 

程式碼灰常簡單,老周直接上,你能看懂的。

            PwmChannel pwmch = PwmChannel.Create(0, 0, 100, 0.0);
            // 開始PWM
            pwmch.Start();
            int x = 5;
            while(x-- > 0)
            {
                for (int i = 0; i < 100; i++)
                {
                    pwmch.DutyCycle = i * 0.01d;
                    Thread.Sleep(20);
                }
                for (int i = 100; i > 0; i--)
                {
                    pwmch.DutyCycle = i * 0.01d;
                    Thread.Sleep(20);
                }
            }
            pwmch.Stop();
            pwmch.Dispose();

DutyCycle 屬性的有效值是 0.0 - 1.0,所以整型的百分比乘以 0.01,讓它變成有效值。

 

接線方法:二極體的長腳(正)接 GPIO 18 引腳,短腳(負)接 GND(有很多個,隨便挑一個),在 GPIO18 和二極體正極之間串聯一個 200 歐姆的電阻。

【.NET 與樹莓派】PWM 調節LED小燈的亮度 

最後,釋出、上傳,執行,效果類似於呼吸燈。

示例的程式碼連結,請用電鑽扎這裡。 

調節小燈的亮度只是 PWM 的其中一個用途,該技術還有很多玩法。比如可以控制舵機的旋轉角度,控制小風扇的轉速,控制玩具喇叭唱歌(頻率不同可以產生不同的音高)…… 下一篇爛文老周將介紹如何用 PWM 讓小喇叭高歌一曲過大年。

 

相關文章