Arduino筆記(64):ST7735 1.77-吋TFT-LCD顯示器(160 x128) 顯示溫濕度

自從上次有了雙色OLED購買失敗的經驗(雙色分成上下兩個顏色),想說再購買一個稍大的顯示器,看中一個價格不高1.7吋的TFT LCD,解析度 160 x 128。購買了這個顯示器後,先在Arduino筆記(63):1.77" TFT LCD顯示INA219電流傳感器電壓值 這篇文章嘗試使用 ST7735 TFT-LCD這個1.77吋顯示器,紀錄一下 TFT-LCD 各接腳的用途,下一篇文章再來詳細說明Afafruit_GFX 程式庫的各種用法,如繪製圖形、放大或縮小文字,甚至改變各種圖形文字的顏色等。
這篇文章使用AM2420溫濕度感測器來偵測溫濕度後,呈現在LCD顯示器上,並計算熱濕度的指數,一般稱為體感溫度。


[安裝程式庫]

本實作需要安裝以下程式庫:
程式庫(Library)安裝方法請參考另一篇文章:  Arduino筆記:安裝 Arduino IDE 程式庫(Library)

[材料]

  • Arduino Uno x 1
  • ST7735 1.7" TFT LCD顯示器 x 1
  • AM2320 溫濕度感測器 x 1
  • 連接線 x n 條


[接線與電路圖]

Arduino UnoST7735 LCD Pin說明
3.3V8. LEDA背光控制
D107. CSChip Select(Slave Select PIN / SPI data)
D96. RSRegister Selection(MISO - Sending to Master)
D85. RESReset / RST, 重設 TFT
D114. SDASerial Data(MOSI-Sending to Slave)
D133. SCKSCLK - Clock Line(SPI Clock Input)
5V2. VCCVoltage Common Collector
GND1. GNDGround


[程式]

#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
#define TFT_SCLK 13   
#define TFT_MOSI 11   

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <stdio.h>
#include <AM2320.h>

AM2320 th(&Wire);

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

//Black theme
#define COLOR1 ST7735_WHITE
#define COLOR2 ST7735_BLACK

//White theme
//#define COLOR1 ST7735_BLACK
//#define COLOR2 ST7735_WHITE

int text_color_humidex;
float humidity, temperature, humidex;
String message;

void setup(void)
{
    Serial.begin(9600);
    
    // 設備初始化
    Wire.begin();
    Serial.println("AM2320 Sensor Initalized");
    tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
    tft.fillScreen(COLOR2);
}

void testdrawtext(char* text, uint16_t color)
{
    tft.setCursor(0, 0);
    tft.setTextColor(color);
    tft.setTextWrap(true);
    tft.print(text);
}

void loop()
{
  switch(th.Read()) {
    case 2:
      Serial.println(F("  CRC failed"));
      break;
    case 1:
      Serial.println(F("  Sensor offline"));
      break;
    case 0:
      humidity = th.Humidity;
      temperature = th.cTemp;
      Serial.print(F("  Humidity = "));
      Serial.print(humidity);
      Serial.println(F("%"));
      Serial.print(F("  Temperature = "));
      Serial.print(temperature);
      Serial.println(F("*C"));
      Serial.println();
      break;
  }
    //計算濕熱指數 
    humidex = calculate_humidex(temperature, humidity);

    // Table
    tft.drawRect(0, 0, 128, 160, COLOR1);
    tft.drawLine(0, 50, 128, 50, COLOR1);
    tft.drawLine(0, 100, 128, 100, COLOR1);

    // 輸出資料
    temperature_to_lcd(temperature, 4);
    humidity_to_lcd(humidity, 55);
    humidex_to_lcd(humidex, 105);
}

// 輸出溫度到 LCD
void temperature_to_lcd(float temperature, unsigned char text_position)
{
    int text_color;
    tft.setCursor(4, text_position);
    tft.setTextColor(COLOR1, COLOR2);
    tft.setTextSize(1);

    tft.print("Temperature:");
    tft.setTextSize(3);
    if (temperature > 0) {
        text_color = ST7735_BLUE;
    }
    else   {
        text_color = ST7735_BLUE;
    }

    tft.setCursor(1, text_position + 20);
    fix_number_position(temperature);
    tft.setTextColor(text_color, COLOR2);
    tft.print(temperature, 1);
    tft.setCursor(108, text_position + 20);
    tft.print("C");
    tft.drawChar(90, text_position + 20, 247, text_color, COLOR2, 2);   //度的符號
}

