2014年5月19日 星期一

[ { 5V } 整合型 1602 LCD ] 使用單晶片 ( AT89S51 ) 偵測環境溫溼度 ( DHT-11 ) 與環境光源強度 ( BH1750 )

本篇網頁中所使用到的零件可到下面商品網址訂購:

使用單晶片偵測環境溫溼度與環境光源強度

環境溫溼度與光的強度偵測時常用在氣候偵測或是 DIY 製作上,配合使用整合型 1602 LCD 可以非常方便的將所取得的數值或是文字直接顯示在這一片液晶螢幕上,不要再使用 UART 將資料取出了!

在這篇網頁中,您將看到:
  • 讓單晶片 8051 動作的基本電路
  • 如何同時控制兩個 I2C 裝置 ( BH1750 環境光源強度偵測模組和整合型 LCD [ IIC 模式 ] )
  • 如何取得單線式通訊的 DHT-11 感測器的溫、濕度值
網頁中所提供的三個單晶片 AST89S51, Keil C 專案檔會放置在雲端硬碟中 ( display_lcd+dht11+bh1750 ),並完成設置與編譯完成可直接使用 .hex 燒錄,有購買的請使用所提供的資料下載連結自行下載,目錄中包含三個專案檔,內容有:
  1. 讀取 DHT-11 溫溼度值並顯示在整合型 LCD 螢幕上
    display_lcd+dht11.uvproj
  2. 讀取 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上
    display_lcd+bh1750.uvproj
  3. 讀取 DHT-11 溫溼度值和 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上
    display_lcd+dht11+bh1750.uvproj
資料夾目錄
主要的 Keil C 專案檔是 display_lcd+dht11+bh1750.uvproj ,是綜合其他兩個專案檔而來的,但建議由 1 至 3 的順序來了解程式的寫作方式。

不管是使用哪一個 Keil C 專案檔,請依照下面所提供的電路圖接線再燒錄程式在單晶片中就可以做測試。

網頁中程式所使用的電路接線圖


在下面的三個程式碼中,預設使用的 AT89S51 頻率是 12 MHz,每個 Keil C 專案檔所使用的檔案會根據所使用的感測器而有所不同,除了含有的 main() 函式檔案之外,分別是:
  • I2C.hI2C.c:AT89S51 I2C 通訊程式的宣告與實作
  • dht11.hdht11.c:讀取 DHT-11 溫溼度值的函式宣告與實作
  • bh1750.hbh1750.c:讀取 BH1750 光強度值得函式宣告與實作
LCD 使用 I2C 模式控制,基本的 LCD 的操作函式直接宣告與實作在主檔案裡。

專案檔如果沒有做什麼修改,直接使用已經編譯好的 .hex 檔就可以燒錄了;若是有做修改,選擇 Project / Rebuild all target files 就可以再次編譯並輸出 .hex 檔。


讀取 DHT-11 溫溼度值並顯示在整合型 LCD 螢幕上

使用 Keil C 直接打開 display_lcd+dht11.uvproj 專案檔,在左邊的 Project 視窗會顯示出所使用到的檔案 ( dht11.c、I2C.c display_lcd+dht11.c )。

AT89S52 + 整合型 LCD ( I2C 模式 )+ DHT-11 溫溼度感測器

DHT-11 的 DATA 接腳接上 4K7 的提升電阻再接到單晶片上的 P2^1 接腳上,溫溼度的資料由此接腳做讀取。如要修改為不同接腳,請在 dht11.c 中做修改即可,如下:

1 // 指定連接到 DHT11 data pin 的接腳 
2 sbit dhtpin = P2^1;

顯示溫溼度值的主程式如下:

 1 void main()
 2 {
 3  unsigned char dhtbuf[5];
 4  unsigned char chrbuf[17];  // LCD 顯示的組字陣列
 5  char percentage = 0x25;  // %
 6  
 7  // LCD 初始化
 8  initLCD();
 9  delay(100);
10  clearLCD();
11  delay(150);
12  
13  for( ;; )
14  {
15   // DHT11, temperature, humidity sensor
16   if( DHT11_read(dhtbuf) == 1 )
17   {
18    sprintf( chrbuf, "**T=%2dC,RH=%2d%c**", \
19     (int)dhtbuf[2], (int)dhtbuf[0], percentage);
20    displayCharAtLCD(1, 1, chrbuf, 16);
21   }
22   
23   delay(1000); // 0.991015 sec, @ AT89S51, 12MHz
24  }
25 }


