微信公眾平臺實(shí)時監(jiān)控室內(nèi)溫度和濕度

摘要:這是一個記錄軟硬件結(jié)合的物聯(lián)網(wǎng)項(xiàng)目,目的是打造微信實(shí)時監(jiān)控室內(nèi)環(huán)境蚁廓,由于傳感器簡陋陌选,這篇文章只介紹溫度和濕度的監(jiān)控,使用的是DHT11溫濕度傳感器肴甸,主機(jī)為Arduino UNO+W5100 Ethernet/SD擴(kuò)展版寂殉,路由器為HG255D Pandorabox by lintel,物聯(lián)網(wǎng)服務(wù)由樂聯(lián)網(wǎng)提供,本篇文章主要內(nèi)容有(1)DHT11硬件基礎(chǔ)(2)Arduino讀取DHT11的溫濕度數(shù)據(jù)(3)LCD1602_I2C硬件基礎(chǔ)及在LCD模塊上顯示DHT11獲取的溫濕度數(shù)據(jù)(4)將數(shù)據(jù)上傳到樂聯(lián)網(wǎng)(5)微信查詢傳感器數(shù)據(jù)

DHT11硬件基礎(chǔ)

DHT11是一款性價比極高的含有已校準(zhǔn)數(shù)字信號輸出的溫濕度復(fù)合傳感器雷滋,傳感器包括一個電阻式感濕元件和一個NTC測溫元件并與一個高性能8位單片機(jī)相連接不撑。

引腳說明

DHT11有四個引腳,一個引腳為空腳不連接元器件(所以一些采用DHT11傳感器的封裝好的溫濕度傳感器只能看到3個引腳)晤斩,其中正極接VCC(工作電壓為3-5.5VDC)焕檬,負(fù)極接GND,由于DHT11是以串行接口以高低電平傳遞數(shù)據(jù)澳泵,所以數(shù)據(jù)總線(SDATA)引腳連接單片機(jī)或Arduino的數(shù)字信號(Digital)引腳实愚,通常在元器件上正極標(biāo)有(+),負(fù)極標(biāo)有(—),數(shù)據(jù)引腳標(biāo)有(S)腊敲,我用的是KEYES的元器件击喂,左邊標(biāo)有(S)為數(shù)據(jù)引腳,右邊標(biāo)有(-)為負(fù)極引腳碰辅,中間則為正極引腳懂昂,不同廠家的元器件引腳順序不同,連接時要找準(zhǔn)引腳没宾,否者單片機(jī)則讀取不到數(shù)據(jù)凌彬。


引腳說明
引腳說明

應(yīng)用電路
應(yīng)用電路

數(shù)據(jù)傳輸原理

MCU發(fā)送開始信號(+-+)->觸發(fā)DHT響應(yīng)(-+-)數(shù)據(jù)采集->{[準(zhǔn)備發(fā)送(-)+發(fā)送數(shù)據(jù)(+)]*5}->機(jī)械拉低(-)->MCU拉高(+)

DHT11采用的是串行接口(單線雙向)的通訊方式,DATA用于微處理器與DHT11之間的通訊和同步,采用單總線數(shù)據(jù)格式,一次通訊時間4ms左右,數(shù)據(jù)分小數(shù)部分和整數(shù)部分,具體格式在下面說明,當(dāng)前小數(shù)部分用于以后擴(kuò)展,現(xiàn)讀出為零.操作流程如下:一次完整的數(shù)據(jù)傳輸為40bit,高位先出循衰。

數(shù)據(jù)格式:

40bit=8bit濕度整數(shù)數(shù)據(jù)+8bit濕度小數(shù)數(shù)據(jù)+8bi溫度整數(shù)數(shù)據(jù)+8bit溫度小數(shù)數(shù)據(jù)+8bit校驗(yàn)和數(shù)據(jù)

傳送正確時校驗(yàn)和數(shù)據(jù)等于“8bit濕度整數(shù)數(shù)據(jù)+8bit濕度小數(shù)數(shù)據(jù)+8bi溫度整數(shù)數(shù)據(jù)+8bit溫度小數(shù)數(shù)據(jù)”所得結(jié)果的末8位铲敛。

數(shù)據(jù)傳輸過程

用戶MCU發(fā)送一次開始信號后,DHT11從低功耗模式轉(zhuǎn)換到高速模式,等待主機(jī)開始信號結(jié)束后,DHT11發(fā)送響應(yīng)信號,送出40bit的數(shù)據(jù),并觸發(fā)一次信號采集,用戶可選擇讀取部分?jǐn)?shù)據(jù).從模式下,DHT11接收到開始信號觸發(fā)一次溫濕度采集,如果沒有接收到主機(jī)發(fā)送開始信號,DHT11不會主動進(jìn)行溫濕度采集.采集數(shù)據(jù)后轉(zhuǎn)換到低速模式。
通訊過程如圖所示


