本帖最後由 小牙 於 2014-12-15 21:43 編輯  
 
回復 2# ates1687  
 
不是喔,是Arduino輕鬆入門範例分析與實作設計// 匯入所需程式庫的標頭檔,謝謝你撥空看我的問題 
#include <LiquidCrystal.h> 
#include <EEPROM.h> 
#include <DHT.h> 
#include <Bounce.h> 
#include <Timer.h> 
// 定義連接腳位 
#define LCD_RS_PIN 2 
#define LCD_E_PIN 3 
#define LCD_D4_PIN 4 
#define LCD_D5_PIN 5 
#define LCD_D6_PIN 6 
#define LCD_D7_PIN 7 
#define BUTTON_MODE_PIN 8 
#define BUTTON_UP_PIN 9 
#define BUTTON_DOWN_PIN 10 
#define BUZZER_PIN 11 
#define DHT_PIN 12 
 
// 建立LiquidCrystal物件 
LiquidCrystal lcd(LCD_RS_PIN, LCD_E_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN); 
 
#define DHTTYPE DHT11   // DHT 11  
//#define DHTTYPE DHT22   // DHT 22, AM2302 
//#define DHTTYPE DHT21   // DHT 21, AM2301 
DHT dht(DHT_PIN, DHTTYPE); 
 
// 建立除彈跳的Bounce物件 
#define DEBOUNCE_DELAY 50 // milliseconds 
Bounce bMode = Bounce(BUTTON_MODE_PIN, DEBOUNCE_DELAY); 
Bounce bUp = Bounce(BUTTON_UP_PIN, DEBOUNCE_DELAY); 
Bounce bDown = Bounce(BUTTON_DOWN_PIN, DEBOUNCE_DELAY); 
 
// 供tone函式使用的音符頻率 
#define NOTE_C5  523 // Do 
#define NOTE_CS5 554 
#define NOTE_D5  587 // Re 
#define NOTE_DS5 622 
#define NOTE_E5  659 // Mi 
#define NOTE_F5  698 // Fa 
#define NOTE_FS5 740 
#define NOTE_G5  784 // So 
#define NOTE_GS5 831 
#define NOTE_A5  880 // La 
#define NOTE_AS5 932 
#define NOTE_B5  988 // Si 
 
float t; // 儲存溫度 
float h; // 儲存濕度 
 
// 定義狀態機的可能狀態,整支程式會有5種狀態,LCD也會有5種顯示模式 
typedef enum{  
  S_Temperature_High_Limit, 
  S_Temperature_Low_Limit, 
  S_Humidity_High_Limit, 
  S_Humidity_Low_Limit, 
  S_Normal, 
  S_Max = S_Normal, 
}State; 
State state; 
// 儲存溫度上限、溫度下限、濕度上限、濕度下限 
byte limits[S_Max] = { 
  50, 10, 80, 10, 
}; 
 
boolean needToRefresh = false; 
void lcdRefresh(){ 
  if(needToRefresh == false){ 
    return; 
  } 
  lcd.clear(); 
  switch(state){ 
    case S_Normal: 
      lcd.print("T "); 
      lcd.print(t); 
      lcd.write(byte(0)); 
      lcd.print('C'); 
      lcd.setCursor(0, 1); 
      lcd.print("H "); 
      lcd.print(h); 
      lcd.print('%'); 
    break; 
    case S_Temperature_High_Limit: 
      lcd.print("T High Limit: "); 
      lcd.setCursor(0, 1); 
      lcd.print(limits[S_Temperature_High_Limit]); 
      lcd.write(byte(0)); 
      lcd.print('C'); 
    break; 
    case S_Temperature_Low_Limit: 
      lcd.print("T Low Limit: "); 
      lcd.setCursor(0, 1); 
      lcd.print(limits[S_Temperature_Low_Limit]); 
      lcd.write(byte(0)); 
      lcd.print('C'); 
    break; 
    case S_Humidity_High_Limit: 
      lcd.print("H High Limit: "); 
      lcd.setCursor(0, 1); 
      lcd.print(limits[S_Humidity_High_Limit]); 
      lcd.print('%'); 
    break; 
    case S_Humidity_Low_Limit: 
      lcd.print("H Low Limit: "); 
      lcd.setCursor(0, 1); 
      lcd.print(limits[S_Humidity_Low_Limit]); 
      lcd.print('%'); 
    break; 
  } 
  needToRefresh = false; 
} 
 
