文章類型
開發平台
解決方案
關注主題
文章類型
開發平台
解決方案
關注主題

【嵌入式學習心得#2】簡易雷達調光的PWM該怎麼實作?

作者:

延續上篇【嵌入式學習心得#1】簡易雷達調光的MCU設定,從看懂Datasheet開始,本篇文章會著重在雷射調光的PWM功能實踐。

Timer 到底應該怎麼切?

先補充一下上回Timer 未分享完的部分。

記得上篇文章的切法,我是以 10 millisecs 為最小單位做切割,當時只是想說,客人的要求既然是 1 min,如果切 1 millisec,豈不是要設定變數值為 60000,因為是 8 bit 的 MCU,資料型態的決定上就需要更加小心,不然真的後患無窮(溢位很容易就出問題),但後來發現這樣真的很不方便,因為刻度不夠細,沒有辦法到非常精準,雖然肉眼看不太出來,但客人還是會拿示波器挑戰你。

從上面的觀點來看,好像要精準就沒辦法計時太久,而要計時久一點,就沒辦法太精準。但其實是有解法的,前輩有提到通常還是習慣用 1 millisec 做切割,如果需要比較長時間的計時,會設多個全域變數,如下片段程式碼:

以上的寫法只是用了三個全域變數做累加,分別區分毫秒、秒、分。至於實際執行(ISR)的程式碼片段,有人會放 main 裡面,也有人喜歡直接放在 ISR function 內做判斷,但現在刻度變得這麼細,還是放在 main 裡面保險一點(雖然說 main 裡面盡可能乾淨沒錯),畢竟如果 ISR 執行時間超過 1 millisec,基本上程式就會開始出現問題(會 crash,之前做 NTP 時鐘的時候就有出現過)。另外,因為現在是 1 millisec,所以 TH0 和 TL0 兩個暫存器的值也要做調整,相關算法請見上篇

PWM 該如何實作?

接下來是本章的重頭戲:PWM該怎麼實作?

由 SN8F5701 的 datasheet 知道 PWM 的實作是在 Timer 3,16-bit up counting timer。PWM 是 output pin,總共有 6 個 channel 的 PWM function,即是和 GPIO shared 腳位,這裡不特別細講 PWM 和 GPIO 之間的轉換。PWM 再回到 GPIO 時,會是上一次變成 PWM 前的 GPIO mode,以及 T3 interrupt,因為這次沒用到。

有趣的是在 Arduino 上直接用 analogWrite 的 function 可以做的事情,在這裡需要自己設定所有東西,就用以下程式碼片段做介紹:

如上程式碼,PWCH 這個暫存器是控制那隻 pin 腳要設為 PWM output,我的例子是 P01,我覺得最有趣的還是 T3YH 和 T3YL 兩個暫存器,他們決定了 PWM 要切成幾個等份,和 T3RATE(速度)配合去做出某種頻率的 pwm,客人的 spec 要求要 1K 的 pwm,我這次很懶,直接讓 T3RATE 設為 fosc/1,算算剛好 T3YH 和 T3YL 切成 120 等份會有 1K pwm 的效果,通常還是切 100 等份比較直覺。

而 PWM 的 duty cycle 即是用 PW1DH 和 PW1DL 兩個暫存器設定的,客人的 spec 要求是 20% duty cycle,而因為電路設計的關係,剛好會是倒過來的,即設定 80% duty cycle 表現出來的才是 20%。

其實 PWM 還有滿多功能可以玩的,比如說 inverse function、頻率倍數調整等。不過這些這次我都還沒有機會實作到,如果之後有遇到會再分享出來。

從datasheet了解fosc / fcpu

這兩個新名詞我第一次看到的時候真的是不知道代表什麼意思,直到全部看完 datasheet 才漸漸瞭解各別代表的意義。fosc 是震盪器的頻率 (system clock -> IHRC 為 32MHz),而 fcpu 是可以根據 CLKSEL 和 CLKCMD 兩個暫存器做調整,意思是說 fcpu <= fosc (固定值)。

小結

本文最後要來分享一下,截至目前為止,無關乎我對埋控(MCU)理解的多寡,純粹是要講在開發的過程中哪些該注意,哪些可以讓未來的維護更容易,或是往後再開發的速度能夠有效掌控的方式。

就從上一篇文章提到的程式碼架構開始,因為客人需求的多變,可能今天開給我們的 spec 跟他現場真的看到的樣子有落差,就會再和我們討論調整,如果程式碼寫死(意即照 spec freestyle 硬幹),客人要我們改點小東西,我們在沒有架構的情況下,可能又要花上一天的時間把程式碼做修正。

為了不讓這麼蠢的事情發生,在開始照著 spec 下手寫 code 前,都習慣會先自己假定幾種客人「可能會再改的部分」,這個很靠經驗,把這些會再改的部分一一變成參數的形式,程式碼會相對變比較肥,但好處絕對勝過沒架構的版本,這樣在完成後只需要做參數,比如說 const 做 #define的調整,程式碼就能依照新的參數執行。

比如說上面的 pwmValue 就是一個 const int,使用者可以直接更改數字去做到不同 duty cycle 的 PWM效果,只是個超小的範例,但就是這個感覺沒錯。

另外,前輩也有跟我提到,「寫久了就會建自己的 Library」,比如說 PWM function 其實每顆埋控的實作都大同小異,所以把 PWM模板寫好,等到下次遇到別顆埋控時,只要照 datasheet 改變參數就可以。但我發現其實沒這麼簡單,因為所謂「模板」,程度上很難抓,會不知道到底要寫的多細節,或是多粗糙才算是有用的模板(我試過,基本上寫到後來整個 PWM function 都移過去了),我發現這個也很靠經驗,所以等我真的知道怎麼拿捏時再分享出來。

建自己的 library 真的有很方便的感覺,同樣的東西就不用一直重寫,對於開發的人也比較好做後續的維護,因為不會每次都不一樣。

p.s:下篇文章是簡易雷達調光的最終章,要談 UART 和 ADC 的功能實作 ,請待下回揭曉。

(本文轉載於自造者萊恩原文連結;責任編輯:周政毅)

Ryan Hu

Ryan Hu

對於 IOT 軟硬整合相關有極大興趣,鍾愛無人機,目前獨自完成的專案像是瓦力號、GPS 自動語音導覽系統、NTP 網路自動校時時鐘,喜歡流浪。
Ryan Hu

上一篇: | 下一篇:

468 ad

我想回應

你的電子郵件位址並不會被公開。 必要欄位標記為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料

成城共創股份有限公司版權所有、轉載必究.Copyright(c) 2017 MakerPRO