這幾日在倒騰新到的Arduino,比起普通單片機來,感受寫程序太簡單了。不過和外設打交道仍是沒那麼容易,好比今天要說的看似簡單的LCD1602液晶,卻費了我一成天才基本搞懂,不過仍是有一個小問題沒有實現/解決。好在不怎麼用那個功能,就沒有再去深究。css
其實以前作課設時接觸過LCD1602,不過那時用的是51,並且是八位數據線接法,當時就挺苦惱1602的連線的,16根連線在板子上飛,那叫壯觀。因此,今天我特意實現並搞懂了LCD1602的四位數據線接法,並完成了驅動程序,除了那個讀數據的功能沒有實現。html
假定你們對LCD1602已經有了必定認識,咱們就先來看下LCD1602的指令:git
序號編程 |
指令electron |
RS函數 |
R/Woop |
D7ui |
D6spa |
D5指針 |
D4 |
D3 |
D2 |
D1 |
D0 |
1 |
清顯示 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
2 |
光標返回 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
* |
3 |
輸入模式設置 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
I/D |
S |
4 |
顯示開關控制 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
D |
C |
B |
5 |
光標或者字符移位 |
0 |
0 |
0 |
0 |
0 |
1 |
S/C |
R/L |
* |
* |
6 |
功能設置 |
0 |
0 |
0 |
0 |
1 |
DL |
N |
F |
* |
* |
7 |
字符發生儲存器地址設置 |
0 |
0 |
0 |
1 |
字符發生儲存器地址 |
|||||
8 |
數據儲存器地址設置 |
0 |
0 |
1 |
顯示數據儲存器地址 |
||||||
9 |
讀忙標誌和地址 |
0 |
1 |
BF |
計數器地址 |
||||||
10 |
寫數到CGRAM(or DDRAM) |
1 |
0 |
要寫的數據內容 |
|||||||
11 |
從CGRAM或DDRAM讀數據 |
1 |
1 |
讀出的數據內容 |
關於對上表格的具體代碼說明:1602液晶模塊的讀寫操做、屏幕和光標的操做都是經過指令編程來實現的。(說明:1爲高電平、0爲低電平)
指令1:清顯示,指令碼01H,光標復位到地址00H位置。
指令2:光標復位,光標返回到地址00H。
指令3:光標和顯示模式設置
I/D:光標移動方向,高電平右移,低電平左移
S:屏幕上全部文字是否左移或者右移。高電平表示有效,低電平則無效。
指令4:顯示開關控制。
D:控制總體顯示的開與關,高電平表示開顯示,低電平表示關顯示
C:控制光標的開與關,高電平表示有光標,低電平表示無光標
B:控制光標是否閃爍,高電平閃爍,低電平不閃爍。
指令5:光標或顯示移位
S/C:高電平時移動顯示的文字,低電平時移動光標。
指令6:功能設置命令
DL:高電平時爲4位總線,低電平時爲8位總線
N:低電平時爲單行顯示,高電平時雙行顯示
F: 低電平時顯示5×7的點陣字符,高電平時顯示5×10的點陣字符。
指令7:字符發生器RAM地址設置。
指令8:DDRAM地址設置。
指令9:讀忙信號和光標地址
BF:爲忙標誌位,高電平表示忙,此時模塊不能接收命令或者數據,若是爲低電平表示不忙。
指令10:寫數據。
指令11:讀數據。
可能你們看了上表有些困惑,怎麼用呢?其實就是幾條不重疊的指令,若是你想要設置成你本身的風格,對應上表指令填充好指定的位後換算成2位16進制,0xFF的形勢。而後在初始化函數中或者顯示以前對1602輸出該指令,便可達到效果。可是上面那麼多設置,有好多指令,怎麼分前後呢?這點我不是很清楚,也沒有去嘗試,通常的手冊給出了1602初始化指令的順序,以下:
至此,初始化完成。
注意:以上1~6條照寫,8~12條則根據本身狀況寫。好比,我要用四位數據總線鏈接LCD1602顯示,則第8條指令相應改成28H。若是要顯示並閃爍光標,12條相應改成0FH。而且,若是想要在使用中對LCD1602設置進行修改,可隨時對其賦相應指令。
同時給出LCD1602時序圖,供你們參考。
讀狀態 輸入:RS=L,R/W=H,E=H 輸出:D0—D7=狀態字
寫指令 輸入:RS=L,R/W=L,D0—D7=指令碼,E=高脈衝 輸出:無
讀數據 輸入:RS=H,R/W=H,E=H 輸出:D0—D7=數據
寫數據 輸入:RS=H,R/W=L,D0—D7=數據,E=高脈衝 輸出:無
下面給出LCD1602的四位數據線接法的驅動函數。
1: /***************************************************************
2: * LCD1602 四位數據線鏈接驅動+實例 For Arduino
3: *
4: *主要實現了在Arduino下四位數據線鏈接LCD1602液晶顯示,未實現數據讀取。
5: (這方面的資料網上彷佛不多,反正我是沒找到。手冊也是五花八門,
6: 未見其介紹如何在四位數據線鏈接下獲取LCD1602的數據。)
7: 代碼中除函數Init_LCD1602中延遲時間較標準外,其它未予深究,
8: 請不要以此拍磚。另外,寫指令和寫數據函數
9: 中的方法引自他處,雖有些晦澀,不過理解後感受挺精妙的,就沒有改。
10: 若要更換顯示風格設置,請自行修改初始化函數中的內容。
11: *做者:Wave
12: *聯繫方式:sxwangbo@live.com
13: *日期:2013年8月9日
14: ***************************************************************/
15:
16: /*若是要更改此三處引腳,請在初始化函數Init_LCD1602()
17: *或setup()中手動指定所用引腳爲輸出模式。這裏的排序可能有點坑爹。
18: *開始是爲了對應Arduino的LCD1602庫的腳排序,方便調試。後來就沒有改。*/
19: int LCD1602_RS=12;
20: int LCD1602_RW=10;
21: int LCD1602_EN=11;
22: //要求四腳連續並從小到大排序,依次對應LCD1602的D七、D六、D五、D4腳。
23: int DB[] = {2,3,4,5};
24: char str1[]="Welcome to";
25: char str2[]="Matrix.Studio";
26: char str3[]="It's My Arduino.";
27: char str4[]="Do U think of it?";
28: char str5[]="Arduino is a single-board microcontroller to "+
29: "make using electronics in multidisciplinary projects "+
30: "more accessible. The hardware consists of a simple open "+
31: "source hardware board designed around an 8-bit Atmel AVR "+
32: "microcontroller, or a 32-bit Atmel ARM. The software "+
33: "consists of a standard programming language compiler "+
34: "and a boot loader that executes on the microcontroller. ";
35:
36:
37: //判斷LCD1602是否忙,遇忙等待
38: void Check_LCD1602_Busy()
39: {
40: digitalWrite(LCD1602_RS,LOW);
41: digitalWrite(LCD1602_RW,HIGH);
42: digitalWrite(LCD1602_EN,HIGH);
43: pinMode(DB[0],INPUT);
44: while(digitalRead(DB[0])==HIGH);
45: pinMode(DB[0],OUTPUT);
46: digitalWrite(LCD1602_EN,LOW);
47: return;
48: }
49:
50: //給LCD1602寫指令
51: void Write_LCD1602_Command(int data)
52: {
53: Check_LCD1602_Busy();
54: Write_LCD1602_Init_Command(data);
55: }
56:
57: //給LCD1602寫指令,未檢測忙狀態,僅供初始化用
58: void Write_LCD1602_Init_Command(int command)
59: {
60: int i,temp;
61: digitalWrite( LCD1602_RS,LOW);
62: digitalWrite( LCD1602_RW,LOW);
63: digitalWrite( LCD1602_EN,LOW);
64:
65: temp=command & 0xf0;
66: for (i=DB[0]; i < DB[0]+4; i++)
67: {
68: digitalWrite(i,temp & 0x80);
69: temp <<= 1;
70: }
71:
72: digitalWrite( LCD1602_EN,HIGH);
73: delayMicroseconds(1);
74: digitalWrite( LCD1602_EN,LOW);
75:
76: temp=(command & 0x0f)<<4;
77: for (i=DB[0]; i < DB[0]+5; i++)
78: {
79: digitalWrite(i,temp & 0x80);
80: temp <<= 1;
81: }
82:
83: digitalWrite( LCD1602_EN,HIGH);
84: delayMicroseconds(1);
85: digitalWrite( LCD1602_EN,LOW);
86: }
87:
88: //寫數據到LCD1602上。
89: void Write_LCD1602_Data(int data)
90: {
91: Check_LCD1602_Busy();
92: int i=0,temp;
93: digitalWrite( LCD1602_RS,HIGH);
94: digitalWrite( LCD1602_RW,LOW);
95: digitalWrite( LCD1602_EN,LOW);
96:
97: temp=data & 0xf0;
98: for (i=DB[0]; i < DB[0]+4; i++)
99: {
100: digitalWrite(i,temp & 0x80);
101: temp <<= 1;
102: }
103:
104: digitalWrite( LCD1602_EN,HIGH);
105: delayMicroseconds(1);
106: digitalWrite( LCD1602_EN,LOW);
107:
108: temp=(data & 0x0f)<<4;
109: for (i=DB[0]; i < DB[0]+5; i++)
110: {
111: digitalWrite(i,temp & 0x80);
112: temp <<= 1;
113: }
114:
115: digitalWrite( LCD1602_EN,HIGH);
116: delayMicroseconds(1);
117: digitalWrite( LCD1602_EN,LOW);
118: }
119:
120: //清除指定屏幕區域內容,即以空格填充
121: void Clear_LCD1602_Display(int x, int y, int length)
122: {
123: int i=0;
124: Write_LCD1602_Command(0x80 + 0x40*x + y);
125: for(i=y;i<length;i++)
126: Write_LCD1602_Data(0x20);//0x20爲空格對應ASCII碼
127: }
128:
129: //將指定字符輸出到LCD1602上。
130: //其中x爲行(0~1),y爲列(0~15),data爲指定字符
131: void Write_LCD1602_Char(int x, int y, int data)
132: {
133: Write_LCD1602_Command(0x80 + 0x40*x + y);
134: Write_LCD1602_Data(data);
135: }
136:
137: //將指定字符串輸出到LCD1602上。
138: //其中x爲行(0~1),y爲列(0~15),*s爲指定字符串指針
139: void Write_LCD1602_String(int x,int y,char *s)
140: {
141: Write_LCD1602_Command(0x80 + 0x40*x + y);
142: while (*s) //寫字符串
143: {
144: Write_LCD1602_Data(*s);
145: s ++;
146: }
147: }
148:
149: //將指定文段輸出顯示到LCD1602上。
150: //其中x爲行(0~1),y爲列(0~15),*s爲指定字符串指針
151: void Write_LCD1602_Paragraph(int x, int y, char *s)
152: {
153: Write_LCD1602_Command(0x0F);
154: Write_LCD1602_Command(0x80 + 0x40*x + y);
155: while (*s) //寫字符串
156: {
157: Write_LCD1602_Data(*s);
158: s ++;
159: if(*s==' ')
160: delay(500);
161: if(y++==15)
162: {
163: Write_LCD1602_Command(0xC0);
164: }
165: if(y==32)
166: {
167: delay(1000);
168: Write_LCD1602_Command(0x01);
169: Write_LCD1602_Command(0x80);
170: y=0;
171: }
172: delay(100);
173: }
174: Write_LCD1602_Command(0x0E);
175: delay(3000);
176: }
177:
178: //較標準的LCD1602初始化函數
179: void Init_LCD1602()
180: {
181: int i = 0;
182: for (i=DB[0]; i < DB[0]+4; i++)
183: {
184: pinMode(i,OUTPUT);
185: }
186: for (i=10; i < 13; i++)
187: {
188: pinMode(i,OUTPUT);
189: }
190:
191: delay(15);
192: Write_LCD1602_Init_Command(0x38);
193: delay(5);
194: Write_LCD1602_Init_Command(0x38);
195: delay(5);
196: Write_LCD1602_Init_Command(0x38);
197:
198: Write_LCD1602_Command(0x28); //4位數據線
199: Write_LCD1602_Command(0x08); //關閉顯示
200: Write_LCD1602_Command(0x01); //清除屏幕內容
201: Write_LCD1602_Command(0x06); //光標右移,文字不移
202: Write_LCD1602_Command(0x0F); //打開顯示,顯示光標且閃爍
203: }
204:
205: void setup (void)
206: {
207: Init_LCD1602();
208: delay(50);
209: }
210:
211: void loop (void)
212: {
213: //清屏
214: Write_LCD1602_Command(0x01);
215: Write_LCD1602_String(0,0,str1);//第1行,第4個地址起
216: delay(50);
217: Write_LCD1602_String(1,0,str2);//第2行,第2個地址起
218: delay(2000);
219: Write_LCD1602_Command(0x01);
220: delay(50);
221: Write_LCD1602_String(0,0,str3);
222: delay(50);
223: Write_LCD1602_String(1,0,str4);
224: delay(2000);
225: Write_LCD1602_Command(0x01);
226: delay(50);
227: Write_LCD1602_Paragraph(0,0,str5);
228: }