Python可以這樣玩(22):兩種 1602 LCD 實作

到目前為止,我們還沒有談到I2C Device,不要著急,我們按部就班。先從最基礎的 1602   LED 開始。完成圖如下:




先來談顯示問題,由於我們的程式都是使用 Serial.print 來顯示,這有個大問題,就是如果沒有電腦,就看不見偵測到的數字了,所以我們來加上一個 1602 LCD 顯示器,如上圖。

要連接LCD,實在是個大工程,由於我買的 1602 是原始的板子,所以並沒有腳位可以連接麵包板,必須自己焊接,這對於沒有工程背景的我而言,的確是一大挑戰。建議各位在買1602 LCD的時候,買已經接好的,順便把支援 L2C的也買起來,因為我們後面談 I2C的時候會用到。

接下來我們先練習使用HD44780相容(或稱1602)液晶顯示 LCD(Liquid crystal display),在2x16的顯示幕印出"Hello World", 並測量可變電阻的數值,也同時學習使用analogRead()函式及LiquidCrystal Library

LCD顯示器若無背光則會有14Pin,若有背光則會有16個,我用的是有背光的,其接腳位置如下:

1: VSS (接地)
2: VDD (5V電源輸入)
3: VO 或稱 Vee:調整對比,需接一個1k的可變電阻
4: Register Select(RS)1: D0-D7 當作資料解釋,0: D0-D7 當作指令解釋(D12)
5: READ/WRITE(RW) 1: LCD 讀取資料,0: 寫資料到 LCD (一般接地)
6: Enable ( D11)
7: DB0 (建議用 4bit 的方式就好,可以省腳位,所以以下四個不接)
8: DB1
9: DB2
10: DB3
11: DB4 (D5)
12: DB5 (D4)
13: DB6 (D3)
14: DB7 (D2)
15: A(+) 背光:可接330 Ohm電阻到電源(我建議也接一個可變電阻)
16: K(-) 背光:接地

了解了這些腳位之後,就可以開始接線了,因為接腳很多,其中只要有一個腳位接錯,都會造成執行的錯誤,所以我們第一步當然是確定 1602是可以運作的,請參考下圖:

PS: 我第一次測試一直出現錯誤,結果發現原來是我的E腳位沒有焊接好。



接好之後,我們直接開啟 Arduino IDE提供的範例草稿,選取 [範例] [LiquidCrystal] [HelloWorld],程式碼如下:


// 引用 LiquidCrystal Library
#include <LiquidCrystal.h>

// 建立 LiquidCrystal 的變數 lcd
//                 LCD 接腳:  rs, enable, d4, d5, d6, d7
//      對應到 Arduino 接腳:  12,     11,  5,  4,  3,  2

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // 設定 LCD 的行列數目 (2 x 16)
  lcd.begin(16, 2);

  // 列印 "Hello World" 訊息到 LCD
  lcd.print("hello, world!");
}

void loop() {
  // 將游標設到 column 0, line 1
  // (注意: line 1 是第二行(row),因為是從 0 開始數起):
  lcd.setCursor(0, 1);

  // 列印 Arduino 重開之後經過的秒數
  lcd.print(millis()/1000);
}

執行之後,就可以看到 Hello, world!,第二排開始讀秒。如果沒有出現這樣的結果,相信我,一定是腳位接錯,或是焊接有問題。另外,我建議在K腳位以及 V0腳位都加上一個可變電阻,這樣方便調整亮度以及對比,因為有時候看不見顯示的文字是因為亮度和對比不對,要先排除。

範例程式的說明中,LCD 接腳:  rs, enable, d4, d5, d6, d7 會對應到 Arduino 接腳:  12,  11,  5,  4,  3,  2 腳位,我建議就按照範例程式的建議腳位來接,這樣就不必修改程式內容了,除非這些腳位已經被占用而且不方便改變。

最後,只要記住把 K, VSS, RW接地,VDD 5V,所有腳位就大功告成。也建議把這些腳位都記起來,以後才可以快速的連接。

我們可以將程式做個小修改,請將1602 V0可變電阻腳位接到Arduino A0腳位,我們用程式來監控可變電阻的數值,程式部分修改如下(loop()裡面)

  // lcd.print(millis()/1000);
  // 讀取A0的類比值
  int sensorValue = analogRead(A0);

  // 將類比的數值顯示在第二列
  lcd.print(sensorValue);

最後,我們就用 D7 腳位接上 DHT11,我用的是下圖中左邊那種,所以不用在接上拉電阻了。



#include <dht.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

dht DHT;

#define DHT11_PIN 7

void setup(){
  lcd.begin(16, 2);
}

void loop()
{
  int chk = DHT.read11(DHT11_PIN);
  lcd.setCursor(0,0);
  lcd.print("Temp: ");
  lcd.print(DHT.temperature);
  lcd.print((char)223);
  lcd.print("C");
  lcd.setCursor(0,1);
  lcd.print("Humidity: ");
  lcd.print(DHT.humidity);
  lcd.print("%");
  delay(30000);
}

最後要注意的是,網路上的範例是用 delay(1000),也就是每秒傳回數值一次,建議改成 delay(30000),三十秒一次就好,不然會有怪怪的值出現。

基本款 1602 測試影片如下:



LCD1602 I2C 接口

做完上面的練習之後您應該會發現,要接1602的腳位非常的複雜,如果我們使用 I2C 1602 就會方便多了,千萬不要自己焊接,可以買到現成的,正面一樣,背面如下圖:



