———————————————————————————————————————————— SMG12864液晶顯示器 128*64個點位,可以顯示圖形或8*4個漢字 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...
————————————————————————————————————————————
SMG12864液晶顯示器
- 128*64個點位,可以顯示圖形或8*4個漢字
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
引腳功能:
基本結構:
- 行驅動器:IC3
- 列驅動器:IC1,IC2
- 128*64全點陣液晶顯示器
內部結構:IC1,IC2,IC3含有的主要功能器件
- 指令寄存器 IR:寫指令時將指令存入IR
- 數據寄存器 DR:寫數據時將數據存入DR
- 忙標誌 BF:BF=1表示模塊在內部操作,此時不接收外部指令和數據。BF=0時為準備狀態,可以接收指令和數據
- 顯示控制觸發器 DDF:屏幕顯示開和關的控制,DFF=1開,DFF=0關
- 顯示數據記憶體 DDRAM:存儲圖形顯示數據
- XY地址計數器:9位計數器(高3位為X,低6位為Y)作為DDRAM指針,X只能通過指令設置,Y地址計數器具有指令迴圈功能,讀寫數據完成後Y地址自動+1
- Z地址計數器:6位計數器,用於顯示行掃描同步,完成一行掃描後Z地址自動+1,向下一行掃描。RST複位後,Z地址歸零。顯示屏幕的起始行由此指令控制。此模塊的DDRAM共64行,屏幕可以迴圈滾動顯示64行。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
操作時序:
讀操作時序圖:
寫操作時序圖:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
操作指令:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DDRAM與地址、顯示位置的關係 p.s.CS2對應左屏,CS1對應右屏
-
DDRAM與頁地址的對應關係
在圖中可以看到每個CS由8頁(64行)*64列組成
-
DDRAM與地址顯示位置的對應關係
- DDRAM與起始行對應關係
DDRAM行 |
62 |
63 |
0 |
1 |
... |
29 |
屏幕顯示行 |
1 |
2 |
3 |
4 |
... |
32 |
————————————————————————————————————————————
SMG12864液晶顯示器使用實例
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
設計要求:一行顯示八個字,滾動顯示
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
實現思路:
- 動態顯示:利用餘暉效應迴圈顯示八個漢字
- 滾動顯示:每次顯示完畢後在下一次迴圈中顯示在下一行(建立新的初始行,每次迴圈將初始行+1)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
主體模塊:
- 初始化LCD,清屏
-
動態顯示
-
滾動控制
- 開始行建立
- 開始行+1
-
漢字顯示
- 第一個字
- 第二個字
- ...
- 第八個字
- 全屏顯示
-
滾動控制
子模塊:
-
初始化
- 清屏
-
漢字顯示
- 選擇左右屏(前四個字在左屏,後四個字在右屏)
-
顯示字的上半部分
- 建立行(頁)
- 建立列
- 遍歷寫入字型檔對應位置
-
顯示字的下半部分
- 同上半部分
LCD基本操作:
-
讀狀態
- rs=0;rw=1;
-
do迴圈(BUSY為1忙碌時)
- P0置空
- 打開使能
- 讀入P0
- 關閉使能
- 檢測BF標誌位狀態(引腳DB7)
-
寫指令:
- 讀狀態
- rs=0;rw=0;
- 寫入指令
- E負跳變沿
-
寫數據
- 讀狀態
- rs=0;rw=1;
- 寫入數據
- E負跳變沿
-
選擇屏幕
- 全屏顯示:CS1/2=0;
- 右屏顯示(CS1控制):CS2高電平,CS1低電平
- 左屏顯示(CS2控制):CS1高電平,CS2低電平
-
清屏:
- 選擇全屏
-
迴圈遍歷8頁
- 建立該頁
- 建立第0行
- 遍歷該頁的所有列寫入內容
- 開始行建立:指令碼 11xxxxxx
- 行(頁)建立:指令碼 10111xxx
- 列建立:指令碼 01xxxxxx
- 顯示開閉:指令碼 0011111x
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
清屏過程:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字顯示過程:
-
第1個字(對應字型檔1~2行)
-
上半部分,第0頁(字型檔第1行)
- 逐列顯示 0,1,2,3,4,5,6,7(字型檔第0,1,2,3,4,5,6,7位)
-
下半部分,第1頁(字型檔第2行)
- 逐列顯示 0,1,2,3,4,5,6,7(字型檔第8,9,10,11,12,13,14,15位)
-
上半部分,第0頁(字型檔第1行)
-
第2個字(對應字型檔前3~4行)
-
第0頁(字型檔第3行)
- 逐列顯示 17,18,19,20,21,22,23,24
-
第1頁(字型檔第4行)
- 逐列顯示 25,26,27,28,29,30,31,32
-
第0頁(字型檔第3行)
- ...
-
第i個字(對應字型檔 i*2-1~i*2行)
-
第0頁(字型檔第 i*2-1行)
- 字型檔第 (i-1)*32,(i-1)*32+1,(i-1)*32+2,(i-1)*32+3...,(i-1)*32+7 位
-
第1頁(字型檔第 i*2行)
- 字型檔第 (i-1)*32+16,(i-1)*32+17,(i-1)*32+18,(i-1)*32+19...,(i-1)*32+31 位
-
第0頁(字型檔第 i*2-1行)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
實現代碼:
1 #include <reg52.h> 2 #include <intrins.h> 3 #define DATA P0 4 typedef unsigned char uchar; 5 sbit rs = P2 ^ 2; 6 sbit rw = P2 ^ 1; 7 sbit en = P2 ^ 0; 8 sbit cs1 = P2 ^ 4; 9 sbit cs2 = P2 ^ 3; 10 uchar code zhCN[] = 11 { 12 //每個位置占據1列8行 13 //第1個字 14 //上半部分:第1列,第2列,第3列...第8列 15 0x00, 0x04, 0x04, 0xC4, 0xB4, 0x8C, 0x87, 0x84, 0xF4, 0x84, 0x84, 0x84, 0x84, 0x04, 0x00, 0x00, 16 //下半部分 17 0x00, 0x00, 0x20, 0x18, 0x0E, 0x04, 0x20, 0x40, 0xFF, 0x00, 0x02, 0x04, 0x18, 0x30, 0x00, 0x00, 18 //第2個字 19 0x20, 0x20, 0x2A, 0x2A, 0xAA, 0x6A, 0x3E, 0x2B, 0xAA, 0xAA, 0xEA, 0xAA, 0x2A, 0x22, 0x20, 0x00, 20 0x82, 0x82, 0x45, 0x45, 0x25, 0x15, 0x0D, 0xFF, 0x04, 0x0C, 0x14, 0x24, 0x65, 0xC2, 0x42, 0x00, 21 //第3個字 22 0x00, 0x00, 0xF8, 0x48, 0x48, 0x48, 0x48, 0xFF, 0x48, 0x48, 0x48, 0x48, 0xF8, 0x00, 0x00, 0x00, 23 0x00, 0x00, 0x0F, 0x04, 0x04, 0x04, 0x04, 0x3F, 0x44, 0x44, 0x44, 0x44, 0x4F, 0x00, 0x70, 0x00, 24 //第4個字 25 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0xE2, 0x12, 0x0A, 0x06, 0x02, 0x00, 0x80, 0x00, 0x00, 26 0x01, 0x01, 0x01, 0x01, 0x01, 0x41, 0x81, 0x7F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 27 //第5個字 28 0x40, 0x20, 0xD0, 0x4C, 0x43, 0x44, 0x48, 0xD8, 0x30, 0x10, 0x00, 0xFC, 0x00, 0x00, 0xFF, 0x00, 29 0x00, 0x00, 0x3F, 0x40, 0x40, 0x42, 0x44, 0x43, 0x78, 0x00, 0x00, 0x07, 0x20, 0x40, 0x3F, 0x00, 30 //第6個字 31 0x20, 0x24, 0x2C, 0x35, 0xE6, 0x34, 0x2C, 0x24, 0x00, 0xFC, 0x24, 0x24, 0xE2, 0x22, 0x22, 0x00, 32 0x21, 0x11, 0x4D, 0x81, 0x7F, 0x05, 0x59, 0x21, 0x18, 0x07, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 33 //第7個字 34 0x00, 0x04, 0x04, 0x04, 0xFF, 0x54, 0x54, 0x54, 0x54, 0x54, 0xFF, 0x04, 0x04, 0x04, 0x00, 0x00, 35 0x11, 0x51, 0x49, 0x4D, 0x4B, 0x49, 0x49, 0x7D, 0x49, 0x49, 0x4B, 0x45, 0x4D, 0x59, 0x09, 0x00, 36 //第8個字 37 0x10, 0x10, 0x10, 0xFE, 0x10, 0x50, 0x40, 0xFE, 0x20, 0x20, 0xFF, 0x10, 0x10, 0xF8, 0x10, 0x00, 38 0x20, 0x20, 0x10, 0x1F, 0x08, 0x08, 0x00, 0x3F, 0x40, 0x40, 0x4F, 0x42, 0x44, 0x43, 0x70, 0x00 39 }; 40 void Delay(uchar m) 41 { 42 uchar i; 43 for (; m > 0; --m) 44 for (i = 0; i < 110; ++i) 45 ; 46 } 47 /* 檢查忙碌狀態 */ 48 void CheckState() 49 { 50 //通過讀取BF標誌位(引腳9,對應P0^7)狀態判斷模塊是否繁忙 51 uchar dat; 52 //讀狀態下RS=0,R/W=1,E=1 53 rs = 0; 54 rw = 1; 55 do 56 { 57 DATA = 0x00; //RST=0正常,BUSY=0準備狀態,ON/OFF=0顯示關, 58 en = 1; 59 _nop_(); //打開使能後檢測模塊狀態 60 dat = DATA; //狀態讀入dat 61 en = 0; 62 dat = 0x80 & dat; // 1000 0000 & dat 通過與操作隔離後7位,僅判斷最高位 63 } 64 while(dat != 0x00); //P0^7為0時跳出迴圈,BUSY=0準備狀態 65 } 66 /* 選擇要顯示的屏幕 */ 67 void SelectScreen(uchar screen) 68 { 69 //CS為低電平時亮 70 switch(screen) 71 { 72 case 0: //全屏顯示 73 cs1 = 0; //IC1控制右半屏 74 _nop_(); 75 _nop_(); 76 _nop_(); 77 cs2 = 0; //IC2控制左半屏 78 _nop_(); 79 _nop_(); 80 _nop_(); 81 break; 82 case 1: //右屏顯示 83 cs1 = 0; 84 _nop_(); 85 _nop_(); 86 _nop_(); 87 cs2 = 1; 88 _nop_(); 89 _nop_(); 90 _nop_(); 91 break; 92 case 2: //左屏顯示 93 cs1 = 1; 94 _nop_(); 95 _nop_(); 96 _nop_(); 97 cs2 = 0; 98 _nop_(); 99 _nop_(); 100 _nop_(); 101 break; 102 } 103 } 104 /* 寫命令操作 */ 105 void SendCommandToLCD(uchar com) 106 { 107 //p.s.在CS1或CS2低電平情況下才能寫入命令 108 CheckState(); 109 rs = 0; 110 rw = 0; 111 DATA = com; 112 en = 1; 113 _nop_(); 114 _nop_(); 115 en = 0; 116 } 117 /* 顯示開閉 */ 118 void SetOnOff(uchar onoff) 119 { 120 //傳入0,關顯示,00111110|00000000 = 00111110 121 //傳入1,開顯示,00111110|00000001 = 00111111 122 onoff = 0x3E | onoff; 123 SendCommandToLCD(onoff); //寫指令onoff 124 } 125 /* 行(頁)建立 */ 126 void SetLine(uchar page) 127 { 128 //10111000|00000000 = 10111000 129 //10111000|00000001 = 10111001 130 //10111000|00000010 = 10111010 131 //... 132 //10111000|00000111 = 10111111 133 //共8頁,設置頁地址 134 page = 0xb8 | page; 135 SendCommandToLCD(page); 136 } 137 /* 列建立 */ 138 void SetColumn(uchar column) 139 { 140 //01xxxxxx 後六位為列地址 141 //先通過與操作屏蔽前2位,將地址範圍限制在0-63之間 142 //再通過或操作將列操作指令前兩位代入 143 column = column & 0x3F; //00000000 & 00111111 = 00000000 144 column = 0x40 | column; //01000000 | 00000000 = 01000000 145 SendCommandToLCD(column); 146 } 147 /* 寫入數據 */ 148 void WriteByte(uchar dat) 149 { 150 CheckState(); 151 rs = 1; 152 rw = 0; 153 DATA = dat; 154 en = 1; 155 _nop_(); 156 _nop_(); 157 en = 0; 158 } 159 /* 清屏 */ 160 void ClearScreen(uchar screen) 161 { 162 uchar i, j; 163 SelectScreen(screen); 164 for (i = 0; i < 8; ++i) //書上源碼建立16頁,此處建立8頁正常運行 165 { 166 SetLine(i); //建立行 167 SetColumn(0); //建立列 168 for (j = 0; j < 64; ++j) //通過遍歷該行的64列寫入內容,列地址自動+1 169 WriteByte(0x00); 170 } 171 } 172 /* 設置開始行 */ 173 void SetStartLine(uchar startline) 174 { 175 //設置開始行時前兩位為11 176 startline = 0xC0 | startline; 177 SendCommandToLCD(startline); 178 } 179 /* 初始化 */ 180 void InitLCD() 181 { 182 CheckState(); //檢查LCD狀態,是否繁忙,每次操作前都要進行檢查 183 SelectScreen(0); //全屏顯示,將要顯示的屏幕部分置為低電平 184 SetOnOff(0); //關顯示,1為開顯示,0位關顯示 185 SelectScreen(0); 186 SetOnOff(1); //開顯示 187 SelectScreen(0); 188 ClearScreen(0); //0清全屏,1清左屏,2清右屏 189 SetStartLine(0); //從第0行開始 190 } 191 /* 顯示漢字 */ 192 void Display(uchar screen, uchar page, uchar column, uchar num) 193 { 194 uchar i; 195 SelectScreen(screen); //選擇對應要亮的屏 196 /* 顯示字的上半部分 */ 197 SetLine(page); //建立行(頁) 198 column = column & 0x3F; // column & 00111111 屏蔽前兩位 199 SetColumn(column); //建立列 200 //寫入字型檔第32*num~32*num+16位的數據 201 //第1個字:0~15,對應字型檔第1行 202 //第2個字:32~47,對應字型檔第3行 203 //第3個字:64~79,對應字型檔第5行 204 //... 205 for (i = 0; i < 16; ++i) 206 WriteByte(zhCN[i + 32 * num]); 207 /* 顯示字的下半部分 */ 208 SetLine(page + 1); 209 SetColumn(column); 210 //寫入字型檔第32*num+16~32*num+32位的數據 211 //第1個字:16~31,對應字型檔第2行 212 //第2個字:48~63,對應字型檔第4行 213 //第3個字:80~95,對應字型檔第6行 214 //... 215 for (i = 0; i < 16; ++i) 216 WriteByte(zhCN[i + 32 * num + 16]); 217 } 218 /* 主函數 */ 219 int main() 220 { 221 uchar i; 222 /* 初始化LCD,書上進行了一系列初始化操作,僅清屏的話不影響運行結果 */ 223 // InitLCD(); 224 ClearScreen(0); //清屏 225 /* 動態顯示 */ 226 while(1) //餘暉效應 227 { 228 for (i = 0; i < 64; ++i) //如果此處改成10,則在向上移動10行後重新出現在第0行,此處使用64的倍數來實現無限迴圈(無間斷),書上源碼迴圈128次,64次也無影響 229 { 230 /* 滾動控制 */ 231 SetStartLine(i); //迴圈建立開始行,每一次迴圈都上移1行 232 /* 漢字顯示 */ 233 Display(2,