通訊過程
通訊過程

總線空閑狀態(tài)為高電平,主機(jī)把總線拉低等待DHT11響應(yīng),主機(jī)把總線拉低必須大于18毫秒,保證DHT11能檢測到起始信號会钝。DHT11接收到主機(jī)的開始信號后,等待主機(jī)開始信號結(jié)束,然后發(fā)送80us低電平響應(yīng)信號.主機(jī)發(fā)送開始信號結(jié)束后,延時等待20-40us后, 讀取DHT11的響應(yīng)信號,主機(jī)發(fā)送開始信號后,可以切換到輸入模式,或者輸出高電平均可, 總線由上拉電阻拉高伐蒋。

總線為低電平,說明DHT11發(fā)送響應(yīng)信號,DHT11發(fā)送響應(yīng)信號后,再把總線拉高80us,準(zhǔn)備發(fā)送數(shù)據(jù),每一bit數(shù)據(jù)都以50us低電平時隙開始,高電平的長短定了數(shù)據(jù)位是0還是1.格式見下面圖示.如果讀取響應(yīng)信號為高電平,則DHT11沒有響應(yīng),請檢查線路是否連接正常.當(dāng)最后一bit數(shù)據(jù)傳送完畢后,DHT11拉低總線50us,隨后總線由上拉電阻拉高進(jìn)入空閑狀態(tài)迁酸。
數(shù)字0信號表示方法如圖所示


數(shù)字0信號表示方法
數(shù)字0信號表示方法

數(shù)字1信號表示方法如圖所示


數(shù)字1信號表示方法
數(shù)字1信號表示方法

Arduino讀取DHT11的溫濕度數(shù)據(jù)

int DHpin=8;    //定義數(shù)字引腳8為DHT11數(shù)據(jù)接收/發(fā)送引腳
byte dat[5];    //聲明數(shù)組先鱼,用于儲存5組8bit的數(shù)據(jù)

void setup()    //只執(zhí)行一次
{
  Serial.begin(9600);   //串口通信波特率(和電腦)
  pinMode(DHpin,OUTPUT);    //輸出模式
  digitalWrite(DHpin,HIGH); //靜息電平,空閑狀態(tài)
}

void start_test()   //MCU發(fā)送開始信號
{
  digitalWrite(DHpin,LOW);  //拉低電平發(fā)送信號
  delay(30);
  digitalWrite(DHpin,HIGH); //拉高電平胁出,發(fā)送信號結(jié)束
  delayMicroseconds(40);
  pinMode(DHpin,INPUT); //輸入模式型型,開始檢測DHT發(fā)來的信號
  while(digitalRead(DHpin)==LOW);   //DHT發(fā)來響應(yīng)信號,低電平80us
  delayMicroseconds(80);
  while(digitalRead(DHpin)==HIGH);  //高電平80us全蝶,響應(yīng)信號結(jié)束
  delayMicroseconds(80);
  for(int i=0;i<4;i++)  //開始讀取數(shù)據(jù)
  dat[i]=read_data();
  pinMode(DHpin,OUTPUT);    //讀取數(shù)據(jù)結(jié)束
  digitalWrite(DHpin,HIGH); //拉高電平闹蒜,空閑狀態(tài)
}

byte read_data()    //讀取數(shù)據(jù)的方法
{
  byte data;
  for(int i=0;i<8;i++)  //1bit的讀取數(shù)據(jù)
  {
    if(digitalRead(DHpin)==HIGH)    
    {
      while(digitalRead(DHpin)==HIGH);  //檢測到高電平開始,延遲30us
      delayMicroseconds(30);
      if(digitalRead(DHpin)==HIGH)  //如果30us后,電平拉高,則為1抑淫,否者則為0
      data|=(1<<(7-i));
    }
  }
return data;
}

void loop() //串口輸出數(shù)據(jù)
{
  start_test(); 
  Serial.print("t1:"); 
  Serial.print(dat[0],DEC); //顯示濕度的整數(shù)位绷落; 
  Serial.print('.'); 
  Serial.print(dat[1],DEC); //顯示濕度的小數(shù)位; 
  Serial.print('%');
  Serial.print("t2:"); 
  Serial.print(dat[2],DEC); //顯示溫度的整數(shù)位始苇; 
  Serial.print('.'); 
  Serial.print(dat[3],DEC); //顯示溫度的小數(shù)位; 
  Serial.print('C');
  delay(5000);      //延遲5s

}

