本文為大大維原創,最早於博客園發表,轉載請注明出處!!!
一、前言:
上文中,筆者系統的闡述了1602的兩種驅動方式,並簡單的提到了Arduino的LiquidCrystal庫。本文緊接上文,對以下兩個問題進行更加深入的探討:如何能夠使1602對Arduino的端口占用降到最少?LiquidCrystal庫到底應該如何學習?閑話少說,下面開始進入正文。
二、減少1602對Arduino的端口占用
<1>不使用I2C
在上文中,筆者分別介紹八線和四線驅動的使用方法,給出了兩種接線方式。接線圖分別如下:
在八線驅動模式下,總共占掉了Arduino 16個端口,四線驅動模式雖然比八線驅動模式少了四個端口,但也達到了驚人的12個。如果實驗只是用於驅動LCD1602還好,但在其他實際應用中,這是不能容忍的。為此,怎么能夠使端口占用達到最少呢?在上面兩張接線圖中,我們使用了兩種電源,+5V的VSS和+3.3V背光。其實,背光完全可以接到+5V,而且亮度還會更高。此為,我們在實際使用操作過程中,RW一般均為低電平寫。沒有什么特殊需求的話可以直接接地。另外,我們如果養成良好的接線習慣,將GND接在一起,這樣,只用占用一個GND端口。由於我們下文要用到Arduino中自帶的示例程序,為了與示例程序的電路連接相符,對相關引腳連線做了一定調整,調整后的連線圖如下:
可以看到,這種接法下,Arduino端口的占用可以少去很多。尤其在四線驅動模式下,除去GND和+5V,LCD1602獨占的端口只有6個。
<1>使用I2C
I2C是由以前的PHILIPS(現在的NXP)公司開發的一種通信協議,其目的就是減少芯片之間的連線。在使用了I2C之后,連接到Arduino上的線總共只有四條,獨占的端口只有兩個!!!
但這種模式也有很多限制,羅列如下:
1.使用的LCD1602必須先焊接到LCD1602 I2C模塊
2.I2C模塊的SDA(串行數據)和SCL(串行時鍾)不可以隨便亂接。對於Arduino Uno來說,SDA必須接A4,SCL必須接A5
盡管有這些限制,但無疑,它的確在很大程度上減少了芯片之間的連線。
使用I2C需要遵循I2C協議。一般在Arduino中,通過導入LiquidCrystal_I2C庫來完成控制。由於筆者手邊沒有LCD1602 I2C模塊,因此,相關實驗在此略過,等有機會再進行補充。
三、LiquidCrystal庫到底應該如何學習?
在Arduino IDE中,官方的示例程序足夠讓你完成對LiquidCrystal的學習,如下圖:(所有這些程序的硬件連接與上文的LCD1602四線驅動硬件連接簡化示意圖相同)
此外,筆者分享一個不錯的LiquidCrystal文檔,可以當作LiquidCrystal說明手冊使用。連接如下:
當然,你如果想深究,打開Arduino文件夾中的libraries文件夾,找到LiquidCrystal.cpp和頭文件LiquidCrystal.h仔細研究(前提是你有良好的C++基礎)。
四、LiquidCrystal庫中的一個BUG以及相應的解決辦法
筆者在學習LiquidCrystal庫的過程中,發現一處LiquidCrystal庫中的bug,記錄如下:
<1>BUG描述
示例程序LiquidCrystal->CustomCharacter無論如何也編譯不過去,即使硬件一點毛病也沒有,編譯也還是報錯。如下圖:
報錯信息如下:
CustomCharacter.ino: In function 'void setup()': CustomCharacter:119: error: call of overloaded 'write(int)' is ambiguous E:\Arduino\libraries\LiquidCrystal/LiquidCrystal.h:82: note: candidates are: virtual size_t LiquidCrystal::write(uint8_t) E:\Arduino\hardware\arduino\cores\arduino/Print.h:49: note: size_t Print::write(const char*)
error: call of overloaded 'write(int)' is ambiguous
翻譯:write的重載是不明確的。//明顯是由於參數判斷不清楚導致的錯誤。
后面的意思是問題在LiquidCrystal::write(uint8_t)和size_t Print::write(const char*)兩個方法之間。
原文代碼如下:
1 #include <LiquidCrystal.h> 2 3 #include <LiquidCrystal.h> 4 5 /* 6 LiquidCrystal Library - Custom Characters 7 8 Demonstrates how to add custom characters on an LCD display. 9 The LiquidCrystal library works with all LCD displays that are 10 compatible with the Hitachi HD44780 driver. There are many of 11 them out there, and you can usually tell them by the 16-pin interface. 12 13 This sketch prints "I <heart> Arduino!" and a little dancing man 14 to the LCD. 15 16 The circuit: 17 * LCD RS pin to digital pin 12 18 * LCD Enable pin to digital pin 11 19 * LCD D4 pin to digital pin 5 20 * LCD D5 pin to digital pin 4 21 * LCD D6 pin to digital pin 3 22 * LCD D7 pin to digital pin 2 23 * LCD R/W pin to ground 24 * 10K potentiometer: 25 * ends to +5V and ground 26 * wiper to LCD VO pin (pin 3) 27 * 10K poterntiometer on pin A0 28 29 created21 Mar 2011 30 by Tom Igoe 31 Based on Adafruit's example at 32 https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde 33 34 This example code is in the public domain. 35 http://www.arduino.cc/en/Tutorial/LiquidCrystal 36 37 Also useful: 38 http://icontexto.com/charactercreator/ 39 40 */ 41 42 // include the library code: 43 #include <LiquidCrystal.h> 44 45 // initialize the library with the numbers of the interface pins 46 LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 47 48 // make some custom characters: 49 byte heart[8] = { 50 0b00000, 51 0b01010, 52 0b11111, 53 0b11111, 54 0b11111, 55 0b01110, 56 0b00100, 57 0b00000 58 }; 59 60 byte smiley[8] = { 61 0b00000, 62 0b00000, 63 0b01010, 64 0b00000, 65 0b00000, 66 0b10001, 67 0b01110, 68 0b00000 69 }; 70 71 byte frownie[8] = { 72 0b00000, 73 0b00000, 74 0b01010, 75 0b00000, 76 0b00000, 77 0b00000, 78 0b01110, 79 0b10001 80 }; 81 82 byte armsDown[8] = { 83 0b00100, 84 0b01010, 85 0b00100, 86 0b00100, 87 0b01110, 88 0b10101, 89 0b00100, 90 0b01010 91 }; 92 93 byte armsUp[8] = { 94 0b00100, 95 0b01010, 96 0b00100, 97 0b10101, 98 0b01110, 99 0b00100, 100 0b00100, 101 0b01010 102 }; 103 void setup() { 104 // create a new character 105 lcd.createChar(0, heart);//方法2:0改為5 106 // create a new character 107 lcd.createChar(1, smiley); 108 // create a new character 109 lcd.createChar(2, frownie); 110 // create a new character 111 lcd.createChar(3, armsDown); 112 // create a new character 113 lcd.createChar(4, armsUp); 114 115 // set up the lcd's number of columns and rows: 116 lcd.begin(16, 2); 117 // Print a message to the lcd. 118 lcd.print("I "); 119 lcd.write(0);//方法一:改作lcd.write(0.0);
//方法2: 0改為5 120 lcd.print(" Arduino! "); 121 lcd.write(1); 122 123 } 124 125 void loop() { 126 // read the potentiometer on A0: 127 int sensorReading = analogRead(A0); 128 // map the result to 200 - 1000: 129 int delayTime = map(sensorReading, 0, 1023, 200, 1000); 130 // set the cursor to the bottom row, 5th position: 131 lcd.setCursor(4, 1); 132 // draw the little man, arms down: 133 lcd.write(3); 134 delay(delayTime); 135 lcd.setCursor(4, 1); 136 // draw him arms up: 137 lcd.write(4); 138 delay(delayTime); 139 }
筆者通過分析,和多處查閱資料。發現這是一個LiquidCrystal庫中的bug。原因與LiquidCrystal.h中關於unit8_t的定義有關。
<2>BUG的解決辦法
目前為止,筆者通過自己研究和多方查找資料,發現了三種可行的辦法,分別介紹如下:
1.將示例程序中119行中的lcd.write(0)改作lcd.write(0.0),在上文的實驗代碼中用紅字已經標注出。
2.將示例程序中lcd.createChar()函數構造自定義字符時,編碼從1開始,放棄0編碼。即將105行和119行的0改作5。同樣在上文的實驗代碼中用藍字已經標注出。
3.修改LiquidCrystal.h頭文件。這種方法雖然比較麻煩,但修改徹底,一勞永逸!示例代碼不用修改,實際應用也可直接從0開始編碼,強烈推薦這種方法!!!修改方法如下:
打開LiquidCrystal.h頭文件,注釋掉第85行的using Print::write。
如下圖所示:(筆者用NotePad++打開):