Outline

  • 什麼是嵌入式系統
  • 通訊協議
  • 開發板介紹
    • Arduino
    • ESP32
    • STM32
  • 如何寫出好程式?
  • 為什麼要使用 WSL

什麼是嵌入式系統

相信很多人有聽過嵌入式系統,但一直都不知道這個名詞的精確定義為何,以及是什麼用途,這裡將為大家做個簡單介紹。

型態

先從眼睛看得到的開始介紹好了。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

取自維基百科,Soekris net4801,適用於網路應用程式

顧名思義,嵌入式系統就是附加在某些設備上面的電腦,會這麼做的原因不外乎就是因為對於這些設備來說,使用一般的電腦要嘛成本太高,要嘛體積太大,所以在產品設計的評估時才會決定使用在體積跟成本皆佔有優勢的嵌入式系統為主控電腦。

程式

語言

通常在嵌入式系統裡面所使用的語言都是以 C 為主,理由很簡單: 因為快。
如果你有修過計算機概論的話通常都有聽說過 C/C++ 的運行效率是很高的,目前所有程式語言裡面能比 C/C++ 更快的只有組合語言了,但那又是更低階的語言了,論高階語言裡面目前沒有更快的語言了,因此在實務開發上 C/C++ 是最符合現實需求的。

架構

說完語言,來說說程式的架構好了。

#include <Arduino.h>
#include <stdint.h>

void setup() {
    // initial setup for global variables, pin configurations,
    // register configurations and baud rate
}

void loop() {
    // tasks to be executed in the infinite loop 
    // during the whole time working
}

通常嵌入式系統的程式會分成兩個部分,分別是void setup()以及void loop()setup()的部分是用來做一些初始化設定的,像是 Serial print 的 baud rate、腳位的設定、暫存器的設定,以及全域變數的初始化,這個函式會在系統在運作的最一開始會執行一次,才會進到loop()。 Speaking of loop()loop()是系統在運作時會不斷重複地執行的一套程式,你可以想像嵌入式系統就是一個長得像電腦的機器,會一直重複地做某件任務,而這個loop()就是在定義要重複進行的工作是什麼的地方。

通常修過程式設計的人看到這個架構會有些困惑,為什麼是loop()而不是計概上課時所教的main()呢?

由於嵌入式系統在執行任務的時候並非以往我們寫程式作業那樣是為了達成某個目的所寫的一個作業流程,而是一台機器在運作時隨時隨刻都要保持的狀態,要保持一個狀態並不是靠只能執行一次的一連串的 tasks 就能做到的,而是要讓一個不停地自我檢測的循環作業不斷進行,才能在偏離某種狀態時能夠及時反應並校正,或是不斷讀取某個資料並顯示給使用者知道,因此我們在嵌入式系統裡看到的程式會是不斷循環執行的,故將其主程式的函式名稱取為loop()

為了幫助你了解setup()loop()main()的關係,我們也可以用另一種表示方式。

#include <Arduino.h>
#include <stdint.h>

int main() {
    
    // do setup() stuff here
    
    while(1) {
        
        // do loop() stuff here
        
    }
}

以這種表示方式應該就可以讓你以你在計概課學到的方式去理解setup()loop()的角色了。事實上,你是可以將 Arduino 的程式寫成這樣的,是可以運作的,並且其它平台的嵌入式系統也是按照這樣的程式架構下去寫的,這證明了其實setup()loop()的本質實際上就是在main()用這樣的方式寫程式。

用途

嵌入式系統的用途很廣,最主要的就是應用在特定功能的機器上面,大至工廠裡面的天車和機械手臂,小至你身上的穿戴式裝置,上面所搭載的電腦都可以被稱作為嵌入式系統。

不管是大型機器上面作為電子及電機元件的控制單元,還是穿戴式裝置上面的微型電腦,都會需要長時間不間斷地持續運作,因此嵌入式系統還有一個要求,就是要穩定、耐用,不然如果它會因為作業系統更新而有幾個小時不能運作的話,在有成千上萬個機器手臂的工廠就要承受大規模的損失,而這是不被市場所接受的,因此開發者們想盡辦法要讓嵌入式系統可以 24/7 不間斷地運作,是慣老闆們的最愛。

功能

這裡說明一些單晶片具備的功能

GPIO

GPIO (General Purpose Input/Output)

  • GPIO 是種具有彈性且可以藉由軟體控制 (software-controlled) 的數位訊號
  • 常見於開發版邊緣,以針腳 (Pin) 的形式呈現
    • 這些針腳即是開發版與外界溝通的重要橋樑
    • 簡單例子,想像成是開關,使用者可以打開或關閉 (input),或由開發版來打開或關閉 (output)
  • 每個 GPIO 可以被當成 input,output,analog 或 alternate function
    • alternate function 是指其他的的功能, 如 I2C, SPI, USART, CCP, PWM, Clock 等。如何控制則取決於外部設備 (peripheral)