LCD1602_I2C硬件基礎(chǔ)

LCD1602_I2C由兩部分組成催式,LCD1602和一個I2C并行串口電路構(gòu)成函喉,LCD提供液晶屏顯示哺窄,I2C并行串口電路為單片機(jī)提供并行串口通訊捐下,減少LCD1602所需的引腳账锹。

LCD1602硬件基礎(chǔ)

LCD:英文全稱為Liquid Crystal Display,即為液態(tài)晶體顯示坷襟,也就是我們常說的液晶顯示了奸柬。1602則是表示這個液晶一共能顯示2行數(shù)據(jù),每一行顯示16個字符婴程。這個就是LCD1602的全部來由廓奕。

我們首先來看1602的引腳定義,1602的引腳是很整齊的SIP單列直插封裝,所以器件手冊只給出了引腳的功能數(shù)據(jù)表:


LCD1602引腳定義
LCD1602引腳定義

我們只需要關(guān)注以下幾個管腳:
3腳:VL档叔,液晶顯示偏壓信號懂从,用于調(diào)整LCD1602的顯示對比度,一般會外接電位器用以調(diào)整偏壓信號蹲蒲,注意此腳電壓為0時可以得到最強(qiáng)的對比度。
4腳:RS侵贵,數(shù)據(jù)/命令選擇端届搁,當(dāng)此腳為高電平時,可以對1602進(jìn)行數(shù)據(jù)字節(jié)的傳輸操作窍育,而為低電平時卡睦,則是進(jìn)行命令字節(jié)的傳輸操作。命令字節(jié)漱抓,即是用來對LCD1602的一些工作方式作設(shè)置的字節(jié)表锻;數(shù)據(jù)字節(jié),即使用以在1602上顯示的字節(jié)乞娄。這是一個選擇數(shù)據(jù)寄存器還是選擇指令寄存器的過程瞬逊,值得一提的是,LCD1602的數(shù)據(jù)是8位的仪或。
5腳:R/W确镊,讀寫選擇端。當(dāng)此腳為高電平可對LCD1602進(jìn)行讀數(shù)據(jù)操作范删,反之進(jìn)行寫數(shù)據(jù)操作蕾域。筆者認(rèn)為,此腳其實(shí)用處不大到旦,直接接地永久置為低電平也不會影響其正常工作旨巷。但是尚未經(jīng)過復(fù)雜系統(tǒng)驗(yàn)證,保留此意見添忘。
6腳:E采呐,使能信號,其實(shí)是LCD1602的數(shù)據(jù)控制時鐘信號昔汉,利用該信號的上升沿實(shí)現(xiàn)對LCD1602的數(shù)據(jù)傳輸懈万。
7~14腳:8位并行數(shù)據(jù)口拴清,使得對LCD1602的數(shù)據(jù)讀寫大為方便。

LCD1602通訊過程

現(xiàn)在來看LCD1602的操作時序:

在此会通,我們可以先不讀出它的數(shù)據(jù)的狀態(tài)或者數(shù)據(jù)本身口予。所以只需要看兩個寫時序:

當(dāng)我們要寫入指令字節(jié),設(shè)置LCD1602的工作方式時:需要把RS置為低電平涕侈,RW置為低電平沪停,然后將數(shù)據(jù)送到數(shù)據(jù)口D0~D7,最后E引腳一個高脈沖將數(shù)據(jù)寫入裳涛。
當(dāng)我們要寫入數(shù)據(jù)字節(jié)木张,設(shè)置LCD1602的工作方式時:需要把RS置為高電平,RW置為低電平端三,然后將數(shù)據(jù)送到數(shù)據(jù)口D0~D7舷礼,最后E引腳一個高脈沖將數(shù)據(jù)寫入。
發(fā)現(xiàn)了么郊闯,寫指令和寫數(shù)據(jù)妻献,差別僅僅在于RS的電平不一樣而已。以下是LCD1602的讀時序圖:

讀指令
讀指令

當(dāng)要寫命令字節(jié)的時候团赁,時間由左往右育拨,RS變?yōu)榈碗娖剑琑/W變?yōu)榈碗娖交渡悖⒁饪词荝S的狀態(tài)先變化完成熬丧。然后這時,DB0~DB7上數(shù)據(jù)進(jìn)入有效階段怀挠,接著E引腳有一個整脈沖的跳變析蝴,接著要維持時間最小值為tpw=400ns的E脈沖寬度。然后E引腳負(fù)跳變唆香,RS電平變化嫌变,R/W電平變化。這樣便是一個完整的LCD1602寫命令的時序躬它。