如果接線沒有問題的話,一插上電之後,就會先清除螢幕,然後將溫溼度值顯示在 LCD 最上面那一行,每隔一秒鐘更新一次。

要注意到的是,LCD 初始化與清除螢幕上的字之後,一定要讓 LCD 有時間完成動作,因此需要加入延遲時間,不然 LCD 會無法動作!

使用 AT89S51 讀取 DHT-11 溫溼度值並顯示在 LCD


讀取 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上

使用 Keil C 直接打開 display_lcd+bh1750.uvproj 專案檔,在左邊的 Project 視窗會顯示出所使用到的檔案 ( bh1750.c、I2C.c 和 display_lcd+bh1750.c )。

AT89S52 + 整合型 LCD ( I2C 模式 )+ DBH1750 光強度感測模組

BH1750 與 LCD 都是使用 I2C 通訊,因此兩個裝置的 SDASCL 可以並接在一起,再分別接到單晶片的 P1^6P1^7 接腳上,就可以使用單晶片兩隻接腳控制兩個裝置。如要修改為不同接腳,請在 I2C.c 中做修改,如下:

1 sbit SCL = P1^7;
2 sbit SDA = P1^6;

顯示光強度值的主程式如下:

 1 void main()
 2 {
 3  unsigned char chrbuf[17];  // LCD 顯示的組字陣列
 4  
 5  // BH1750 初始化指令
 6  unsigned char bhinsts[2] = { 0x01, 0x10 }; 
 7  
 8  // LCD 初始化
 9  initLCD();
10  delay(100);
11  clearLCD();
12  delay(150);
13 
14  // BH1750 初始化
15  BH1750_init( IIC_BH1750_ADDR, bhinsts, 2);
16  delay(150);
17  
18  for( ;; ) 
19  {
20   // BH1750, Ambient light sensor  
21   sprintf( chrbuf, "***Light:%5.0fLx", BH1750_read() );
22   displayCharAtLCD(2, 1, chrbuf, 16);
23   
24   delay(1000); // 0.991015 sec, @ AT89S51, 12MHz
25  }
26 }

如果接線沒有問題的話,一插上電之後,就會先清除螢幕,然後將現在所偵測到的光強度值顯示在 LCD 最下面那一行,每隔一秒鐘更新一次,使用手電筒或是移動 BH1750 對著不同光源,就可以感測到不同的光強度值。

使用 AT89S51 讀取 BH1750 光強度值並顯示在 LCD

相對應的光源強度值,可參考 wiki 這篇說明:Lux。網頁中有一個表格,分別列出在不同環境下所對應的亮度值 ( Lux ),可用來作為實際值的對照。


讀取 DHT-11 溫溼度值和 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上

使用整合型 LCD 作為電子實驗的好處是接線簡潔,並且可以與 I2C 裝置共用一組通訊線。於此之外,解開束縛的整合型 LCD 更可以擴展成適用 SPI 通訊以及一般傳統式的 4-BIT 與 8-BIT 通訊模式 ( 如何解開束縛,請參考 雲端硬碟 datasheet 目錄下的 "整合型 JLX1602A 液晶螢幕資料手冊_watermark_proteuslcd.pdf",文件中有這部分的說明。當然,使用上有問題可直接通過電子郵件做討論 )。

一旦解開束縛,在 I2C 模式下:可以調整四個 I2C 通訊位址;在 SPI 模式下,可以使用 CS ( 預設是開啟,無法手動關閉 ) 的功能;4-BIT 和 8-BIT 通訊。共四種可供選擇的通訊控制模式。

使用 Keil C 直接打開 display_lcd+bh1750.uvproj 專案檔,在左邊的 Project 視窗會顯示出所使用到的檔案 ( dht11.c、bh1750.c、I2C.c 和 display_lcd+dht11-bh1750.c )。

在前面的例子裡,並沒有針對 I2C 通訊做過討論,這是因為留在這邊做討論會比較合適,因為在這個例子裡,使用了兩個使用 I2C 通訊做控制的裝置。

在 I2C 通訊,使用 7 個 bit 做定址,這意味著一組 I2C 通訊線只能控制 128 個裝置。而由於每個 I2C 裝置都應具有讀與寫的功能,因此在通訊時會把位址先向左移一位,留下最右邊 ( Bit 0 ) 作為讀寫的指定位元。例如,BH1750 的 I2C 位址是 0x23  ( 所以寫用 0x46 讀用 0x47 ,8-Bit數值傳送對裝置讀寫的指令 ),詳細的操作看 displayEnvironment.c 就會清楚。

