☛ 功能說明

利用 Arduino UNO 開發板、 FreeRTOS 函式庫及 semphr 函式庫,使用互斥旗標的機制控制兩個溫度感測器 ( DHT11、DS18B20 ) ,並將偵測的溫度、濕度顯示於 LCD 上,當 DHT11 取得互斥旗標顯示於偵測值於 LCD 時,點亮 LED1,釋放互斥旗標時,熄滅 LED1。當 DS18B20 取得互斥旗標顯示於偵測值於 LCD 時,點亮 LED2,釋放互斥旗標時,熄滅 LED2。

☛ 使用材料

Arduino UNO R3 開發板 × 1、DHT11 溫度感測器模組 × 1、DS18B20 溫度感測器模組 × 1、LCD 1602A 顯示器模組 × 1、可變電阻 20KΩ × 1、電阻 220Ω × 1、LED × 2。

☛ 電路圖及麵包板接線圖

☛ 程式碼

#include <Arduino_FreeRTOS.h>                            //引用 FreeRTOS 函式庫
#include <semphr.h>                                      //引用 semphr.h 互斥旗標函式庫
#include <DHT.h>                                         //引用 DHT11 函式庫
#include <OneWire.h>                                     //引用 OneWire 函式庫
#include <DallasTemperature.h>                           //引用 DallasTemperature 函式庫
#include<LiquidCrystal.h>                                //引用 LiquidCrystal.h 函式庫

SemaphoreHandle_t mutex_v;                               //宣告一個 SemaphoreHandle_t 類型的變數來存儲互斥旗標的值
LiquidCrystal lcd(12,11,5,4,3,2);                        //宣告 LCD 變數並定義使用接腳

void setup() 
{
     lcd.begin(16,2);                                    //使用 16 行 × 2 列 LCD
     lcd.setCursor(0,0);                                 //設定游標位置於第 0 列第 0 行
     lcd.print("DHT:");                                  //顯示 "DHT:"
     lcd.setCursor(0,1);                                 //設定游標位置於第 1 列第 0 行
     lcd.print("DS18:");                                 //顯示 "DS18:"
     mutex_v = xSemaphoreCreateMutex();                  //創建一個互斥旗標 mutex_v
     if (mutex_v == NULL) 
     {
         lcd.setCursor(0,0);
         lcd.print("Mutex can not");
         lcd.setCursor(1,0);
         lcd.print("be created");
     }
     xTaskCreate(Sens1, "Task 1", 128, NULL, 1, NULL);   //建立 DHT11 任務
     xTaskCreate(Sens2, "Task 2", 128, NULL, 1, NULL);   //建立 DS18B20任務
}

void loop() 
{

}

void displayLCD(int col,int row, float num)              //LCD 顯示溫濕度副程式
{
     char c[10];                                         //宣告字元陣列 c
     dtostrf(num,2,2,c);                                 //將浮點數轉換成字串,整數 2 位,小數 2 位
     lcd.setCursor(col,row);                             //設定 LCD 顯示字串的位置
     lcd.print(c);                                       //在 LCD 上顯示轉換的溫度、濕度值
}

void Sens1(void *pvParameters)                           //DHT11 任務
{
     int led=8;                                          //LED 連接數位接腳 8
     DHT dht;
     pinMode(led,OUTPUT);                                //設定數位接腳 8 為輸出模式
     dht.setup(7);                                       //DHT11 資料接腳連接數位接腳 7

     while(1) 
     {
           // 根據溫濕度感測器型號來選取取樣時間
           vTaskDelay(dht.getMinimumSamplingPeriod()/portTICK_PERIOD_MS);
           float humidity = dht.getHumidity();           //讀取感測器的濕度值
           float temperature = dht.getTemperature();     //讀取感測器的溫度值
           
           xSemaphoreTake(mutex_v, portMAX_DELAY);       //獲取互斥旗標 Mutex_v
           digitalWrite(led,HIGH);                       //點亮 LED1
           displayLCD(5,0,temperature);                  //在 LCD 上顯示 DHT 的溫度
           displayLCD(11,0,humidity);                    //在 LCD 上顯示 DHT 的濕度
           digitalWrite(led,LOW);                        //熄滅 LDE1
           xSemaphoreGive(mutex_v);                      //返回互斥旗標 Mutex_v
           vTaskDelay(pdMS_TO_TICKS(1000));              //延遲1秒
     }
}

void Sens2(void *pvParameters)                           //DS18B20 任務
{
     int led=9; 
     OneWire oneWire(10);                                //連接至數位接腳 10,設置一個單線實例以與任何單線設備進行通信
     DallasTemperature sensors(&oneWire);                //參考 Dallas 溫度。
     
     sensors.begin();                                    //啟動 DS18B20 感測器
     pinMode(led,OUTPUT);                                //設定數位接腳 9 為輸出模式
     
     while(1) 
     {
           sensors.requestTemperatures();                //發送命令以獲得溫度
           xSemaphoreTake(mutex_v, portMAX_DELAY);       //獲取互斥旗標 Mutex_v
           digitalWrite(led,HIGH);                       //點亮 LED2
           displayLCD(5,1,sensors.getTempCByIndex(0));   //在 LCD 上顯示 DS18B20 的溫度
           digitalWrite(led,LOW);                        //熄滅 LED2
           xSemaphoreGive(mutex_v);                      //返回互斥旗標 Mutex_v
           vTaskDelay(pdMS_TO_TICKS(1000));              //延遲1秒
     }
}