讀寫指令
讀寫指令

LCD1602基本指令

基本指令
基本指令

Arduino與LCD1602的通訊

8針接法腾啥,數(shù)據(jù)輸出口:DB0-DB7。

// 8pinlcd1602.ino
int DI = 12;    //定義數(shù)據(jù)/命令針腳
int RW = 11;    //定義讀/寫針腳
int DB[] = {3, 4, 5, 6, 7, 8, 9, 10};//使用數(shù)組來定義總線需要的管腳
int Enable = 2; //定義使能管腳
 
//LCD寫命令的方法
void LcdCommandWrite(int value) {
 // 定義所有引腳
 int i = 0;
digitalWrite(DI, LOW);  //DI為O冯吓,RW為0倘待,寫入命令
 digitalWrite(RW, LOW);
 for (i=DB[0]; i <= DI; i++) //總線賦值
{
   digitalWrite(i,value & 01);  //獲取每個字節(jié)的第一位
   value >>= 1; //2進(jìn)制移位,將要獲取的位移至第一位
 }
 digitalWrite(Enable,LOW);  //使能拉低電平组贺,準(zhǔn)備觸發(fā)高脈沖
 delayMicroseconds(1);
 digitalWrite(Enable,HIGH); //Arduino拉高電平凸舵,高脈沖將數(shù)據(jù)泵入指令寄存器
 delayMicroseconds(1);  
 digitalWrite(Enable,LOW);  //使能恢復(fù)低電平,靜息電平
 delayMicroseconds(1);  
}
 
void LcdDataWrite(int value) {
 // 定義所有引腳
 int i = 0;
 digitalWrite(DI, HIGH);    //DI為1失尖,RW為0啊奄,寫入數(shù)據(jù)
 digitalWrite(RW, LOW);
 for (i=DB[0]; i <= DB[7]; i++) {
   digitalWrite(i,value & 01);  //獲取每個字節(jié)的第一位渐苏,0xXX & 01 =0 | 1
   value >>= 1;
 }
 digitalWrite(Enable,LOW);
 delayMicroseconds(1);
 digitalWrite(Enable,HIGH); //高脈沖泵入數(shù)據(jù),寫入數(shù)據(jù)寄存器
 delayMicroseconds(1);
 digitalWrite(Enable,LOW);
 delayMicroseconds(1);  
}
 
void setup (void) { //起始函數(shù)菇夸,只執(zhí)行一次
 int i = 0;
 for (i=Enable; i <= DI; i++) { //將所有管腳設(shè)置為輸出
   pinMode(i,OUTPUT);
 }
 delay(100);
 // 短暫的停頓后初始化LCD
 // 用于LCD控制需要
 LcdCommandWrite(0x38);  // 設(shè)置為8-bit接口琼富,2行顯示,5x7文字大小                     
 delay(64);                      
 LcdCommandWrite(0x38);  // 設(shè)置為8-bit接口庄新,2行顯示鞠眉,5x7文字大小                        
 delay(50);                      
 LcdCommandWrite(0x38);  // 設(shè)置為8-bit接口,2行顯示择诈,5x7文字大小                        
 delay(20);                      
 LcdCommandWrite(0x06);  // 輸入方式設(shè)定
                         // 自動增量械蹋,沒有顯示移位
 delay(20);                      
 LcdCommandWrite(0x0E);  // 顯示設(shè)置
                         // 開啟顯示屏,光標(biāo)顯示羞芍,無閃爍
 delay(20);                      
 LcdCommandWrite(0x01);  // 屏幕清空哗戈,光標(biāo)位置歸零  
 delay(100);                      
 LcdCommandWrite(0x80);  // 顯示設(shè)置
                         // 開啟顯示屏,光標(biāo)顯示荷科,無閃爍
 delay(20);                      
}
 
