51單片機 | 實現SMG12864液晶顯示器操作


————————————————————————————————————————————

SMG12864液晶顯示器

  • 128*64個點位,可以顯示圖形或8*4個漢字

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

引腳功能:

基本結構:

  • 行驅動器:IC3
  • 列驅動器:IC1IC2
  • 128*64全點陣液晶顯示器

內部結構:IC1IC2IC3含有的主要功能器件

  • 指令寄存器 IR:寫指令時將指令存入IR
  • 數據寄存器 DR:寫數據時將數據存入DR
  • 忙標志 BFBF=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地址歸零。顯示屏幕的起始行由此指令控制。此模塊的DDRAM64行,屏幕可以循環滾動顯示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位)
  • 2 個字(對應字庫前 3~4 行)
    • 0 頁(字庫第 3 行)
      • 逐列顯示 17,18,19,20,21,22,23,24
    • 1 頁(字庫第 4 行)
      • 逐列顯示 25,26,27,28,29,30,31,32
  • ...
  • 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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

實現代碼:

 

  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, 0, 0 * 16, 0); //左屏,第0頁,  0列,第0個字
234             Display(2, 0, 1 * 16, 1); //左屏,第0頁, 16列,第1個字
235             Display(2, 0, 2 * 16, 2); //左屏,第0頁, 32列,第2個字
236             Display(2, 0, 3 * 16, 3); //左屏,第0頁, 48列,第3個字
237             Display(1, 0, 4 * 16, 4); //右屏,第0頁, 64列,第4個字
238             Display(1, 0, 5 * 16, 5); //右屏,第0頁, 80列,第5個字
239             Display(1, 0, 6 * 16, 6); //右屏,第0頁, 96列,第6個字
240             Display(1, 0, 7 * 16, 7); //右屏,第0頁,128列,第7個字
241             SelectScreen(0); //由於顯示后四個字符時左屏處於關顯示狀態,需要打開全屏
242             Delay(50);
243         }
244     }
245 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM