2011年1月16日 星期日

Arduino 筆記 - 製作一個溫溼度記錄器 (2)

前一篇文章中,我們已經用 Arduino 做出了一個溫溼度計,這個溫溼度計可以在 LCD 上顯示即時的溫度與溼度,而且也會定時把溫度與溼度讀值送到 Serial Port 上,每兩秒鐘一次。接下來我們要寫一支 Log 程式,這支程式會在 PC 端上跑,它的任務是把 Arduino 送過來的溫溼度資料保存到檔案中。

Log 程式

底下就是這支 Log 程式(Log.tcl):


# 定義 Serial Port 以及通訊設定
set serialPort COM4:
set iomode "9600,n,8,1"

# 從 Serial Port 收資料
proc GetData {channel} {
    if {[gets $channel line] > 0} {
        # 取得一個時間戳記
        set now [clock seconds]
        set timestamp [clock format $now -format {%Y/%m/%d,%H:%M:%S}]
        
        # 在收到的資料行(line)前面加上時間戳記後印出
        puts $timestamp,$line
    }
}

# 開啟 Serial Port
set channel [open $serialPort RDWR]

# 設定 Serial Port
# 預設 9600bps, no parity, 8-bit data, 1 stop bit
fconfigure $channel -mode $iomode -blocking 0 -buffering line

# 當 Serial Port 有資料可讀時,自動呼叫 GetData 收資料
fileevent $channel readable [list GetData $channel]

# 進入 Event-Loop 處理 file events
vwait forever

程式說明:

  • 因為任務是把 Arduino 送過來的溫溼度資料保存到檔案中,所以 Log 程式涉及「開啟 Serial Port」、「設定 Serial Port 的 Baud Rate 等通訊設定」並且「從 Serial Port 上接收 Arduino 送過來的資料」這些工作。
  • 值得注意的一件事是,因為 Arduino 送過來的只有溫溼度的資料,並沒有時間的資訊,所以在把溫溼度資料保存到檔案前,Log 程式會順便在每一行資料前面加個時間戳記。
  • 這支 Log 程式是用 Tcl 語言寫的,你需要一個 Tcl 直譯器(Tcl Interpreter)才能執行它,Tcl 直譯器我們建議你使用 tclkit。你可以直接點這裏下載壓縮檔,壓縮檔裏已經打包了 Log 程式以及 tclkit,檔名分別是 Log.tcl 與 tclkitsh.exe。
Log 程式操作說明

前一篇的溫溼度計程式上傳到 Arduino 板子上,而且打開 Serial Monitor 也確定 Arduino 可以把溫溼度資料送到 Serial Port 了:

image_thumb14

接著我們就用 Log 程式把溫溼度資料保存到檔案。請先點這裏下載 Log 程式與 tclkit 的壓縮檔,並解壓縮檔案。

Log 程式的操作辦法如下,開一個 DOS 視窗,然後輸入指令,像這樣:

image

(註: 記得先關掉 Serial Monitor 以免 Serial Port 被佔住而導致 Log 程式開不了 Serial Port)

接著 Arduino 送過來的資料就會被保存到 SHT15data.txt 文字檔中了:

image

假如 SHT15data.txt 已經有存一些資料,不想讓 SHT15data.txt 的內容被覆蓋掉的話,可以用 >> 把資料附加到檔案中:

用 Excel 繒製折線圖

有了溫溼度資料後,我們可以用 Excel 繒製溫度和溼度的折線圖。請用 Excel 開啟文字檔,Excel 會跳出這個匯入字串精靈視窗:

image

選擇「分隔符號」,然後按「下一步」。

image

分隔符號選「逗點」即可,然後按「完成」,資料便會匯入到 Excel 裏,接著再利用 Excel 的圖表功能繒製折線圖就可以了。 下圖是我用 Exel 畫出的溫度折線圖與溼度折線圖:

image

以上是一個 Arduino 教學實例,教你如何用 Arduino 製作一個溫溼度記錄器。Arduino 真的很簡單,在看完前面的介紹後,相信你也會有同感。下回我們將改用 Google Chart API 來製作圖表。