void loop (void) {
  LcdCommandWrite(0x01);  // 屏幕清空谱醇,光標(biāo)位置歸零  
  delay(10); 
  LcdCommandWrite(0x80+3); //0x80+為第一行命令地址,0x80+3表示第1行第4列的字符
  delay(10);                     
  // 寫入歡迎信息 
  LcdDataWrite('W');
  LcdDataWrite('e');
  LcdDataWrite('l');
  LcdDataWrite('c');
  LcdDataWrite('o');
  LcdDataWrite('m');
  LcdDataWrite('e');
  LcdDataWrite(' ');
  LcdDataWrite('t');
  LcdDataWrite('o');
  delay(10);
  LcdCommandWrite(0xc0+1);  // 定義光標(biāo)位置為第二行第二個位置  
  delay(10); 
  LcdDataWrite('M');
  LcdDataWrite('a');
  LcdDataWrite('k');
  LcdDataWrite('e');
  LcdDataWrite('B');
  LcdDataWrite('l');
  LcdDataWrite('a');
  LcdDataWrite('z');
  LcdDataWrite('e');
  delay(5000);
  LcdCommandWrite(0x01);  // 屏幕清空步做,光標(biāo)位置歸零  
  delay(10);
  LcdDataWrite('I');
  LcdDataWrite(' ');
  LcdDataWrite('a');
  LcdDataWrite('m');
  LcdDataWrite(' ');
  LcdDataWrite('R');
  LcdDataWrite('i');
  LcdDataWrite('c');
  LcdDataWrite('e');
  LcdDataWrite('L');
  LcdDataWrite('y');
  LcdDataWrite('n');
  delay(3000);
  LcdCommandWrite(0x02); //設(shè)置模式為新文字替換老文字,無新文字的地方顯示不變奈附。
  delay(10);
  LcdCommandWrite(0x80+5); //定義光標(biāo)位置為第一行第六個位置
  delay(10);  
  LcdDataWrite('t');
  LcdDataWrite('h');
  LcdDataWrite('e');
  LcdDataWrite(' ');
  LcdDataWrite('a');
  LcdDataWrite('d');
  LcdDataWrite('m');
  LcdDataWrite('i');
  LcdDataWrite('n');
  delay(5000);
}

4針接法全度,數(shù)據(jù)輸出口:DB4-DB7,傳輸一個字節(jié)分兩次傳輸斥滤,每次傳輸4bit将鸵,需要2倍的時間。

// 4pinlcd1602.ino

int LCD1602_RS=12;   
int LCD1602_RW=11;   
int LCD1602_EN=10;   
int DB[] = { 6, 7, 8, 9};   //定義4位總線
char str1[]="Welcome to";   //自定義字符佑颇,數(shù)據(jù)格式為字符(一個數(shù)組的值等于一個字符)
char str2[]="MakeBlaze";
char str3[]="this is the";
char str4[]="4-bit interface";
 
void LCD_Command_Write(int command) //LCD寫命令函數(shù)
{
 int i,temp;
 digitalWrite( LCD1602_RS,LOW);
 digitalWrite( LCD1602_RW,LOW);
 digitalWrite( LCD1602_EN,LOW);
 
 temp=command & 0xf0;   //切割字節(jié)顶掉,獲取高4位,0xff=11110000
 for (i=DB[0]; i <= 9; i++)
 {
   digitalWrite(i,temp & 0x80); //獲取最高位挑胸,0x80=10000000
   temp <<= 1;
 }
 
 digitalWrite( LCD1602_EN,HIGH);    //高脈沖泵入指令寄存器痒筒,位于棧底,D7位為0
 delayMicroseconds(1);
 digitalWrite( LCD1602_EN,LOW);
 
 temp=(command & 0x0f)<<4;  ////切割字節(jié)茬贵,獲取低4位簿透,0xff=11110000
 for (i=DB[0]; i <= 9; i++)
 {
   digitalWrite(i,temp & 0x80); //獲取最高位,0x80=10000000
   temp <<= 1;
 }
 
 digitalWrite( LCD1602_EN,HIGH);    //高脈沖泵入指令寄存器解藻,位于棧頂
 delayMicroseconds(1); 
 digitalWrite( LCD1602_EN,LOW);
}
 
void LCD_Data_Write(int dat)    //LCD寫數(shù)據(jù)的函數(shù)
{
 int i=0,temp;
 digitalWrite( LCD1602_RS,HIGH);
 digitalWrite( LCD1602_RW,LOW);
 digitalWrite( LCD1602_EN,LOW);
 
 temp=dat & 0xf0;
 for (i=DB[0]; i <= 9; i++)
 {
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
 }
 
 digitalWrite( LCD1602_EN,HIGH);
 delayMicroseconds(1);
 digitalWrite( LCD1602_EN,LOW);
 
 temp=(dat & 0x0f)<<4;
 for (i=DB[0]; i <= 9; i++)
 {
   digitalWrite(i,temp & 0x80);
   temp <<= 1;
 }
 
 digitalWrite( LCD1602_EN,HIGH);
 delayMicroseconds(1); 
 digitalWrite( LCD1602_EN,LOW);
}
 