// 每隔一段時間就讀取最新的溫濕度讀數 
Timer timerUpdateReadings; 
void updateReadings(void *context){ 
  t = dht.readTemperature(); 
  h = dht.readHumidity(); 
  needToRefresh = true; 
} 
 
// 每隔一段時間就檢查目前溫濕度與上下限,若超過就發出警告聲 
Timer timerCheckLimits; 
void checkLimits(void *context){ 
  if(t < limits[S_Temperature_Low_Limit]){ 
    tone(BUZZER_PIN, NOTE_C5, 3000 / 4); 
  } 
  else if(limits[S_Temperature_High_Limit] < t){ 
    tone(BUZZER_PIN, NOTE_D5, 3000 / 4); 
  } 
 
  if(h < limits[S_Humidity_Low_Limit]){ 
    tone(BUZZER_PIN, NOTE_E5, 3000 / 4); 
  } 
  else if(limits[S_Humidity_High_Limit] < h){ 
    tone(BUZZER_PIN, NOTE_F5, 3000 / 4); 
  } 
} 
 
byte degreeCircle[8] = { // 度數小圈圈的字型 
  B00010, 
  B00101, 
  B00010, 
  B00000, 
  B00000, 
  B00000, 
  B00000, 
}; 
void setup(void) { 
  pinMode(BUTTON_MODE_PIN, INPUT_PULLUP); 
  pinMode(BUTTON_UP_PIN, INPUT_PULLUP); 
  pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); 
  lcd.createChar(0, degreeCircle); 
  lcd.begin(16, 2); 
  dht.begin(); 
  timerUpdateReadings.every(2000, updateReadings, NULL); 
  timerCheckLimits.every(1000, checkLimits, NULL); 
  state = S_Normal; 
  needToRefresh = true; 
 
  // 從EEPROM讀取先前儲存的上下限 
  // 若是0xFF,代表這是第一次讀取 
  byte v; 
  for(int i = S_Temperature_High_Limit; i < S_Max; i++){ 
    v = EEPROM.read(i); 
    if(v != 0xFF){ 
      limits = v; 
    } 
  } 
} 
 
// 使用者修改上下限後,將新數值儲存到EEPROM裡 
boolean needToSaveLimits = false; 
void saveLimits(){ 
  if(needToSaveLimits == false){ 
    return; 
  } 
  for(int i = S_Temperature_High_Limit; i < S_Max; i++){ 
    EEPROM.write(i, limits); 
  } 
  needToSaveLimits = false; 
} 
void loop(void) {  
  // 更新計時器,若時間到了就會呼叫先前設定的回呼函式 
  timerUpdateReadings.update(); 
  timerCheckLimits.update(); 
  lcdRefresh(); // 更新LCD畫面 
  saveLimits(); // 儲存上下限數值 
 
  // 讀取開關狀態,是否被按下 
  boolean bModePressed = bMode.update() == true && bMode.read() == LOW; 
  boolean bUpPressed = bUp.update() == true && bUp.read() == LOW; 
  boolean bDownPressed = bDown.update() == true && bDown.read() == LOW; 
 
  if(bModePressed){ // 若按下BUTTON_MODE_PIN就跳到下一個模式 
    needToRefresh = true; 
    switch(state){ 
      case S_Normal: 
        state = S_Temperature_High_Limit; 
      break; 
      case S_Temperature_High_Limit: 
        state = S_Temperature_Low_Limit; 
      break; 
      case S_Temperature_Low_Limit: 
        state = S_Humidity_High_Limit; 
      break; 
      case S_Humidity_High_Limit: 
        state = S_Humidity_Low_Limit; 
      break; 
      case S_Humidity_Low_Limit: 
        state = S_Normal; 
      break; 
    } 
  } 
 
  switch(state){ 
    case S_Temperature_High_Limit: 
    case S_Temperature_Low_Limit: 
    case S_Humidity_High_Limit: 
    case S_Humidity_Low_Limit: 
      if(bUpPressed){ // 按下BUTTON_UP_PIN,增加數值 
        limits[state]++; 
        needToRefresh = true; 
        needToSaveLimits = true; 
      } 
      if(bDownPressed){ // 按下BUTTON_DOWN_PIN,減少數值 
        limits[state]--; 
        needToRefresh = true; 
        needToSaveLimits = true; 
      } 
      delay(100); 
    break; 
  } 
} |