PWM

  • PWM (Pulse-Width Modulation),又稱 pulse-duration modulation (PDM),是將脈波轉為類比信號的“一種技術”,利用在頻率不變的狀態下,改變工作週期大小,使整體平均電壓值上升或下降,藉此間歇性電壓及功率切換以節省能源及控制等效果。

  • Duty cycle 在一個信號週期裡,代表1的正脈衝的持續時間與脈衝總周期的比值。舉例來說,發出訊號1秒鐘,之後99秒沒有訊號,這是一個週期;之後又是發出一秒鐘的訊號,如此循環下去。而該訊號的工作週期就是 1/(1+99)=1%。

  • PWM 會較省電的原因 因為一般類比電壓要降低電壓輸出需靠增加電阻,源頭輸出電壓“持續”都為同一電壓,不過利用電阻改變最後輸出電壓,而 PWM 他靠的是一段時間內輸出的頻率來模擬類比電壓,“不需要持續的輸出”,故不會將電浪費在電阻上,即可達到省電效果。

  • STM32 內部要產生 PWM 訊號時,需要透過 Timer 來實現。

System Clock

系統時鐘的原理是利用開發板上面搭載的石英片振動作為基準,為系統提供一個準確的時間標準,讓系統裡面的訊號、頻率等,有一個參考的對象用於校正。

Timer Events

除了將一般函式放在 main( ) 執行以外,由於我們無法確定 main( ) 跑完一次所需要的時間,因此當有些函式有需要定時執行的需求時,會了確保這個要求被達成,我們會使用 Timer 的方式去觸發這個函式。使用這個方式觸發函式並不會將這個函式放在 main() 的 while(1) 迴圈裡面,而是利用創建一個 task 並根據 System clock 所提供的時間去定期觸發這個函式。

Interrupt Processing

有些函式我們不需要它放在 while(1) 迴圈或是用 Timer 定期執行,而是在某個條件達到時再去執行即可,像是某個燈只需要在我按按鈕的時候亮,我便不需要將亮燈的函式放在 while(1) 裡面,而是利用 Interrupt 功能偵測按鈕是否有被按下,當按鈕被按下,系統就會被按鈕的訊號給 "inturrupted" 而去觸發亮燈的函式。

Watch Dog

有些程序會有卡住的風險,並佔用系統資源使系統停擺。為了預防這樣的事發生才有了看門狗 (Watch Dog) 的存在。看門狗可以設定一個計時器,如果沒有定期去重設這個計時器,看門狗會認定你的程式卡住了,並強制結束卡住的程序,以確保系統不會因為那個卡住的程序而停擺。

通訊協議

在嵌入式系統裡面有一個東西特別重要,那就是通訊。這裡的通訊並不是指無線電或是行動網路的那種通訊,而是指在一個系統裡面,每一個負責不同工作的子系統要怎麼和其他子系統溝通、分工、整合,這就要牽扯到通訊協議了。

資料傳輸並不是一件簡單的事情,你要考慮的事情不僅僅只有兩個成員之間的那條線有沒有斷掉,還需要考慮訊號的干擾、錯誤的偵測、以及訊息的加密,好在人類的智慧很偉大,已經有許多現有的通訊協議專門就是為了解決這些問題的,你可以參考這部影片去稍微了解各個通訊協議的原理和常見應用場景。

除了前面這部影片所介紹到的幾個通訊協議以外,還有一個非常重要,我們常常會用到的通訊協議,叫做 CAN Bus。它是車上各個不同系統之間的通訊所使用的協議,因為其物理特性使其在材料的使用上很經濟,並且訊號傳輸也很可靠,因此廣受汽車產業的使用。在我們這裡也是,如果我們讓所有的車載設備都透過 CAN Bus 通訊的話,既可以減少線束的數量,也可以提升訊號的可靠度,因此被放到這門教學的重點之中。CAN Bus 原理的簡單介紹你可以參考這部影片,更詳細的話你可以參考這個系列課程

開發板介紹

市面上充斥著各式各樣的嵌入式系統開發板,有大企業在設計方案產品時常用的商務款式,也有作為初學者的你所適合的基本款式,而這邊介紹幾個學生以及開發者社群常用的幾個款式。

Arduino

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

最常見的 Arduino Uno

介紹

這應該是大家最常看到的吧,擁有自帶的 IDE 可以簡單設置環境並快速開始專注於功能的實作,是大多數人的第一個嵌入式系統實作平台。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Arduino IDE 的介面