void LCD_SET_XY( int x, int y ) //設(shè)置字符位置
{
  int address;
  if (y ==0)    address = 0x80 + x; //如果是第一行老充,則地址設(shè)置為0x80+
  else          address = 0xC0 + x; //如果是第二行,則地址設(shè)置為0xC0+
  LCD_Command_Write(address); //寫入地址寄存器
}
 
void LCD_Write_Char( int x,int y,int dat)   //設(shè)置LCD顯示數(shù)據(jù)
{
  LCD_SET_XY( x, y );   //設(shè)置LCD位置
  LCD_Data_Write(dat);  //將字模對應(yīng)的地址編號寫入數(shù)據(jù)寄存器
}
 
void LCD_Write_String(int X,int Y,char *s)
{
    LCD_SET_XY( X, Y );    //設(shè)置地址 
    while (*s)             //寫字符串
    {
      LCD_Data_Write(*s);   
      s ++;
    }
}
 
void setup (void) 
{
  int i = 0;    //設(shè)置所有管腳為輸出
  for (i=6; i <= 12; i++) 
   {
     pinMode(i,OUTPUT);
   }
  delay(100);
  LCD_Command_Write(0x28);  //4線 2行 5x7螟左,8線我0x38
  delay(50); 
  LCD_Command_Write(0x06);  //寫一個字符后地址指針加1啡浊,光標(biāo)向后移一位
  delay(50); 
  LCD_Command_Write(0x0c);  //打開顯示觅够,不顯示光標(biāo)
  delay(50); 
  LCD_Command_Write(0x80);  // 顯示設(shè)置
                            // 開啟顯示屏,光標(biāo)顯示巷嚣,無閃爍
  delay(50); 
  LCD_Command_Write(0x01);  //顯示清屏
  delay(50); 
 
}
 
void loop (void)
{
   LCD_Command_Write(0x01);
   delay(50);
   LCD_Write_String(3,0,str1);//第1行喘先,第4個地址起
   delay(50);
   LCD_Write_String(1,1,str2);//第2行,第2個地址起
   delay(5000);
   LCD_Command_Write(0x01);
   delay(50);
   LCD_Write_String(0,0,str3);
   delay(50);
   LCD_Write_String(0,1,str4);
   delay(5000);
 
}

LCD1602內(nèi)部構(gòu)造

LCD1602內(nèi)部構(gòu)造
LCD1602內(nèi)部構(gòu)造

LCD1602模塊內(nèi)部由一塊LCD顯示屏(LCDpanel)涂籽,控制器(controller),列驅(qū)動器(segment driver)和偏壓產(chǎn)生電路構(gòu)成苹祟。
控制器接收來自MPU(這里為Arduino)的指令和數(shù)據(jù),控制著整個模塊的運(yùn)行评雌,控制器主要指令寄存器(IR),數(shù)據(jù)寄存器(DR)树枫,忙標(biāo)志(BF),地址計(jì)數(shù)器(AC)景东,顯示數(shù)據(jù)寄存器(DDRAM)砂轻,字符發(fā)生器(CGROM(內(nèi)置字符庫),CGRAM(自定義字符庫))構(gòu)成斤吐。

Arduino傳輸過來的指令儲存在指令寄存器之中搔涝,內(nèi)部存儲著DDRAM和CGRAM中數(shù)據(jù)顯示的指令代碼或地址信息,然后主控芯片(SoC)讀取數(shù)據(jù)和措,儲存DDRAM中根據(jù)指令代碼執(zhí)行具體的命令庄呈,如字符的位置,光標(biāo)的開關(guān)派阱,字符和光標(biāo)的移位等等诬留。
而Arduino傳輸過來的數(shù)據(jù)則儲存在數(shù)據(jù)寄存器之中,從CGROM中查找到想要顯示的字符的字符碼贫母,送入DDRAM之中文兑,在LCD顯示屏上與DDRAM存儲單元對應(yīng)的規(guī)定位置顯示出該字符。

主控芯片根據(jù)DDRAM中儲存的信息腺劣,從數(shù)字引腳中發(fā)出40SEG的掃描信號外加將信息傳輸?shù)絊egment Driver绿贞,由Segment Driver構(gòu)成的40SEG掃描信號,構(gòu)成LCD顯示屏的列橘原,行由公共電極(ROM)籍铁,原理類似掃描鍵盤,從而控制整個LCD顯示屏的輸出趾断。


I2C并口擴(kuò)展電路