也許你可以為這個溫溼度記錄器做一些改良,比如加上幾顆不同顏色的 LED 燈,然後調整一下程式的邏輯,讓 Arduino 在發現溫度超出某個門檻時就自動打開 LED 燈號,例如低於 27 度開綠燈,超過 27 度開黃燈,超過 30 度就開紅燈等,諸如此類的。你也可以用 Java, C# , Python 或是任何你熟悉的程式語言重新翻寫 Log 程式,趁這個機會學習或複習寫 Serial Port 的程式。

參考資料

46 意見:

不阿 提到...

哇~~真的很不錯!!我按照這樣做,真的就變成一個便宜的資料擷取卡,但是想要在有限的時間後,把serial停止login到資料檔,不知道要修改哪一個Tcl檔的哪一部分?

coopermaa 提到...

Hi 不阿,

你的意思,是要 Log 一段時間就好,然後讓程式自動停下來嗎?假如是這樣的話,可以加一行像底下這樣的 code:

# Log 5 分鐘就好(即 300 秒)
# 5 分鐘後關掉 Serial port 並結束程式
after 300000 {close $channel; exit}

把這行加到 Log.tcl 的倒數第二行,也就是放在 vwait forever 這行之前就行了。

你也有在玩 Arduino 嗎? 歡迎,歡迎。:)

不阿 提到...

多謝啊~Orz救星
是啊~就是你所猜得這樣~~
我只要差不多幾十秒一個脈波或幾個小時的腦波測量~~

我剛剛試了,ok囉~我今天看了一堆Tk/Tcl的指令網頁,完全沒有效果,只好網頁問囉~~想不到真的問得到~~

其實我是在把心跳計的訊號拉出來,然後再用Matlab或者Mathematica把訊號檔案用小波分析轉換成時頻分析,這樣我們就可以看到哪一秒鐘有哪個頻率發生,我也有在玩Arduino,不過很淺的(事實上只有一星期的資歷^_^).我自己早就有NI的USB與擷取卡(但是不便宜啊!最便宜的也要5000~6000),但有些中醫的朋友想先看看有沒有值得玩一玩的訊號,還有要讓學生回家也能玩訊號分析,一定要幫他們找到便宜又大眾化的擷取卡,Arduino是很好的選擇~~
謝謝啦~以後一定還有機會問東問西~

coopermaa 提到...

心跳計? 是健康檢查的心電圖那種東西嗎?

哇!好酷喔!這東西很實用耶,每個人都用得到。

我記得在做心電圖檢查時,護士會在我們胸口上貼一個好像是量電極的貼片,像這種 Sensor 外面也有在賣嗎? 我知道學硬體的人好像都會用示波器,示波器是利用探棒感應訊號,不知道心電圖的電極貼片跟示波器的探棒原理是否相同?

我 Arduino 的資歷也淺。不過學 Arduino 不用擔心,因為 Arduino 實在太簡單了,我已經在短短一兩個月學到好多東西了,很歡迎你一起來切磋。

BTW, 推薦你一個很棒的中文 Tcl 的討論區: E-office 學園,如果你有任何 Tcl 的問題,可以在那邊發問,相信很快就得到答覆,因為那邊有位很熱心助人的 XO 老師。

不阿 提到...

所謂心跳計有好幾種:
1.你說的醫院檢查的那種,我們人的心臟會從心竇放出脈衝,激發心肌抽動,這個電位會傳到體表,所以就像你說的貼個貼片,然後夾住腳踝當接地,就可看到電壓差!有在賣,沒錯~益眾有出產套件,但是似乎他們的網站說停售!?
2.脈博心跳,我們戴手錶有脈搏,經過錶上的壓電材料,可以錄下脈波,我們再配合download的元件取得資料,這個arduino有配合的元件,藝科的網站有賣!
3.低科技的紅外線穿透變化,我們的皮肉會被紅外線穿透,通不過時就是血流量最大,所以我們可以利用血紅素濃度的倒數來看該局部心臟推力的大小!這個在阿簡兄的部落格有捏~套件在堃喬有賣,一個120元~小弟玩的就是這個低科技~~或者自己去買個紅外線收發,各8元(大批發3元),配個放大電路,也可以量到~

coopermaa 提到...

藝科的是Polar 心跳接收器這個嗎?售價 NT2000, 不便宜耶。