AT89S52 + 整合型 LCD ( I2C 模式 ) + DHT-11 溫溼度感測器 + DBH1750 光強度感測模組

結合溫溼度與光強度兩個程式之後,主程式的程式碼如下:

 1 void main()
 2 {
 3  unsigned char dhtbuf[5];
 4  unsigned char chrbuf[17];  // LCD 顯示的組字陣列
 5  char percentage = 0x25;  // %
 6  
 7  // BH1750 初始化指令
 8  unsigned char bhinsts[2] = { 0x01, 0x10 }; 
 9  
10  // LCD 初始化
11  initLCD();
12  delay(100);
13  clearLCD();
14  delay(150);
15 
16  // BH1750 初始化
17  BH1750_init( IIC_BH1750_ADDR, bhinsts, 2);
18  delay(150);
19  
20  for( ;; )
21  {
22   // DHT11, temperature, humidity sensor
23   if( DHT11_read(dhtbuf) == 1 )
24   {
25    sprintf( chrbuf, "**T=%2dC,RH=%2d%c**", 
26     (int)dhtbuf[2], (int)dhtbuf[0], percentage);
27    displayCharAtLCD(1, 1, chrbuf, 16);
28   }
29   
30   // BH1750, Ambient light sensor  
31   sprintf( chrbuf, "***Light:%5.0fLx", BH1750_read() );
32   displayCharAtLCD(2, 1, chrbuf, 16);
33   
34   delay(1000); // 0.991015 sec, @ AT89S51, 12MHz
35  }
36 }

如果接線沒有問題的話,一插上電之後,就會先清除螢幕,然後將現在所偵測到的溫溼度值與光強度值分別顯在 LCD 的上下兩行,每隔一秒鐘更新一次。

使用 AT89S51 讀取 BH1750 溫溼度值和 BH1750 光強度值並顯示在 LCD
*****
這網頁是專門為了 5V 整合型 LCD 寫的,但若是您的單晶片是使用 3V3 的,同樣的也可以很容易的將程式碼移植過去,只不過 3V3 整合型 LCD 預設就是發送 Raspberry Pi 的測試程式碼,因此在購買之後可以指定發送的程式碼是單晶片或是 Raspberry Pi。

Keil C 專案檔裡,針對不同裝置使用上都有相對應的程式碼,這些檔案都可以分開或是整合做使用,請再自行參考所提供的資料連結中的檔案及資料。

ps: 程式碼裡面所使用的指令格式請參考所附資料手冊上第 16 頁的表格。