我這里用的是一顆PCF8574T芯片寨辩,其他型號的芯片應(yīng)該工作原理相同,它通過兩條雙向總線(I2C)可以使大多數(shù)的MCU(這里是Arduino)實(shí)現(xiàn)遠(yuǎn)程I/O口擴(kuò)展歼冰,當(dāng)然要以犧牲部分性能為代價靡狞,不過這里我們傳遞的數(shù)據(jù)量小,所以性能的丟失可以忽略不計(jì)隔嫡,該器件包含一個8位準(zhǔn)雙向口(這里用于連接LCD1602甸怕,采用4位接法甘穿,加上RS,RW,E共占用7個I/O,當(dāng)然也可以使用I/O口更多的芯片實(shí)現(xiàn)8位接法)和一個I2C總線接口(這里連接Arduino梢杭,占用2個數(shù)字引腳)温兼。


PCF8574T針腳定義
PCF8574T針腳定義

I2C通訊過程

I2C總線由兩條線組成,一條串行數(shù)據(jù)中線(SDA)和一條串行時鐘總線(SCL)武契,當(dāng)總線空閑時募判,SDA和SCL均保持高電平,這時如果咒唆,SDA電平由高電平變化為低電平届垫,標(biāo)志著起始信號的開始,隨后SCL電平由高變低開始位傳輸全释,SDA開始傳遞數(shù)據(jù)(電平拉高或拉低)装处,SCL隨后由低變高,并保持一段時間浸船,若SDA線上的電平保持穩(wěn)定妄迁,則認(rèn)為SDA是在傳輸數(shù)據(jù)bit,此時SDA上高電平表示1李命,低電平表示0登淘,SLC由高變低,改變數(shù)據(jù)封字,準(zhǔn)備檢測下一個bit形帮,連續(xù)傳遞8個bit(7個數(shù)據(jù)位加一個R/W操作位1bit),等待PCF8574T應(yīng)答周叮,第9個clock,若從IC發(fā)ACK界斜,SDA會被拉低仿耽,若沒有ACK,SDA會被置高各薇,這會引起Master發(fā)生RESTART或STOP流程项贺,一個字節(jié)的寫入完成。電平由低至高變化定義為總線的停止信號峭判。


I2C時序圖
I2C時序圖

PCF8574T內(nèi)部結(jié)構(gòu)


由MCU傳遞過來的數(shù)據(jù)存儲在每個引腳的寄存器中开缎,然后寫入LCD1602。完成通過I2C控制LCD1602的過程林螃。

I2C驅(qū)動

********************************************************************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char /*宏定義*/
#define uint unsigned int
#define _Nop() _nop_()        /*定義空指令*/

sbit SDA=P3^4;            /*模擬I2C數(shù)據(jù)傳送位*/
sbit SCL=P3^5;            /*模擬I2C時鐘控制位*/
bit ack;          /*應(yīng)答標(biāo)志位*/
/*******************************************************************
                     起動總線函數(shù)               
函數(shù)原型: void Start_I2c(); 
功能:     啟動I2C總線,即發(fā)送I2C起始條件. 
********************************************************************/
void Start_I2c()
{
SDA=1;   /*發(fā)送起始條件的數(shù)據(jù)信號*/
_Nop();
SCL=1;
_Nop();    /*起始條件建立時間大于4.7us,延時*/
_Nop();
_Nop();
_Nop();
_Nop();     SDA=0;   /*發(fā)送起始信號*/
_Nop();    /* 起始條件鎖定時間大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();       
SCL=0;   /*鉗住I2C總線奕删,準(zhǔn)備發(fā)送或接收數(shù)據(jù) */
_Nop();
_Nop();
}
/*******************************************************************
                      結(jié)束總線函數(shù)               
函數(shù)原型: void Stop_I2c(); 
功能:     結(jié)束I2C總線,即發(fā)送I2C結(jié)束條件. 
********************************************************************/
void Stop_I2c()
{
SDA=0; /*發(fā)送結(jié)束條件的數(shù)據(jù)信號*/
_Nop();   /*發(fā)送結(jié)束條件的時鐘信號*/
SCL=1; /*結(jié)束條件建立時間大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*發(fā)送I2C總線結(jié)束信號*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
                 字節(jié)數(shù)據(jù)發(fā)送函數(shù)               
函數(shù)原型: void SendByte(uchar c);
功能:     將數(shù)據(jù)c發(fā)送出去,可以是地址,也可以是數(shù)據(jù),發(fā)完后等待應(yīng)答,并

對
          此狀態(tài)位進(jìn)行操作.(不應(yīng)答或非應(yīng)答都使ack=0)     
        發(fā)送數(shù)據(jù)正常,ack=1; ack=0表示被控器無應(yīng)答或損壞疗认。
********************************************************************/
void SendByte(uchar c) {
uchar BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++) /*要傳送的數(shù)據(jù)長度為8位*/
    {
     if((c<<BitCnt)&0x80)SDA=1;   /*判斷發(fā)送位*/
       else SDA=0;                
     _Nop();
     SCL=1;               /*置時鐘線為高完残,通知被控器開始接收數(shù)據(jù)位*/
      _Nop(); 
      _Nop();             /*保證時鐘高電平周期大于4μs*/
      _Nop();
      _Nop();
      _Nop();         
     SCL=0; 
    }
    
    _Nop();
    _Nop();
    SDA=1;                /*8位發(fā)送完后釋放數(shù)據(jù)線伏钠,準(zhǔn)備接收應(yīng)答位*/
    _Nop();
    _Nop();   
    SCL=1;
    _Nop();
    _Nop();
    _Nop();
    if(SDA==1)ack=0;     
       else ack=1;        /*判斷是否接收到應(yīng)答信號*/
    SCL=0;
    _Nop();
    _Nop();
}
/*******************************************************************
                 字節(jié)數(shù)據(jù)接收函數(shù)               
函數(shù)原型: uchar RcvByte();
功能:    用來接收從器件傳來的數(shù)據(jù),并判斷總線錯誤(不發(fā)應(yīng)答信號),
          發(fā)完后請用應(yīng)答函數(shù)應(yīng)答從機(jī)谨设。 
********************************************************************/ 
uchar RcvByte()
{
uchar retc;
uchar BitCnt; 
retc=0; 
SDA=1;                /*置數(shù)據(jù)線為輸入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        _Nop();           
        SCL=0;                  /*置時鐘線為低熟掂,準(zhǔn)備接收數(shù)據(jù)位*/
        _Nop();
        _Nop();                 /*時鐘低電平周期大于4.7μs*/
        _Nop();
        _Nop();
        _Nop();
        SCL=1;                  /*置時鐘線為高使數(shù)據(jù)線上數(shù)據(jù)有效*/
        _Nop();
        _Nop();
        retc=retc<<1;
        if(SDA==1)retc=retc+1; /*讀數(shù)據(jù)位,接收的數(shù)據(jù)位放入retc中 */
        _Nop();
        _Nop(); 
      }
