首先先學會驅動每一個sensor,例如
壓力: http://jjpaid.blogspot.tw/2016/06/mpx4115.html
溫度:http://jjpaid.blogspot.tw/2015/12/arduino.html
要做到每一個單一sensor都可以運作不難,就是搜尋那個 sensor的名稱,通常就可以找到別人接線的方式和寫好的程式。照著接,然後程式複製貼上,該下載的library下載安裝一下,大概就贏了。
每一個sensor都會動之後,就可以保證每一個需要的library都有了,接著就是要組合了。首先看一下每一個程式大概就是分成幾個部分
1.呼叫一些library和定義腳位
2.設定
3.反覆執行的部份
以DHT11為例程式碼如下(來源)
- #include <dht.h>
- #define dht_dpin 2 //定義訊號要從Pin A0 進來
- dht DHT;
- void setup(){
- Serial.begin(9600);
- delay(300); //Let system settle
- Serial.println("Humidity and temperature\n\n");
- delay(700); //Wait rest of 1000ms recommended delay before
- //accessing sensor
- }
- void loop(){
- DHT.read11(dht_dpin); //去library裡面找DHT.read11
- Serial.print("Humidity = ");
- Serial.print(DHT.humidity);
- Serial.print("% ");
- Serial.print("temperature = ");
- Serial.print(DHT.temperature);
- Serial.println("C ");
- delay(1000); //每1000ms更新一次
- }
從01~05 就是在呼叫library, 定義腳位等等的。
從void setup後面到void loop() 也就是07~12這一段,就是一些設定
從15~24就是反覆執行的部份,例如每隔多少時間,就要輸出一次什麼樣的數據之類的。
各種sensor的寫法大概都差不多。所以我要做的事情很簡單,把每一個sensor的1, 2 3三個部分分別抓出來,所有sensor的1就集中在一起,2集中在一起,3也集中在一起。
這樣的話,就變成一個程式碼可以驅動所有的sensor啦。然後一次就把所有sensor的訊息全部都顯示出來。當然要注意一下腳位的問題,每個地方抓到的程式碼,腳位都不一定,如果遇到重複的部份,就要避開換另一個腳位。
這樣雖然可以驅動全部的sensor,但是顯然跑出來的訊息太多了,所以就要想辦法用電腦或平板告訴arduino,我想要看什麼訊息,讓arduino顯示我想要的。(參考資料)
這部份就要先用一個serial.avalible() 去判定有沒有資料輸入,然後把輸入的資料用Serial.read()丟給一個預先設定好的變數。然後再用if判斷變數的數值,就能用這個條件判斷來告訴arduino我現在想看什麼。不過這個數值進位方式不同,假設你輸入1, 其實它讀到的是49, 輸入2,讀到的是50,依此類推,所以判斷的時候要注意這個事情。雖然概念是這樣,但是我中間卡關卡了好多次。大多出於對於程式碼的概念不熟悉。像是 =和 ==傻傻分不清楚; 各種() {} 要放哪邊這類的事,就搞掉我好多時間。
這些程式碼都解決了之後,基本上sensor都可以運作了,可是又出了一個怪問題,就是明顯每個sensor都delay太久才收數據。我原本想,環境數據不需要太快重複收,一秒收一次已經很快了。運動學部分,0.1秒收一個數據是差不多的;單擺的實驗,就得要更快,我直接設定1毫秒要收一個數據。
但是執行的結果,每個都大約一秒才收一個數據。找了非常非常久,把寫好的程式碼又拆了重組了好幾次才發現,DS18b20溫度計的讀取要經過requestTemperature和getTempByIndex這些指令,本身就會延遲時間。
因為我在兩個地方都有用到DS18b20來讀溫度數據,所以我本來把這些指令放到if判斷式外面,也就是不管我輸入什麼數字,這些事情都會一直loop重複做。結果就變成不管我輸入什麼數字,每一次這些指令的執行都造成延遲。
所以解決方法很簡單,就把這些東西通通搬進if裡面就好。
以下是完整程式碼
- #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,blpol
- LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 設定 LCD I2C 位址
- //以上是驅動LCD的部分
- int va1 = 1; //用來設定選單的變數,預設為1 讓最開始就直接顯示環境變數
- #include <dht.h> //抓溫溼度計的資料庫
- #define dht_dpin 3 //定義訊號要從Pin D3 進來
- dht DHT;
- // 匯入程式庫標頭檔
- //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>
- // from http://arduino-info.wikispaces.com/file/view/LiquidCrystal_I2C1602V1.zip
- // Arduino數位腳位2接到1-Wire裝置
- #define ONE_WIRE_BUS 4
- // 運用程式庫建立物件
- OneWire oneWire(ONE_WIRE_BUS);
- DallasTemperature sensors(&oneWire);
- // HCSR04Ultrasonic/examples/UltrasonicDemo/UltrasonicDemo.pde
- #include <Ultrasonic.h>
- #define TRIGGER_PIN 12
- #define ECHO_PIN 13
- Ultrasonic ultrasonic(TRIGGER_PIN, ECHO_PIN);
- //運動學
- int x0=0;//一開始的位置
- int v0=0;//初速
- float temp=20.0;//溫度
- float c=(331.5+0.6*temp)/10000;//單位是每微秒幾公分
- float intervaltime=100; //每幾毫秒測量一次
- float duration, distance,velocity,acceleration;
- //pH meter
- #define SensorPin A2 //pH meter Analog output to Arduino Analog Input 2
- #define Offset 0.00 //deviation compensate
- #define LED 11 //不知道幹嘛用的腳位
- #define samplingInterval 20
- #define printInterval 800
- #define ArrayLenth 40 //times of collection
- int pHArray[ArrayLenth]; //Store the average value of the sensor feedback
- int pHArrayIndex=0;
- void setup(){
- Serial.begin(9600);
- Serial.println("1.enviroment data"); //弄個選單出來
- Serial.println("2.temperature and pressure");
- Serial.println("3.Super sonic reflection time and distance");
- Serial.println("4.dynamic experiment");
- Serial.println("5.pendulum");
- Serial.println("6.pH meter");
- pinMode(TRIGGER_PIN, OUTPUT); //超音波的輸出腳位
- pinMode(ECHO_PIN, INPUT); //超音波的輸入腳位
- pinMode(LED,OUTPUT); //這是給pH meter用的,但我不知道功能
- lcd.begin(16, 2); //起始lcd
- sensors.begin(); //起始ds18b20溫度計
- }
- void loop(){
- DHT.read11(dht_dpin); //去library裡面找DHT.read11
- float pressure = readPressure(A1);
- float millibars = pressure/100;
- if (Serial.available() >0) {
- va1 = Serial.read();
- }
- if (va1 == 49){
- Serial.print("temperature = ");
- Serial.print(DHT.temperature);
- Serial.println("C ");
- Serial.print("Humidity = ");
- Serial.print(DHT.humidity);
- Serial.print("% ");
- Serial.print(" Pressure = ");
- Serial.print(pressure/101300);
- Serial.println(" atm");
- 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(1000);
- }
- if (va1 == 50){
- sensors.requestTemperatures(); //這東西會吃很多時間,所以要擺進if裡面
- float T1=sensors.getTempCByIndex( //這東西會吃很多時間,所以要擺進if裡面
- float T2=sensors.getTempCByIndex(1); //這東西會吃很多時間,所以要擺進if裡面
- Serial.print(" Pressure = ");
- Serial.print(pressure);
- Serial.println(" pascals");
- Serial.print("T1:");
- 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)
- {Serial.print ("N/A");
- lcd.print("N/A");
- }
- else
- {
- Serial.print(T1);
- Serial.print(" C");
- lcd.print(T1);
- lcd.print("C");
- }
- Serial.print(" T2:");
- lcd.print(" T2:");
- if (T2 == -127)
- {Serial.print ("N/A");
- lcd.print ("N/A");
- }
- else
- {
- Serial.print(T2);
- Serial.print(" C");
- lcd.print(T2);
- lcd.print("C");
- }
- }
- if (va1 == 51){
- sensors.requestTemperatures(); //這東西會吃很多時間,所以要擺進if裡面
- float T1=sensors.getTempCByIndex(0); //這東西會吃很多時間,所以要擺進if裡面
- float T2=sensors.getTempCByIndex(1); //這東西會吃很多時間,所以要擺進if裡面
- float cmMsec;
- long microsec = ultrasonic.timing();
- cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM); // 計算距離,單位: 公分
- Serial.print("t=");
- Serial.print(microsec);
- Serial.print("ms ");
- Serial.print("distance=");
- Serial.print(cmMsec);
- Serial.print("cm ");
- lcd.clear();
- lcd.setCursor(0 ,0);
- lcd.print("t=");
- lcd.print(microsec);
- lcd.print("ms ");
- lcd.print("D=");
- lcd.print(cmMsec);
- lcd.print("cm");
- lcd.setCursor(0, 1);
- lcd.print("T:");
- Serial.print("T:");
- if (T1 == -127)
- {Serial.println ("N/A");
- lcd.print("N/A");
- }
- else
- {
- Serial.print(T1);
- Serial.println(" C");
- lcd.print(T1);
- lcd.print("C");
- }
- }
- if (va1 == 52){
- digitalWrite(TRIGGER_PIN, HIGH);
- delayMicroseconds(1000);
- digitalWrite(TRIGGER_PIN, LOW);
- duration = pulseIn(ECHO_PIN, HIGH);//超音波來回經過的時間,單位是微秒
- distance = (duration/2) *c;//單位是公分
- velocity=(distance-x0)/(intervaltime/1000);//每秒速度
- acceleration=(velocity-v0)/(intervaltime/1000);//每秒加速度
- x0 = distance;
- v0 = velocity;
- Serial.print(distance);
- Serial.print(",");
- Serial.print(velocity);
- Serial.print(",");
- Serial.println(acceleration);
- lcd.clear();
- lcd.print("D=");
- lcd.print(distance);
- lcd.print(" cm");
- delay(intervaltime);
- }
- if (va1 == 53){
- unsigned long time;
- time=millis();
- float cmMsec, inMsec;
- long microsec = ultrasonic.timing();
- cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM); // 計算距離,單位: 公分
- if (cmMsec < 5) //只要距離小於五公分就把累計的秒數ㄒ出來
- {
- Serial.println(time);
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print(time);
- }}
- if(va1 ==54){
- 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("E");
- Serial.print(" pH=");
- Serial.println(pHValue,2);
- lcd.clear();
- lcd.print("pH= ");
- lcd.print(pHValue,2);
- digitalWrite(LED,digitalRead(LED)^1);
- printTime=millis();
- }
- }
- }
- //以下是pH meter的程式碼,要放在if外面,我也不知道是啥東西
- 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 statistics
- for(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<min
- min=arr[i];
- }else {
- if(arr[i]>max){
- amount+=max; //arr>max
- max=arr[i];
- }else{
- amount+=arr[i]; //min<=arr<=max
- }
- }//if
- }//for
- avg = (double)amount/(number-2);
- }//if
- return avg;
- }
- //以下是MPX4115的程式碼,要放在if外面,我也不知道是啥東西
- /* 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;
- }