我去阿簡老師網站看過他那篇「心跳偵測器」了,原來紅外線也可以用來做偵測心跳。所以你想用紅外線收發+Arduino 來做心跳計嗎?

請問你是學醫還是學電子的啊?

不阿 提到...

藝科的是Polar 心跳接收器這個嗎?售價 NT2000, 不便宜耶。
>>素啊~而且這個東西,我看了說明,是心率(也就是每分鐘多少下),不是即時的心跳大小.我要的不是這個,還好有看清楚,不然買了可能要供起來在神桌上~

我去阿簡老師網站看過他那篇「心跳偵測器」了,原來紅外線也可以用來做偵測心跳。所以你想用紅外線收發+Arduino 來做心跳計嗎?
>>>Just it!低科技吧~


請問你是學醫還是學電子的啊?
>>都不是呢~學航太的!曾經在醫學院教過醫學物理與微積分,所以曾經做過核子醫學影像的論文,本來還想搞點心臟科的題目,不過合約到了,所以沒做了~~現在要搞教育的題目,所以想到這個arduino!因為有廠商送一些樣品希望採用,誰知道一摸後就一直玩了~~今天還去買了16*2LCD要把訊號呈現,另外還買了一塊TFT LCD,結果找不到資料,因為它是32PIN!這張LCD恐怕要供起來膜拜!慘~~

coopermaa 提到...

核子醫學影像!聽起來就覺得很不簡單。:)

我是唸資管的,在我這種不懂電子的人眼中,這些都是高科技啊,好好玩。

2x16 LCD 我前陣子也玩過,我有整理一篇筆記,你可以參考看看。

歡迎常來啊。

不阿 提到...

核醫並非想像的那麼神秘或深澳~就是一堆影像處理的東西,不同的是它是用放射藥劑注射到人體,當成光源,儀器放一堆數位sensor,反推算出哪裡的放射計量多少,依每個點的放射強度大小畫出圖就是組織的活性!!會用到雞兔同籠的聯立方程式~~超有趣的!

我已經看了你的2*16-LCD的文章~~(Arduino+紅外線心跳電路+LCD顯示)大概都Setup好了,感謝~一共只花了九天,九天前連Arduino是啥都沒聽過!

我問你一件事喔!用Tcl/Tk應該可以把Log進來的data即時畫出吧?那應該要看甚麼資料?

coopermaa 提到...

你懂的還真多,從你這邊我才知道還有 「核子醫學」這門學問,受教了。哈!玩 Arduino 會很有成就感!

如果你要把資料即時畫成圖形,也許可以試試 Canvas 元件,可以看看 "Simple Canvas Demo" 這邊的範例。Tk 我就比較少用了。

coopermaa 提到...

不阿,請問一下,你的紅外線心跳計軟體的部份打算怎麼做? 要怎麼判斷有無心跳?是送一個紅外線波形然後看有沒有反射回來嗎?那可以做到什麼樣的程度,除了算每分鐘跳幾下外,可以檢查心跳的強弱大小嗎?

不阿 提到...

好問題啊~~這是我10年前遇到的問題,然後呢那時自己焊接的電路又不能通電,所以就放棄了~~可是誰知道今年心血來潮又重來一次,結果連資料擷取都有了還可以LCD來Show資料!我還花一個下午來欣賞成品!

這個堃喬套件(就是阿簡兄示範的那個套件)的電路上的電阻R9可以拉出一條訊號就是手指頭的紅外透明度的起伏(數位的),這個電路會錄下一個週期,所以你手擺上去會停三秒(看阿簡兄的錄影),然後後面就會比對這個波,下次到達波峰的高點就會嗶一聲,所以才會有心跳的一閃一閃,事實上這個心跳電路是把類比變成數位的有無有無然後引導LED燈閃滅與蜂鳴器嗶嗶叫!!

所以你想看大小就是把R9的正極拉到Arduino的A0(類比輸入0埠),負極拉到Grand.然後修改
你的濕度程式與LOG程式就是時間序列!!

把這個時間序列丟到Matlab的Plot你就看到了類似心跳的波,但是不是這個要倒數才是心跳!!