SCL=0;    
_Nop();
_Nop();
return(retc);
}
/********************************************************************
                     應(yīng)答子函數(shù)
函數(shù)原型: void Ack_I2c(bit a);
功能:      主控器進(jìn)行應(yīng)答信號(可以是應(yīng)答或非應(yīng)答信號,由位參數(shù)a決定)
********************************************************************/
void Ack_I2c(bit a)
{

if(a==0)SDA=0;           /*在此發(fā)出應(yīng)答或非應(yīng)答信號 */
        else SDA=1;
_Nop();
_Nop();
_Nop();      
SCL=1;
_Nop();
_Nop();                    /*時鐘低電平周期大于4μs*/
_Nop(); _Nop();
_Nop(); 
SCL=0;                     /*清時鐘線扎拣,鉗住I2C總線以便繼續(xù)接收*/
_Nop();
_Nop();    
}
/******************************************************************* 

I2C&LCD連接電路

I2C&LCD連接電路
I2C&LCD連接電路
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赴肚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子二蓝,更是在濱河造成了極大的恐慌誉券,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侣夷,死亡現(xiàn)場離奇詭異横朋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)百拓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門琴锭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衙传,你說我怎么就攤上這事决帖。” “怎么了蓖捶?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵地回,是天一觀的道長。 經(jīng)常有香客問我俊鱼,道長刻像,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任并闲,我火速辦了婚禮细睡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帝火。我一直安慰自己溜徙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布犀填。 她就那樣靜靜地躺著蠢壹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪九巡。 梳的紋絲不亂的頭發(fā)上图贸,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼求妹。 笑死乏盐,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的制恍。 我是一名探鬼主播父能,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼净神!你這毒婦竟也來了何吝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鹃唯,失蹤者是張志新(化名)和其女友劉穎爱榕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坡慌,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黔酥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了洪橘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跪者。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熄求,靈堂內(nèi)的尸體忽然破棺而出渣玲,到底是詐尸還是另有隱情,我是刑警寧澤弟晚,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布忘衍,位于F島的核電站,受9級特大地震影響卿城,放射性物質(zhì)發(fā)生泄漏枚钓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一瑟押、第九天 我趴在偏房一處隱蔽的房頂上張望搀捷。 院中可真熱鬧,春花似錦勉耀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至威始,卻和暖如春枢纠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背黎棠。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工晋渺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镰绎,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓木西,卻偏偏與公主長得像畴栖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子八千,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容