Open Source
    Microcontroller
    Automatic Control
    Coding Notes

2014年5月13日 星期二

利用 Arduino + Processing 做簡易示波器(Oscilloscope)

中午12:28 Posted by Unknown , , 1 comment


Arduino 內建 10 位元的ADC,可以整合各式感測器,像是磁力感測器、紅外線感測器、旋轉編碼器或是加速規等等,利用 Arduino 量測各種類比訊號,通常只能透過串列埠(Serial port)的監控視窗來檢查讀值的狀況,串列埠畫面的快速刷新有時候不好判斷訊號的前後關係,這時候利用 Processing 豐富的視覺化輸出,便可以做一個簡易的示波器介面。

Processing 的 serial library 可以讓 Processing 使用串列埠的通訊功能,當 Arduino 將感測器的讀值丟到串列埠時,Processing 便可以從那將他們抓進來做繪圖處理。 串列阜通訊是由 UART 傳輸器控制,一般以 10 位元為一個傳輸組,包含 1 位元的起始位元, 1 位元的停止位元,以及夾在兩者之間的 8 位元資料,這 8 位元才是我們真正要傳輸的感測值。 8 位元亦即 0 ~ 255,因此當感測器的值大於 255 (或是資料宣告的型態大於 8 位元,如:float ),在串列埠傳輸時便需要拆成數個傳輸組,待接收之後才能將他們一一合併為原始讀值。

串列埠通訊以鮑率 (Baud rate) 為資料傳輸速度的單位,例如鮑率 9600 Bd,表示每秒可傳輸 9600 個位元,按前述可知,此時每秒傳輸 960 個傳輸組,也就是 960 的位元組,所以是 960 Bps,其實很慢,如果傳輸的值較大,或占用較多的位元組,速度將會更慢。因此,使用這種方法做的示波器,其頻寬最高也只在數百 ~ 數 kHz 之間,變化太快的感測值,示波器是量不到的,若進一步考量 Arduino 與 Processing 處理接收資料的速度,頻寬更是會低到不行喔

以下簡介簡易示波器的實現流程:



$ Arduino端 $


為求 demo 方便,利用 Arduino 來模擬感測器讀值的產生,並將其不斷的丟到串列埠上。



1. 在 setup() 的設定中, 以 Serial.begin(115200) 初始化串列通訊,115200為傳輸鮑率,依需求可變更,前提是接收端所設鮑率必須跟此值一樣。



2. 在 loop() 中,產生虛擬的時變感測值,例如低頻的弦波訊號,值域為 0 ~ 1023 的整數intValue,有接上感測器的話,這裡便是存入感測器的原始讀值。




3. 由於 Arduino 的 int 變數會佔用 2 個位元組 (16個位元),為確保傳輸資料的正確性,在串列傳輸前必須先拆解為2 個獨立的位元組,可分別設為高位元 ( byteHigh ) 與低位元組 (byteLow),以 uint8_t ( unsigned int 8 bit ) 宣告這兩個變數。

   a. intValue >> 8 : 將 intValue 的二進位碼全部向右移 8 個位元,用這個方法取高位元組。

    b. intValue  & 0xff : 由 intValue 二進位碼的邏輯運算取出低位元組。














4. 準備好傳輸的位元組,就可以依序丟到串列埠了,但由於資料是連續不間斷的傳輸,資料又被分成兩個傳輸組,為了讓接收端 ( Processing ) 知道哪裡是資料的開端,在每個讀值前應要加上一個可供判別的標頭字元,例如 'H' 字元,讓傳輸資料依序為 標頭字元、高位元組、低位元組,如此重複。

















以上完成 Arduino 端的設定,便可以直接燒入單晶片,Arduino便會不間斷的將虛擬感測值送到串列埠。





$ Processing 端 $


首先 Processing 64 bit 版本不支援 Serial 傳輸應用,所以若要使用 Serial  librery,必須下載 Processing 32 bit 的版本。



1. import Serial 的 library ,並宣告 Serial 物件 Ard。

















2. 在 setup() 中,建構 Serial 物件,Serial.list() 會將連上電腦 com port 的裝置都列出來,通常沒有連其他裝置的話, Arduino 會列在第一個,在此例中其名稱為 COM4,此名稱應該與 Arduino 燒綠時的串列埠名稱相同。後面指定傳輸鮑率。
















3. 建立一個陣列 Rec[],用來暫存串列埠抓來的值。並利用自訂函數 receive() 接收串列埠的值。由於感測值的大小 mapping 為視窗的高度,而陣列 Rec[] 的長度為視窗的寬度,因此陣列中的每一個元素便可以對應到視窗中的一個座標,以此達成讀值的視覺化輸出。
















4.  自訂的函數 receive() 中,預設接收值 Val 為 -1,直到確實收到值在回傳。 由於已經知道三個位元組為一個完整的感測資料,透過 p.available() 確認 Serial buffer 中有足夠的位元組再開始接收值。以 p.read() 抓取 buffer 中的資料,直到抓到標頭字元確認讀值的起始端。每從 buffer read 一次,buffer 後面的資料便會向前遞補,因此抓到標頭字元後,就可以知道下兩次 read 分別為資料高位元組與低位元組。將兩者合併為 16 位元資料完成感測值還原。
















5. 在迴圈 draw() 中,每次僅  receive() 一個感測值,並從視窗左方出現,剩餘舊資料全部向視窗右側平移,將所有資料點連接為曲線,視覺上便可以看到如弦波的波形並呈現資料持續刷新。





1 則留言:

  1. 想請問你Wid 和Hei是宣告在什麼地方
    還有初始值是多少

    回覆刪除