R9拉出的訊號是血紅素濃淡,不透光時血液充滿
心臟推力最大,電壓最小,透光時電壓訊號高,沒啥血液在血管所以組織透明,紅外線接受器收到到最多紅外線,事實上你聽到嗶聲時心臟剛好在鬆沒用力!

不阿 提到...

更正:寫錯了Grand,而是GND!!

另外我想問你一個問題,這個Log.tcl中的fileevent可以把資料塞到某個變數裡面嗎?好像不行耶!還是要用read的指令?

我是打算一面Log資料一面畫圖,就變成即時的心跳推力計(現在就缺這個)!

而且完了之後就把資料塞到matlab去作頻率分析(這部份我會)!!

不阿 提到...

其實我要做的設備,醫院早就有了,去急診室或加護病房裡會用一個夾子夾病人的食指,然後監視器會畫出波形,有心跳就嗶一聲,心跳忽然斷了就長嗶~~~(這個情節偶像劇經常有)

我想做這個其實就是要Log進來的Data(時間序列)才能做fft,其實醫院也有儀器有小波分析,但是很貴很貴!儀器公司當初也是像我們這樣做出來的,然後介面包裝,產品包裝!就是這樣而已!

所以做出來會有成就感,幾萬的儀器說穿了成本不到幾千元!

coopermaa 提到...

請問一下,堃喬套件電路上沒有看到 MCU,比對方波這件事是 4069 這顆 IC 負責的嗎?那顆 4069 是專用的 IC 嗎?

coopermaa 提到...

「這個Log.tcl中的fileevent可以把資料塞到某個變數裡面嗎?好像不行耶!還是要用read的指令」

把資料塞到某個變數?你是說 A0 的資料傳到 PC 後,接著把資料塞到變數,然後再利用變數即時畫圖嗎?這個在 GetData 裏就有了:

# 從 Serial Port 收資料
proc GetData {channel} {
if {[gets $channel line] > 0} {
# 取得一個時間戳記
set now [clock seconds]
set timestamp [clock format $now -format {%Y/%m/%d,%H:%M:%S}]

# 在收到的資料行(line)前面加上時間戳記後印出
puts $timestamp,$line
}
}

gets $channel line 這行就會把資料收到 line 變數裏,如果 Arduino 傳過來的是紅外線透明度的資料,就會被儲存在 line 變數裏。

coopermaa 提到...

嗯,DIY 是很享受的一件事。

我其實就是透過 Arduino 在學習一些基礎的電子知識。沒想到好玩的東西這麼多,每天都有新奇的東西出現。

不阿 提到...

是啊~是用IC跟電容來完成此項"類似比對"的功能!

不阿 提到...

我知道這個函數的作用啊~而且我還改成把時間印記拿掉,這樣比較容易處理數學軟體對資料的讀入.

因為我完全不懂Tcl(我是有勉強看一點),所以
我的疑問是這樣的,我是用C的觀點來看,比如我們定義一個函數read(),那我們就可以利用一個
變數名比如:
value=read();
我們再把value畫出來一個點比如
plot(value);


如果我們不停的讀入畫出就可以變成即時監測的功能!我的意思:是能一次讀一列COM就停下來,去執行canvas的指令,然後不停地更新讀入並畫圖,應該要怎麼改?

coopermaa 提到...

可以試試這個寫法:

proc GetData {channel} {
# Read sensor data and save to the value variable
if {[gets $channel value] > 0} {
# plot data
# note: need to implement plot proc with canvas widget
plot $value
}
}

或是這樣寫:

proc GetData {channel} {
# Read sensor data and save to the value variable
set value [gets $channel]

# is it a valid line(not empty line)?
if {set $value > 0} {
# plot data
# note: need to implement plot proc with canvas widget
plot $value
}
}

hope this work.

不阿 提到...

我找到了一個類似的範例~~但是要用processing,我現在才知道原來processing
跟arduino是同一種介面~~arduino是與processing配套的

coopermaa 提到...

Arduino 的 IDE 是 based on Processing 的,所以兩個長得很像。

如果用 Processing 來畫圖的話,應該就不需要再經過 Tcl 的 Log 程式了。這部份我還沒有開始研究,不過上次有大概看了一些資料,比較簡單的方法應該是利用 Firmata Protocol 讓 Processing 跟 Arduino 建立通訊。