16 則留言:

  1. 您好!我是在露天那位,想請教你dht11程式

    回覆刪除
    回覆
    1. 你lcd只有兩隻接腳到8051是如何設定的?
      若換掉到其他腳為是否可以?
      另外請教一下dht11的程式,因為這邊沒看到,若想加入控制功能因如何修改??
      我問題很多,抱歉喔!

      刪除
    2. 上面用的 LCD 是賣場的整合型 LCD,可使用 I2C ( 預設 ) 、SPI、4/8-bit 方式控制,單晶片的控制街角可以任意變換,但是在 LCD 上有固定的 I2C 接腳則不能變。
      //------
      網頁中所提供的三個單晶片 AST89S51, Keil C 專案檔會放置在雲端硬碟中 ( display_lcd+dht11+bh1750 ),並完成設置與編譯完成可直接使用 .hex 燒錄,有購買的請使用所提供的資料下載連結自行下載,目錄中包含三個專案檔,內容有:
      讀取 DHT-11 溫溼度值並顯示在整合型 LCD 螢幕上
      display_lcd+dht11.uvproj
      讀取 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上
      display_lcd+bh1750.uvproj
      讀取 DHT-11 溫溼度值和 BH1750 光源強度值 ( Lux ) 並顯示在整合型 LCD 螢幕上
      display_lcd+dht11+bh1750.uvproj
      //------
      如果有向賣場購買東西的話,這些程式碼您應該都會有;若是沒有,就要自己去撰寫或是找到這些程式碼來使用。

      刪除
    3. 那我現在買LCD版!!這禮拜能到貨嗎??
      程式都會附??那我想加入控制元件有問情是否能請教?

      刪除
    4. 今天完成結帳動作晚上就會寄出,所附的資料在賣場網頁最下面都有說明。
      不管有無購買物品,只要發問而且我能幫忙的話都可以討論;要加入其他控制元件的話,要看是什麼東西 ? 只要可以幫忙的話都可以討論。

      刪除
  2. 請問您雲端硬碟裡的程式碼是要購買後才能下載嗎???

    回覆刪除
  3. 請問,文中有一段說 : 使用 Keil C 直接打開 display_lcd+dht11.uvproj 專案檔,在左邊的 Project 視窗會顯示出所使用到的檔案 ( dht11.c、I2C.c 和 display_lcd+dht11.c )。
    可是我用 Keil C 開啟 display_lcd+dht11.uvproj 時,並沒有在左邊的 Project 視窗顯示 dht11.c、I2C.c 和 display_lcd+dht11.c。
    此外,我直接將已經編譯好的 .hex 檔直接燒進8051裡,並按照上方的電路圖接線,可是 LCD 並沒有顯示任何字。

    回覆刪除
    回覆
    1. 若是專案檔有問題,編譯就會失敗;若編譯沒問題,就是數於 Keil C 的操作問題,您要自己搞定!

      刪除
  4. 那個,關於 hex. 檔直接燒入的部分,已經沒有問題了,是我一個小地方沒接好。但是另一個問題我還是不知要如何解決。

    回覆刪除
    回覆
    1. 如果是專案檔的問題,上面已經回答!

      刪除
  5. 小弟用PIC30F4011內建的SPI模組進行通訊
    現在遇到有時候不會換行的問題
    https://youtu.be/qa-yzGS1g2g
    請問有沒有什麼建議的解決辦法呢

    下面是傳輸到LCD的副程式

    void WriteCmdLCD(unsigned char LCD_CMD) {
    LCD_CS = 0;
    LCD_RS = 0;
    WriteSPI(LCD_CMD);
    LCD_CS = 1;
    LCD_S_Delay();
    }

    void WriteDataLCD(unsigned char LCD_CMD) {
    LCD_CS = 0;
    LCD_RS = 1;
    WriteSPI(LCD_CMD);
    LCD_CS = 1;
    LCD_S_Delay();
    }

    回覆刪除
    回覆
    1. 如果可以正常顯示的話!每一行都有起始的位址,超過 16 個字之後就會移進去顯示暫存的地方,即便你的字串上面有換行。要換行,要自己變更起始的位址到第二行。
      這些資訊資料手冊上面有寫,而且有基本的測試範例可以做參考,看一下就會清楚!
      參考 testLCDspiMode.c 裡 disp_char() 函式裡面的程式碼,修改一下就可以用!

      刪除
    2. 小弟有指定顯示的位置喔~

      上面留言我有錄製一段14秒的影片,看過應該很清楚
      兩個變數分別顯示在(3,1)(6,2)的位置,
      不過第2個變數偶爾會顯示在(3,8)的位置
      造成畫面閃動

      目前測試到的結果是
      FCK(串列時脈)=1.84MHz時,幾乎無法識別畫面顯示什麼
      FCK(串列時脈)=3.75MHz時,約10次有3次不換行,看起來非常不舒服
      FCK(串列時脈)=7.37MHz時,如上方影片偶爾閃爍
      FCK(串列時脈)=9.83MHz以上時,畫面會全部都是0

      因為想要節省腳位,所以使用SPI模組輸出,如果用範例中的方式就必須再增加2個腳位給LCD使用
      (SPI未來還要掛上DA轉換器等其他周邊)

      想請問proteus兄,範例中的FCK是多少呢?

      刪除
    3. 單看你的影片只能看到數字一直在變動,其中一段在第一行有覆蓋的情況出現;出了問題除了對照程式碼,我也不清楚!
      第一個問題是換行,你說你有指定顯示位置,所以我的回答就是參考原始程式碼。除了通訊方式不同,給定文字顯示的格式都是一樣;你沒有提供相關的程式碼,除了你之外沒人會知道你的文字組合模式是怎麼寫的 ?

      第二個問題問 FCK;這個速度不是你要設多少就多少 ? 需要根據規格書來做設定並測試。在樹莓派的 LCD SPI 函式庫,使用 500kHz 測試,沒有再往上試過,你可以自己試試其他速度,能夠正常運行就可以用! 速度太怪導致通訊失敗大多是無法顯示與動作 !

      文字覆蓋的問題,檢查一下你的文字組合格式是否沒有設定限制顯示的數字數目 (查一下 printf() 函式裡面的格式設定);另外,每一次顯示的間隔不能太快,這樣上下兩次顯示的文字就會互相干擾到,不會清楚 !

      以上,做個參考 !

      刪除