這個多功能sensor設計的想法,基本上是把韌體整合在一起,不用每次想測不同東西,就要重灌一次韌體。學生使用的時候,只要電腦上有arduino,可以看到serial monitor就可以進行實驗收集數據。
雖然我會盡量把東西整理包起來,不過如果要自己弄一台的話,基本arduino的知識是需要知道一些的。像是library的安裝,一些接點、插孔大致上的意義等等。我想大概就是需要自己玩過三四種不同的sensor,然後有要用到library,這樣就夠了。
所有的sensor都做成USB的頭,可以隨時插拔,不同功能的切換,則是利用3pin滑動開關達成。實驗時一些取樣方式的調控,或者輸出的模式,則由可變電阻VR來調整。(主要是取樣的時間間隔)
一、元件
(一)SciCore本體
1.Arduino UNO
2.LCD IIC 1602
3.USB母頭三個
4. 5k可變電阻三個
5. 3pin的滑動開關三個
Scicore基本設計的想法請看阿簡的影片 https://www.youtube.com/watch?v=dAjlLz8IFAo
不過從影片可以看到USB母頭其實會有點晃,即使有壓條固定,USB插拔的時候還是會不太好操作。另外USB底座接點也比較弱,所以我後來用另外的元件重新處理了。
我買了直的USB母頭,和左邊那個接腳,焊起來就行。(焊接這件事情,大概花了我十幾個小時有!)
這樣焊好之後,把前面金屬部分和後面塑膠部分,都上一點熱融膠,就可以黏在壓克力上,很緊,插拔的時候很穩定。不過要小心,熱融膠如果從USB洞進去一些,就很難插拔了。
(二)接在麵包板上的sensor
1. DHT11 溫濕度感測:參考資料。這東西理論上很容易處理,不過我之前去光華商場要買的時候,發現兩個版本。一個是後面有紅色電路板的,一個沒有。價格一樣都是 NT80。那當然要買有電路板的啊!結果買回來測到的數據都有問題,下雨天記錄到的濕度是18%。五顆都一樣,於是就拿回去換了沒有電路板的,就運作正常了。
(三)外接的sensors與其他
1.氣壓 MPX4115:參考資料
2.酸鹼pH計:參考資料
3.超音波模組:參考資料
4.光敏電阻:參考資料
5.DS18b20溫度計:參考資料
6.RGB燈:我用的是四個接點的,RGB接點是正極,第四個接點是共用負極的。有些RGB燈會設計成共用正極,就不適用了。參考資料
7. USB轉3.5mm 耳麥公頭:這本來江老師是設計可以做成縮時攝影等功能,可以做成photoduino。不過我暫時用不到,就只拿這個東西作為頻率產生器的輸出。要做縮時攝影的話看這裡
二、接線方式
(一)LCD SDA, SCL部分,通常會接到A4, A5。不過板子有另一個地方可以接。下面圖的左上角,另外有SDA和SCL(圖片來源:https://forum.arduino.cc/index.php?topic=84190.0)
我會習慣插在左上角的位置,把Analog的腳位都空下來用。但其實A4, A5和左上角的SDA SCL根本是連通的。所以A4, A5就不是所有的sensor都可以接了,有些東西接上去,會影響LCD。
元件
|
元件腳位
|
連接腳位
|
LCD IIC1602
|
GND
VCC SDA SCL |
GND
VCC SDA SCL |
(二)USB們,USB的腳位定義,請參考。這四個腳位要看清楚相對位置,最好都按照原本的定義去接線,之後要找線比較容易。要轉接成PS/2的時候,也比較知道怎麼對應。
基本上,1號腳位都是正極,4號腳位都接地。主要訊號都是從2號腳位進去的。3號腳位的話,就是如果元件還需要多一個接點,就用下去。
像超音波模組,需要有一個輸出聲音的和一個輸入聲音的,就分別用3號腳位輸出,2號腳位就固定做輸入。這件事情由USB1擔任。
元件
|
元件腳位
|
連接腳位
|
USB1
|
1
2 3 4 |
VCC
D3 D4 GND |
元件
|
元件腳位
|
連接腳位
|
USB2
|
1
2 3 4 |
VCC
A0 A4 GND |
其實USB1也可以這樣做,變化就會多一點,不過我懶得改了...
(三)可變電阻VR。可變電阻都三隻腳,兩邊分別接上正負極,調整旋鈕就等於控制了中間腳位的電位(基礎電學用上囉~)三個可變電阻中間的腳,分別就輸出給A1, A2, A3三個類比輸入。三個旋鈕設計成可以控制RGB的燈泡亮度。如果不是在用RGB的時候,R的旋鈕基本上都是控制取樣頻率,越順時針轉,取樣頻率就越高。不同實驗取樣頻率不同。像超音波實驗的話,最快是50ms取一個數據,最長是1秒;環境溫濕度壓力的話,最短是一秒,最長是五秒等等...
(四)3p滑動開關們。SciCore上面設計了四個3p滑動開關。可以作為功能調控使用。四個開關可以有十六種組合。我用不到那麼多,實際運用的只有3個。
元件
|
元件腳位
|
連接腳位
|
USB3
|
1
2 3 4 |
D9
D10 D11 GND |
元件
|
元件腳位
|
連接腳位
|
VR1
|
右
中間 左 |
VCC
A1 GND |
元件
|
元件腳位
|
連接腳位
|
VR2
|
右
中間 左 |
VCC
A2 GND |
元件
|
元件腳位
|
連接腳位
|
VR3
|
右
中間 左 |
VCC
A3 GND |
本來三個接點的接法,是分別接上 正極,digital接腳,負極的。不過因為arduino有一個PULL UP指令,於是可以少接一條線。少接一條是一條啊!參考資料1 參考資料2
元件
|
元件腳位
|
連接腳位
|
3pin 滑動開關
S1 |
上
中 下 |
x
D7 GND |
元件
|
元件腳位
|
連接腳位
|
3pin 滑動開關
S2 |
上
中 下 |
x
D8 GND |
元件
|
元件腳位
|
連接腳位
|
3pin 滑動開關
S3 |
上
中 下 |
x
D12 GND |
元件
|
元件腳位
|
連接腳位
|
3pin 滑動開關
S4 |
上
中 下 |
x
D13 GND |
這是外接sensor接線時需要知道的。
幾乎所有的sensor,都是三隻腳,分別是正極、負極還有資料輸出。所以基本上只要認得這三個孔就行。
再看一下PS/2的腳位意義。
4號孔是正極,3號是負極,就是連結到剛剛USB的1, 4號。不過不用管數字,反正這兩個孔就是正負極,都固定的。
最後一個孔,是資料輸入的地方,就是1號孔了,在負極的下方。這個孔連著USB的2號,是我們前面USB設定要輸入資料的地方。
如果還有第四隻腳怎辦?那就接到5號孔,就在負極上方。
總之,正負極反正一定要接的。然後訊號就從1號孔進去,如果還有一條線,就接到5號。
(五)韌體。有些基本設計的想法已經寫在前面了。如果library都準備好,下面程式碼理論上複製貼上,上傳就能運作了。我基本上不會寫程式,下面的程式碼都是複製貼上後,再做修改的。可能很亂或笨笨的,如果有神人願意再把程式碼修的更好,就太棒啦。
//SciCore 1.0#include <Wire.h> // Arduino IDE 內建// LCD I2C Library,從這裡可以下載:// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads#include <LiquidCrystal_I2C.h>// Set the pins on the I2C chip used for LCD connections:// addr, en,rw,rs,d4,d5,d6,d7,bl,blpolLiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 設定 LCD I2C 位址//以上是驅動LCD的部分//以下呼叫library們#include <dht.h> //抓溫溼度計的資料庫// 匯入程式庫標頭檔//from http://playground.arduino.cc/Learning/OneWire#include <OneWire.h>//from https://github.com/milesburton/Arduino-Temperature-Control-Library#include <DallasTemperature.h>#include <Wire.h>// HCSR04Ultrasonic/examples/UltrasonicDemo/UltrasonicDemo.pde#include <Ultrasonic.h>//數位接腳定義#define dht_dpin 2 //定義DHT11的訊號要從Pin D2 進來#define DigitalIN 3 //第一個USB的二號腳位連接到D3,作為數位訊號輸入#define DigitalOUT 4 //第一個USB的三號腳位連接到D4,作為數位訊號輸出#define Switch1 7 //D5, D6, D7作為switch的切換腳位,是digital input_pullup#define Switch2 8#define Switch3 12#define Switch4 13#define LEDR 9 //D9, 10, 11為PWM,作為三個可變電阻數值的輸入腳位#define LEDG 10#define LEDB 11#define SensorPin A0 //定義SensorPin是0號類比腳位dht DHT;// DS18B20溫度OneWire oneWire(LEDG);DallasTemperature sensors(&oneWire);Ultrasonic ultrasonic(DigitalOUT, DigitalIN);//運動學unsigned long time;float intervaltime; //測量的時間間隔(由控制紅光的電阻決定)float x0, v0,cmMsec, duration, distance,velocity,acceleration; //定變數int showtime; //要在LCD上呈現取樣時間間隔,要整數//pH meter#define Offset 0.00 //deviation compensate#define samplingInterval 20#define printInterval 800#define ArrayLenth 40 //times of collectionint pHArray[ArrayLenth]; //Store the average value of the sensor feedbackint pHArrayIndex=0;int potPinR = 1;int potPinG = 2;int potPinB = 3;void setup(){Serial.begin(9600);pinMode(DigitalOUT, OUTPUT); //數位輸出腳位pinMode(DigitalIN, INPUT); //數位輸入腳位pinMode(Switch1, INPUT_PULLUP); //檔位輸入的三個腳位pinMode(Switch2, INPUT_PULLUP);pinMode(Switch3, INPUT_PULLUP);lcd.begin(16, 2); //起始lcdsensors.begin(); //起始ds18b20溫度計delay(5000);//RGB setup}int r = 0;int g = 0;int b = 0;void loop(){int S1 = digitalRead(Switch1);int S2 = digitalRead(Switch2);int S3 = digitalRead(Switch3);DHT.read11(dht_dpin); //去library裡面找DHT.read11float pressure = readPressure(A0); //壓力數值從A0讀取float millibars = pressure/100;//switch 說明 000=0, 100=1, 010=2, 001=3, 110=4, 101=5, 011=6, 111=7if ((S1 == 0)&&(S2 ==0) && (S3==0)){intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 900, 0, 500, 4000);Serial.println ("000 = menu");Serial.println ("100 = enviroment data");Serial.println ("010 = temperature and pressure");Serial.println ("001 = supersonic");Serial.println ("110 = RGB light and LUX");Serial.println ("101 = Frequency output");Serial.println ("011 = pH meter");lcd.clear();lcd.setCursor(0,0);lcd.print ("000=menu");lcd.setCursor(0,1);lcd.print("100=enviroment data");delay (intervaltime);lcd.clear();lcd.setCursor(0,0);lcd.print ("010=temp & press");lcd.setCursor(0,1);lcd.print("001=supersonic");intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 900, 0, 500, 4000);delay (intervaltime);lcd.clear();lcd.setCursor(0,0);lcd.print ("110=RGB 011=pH");lcd.setCursor(0,1);lcd.print("101=Freq generator");intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 900, 0, 500, 4000);delay (intervaltime);}//1.環境溫溼度與壓力,溫溼度來自於DHT, 壓力來自於MPX4115if ((S1 == 1)&&(S2 ==0) && (S3==0)){intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 900, 0, 1000, 5000);Serial.print(DHT.temperature);Serial.print(",");Serial.print(DHT.humidity);Serial.print(",");Serial.println(pressure/101300);lcd.clear();lcd.setCursor(0, 0);lcd.print("T=");lcd.print(DHT.temperature);lcd.print("C ");lcd.print("H=");lcd.print(DHT.humidity);lcd.print("% ");lcd.setCursor(0, 1);lcd.print("P=");lcd.print(pressure/101300);lcd.print(" atm");delay(5000);}//2兩個溫度和壓力,溫度用外接的溫度計,壓力還是MPX4115if ((S1==0)&&(S2==1)&&(S3==0)){pinMode (LEDG, INPUT);pinMode (LEDR, OUTPUT);digitalWrite(LEDR, HIGH);intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 900, 0, 100, 10000);sensors.requestTemperatures(); //這東西會吃很多時間,所以要擺進if裡面float T1=sensors.getTempCByIndex(0); //這東西會吃很多時間,所以要擺進if裡面float T2=sensors.getTempCByIndex(1); //這東西會吃很多時間,所以要擺進if裡面time=millis();Serial.print(time);Serial.print(pressure/1000);Serial.print(",");Serial.print(T1);Serial.print(",");Serial.println(T2);lcd.clear();lcd.setCursor(0, 1);lcd.print("P= ");lcd.print(pressure);lcd.print("pa");lcd.setCursor(0, 0);lcd.print("T1:");if (T1 == -127){lcd.print("N/A");}else{lcd.print(T1);lcd.print("C");}lcd.print(" T2:");if (T2 == -127){lcd.print ("N/A");}else{lcd.print(T2);lcd.print("C");}delay(intervaltime);}//3.超音波測距if ((S1==0)&&(S2==0)&&(S3==1)){pinMode (LEDG, INPUT);pinMode (LEDR, OUTPUT);digitalWrite(LEDR, HIGH);intervaltime = analogRead(potPinR);intervaltime = map (intervaltime , 1000, 0, 50, 1000);showtime = intervaltime;sensors.requestTemperatures(); //這東西會吃很多時間,所以要擺進if裡面float T1=sensors.getTempCByIndex(0); //這東西會吃很多時間,所以要擺進if裡面float cmMsec;long microsec = ultrasonic.timing();DHT.read11(dht_dpin); //去library裡面找DHT.read11float c;if (T1==-127){c=(331.5+0.6*DHT.temperature)*0.0001;}else{c=(331.5+0.6*T1)*0.0001;}digitalWrite(DigitalOUT, HIGH);delayMicroseconds(1000);digitalWrite(DigitalOUT, LOW);time=millis();distance = (microsec/2)*c;distance +=(microsec/2)*c;distance +=(microsec/2)*c;distance +=(microsec/2)*c;distance +=(microsec/2)*c;distance =distance/5;Serial.print("Time=");Serial.print(time);Serial.print(", ");Serial.print("dt =");Serial.print(microsec);Serial.print ("distance= ");Serial.print(distance);Serial.print(", Temp=");if (T1==-127){Serial.println(DHT.temperature);}else{Serial.println(T1);}lcd.clear();lcd.setCursor(0 ,0);lcd.print("t=");lcd.print(microsec);lcd.print("ms ");lcd.setCursor(8,0);lcd.print("D=");lcd.print(distance);lcd.print("cm");lcd.setCursor(0, 1);lcd.print("T:");if (T1 == -127){lcd.print(DHT.temperature);lcd.print("C");}else{lcd.print(T1);lcd.print("C");}lcd.print (" dt");lcd.print (intervaltime);delay(intervaltime);}//4.RGB光源輸出極光敏電阻測光實驗if ((S1==1)&&(S2==1)&&(S3==0)){int pr = analogRead(A0);pinMode(LEDR, OUTPUT);pinMode(LEDG, OUTPUT);pinMode(LEDB, OUTPUT);r = analogRead(potPinR);r = map(r, 0, 900, 0, 200);analogWrite(LEDR, r);g = analogRead(potPinG);g = map(g, 0, 900, 0, 200);analogWrite(LEDG, g);b = analogRead(potPinB);b = map(b, 0, 900, 0, 200);analogWrite(LEDB, b);lcd.clear();lcd.setCursor(0,0);lcd.print("R= ");lcd.print(r);lcd.print(" G= ");lcd.print(g);lcd.setCursor(0,1);lcd.print("B= ");lcd.print(b);lcd.print(" LUX =");lcd.print(pr);Serial.print("R= ");Serial.print(r);Serial.print(" G= ");Serial.print(g);Serial.print(" B= ");Serial.print(b);Serial.print(" LUX =");Serial.println(pr);delay(1000);}//5.頻率產生器if ((S1 == 1)&&(S2 ==0) && (S3==1)){pinMode (LEDG, OUTPUT);pinMode (LEDR, OUTPUT);digitalWrite(LEDR, HIGH);int frequency;r = analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r +=analogRead(potPinR);r=r/10;r = map(r, 0, 1023, 0, 20000);g = analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g +=analogRead(potPinG);g=g/10;g = map(g, 0, 1023, 0, 200);b = analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b +=analogRead(potPinB);b=b/10;b = map(b, 0, 1023, 0, 20);Serial.print("R= ");Serial.print(r);Serial.print(" G= ");Serial.print(g);Serial.print(" B= ");Serial.println(b);frequency = r + g +b;lcd.clear();lcd.setCursor(0,0);lcd.print("F= ");lcd.print(frequency);lcd.setCursor(8,0);lcd.print (" HZ");tone (LEDG, frequency, 500);}//6.pH meterif((S1==0)&&(S2==1)&&(S3==1)){pinMode(LEDR,OUTPUT);static unsigned long samplingTime = millis();static unsigned long printTime = millis();static float pHValue,voltage;if(millis()-samplingTime > samplingInterval){pHArray[pHArrayIndex++]=analogRead(SensorPin);if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;pHValue = 3.5*voltage+Offset;samplingTime=millis();}if(millis() - printTime > printInterval) //Every 800 milliseconds, print a numerical, convert the state of the LED indicator{Serial.print(" pH=");Serial.println(pHValue,2);lcd.clear();lcd.print("pH= ");lcd.print(pHValue,2);digitalWrite(LEDR,digitalRead(LEDR)^1);printTime=millis();}}}double avergearray(int* arr, int number){int i;int max,min;double avg;long amount=0;if(number<=0){Serial.println("Error number for the array to avraging!/n");return 0;}if(number<5){ //less than 5, calculated directly statisticsfor(i=0;i<number;i++){amount+=arr[i];}avg = amount/number;return avg;}else{if(arr[0]<arr[1]){min = arr[0];max=arr[1];}else{min=arr[1];max=arr[0];}for(i=2;i<number;i++){if(arr[i]<min){amount+=min; //arr<minmin=arr[i];}else {if(arr[i]>max){amount+=max; //arr>maxmax=arr[i];}else{amount+=arr[i]; //min<=arr<=max}}//if}//foravg = (double)amount/(number-2);}//ifreturn avg;//7.導電度}/* Reads pressure from the given pin.* Returns a value in Pascals*/float readPressure(int pin){int pressureValue = analogRead(pin);float pressure=((pressureValue/1024.0)+0.095)/0.000009;return pressure;}
(六)後續及延伸:上面只有設計7種功能,用到3個Switch的話,其實可以有八種功能。接下來或許會想再把縮時攝影和碼錶計時的功能加進去。還有高斯計、加速度計也是想放進去的東西,不過可能會還要好一陣子才能做出來吧。
感謝江宏仁老師設計的SciCore本體,感謝阿簡一直被我煩著問問題,感謝網路上諸多神人願意把他們的知識心血放在網路上,讓我可以自學。
沒有留言:
張貼留言