coopermaa 提到...

不曉得這你感不感興趣: Forward FFT,剛在 processing 網站發現的。

不阿 提到...

嗯~下午已經Run過了~你在Processing的選單中拉下File>Examples>Library>Minim
(Sound)的第三個例子就素啦~~

啪謝~已經下午先玩了:)
你還可以玩碎形與自相似植物L系統~~
光看到這些就已經迷上了Processing. Orz
再加上可跟Arduino搭配寫介面~~我已經放棄
Tcl\TK~
可惜了那本簡體的Tcl\Tk經典入門,還在到台灣的路上,已經被我趴棄!^^

不阿 提到...

我今天真的花了一天從早上九點到下午六點,找有關Processing+Arduino~~,與其說垃圾很多,還不如說很多關鍵點都lost!跟當初讀量子力學一樣,越接現代的書越看不懂,最後只好從1930年代的老書看起,原來如此!!大家都以為你知道一些背景知識,但是初入門者就是不知道咩~卡在那邊~桌子都被我搥壞~

建議你
1.先看 http://arduino.tw/allarticlesindex/3rd/209-arduino-processing.html
2.再看(我要的功能都有了,現在想改成一次可以輸出雙個類比讀入)
http://accrochages.drone.ws/en/node/90
3.這個也是我要的
http://am3thyst.net/blog/2010/11/17/logging-applet-for-reading-sensor-data/

最關鍵的一句話是失樂園的:
port = new Serial(this, Serial.list()[1], 9600); //建立port這個元件,指定連接阜和連線速度.

我的經驗是:大部分的範例程式不是
port = new Serial(this, Serial.list()[放空], 9600);
不然就是輸入[0] [1],實際上你要看Processing下方的顯示是不是你的Arduino的實際上的COM是哪個?

我的Processing顯示如下:
[0] Com1
[1] Com3

所以要填[1]~依此類推

coopermaa 提到...

Processing 跟 Arudino 是天生一對,很速配啊!

謝謝你提供的資訊,我來好好 K 一下,然後再來整理筆記給像我這樣的初學者看。

不阿 提到...

感恩啊~~你的整理都很好~一定有助於大家活用~~
再貼一次有用的整理網站,因為這些資訊好像消失了~


建議你
1.先看 http://arduino.tw/allarticlesindex/3rd/209-arduino-processing.html
2.再看(我要的功能都有了,現在想改成一次可以輸出雙個類比讀入)
http://accrochages.drone.ws/en/node/90
3.這個也是我要的
http://am3thyst.net/blog/2010/11/17/logging-applet-for-reading-sensor-data/

coopermaa 提到...

謝謝你的鼓勵。因為怕文章裏有錯字或表達不清楚,每次寫完後,我都會多看幾遍才發出去,不過有時候還是免不了會大意或是有自己看不出問題的盲點,所以我還蠻期望有人可以幫忙校閱的。

你現在用的是 Processing 0191 最新版吧?告訴你一個好東西!你打開 Processing IDE 的時候,注意一下 IDE 的選單,裏面有個 Android 選單!!

用 Processing IDE 寫好的程式,不僅可以 Export 成網頁 Java Applet,可以 Export 成獨立的執行檔(Application),還且還可以 Export 成 Android 的應用程式耶!可以參考一下「在 Processing 上開發 Android 應用程式」這篇。

這功能真是超吸引人的! :)

不阿 提到...

你的Arduino我大都會看~還有很多網友會看~
所以不擔心會有瑕疵,我們會看就等於校閱啦!
你的粉絲也不少呢~至於其他非Arduino的部份我可能懂得比較少,沒辦法校閱!!
開個Processing部份吧~~我就可以多幫忙看一個part!

喔~我用的Processing是1.2.1版~

確實真很方便,可以變成Java執行檔!但是我這個網上抓來的即時測量監視器功能,只能做成Window applica-tion,沒變法做成Java檔嵌在網頁中,它說缺乏執行的class,不知道為何?這個我還真不懂耶!!

基本上,便宜的供研究非治療用的生醫設備,是可以做到了~~很滿足了~花不到兩星期就交差了~~