在顯示器背面的 1602 IIC/I2C 控制板有 I2C 的四個針腳,分別為 GNDVCCSDA SCL,你可以買 -的杜邦線接出來,會比較方便,因為另一頭可以直接插入麵包板。連接的方式很簡單,VCC 接到 5VGND 接到 GNDSDA 接到 SDA(A4)SCL 接到 SCL(A5)


安裝 LiquidCrystal 函式庫,網址為:

下載第一個即可,如下圖:



下載之後不要解壓縮,直接用 Arduino IDE 標準的方式安裝。選取 [草稿碼] [匯入程式庫] [選取 zip 程式庫]

我直接從網路上下載一段程式碼,如下,無須修改,直接執行:

#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 位址

void setup() {
  Serial.begin(115200);  // 用於手動輸入文字
  lcd.begin(16, 2);     
  // 初始化 LCD,一行 16 的字元,共 2 行,預設開啟背光

  // 閃爍三次
  for(int i = 0; i < 3; i++) {
    lcd.backlight(); // 開啟背光
    delay(250);
    lcd.noBacklight(); // 關閉背光
    delay(250);
  }
  lcd.backlight();

  // 輸出初始化文字
  lcd.setCursor(0, 0); // 設定游標位置在第一行行首
  lcd.print("Hello, world!");
  delay(1000);
  lcd.setCursor(0, 1); // 設定游標位置在第二行行首
  lcd.print("Andrew Wang");
  delay(8000);

  // 告知使用者可以開始手動輸入訊息
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Use Serial Mon");
  lcd.setCursor(0, 1);
  lcd.print("Type to display");
}

void loop() {
  // 當使用者手動輸入訊息
  if (Serial.available()) {
    // 等待一小段時間,確認資料都接收下來了
    delay(100);
    // 清除舊訊息
    lcd.clear();
    // 讀取新訊息
    while (Serial.available() > 0) {
      // 將訊息顯示在 LCD
      lcd.write(Serial.read());
    }
  }
}

執行結果如下圖,首先比較一下,上面那個LCD 與下面 I2C LCD 接線的數量基本上是天差地遠:



另外一點要注意,所以,如果你開始使用 I2C Device 之後,基本上應該不會再回頭使用原始的 1602 LCD了。


接著,您可以用 Serial Monitor 來將字串傳到LCD裡面,如下圖,請選擇 115200 baud



按下傳送按鈕之後,字串便傳過去了。如下圖:



最後說明一下,這兩個 LCD 並不會相互衝突,你可以自行修改程式,讓兩個LCD同時運作。不過,如果同時接兩個 I2C 1602,可能就會有問題了。

影片展示如下:



PyMata 程式設計

了解了 I2C 的運作之後,我們嘗試使用 Python 來讀取 I2C 設備回傳的資料,首先,請按照下面的指令安裝 PyMata



市面上要找I2C 的感應器還真的不太容易,我逛了一圈光華商場,光是溫度感應器我就買了三個,但是幾乎都不是 I2C 的設備,基本上,如果要找 I2C的感應器,基本上先找有四支腳的,然後再看這四支腳位是否有 SDASCL這兩個腳位,由於設備真的不多,我就以 TMP102作為例子來討論PyMata 的用法。

為何不用前一單元的 I2C 1602 LCD 來說明?那是因為大部分實際應用都在 Raspberry Pi 上面,單純在 Arduino 上面的應用太少,所以我們會在後面討論 Raspberry 的時候再深入探討。

下面的分享,我參考了 Pratik Desai 所寫的 Python Programming for Arduino 一書,雖然不是最新的,但是裡面有很多基本的應用,大家可以參考。 

首先,依照下圖的方式連接:



這裡分別分享使用 Arduino 程式與 Python 程式的讀取方始,首先開啟 Arduino IDE,複製以下的程式碼:

#include <Wire.h>
int partAddress = 0x48;

void setup(){
  Serial.begin(9600);
  Wire.begin();
}

void loop(){

  Wire.requestFrom(partAddress,2);
  byte MSB = Wire.read();
  byte LSB = Wire.read();

  int TemperatureData = ((MSB << 8) | LSB) >> 4;

  float celsius = TemperatureData*0.0625;
  Serial.print("Celsius: ");
  Serial.println(celsius);

  float fahrenheit = (1.8 * celsius) + 32; 
  Serial.print("Fahrenheit: ");
  Serial.println(fahrenheit);

  delay(500);
}

Python 的程式碼如下:

import time
from PyMata.pymata import PyMata

#Initialize Arduino using port name
port = PyMata("COM5")

#Configure I2C pin
port.i2c_config(0, port.ANALOG, 4, 5)

# One shot read asking peripheral to send 2 bytes
port.i2c_read(0x48, 0, 2, port.I2C_READ)
# Wait for peripheral to send the data
time.sleep(3)

# Read from the peripheral
data = port.i2c_get_read_data(0x48)

# Obtain temperature from received data
TemperatureSum = (data[1] << 8 | data[2]) >> 4

celsius = TemperatureSum * 0.0625
print celsius

fahrenheit = (1.8 * celsius) + 32
print fahrenheit

port.close()

到目前為止我們已經討論過三種溫度感應器了,而每種感應器讀取回來的數據之轉換方式都不一樣,沒有辦法,這需要自行找到該設備的 Datasheet 才行。

留言

這個網誌中的熱門文章

Python可以這樣玩(16):共陰/共陽七段顯示器

Python可以這樣玩(11):數學繪圖

Python可以這樣玩(15):蜂鳴器與音樂