Arduino IDE 的特色就是擁有整潔的介面以及從建置到燒錄都非常直覺的步驟,開發板本身也非常好取得,又因為是開源的關係,可以看見有許多不同製造商使用各種不同規格的零件去打造同一塊板子,讓你有不同價位可以選擇,甚至你可以根據自己的需求去設計自己的板子,讓 Arduino 同時兼具很低的入門門檻以及很高的可玩性。

開發

開發 Arduino 所使用的語言是基本上就是 C++,它和一般 C++ 的不同在於它的副檔名是*.ino,然後它必須要被放在一個同名的資料夾底下才算一個完整的程式專案,雖然有點怪,but it is what it is for now,你就用就對了。

在你寫完程式之後還要做兩件事情才可以開始運作:

  1. 設定開發板的型號
    使用這個 IDE 的好處就是你不用親自準備專案的 SDK (Software Development Kit),只要選擇你使用的板子型號讓 IDE 知道,它就會在編譯的時候自動在後台幫你建置,所以大大地降低了操作的門檻。
  2. 編譯 + 燒錄程式
    最後還要記得編譯 + 燒錄程式到板子上,才可以讓板子確實運行你所撰寫的程式。另外,編譯階段可以幫你偵測程式有沒有語法錯誤的地方,讓你有機會發現程式的錯誤。

ESP32

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

介紹

也是一個常用的便宜 MCU,最主要的特色是有 WiFi 和 藍芽 雙模的功能,所以可以進行許多物聯網的實作,像是智慧家電之類的,也因為在內網裡面傳輸資料很方便,有像是外接 sensor 監測氣溫跟濕度並透過無線網路傳到 Database server 的使用案例。另一個特色是只要設置得當,就可以使用 Arduino IDE 進行開發,某種程度上也將開發的難度降低到和 Arduino 一樣。

開發

這裡可以分成三個部分講:

  1. Arduino IDE
  2. PlatformIO
  3. ESP-IDF

Arduino IDE

ESP32 其中一個最大的特色就是它通用於 Arduino IDE 的開發,只要在 Arduino IDE 的套件管理中下載 ESP 官方推出的套件,就可以在 Arduino IDE 中開發 ESP32,讓你可以同時享有像 Arduino 一樣的入門門檻以及 ESP32 獨有的 WiFi/藍芽 功能。

安裝 ESP 套件在 Arduino IDE 的方法可以參考這份教學

PlatformIO

image

PlatformIO 是一款開源且跨平台的嵌入式系統與產品程序的開發工具,你可以想像它是另一個 ArduinoIDE,只是它在專案裡面展露出來的資訊又更完整一點,比起 Arduino IDE 只露出 .ino 的檔案讓你看到,其餘全部藏在 IDE 裡面,Platform IO 至少會將所有的 configuration 寫在專案底下的 .json 裡面讓你知道,雖然以體驗上來說和 Arduino IDE 一樣傻瓜,但如果你是一個有資訊焦慮症的人,這個平台什麼都會告訴你,所以大可放心。目前已知這個平台最大的缺點就是它沒辦法加入 RTOS 功能,因此只能用傳統的 loop() 的形式去寫,讓它在一些應用上有所限制。

我們對這個平台最常見的使用方式是在 VS code 裡面下載它的擴充套件(事實上它自己獨立的 IDE 也是基於 VS code 改良的),詳情網路上有許多教學可以參考,在這裡你只需要知道它的語言也是以 C/C++ 為主,所以 C/C++ 很重要,希望你大一計概都有學好。

ESP-IDF

ESP-IDF 是 ESP 官方的 SDK。用這個方法的好處就是可以加入 FreeRTOS 的功能,也有許多官方寫好的現成的 Library 可以用,讓一些操作外部設備的功能比較好實作。總而言之,這個方法可以帶出的開發潛力是最大的,相比前兩個方法可以依賴更少的環境,卻可以實作出最多樣性的玩法組合。另一方面,這個開發方式也有比較高的技術門檻,它的操作方式大多是透過 CLI 介面來執行,並且還要按照官方規定的格式去寫 CMake 文件才能使自定義的函式庫可以正常運作,建議先有 shell command、CMake、Makefile 的基礎再來學習使用此方法才不會一直卡住。

STM32

介紹

我們常常聽到的意法半導體的一個產品線,是低功耗的 ARM 架構單晶片系列,常常用於嵌入式系統,優點是高性能、低成本、低功耗。

開發

Part 1
首先要能夠創建你所使用的晶片型號所對應的初始專案文件,創建的方式也有好幾種,這裡介紹兩種最常用的:

  1. 使用 STM32CubeMX
    STM32CubeMX 是 STM32 官方的一個 Code 產生器,在裡面你可以透過 GUI 定義你所需要的腳位以及 Timer 設定,他會將這些設定連帶初始專案一同生成,還可以讓你選擇要使用的平台去決定你的專案檔案架構,是個經濟又簡單的做法。

  2. 去官網下載 STM32 Standard Peripheral Libraries
    基本上就是官方他也有提供模板讓你做延伸應用,是比較接近 Build from scratch 的範疇,有興趣的網址在這