coopermaa 提到...

感謝。我的粉絲不少?這話從何說起?

我之後會寫一些 Processing 的筆記,現在還在構思目標要訂在哪裏,打算要怎寫什麼內容。

恭禧你啊!你現在做的應該是純 Serial 介面的心跳監測程式吧?將來有打算把它做成網路介面嗎?

不阿 提到...

因為Google查Arduino關鍵字在台灣的網頁,還排得蠻前面的,因為你寫得還蠻勤的~~之前的另外兩個仁兄排得比較前面,但是他們在自己網頁說去當兵了,所以就被你追過了~~


寫手機跟Processing的東西應該不錯,因為流行嘛而且真的很有用!Processing最大的用意就在"互動"!


我確實想用成網頁鑲嵌的程式,但是我今天試過了,不知道為何,就是不能在Java Runtime下執行,其他的範例都可以~~

coopermaa 提到...

不阿兄,這個你可能會有興趣, Android 手機的心跳計:

Instant Heart Rate

chenanco 提到...
作者已經移除這則留言。
TsaiTe Chu 提到...

想請問一下,他能夠讀取電腦中的文字檔嗎?

coopermaa 提到...

「讀取電腦中的文字檔?」

你是說誰讀取電腦中的文字檔?

TsaiTe Chu 提到...

Arduino 板子可以讀取電腦的文字檔(.txt)嗎?
上面文章是利用dos視窗將Arduino所得到的資訊寫入文字檔中,反過來,這塊板子能不能讀取文字檔的內容呢?若能讀取我便可以將文字檔的資訊顯示在外接的裝置上。

coopermaa 提到...

Arduino 沒辦法存取電腦端的文字檔,電腦這端要寫支程式把文字檔內容主動送給 Arduino 才行喔!

另外,如果文字檔裏有中文,那麼 Arduino 收到的只是編碼,如果要把中文顯示在外接的裝置上,我沒這方面的經驗,不過我想可能還需要字型檔,或者是在電腦端先將中文轉成 pixel 再給 Arduino 處理

TsaiTe Chu 提到...

感謝你的回覆,想再請教一下,你說PC端要寫程式主動將內容送給Arduino才行,不知道你有沒有這方面的經驗,可以提點一下~
PS.我的文字內容應該只是阿拉伯數字而已,所以應該不會遇到像是中文那麼麻煩的問題~感謝你的補充說明,謝謝!

coopermaa 提到...

PC端要寫程式主動將內容送給Arduino,這部份很簡單啊。大概分兩個步驟: (1) 讀檔 (2) 開 Serial Port 並把檔案內容丟到 Serial Port。這很多程式語言都辦得到,應該不難。

在 Tcl 的話,讀檔這樣寫:
set fd [open c:/autoexec.bat r]

while {[gets $fd line] >= 0} {
puts $line
}

close $fd

而開 Serial Port 則是這樣寫:

# 開啟 Serial Port
set channel [open $serialPort RDWR]

# 設定 Serial Port
# 預設 9600bps, no parity, 8-bit data, 1 stop bit
fconfigure $channel -mode $iomode -blocking 0 -buffering line

然後你只要把檔案內容丟到 $channel 即可,例如:

gets $fd line
puts $channel $line

當然,Arduino 這邊也要寫一支程式處理 Serial 的資料就是了

coopermaa 提到...

我有做過一份 Tcl 檔案處理的簡報,供你參考:

http://www.cqi.com.tw/coopermaa/951-DB/tcl/FileIO.ppt

TsaiTe Chu 提到...

感謝你這麼詳細的解說!!
有問題再向你請益,謝謝!

coopermaa 提到...

不客氣,如果你熟 C#,也可以參考我這幾篇筆記:
C# Serial Port Communication #1
C# Serial Port Communication #2
C# Serial Port Communication #3

TsaiTe Chu 提到...

Thanks a lot.
你的筆記寫得很詳細,有附圖、程式碼、短片,真的很讚!!

coopermaa 提到...

謝謝!
You're welcome. :)

Yi Ting Liu 提到...

想請問一下
這個也可以套用在別的sensor嗎?

cooper maa 提到...

你是說 Excel 圖表嗎?
當然可以啊!