// 輸出濕度到 LCD
void humidity_to_lcd(float humidity, unsigned char text_position)
{
    tft.setTextColor(COLOR1, COLOR2);
    tft.setCursor(4, text_position);
    tft.setTextSize(1);
    tft.println("Humidity:");
    tft.setTextSize(3);
    tft.setCursor(1, text_position + 20);
    fix_number_position(humidity);
    tft.print(humidity, 1);
    tft.print(" %");
}

// 輸出濕熱指數 LCD
void humidex_to_lcd(float humidex, unsigned char text_position)
{
    tft.setCursor(4, text_position);
    tft.setTextSize(1);
    tft.println("Humidex [Feel Like]:");
    tft.setTextSize(3);
    tft.setCursor(1, text_position + 17);

    if ((humidex >= 21) && (temperature < 44)) {
        fix_number_position(humidex);
        get_humidex_color_warning_message(humidex);
        tft.setTextColor(text_color_humidex, COLOR2);
        tft.print(humidex, 1);
        tft.setCursor(108, text_position + 17);
        tft.print("C");
        tft.drawChar(90, text_position + 17, 247, text_color_humidex, COLOR2, 2); //degree symbol
        tft.setCursor(3, text_position + 43);
        tft.setTextSize(1);
        tft.print(message);
    }
    else  {
        tft.print(" --.-");
        tft.setCursor(108, text_position + 17);
        tft.print("C");
        tft.drawChar(90, text_position + 17, 247, COLOR1, COLOR2, 2); //degree symbol
        tft.setCursor(1, text_position + 43);
        tft.setTextSize(1);
        tft.println(" ");
    };
}

// 調整數字在固定位置
void fix_number_position(float number)
{
    if ((number >= -40) && (number < -9.9)){
        ;
    }
    if ((number >= -9.9) && (number < 0.0)){
        tft.print(" ");
    }
    if ((number >= 0.0) && (number < 9.9)) {
        tft.print(" ");
    }
    if ((number >= 9.9) && (number < 99.9)){
        tft.print(" ");
    }
    if ((number >= 99.9) && (number < 151)){
        tft.print("");
    }
}


// 將 8-bit R,G,B的三個顏色值(0-255)轉成 16-bit 顏色值
uint16_t Color565(uint8_t r, uint8_t g, uint8_t b)
{
    return ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3);
}

// 計算濕熱指數 
float calculate_humidex(float temperature, float humidity)
{
    float e;
    e = (6.112 * pow(10, (7.5 * temperature / (237.7 + temperature))) * humidity / 100); //vapor pressure
    float humidex = temperature + 0.55555555 * (e - 10.0); //humidex
    return humidex;
}

// 根據濕熱指數顯示顏色及訊息
void get_humidex_color_warning_message(float humidex)
{
    // 暗綠色
    if ((humidex >= 21) && (humidex < 27)) {
        text_color_humidex = Color565(0, 137, 0);
        message = "No discomfort ";
    } 
    // 亮綠色
    if ((humidex >= 27) && (humidex < 35)) {
        text_color_humidex = Color565(76, 255, 0); 
        message = "Some discomfort ";
    }
    // 黃色
    if ((humidex >= 35) && (humidex < 40)) {
        text_color_humidex = Color565(255, 255, 0);
        message = "Great discomfort ";
    }
    // 亮橘色
    if ((humidex >= 40) && (humidex < 46)) {
        text_color_humidex = Color565(255, 140, 0);
        message = "Health risk ";
    }
    // 暗橘色
    if ((humidex >= 46) && (humidex < 54)) {
        text_color_humidex = Color565(221, 128, 0);
        message = "Great health risk ";
    } 
    // 紅色
    if ((humidex >= 54)) {
        text_color_humidex = Color565(255, 0, 0);
        message = "Heat stroke danger ";
    } 
}

[實作結果]

      請參考最上方圖片。

[參考資料]


3 留言

  1. 感謝分享,這支程式的RGB轉換方程式,與上一篇(Arduino 筆記63)有出入,經比較後,上一篇的RGB轉換方程式為正確的。

    回覆刪除
    回覆
    1. 您好, 這已是很久以前做的, 沒注意到顏色轉換的副程式竟然不同,已經更新, 謝謝告知。

      刪除
  2. 請問可以加入MAX6675的溫度程式來執行嗎。

    我用好幾次,都是錯誤?

    回覆刪除

張貼留言

較新的 較舊