Part 2
在初始專案創建好之後,下一步就是針對你要的功能作詳細實作,並燒錄到你的板子上,而說到燒錄板子就不得不提到 IDE 的必要性。

不同廠家的開發板通常都會有自家官方的 IDE 提供燒錄程式所需要的 SDK 讓你省下手刻的麻煩,但缺點就是你只要換不同家的開發板就會需要重新學習新的 IDE,因此我這裡也介紹幾個做法。

  1. Keil IDE
  2. Cube IDE
  3. 寫 Makefile

但我沒有要一一介紹他們是什麼東西,因為網路上都找得到,所以自己去看,反正就是一些 IDE 的操作跟燒錄說明而已,沒什麼特別的。

目前我們在用的是利用將 pyOCD 燒錄命令寫進 Makefile 搭配 CubeMX 生成的 CMake 去執行組建,這個部分以後有機會再教大家,也是有比較多細節要說明的。

如何寫出好程式?

這裡所謂的寫好程式並不是寫出功能強大或運行效率極佳的程式,而是寫出易於閱讀、維護、管理、移植、測試等特性的程式,由於大家是在一個團隊內互相合作,因此寫程式也是要和大家一起進行,一個合格的工程師最重要的就是要能夠互相溝通,而為了讓溝通更為順利,一個好的程式以及完整的配套措施是必要的。

為了達成上述的目標,我將向大家介紹幾個準則,希望大家能學習並在往後的開發路程上遵守這些準則,讓開發的工作可以更為順利地進行。

準則

  1. 善用 Readme
    一個完整的專案裡面一定會有一個向使用者說明的文件,用意是讓使用者可以正確地理解程式的功能和使用方式,也可以將維護方式跟聯絡資訊放進去。總之,是個重要的組成。
  2. 善用版控工具 (Git)
    你在開發的過程中會不斷迭代新的版本,而為了完整保存你在開發中的所有過程,可以善用 Git 去紀錄所有發生過的變化,這樣有幾個好處。首先,要是你新的版本有 Bug 或是無法使用,至少有保存著過往可以用的版本;再來,在開發的過程中難免會有忘記自己寫的東西的前因後果的時候,這時候可以利用各版本的留言訊息來回顧當下的思考內容;最後,使用版控工具利於多人協作一份專案,如果要和別人合作的話版控工具是不可或缺的。
  3. 善用排版工具 (Clang-format)
    不同人會有各自的 coding style,導致程式的版面會有不統一的情況,因此為了避免版面不統一所導致閱讀困難,希望寫程式的各位要多佳善用 clang-format 排版工具,讓專案的格式得到統一,不僅可以改善 coding style 不同的問題,也可以修復亂掉的排版讓函式、條件式或迴圈的辨識更加容易。

為什麼要用 WSL

image

相信在座的各位大部分都還是使用 Windows 電腦吧,我在這裡要向大家推坑 WSL (Windows Subsystem for Linux),之所以鼓勵大家使用 WSL 有一個主要原因。

先來說說 Windows 的缺點吧,這會帶到一點電腦的歷史。Microsoft Windows 的前身是 MS-DOS,是一個從 1985 就發跡的作業系統,並不斷演進堆疊,直到現今所使用的 Windows。另一方面,Unix-like 的作業系統雖然從 70 年代就發跡,但一直到 1990 年的 Linux 的誕生隨著開源的概念普及才將其發揚光大,讓 Unix based 的作業系統以及 GNU、Posix 等協議成為軟體開發中的主流,也就是為什麼 Microsoft Windows 在原生上並不適用 Unix-like 的操作介面,也讓許多開源的工具和手法無法直接應用在 Windows 的開發環境。

那怎麼辦,Microsoft Windows 作為全世界個人主機市場市佔率最高的作業系統,難道它注定與 Unix 水火不容嗎? 這就是 WSL 的由來的,為了讓獨樹一格的 Windows 也支援 Unix 所擁有的一切,透過 WSL 就可以在 Windows 上面使用許多開源工具,或是下載許多在 Linux 上面可以輕易取得卻在 Windows 上不支援的套件,讓開發者們不必為了應對不同的開發需求而準備雙系統甚至多台裝置。

回到標題,那為什麼要用 WSL 呢,主要就是因為在軟體開發中有很多好用的工具雖然可以在 Windows 裡面使用,但很麻煩,而在 Unix-like 的系統裡面卻只需要幾個簡單的指令操作就可以輕易使用,所以為了讓大家省事一點,還是鼓勵大家及早適應,並且將來如果有往相關領域發展的話遲早也會接觸到,所以早點熟悉還是有很多好處的。