芭乐推广APP网站入口官网_芭乐视频在线下载_芭乐APP色版_芭乐视频在线播放

歡迎訪問杭州精顯科技有限公司液晶顯示屏網(wǎng)站! 設(shè)為首頁 | 收藏本站| 網(wǎng)站地圖
全國統(tǒng)一服務(wù)熱線
15382323032
?

技術(shù)知識(shí)

您只需一個(gè)電話我們將推薦性價(jià)比高的液晶屏產(chǎn)品選型,讓您花合理的價(jià)格,達(dá)到預(yù)期的效果

全國統(tǒng)一服務(wù)熱線
15382323032

產(chǎn)品動(dòng)態(tài)

聯(lián)系我們

全國統(tǒng)一服務(wù)熱線:

15382323032

客服QQ:3234659108

手機(jī):15382323032

地址:浙江省杭州市余杭區(qū)五常街道西溪軟件園金牛座B2座4層4118-4119

當(dāng)前位置: 主頁 > 資訊中心 > 技術(shù)知識(shí) > >

在點(diǎn)陣屏上面繪圖—LCD12864控制的詳解

文章出處:原創(chuàng) 人氣:發(fā)表時(shí)間:2017-08-28


怎樣在點(diǎn)陣屏上繪圖——基于LCD12864

LCD12864:12864液晶屏

   — 預(yù)備知識(shí) — 
其實(shí),本文應(yīng)該算是計(jì)算機(jī)圖形學(xué)中的一個(gè)具體分支,所以,計(jì)算機(jī)圖形學(xué)的最基本要求就是本文的基本要求了,由于考慮到各位大兄弟的胃口,我就多啰嗦下。 

1、位操作 
像LCD12864這一種二值屏幕,我們往往習(xí)慣于使用1個(gè)字節(jié)表示連續(xù)的8個(gè)點(diǎn),1對(duì)應(yīng)的對(duì)應(yīng)位被點(diǎn)亮,0則表示不亮,所以對(duì)于圖形的操作最基本的手段那就是位操作了。 
復(fù)習(xí)一下常用的位操作,假設(shè)Dis表示是某一個(gè)現(xiàn)存地址的內(nèi)容 
Dis = Dis~     黑白顛倒 
Dis &= ~(1<<n) 第n處被擦去, 
Dis |= (1<<n)   第n處被畫了一個(gè)點(diǎn) 
Dis ^= (1<<n)   如果n處是亮的,就變被擦掉;如果n處是空白的,就被點(diǎn)亮了…… 
…… 差不多也就是這些 

2、作圖的原理 
點(diǎn)是一切光柵顯示設(shè)備最基本的要素,所有的操作也都是以點(diǎn)為基礎(chǔ)的,所以要學(xué)會(huì)如何去利用點(diǎn)構(gòu)成線、圓、填充就是必須要掌握的——幾何不能夠太差。 
還有,結(jié)合屏幕硬件的特點(diǎn),對(duì)于算法進(jìn)行優(yōu)化的一些方法也是需要去掌握的。比方說:如何填充之類的……后面還會(huì)針對(duì)于LCD12864來作詳細(xì)的介紹。 

3、人機(jī)交互學(xué) 
雖然說很多的人都沒有去實(shí)實(shí)在在的學(xué)過這門功課,但是多多少少還是對(duì)于界面應(yīng)該都有些許了解。如何去利用手中的基本操作函數(shù)來做出一些特效?如何安排窗體?如何繪制圖形界面的一些基本元素,例如按鈕,
甚至如何的顯示漢字,都是人際交互學(xué)需要教會(huì)你的——總而言之,如果你是沒有學(xué)過這一門課程,你的產(chǎn)品 只有你自己一個(gè)人用的話——那就跟著感覺走,沒錯(cuò)的。 

4、最最重要的物質(zhì)基礎(chǔ) 
你需要掌握一種單片機(jī),掌握到一種點(diǎn)陣屏幕。 

怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
Chapter One  

— 從點(diǎn)滴開始 —  



前面就已經(jīng)說過了,對(duì)于柵格的顯示設(shè)備來說,點(diǎn)是一切圖形的基礎(chǔ),說白了,不會(huì)在液晶屏幕的任意位置隨心所欲的畫點(diǎn)就不能夠說你已經(jīng)掌握了某一種液晶屏幕的使用了。事實(shí)上,根據(jù)筆者的一些經(jīng)驗(yàn),嘗試畫點(diǎn)
往往就能暴露出很多的問題。就拿LCD12864來說,一段時(shí)間,筆者經(jīng)常發(fā)現(xiàn),在片切換的地方就會(huì)有一點(diǎn)點(diǎn)錯(cuò)誤…… 



在說明如何畫點(diǎn)之前我先說明一個(gè)概念:顯示緩沖區(qū)。 

所謂的顯示緩沖區(qū),顧名思義,它就是顯示數(shù)據(jù)的一個(gè)緩沖地帶罷了。在一般情況下,我們繪圖也是直接的對(duì)
這塊緩沖區(qū)域進(jìn)行操作。 

很多朋友現(xiàn)在就要提問了:我們?yōu)槭裁床恢苯拥膶?duì)屏幕進(jìn)行操作呢? 

事實(shí)上,LCD本身就存在著一塊顯示存儲(chǔ)器,也可以被認(rèn)為是一個(gè)顯示緩存,直接寫在這個(gè)存儲(chǔ)器上的數(shù)據(jù)并非是直接顯示出來的,而多半是需要一個(gè)顯示指令來影射一下。我們有的時(shí)候也會(huì)通過這種類似的技術(shù)來實(shí)現(xiàn)很大的圖片顯示——先畫好,然后再拿給大家看,讓人以為你是一下就畫好了的,當(dāng)然如果你刻意的需要那種圖片被“畫”出來的效果,則不在討論之列了。問題就在于,LCD是片外的資源,對(duì)其存儲(chǔ)器的訪問可以被認(rèn)為是對(duì)片外存儲(chǔ)器的訪問,其速度顯然是沒有對(duì)片內(nèi)SRAM的操作速度快。如果我們使用的是那種常用的串行方式來作圖(所謂串行方式作圖,就是繪圖指令的執(zhí)行和系統(tǒng)的其他操作是串行的,指令不完成,其它的操作就不會(huì)被執(zhí)行),那么對(duì)于一些實(shí)時(shí)性要求比較高的系統(tǒng)來說就會(huì)造成一些重大的隱患——甚至是不符合要求的;如果開辟一段片內(nèi)存儲(chǔ)空間和LCD的存儲(chǔ)器一一對(duì)應(yīng),在相同的時(shí)間段之內(nèi),花費(fèi)相同的資源來保持這兩個(gè)存儲(chǔ)空間的一致性,那么就可以保證實(shí)時(shí)系統(tǒng)的穩(wěn)定和可靠了,保證畫面顯示的正常(因?yàn)樵试S跳幀嘛^_^ )。這就是我們?yōu)槭裁催€需要另外在片內(nèi)選取一個(gè)顯示緩沖區(qū)的原因了。 

以后,我們的操作都是針對(duì)于顯示緩沖區(qū)的。顯示緩沖區(qū)將會(huì)成為一個(gè)概念,無論這個(gè)緩沖區(qū)位于SRAM內(nèi)還是LCD的內(nèi)部。比方說,我們現(xiàn)在需要一個(gè)低成本的游戲機(jī) ——比如做一個(gè)貪食蛇游戲機(jī)送給老師作為課程設(shè)計(jì),或者是送給小侄子,那么,M8甚至是M48將會(huì)成為首選,問題是,M8是絕對(duì)無法開辟出一個(gè)8 * 128 = 1K大小的數(shù)組,所以,在這個(gè)時(shí)候,認(rèn)定LCD的片內(nèi)存儲(chǔ)器作為顯示緩沖區(qū)就是不二的選擇——好在貪食蛇的速度太快了也沒有辦法玩哈。 



繞了這么多的彎子,究竟如何去畫點(diǎn)呢?我還想多補(bǔ)充一個(gè)原因,關(guān)于,為什么需要顯示緩沖區(qū),由于點(diǎn)陣屏使用的是1個(gè)字節(jié)來表示8個(gè)點(diǎn)的,如果你想使得其中一個(gè)字節(jié)中的某一個(gè)點(diǎn)被操作而不影響到別的點(diǎn),你起碼要知道原來這個(gè)位置是顯示的什么內(nèi)容,對(duì)于有一些使用595級(jí)聯(lián)的LCD設(shè)備來說,無法直接從LCD讀取現(xiàn)存的數(shù)據(jù),所以開辟了一個(gè)緩沖區(qū),從中獲得信息加以加工以后再放回去,是這種設(shè)備處理顯示圖形的唯一方法——當(dāng)然我們還沒有那么慘,但是從LCD中獲取所需點(diǎn)所在字節(jié)的內(nèi)容還是必須的,不然你畫一個(gè)點(diǎn)就會(huì)破壞其一條線上所有的數(shù)據(jù)。 



   好的,那么我們實(shí)際上已經(jīng)明確了如何去畫一個(gè)點(diǎn)。 

   首先,根據(jù)用戶給出的坐標(biāo)計(jì)算出所要畫的點(diǎn)所在現(xiàn)存內(nèi)的地址偏移量; 

   然后,我們讀出該地址內(nèi)的數(shù)據(jù); 

   再次,根據(jù)用戶所需畫點(diǎn)的類型(擦除、畫點(diǎn)、反相點(diǎn))來進(jìn)行相應(yīng)的操作獲得一個(gè)新的數(shù)據(jù); 

   最后,將該數(shù)據(jù)寫回原來的地址。 



   不是很難吧? 

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

LCD12864補(bǔ)充知識(shí) 

1、關(guān)于坐標(biāo)系。很多人,包括筆者,一開始都看不懂LCD12864的內(nèi)存影射方式,感覺X、Y似乎不是那么回事。后來才發(fā)現(xiàn),只要把屏幕豎著放一切就好懂了。X還是橫軸,Y還是豎軸……但是這顯然不符合我們的習(xí)慣,我們習(xí)慣于長的那個(gè)邊作為橫軸,所以需要一點(diǎn)點(diǎn)坐標(biāo)之間的轉(zhuǎn)換。 

假設(shè)輸入的是正常習(xí)慣的坐標(biāo) X,Y DX DY就是LCD上的坐標(biāo),那么轉(zhuǎn)換關(guān)系是 



char DX = (Y >> 3);                               //計(jì)算出屬于哪個(gè)字節(jié) 

char BX = Y - (DX << 3);                             //屬于該字節(jié)的哪個(gè)位 

char DY = X; 



2、讀取12864的數(shù)據(jù)的時(shí)候,一定要注意,E信號(hào)要在一個(gè)下降延之后持續(xù)拉高,然后才能正常獨(dú)處數(shù)據(jù);假設(shè)直接拉高,的確也能讀出數(shù)據(jù),但是,等著抓頭皮,發(fā)帖子“[跪求]大俠幫忙關(guān)于12864——請(qǐng)使用明確的大標(biāo)題……”^_^ 



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

廢話少說(說的不少了),看源代碼: 

# define LCD12864_Graphic_Draw          0x01 

# define LCD12864_Graphic_Clear           0x00 

# define LCD12864_Graphic_Not          0x02 



…… 



void LCD12864Draw(char X,char Y,char Type) 



char DX = (Y >> 3);                               //計(jì)算出屬于哪個(gè)字節(jié) 

       char BX = Y - (DX << 3);                      //計(jì)算出屬于字節(jié)哪一位 

       char TempData = 0; 



       LCD12864_ChooseBoth; 

      

       setX(DX); 

       if (X > 63) 

       { 

         LCD12864_ChooseCS2; 

            X -= 64; 

       } 

       else 

       { 

         LCD12864_ChooseCS1; 

       } 

       setY(X); 

      

       TempData = getLCD12864Data(); 

      

       switch (Type) 

       { 

         case LCD12864_Graphic_Clear: 

                   TempData &= ~(1<<BX); 

                   break; 

            case LCD12864_Graphic_Not: 

                   TempData ^= (1 << BX); 

                   break; 

            default: 

                   TempData |= (1 << BX);  

       } 

      

setY(X); 

      

       sendDataToLCD(TempData); 

}

12864圖形屏
怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
特別說明一下,關(guān)于貪食蛇范例的問題,這篇文章里面只會(huì)簡(jiǎn)單得提及一下。 

作為嵌入式系統(tǒng)開發(fā)的一個(gè)范例,我會(huì)另外開一個(gè)帖子詳細(xì)說明開發(fā)過程。 
這個(gè)范例將作為介紹嵌入式系統(tǒng)開發(fā)方法的一個(gè)很好的例子,用于解釋一個(gè)系統(tǒng)和一段表示您調(diào)通了某一個(gè)功能的代碼之間有什么區(qū)別,同時(shí)也將介紹嵌入式開發(fā)系統(tǒng)的幾種模式(超級(jí)循環(huán)、調(diào)度器),順便侃一侃時(shí)間驅(qū)動(dòng)的系統(tǒng)RTOS (Real Time Operation System實(shí)時(shí)操作系統(tǒng))和RTS(Real Time System)實(shí)時(shí)系統(tǒng)。
怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
[本章導(dǎo)讀] 

直線由點(diǎn)構(gòu)成,更精確的說,直線是由靠近這條線的像素構(gòu)成。這就引出一個(gè)問題,究近那些點(diǎn)算是靠近一條直線;哪些點(diǎn)不算是靠近一條直線,這必須使用一種算法作為依據(jù)。實(shí)際上,圖形學(xué)算法和純幾何算法還是有很大差別的,問題就出在一個(gè)離散化上面,說白了,你畫出的直線很可能是一組波動(dòng)厲害的鋸齒象素群而不是一條看起來有規(guī)則變化的直線。 
當(dāng)然,太過于理論的東西對(duì)我們是沒有多少實(shí)際價(jià)值的。下面,我就介紹兩種常見的畫線思路,一種就是最容易被想到的直線方程計(jì)算的方法,另外一種則是被稱為布蘭森漢姆(Bresenham)的計(jì)算機(jī)圖形學(xué)主流算法。 
   
在介紹完這兩種算法以后,我們會(huì)針對(duì)LCD12864的硬件結(jié)構(gòu)為例子,介紹,具體算法的實(shí)現(xiàn)和優(yōu)化。
怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
首先,我們從最基本的數(shù)學(xué)算法說起。 
如果我們使用公式y(tǒng) = kx + b來作為繪圖的依據(jù),那么就需要分3種情況:水平直線,斜率為0;垂直直線,斜率為五窮達(dá)(或者說k不存在);普通直線。 
假設(shè)我們已經(jīng)知道直線的起始坐標(biāo)點(diǎn)(Xbegin,Ybegin)和終點(diǎn)(Xend,Yend),x,y,是當(dāng)前的坐標(biāo)點(diǎn),如果我們通過增加x反算出y的方法的話,這個(gè)公式就可以很容易轉(zhuǎn)換為偽代碼。 
LineMode 為直線的類型:水平,垂直,普通 
if Xbegin == Xend then LineMode = 水平 
elseif Ybegin = Yend   then LineMode = 垂直 
else k = (Yend - Ybegin) / (Xend - Xbegin) 

switch LineMode 
   case 水平 
      for x = Xbegin to Xend 
         在x,Ybegin處畫點(diǎn) 
   case 垂直 
      for y = Ybegin to Yend 
         在Ebegin,y處畫點(diǎn) 
   default: 
      for x = Xbegin to Xend 
      { 
         y = kx + b 
         在x,y處畫點(diǎn) 
      } 

非常簡(jiǎn)單,不是么?注意,大部分情況下,這個(gè)算法存在很多乘法和除法,對(duì)單片機(jī)系統(tǒng)來說,可能不是那么合適哦。畫出的點(diǎn)也基本令人滿意。
怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
有了上面的代碼墊底,我想很多人都可以放心了,因?yàn)榇蟛涣伺芤粋€(gè)高速晶振也能快速的畫出直線,否則你還需要耐心的閱讀下面的算法。 

首先,我們給出這個(gè)算法的偽代碼。 
在(x1,y1)到(x2,y2)之間畫一條直線 

dx 是x到終點(diǎn)橫坐標(biāo)的距離 
dy 是y到終點(diǎn)縱坐標(biāo)的距離 
ix 是dx的絕對(duì)值 
iy 是dy的絕對(duì)值 
inc是dx和dy中較大的那個(gè) 
plot是是否要畫一個(gè)點(diǎn)的標(biāo)志位,boolean變量 

plotx 是當(dāng)前點(diǎn)所在的橫坐標(biāo) 
ploty 是當(dāng)前點(diǎn)所在的縱坐標(biāo) 
  
plotx = x1 
ploty = y1 
x = 0 
y = 0 

在 plotx,ploty畫一個(gè)點(diǎn)——起點(diǎn) 

for i = 0 to inc 增量1 
   x += ix 
   y += iy 
   plot = false 

   if x > inc then 
          plot = true 
          x -= inc 
            if dx > 0 then plotx ++ 
            if dx < 0 then plotx -- 
  
   if y > inc then 
          plot = true 
          y -= inc 
            if dy > 0 then ploty ++ 
            if dy < 0 then ploty -- 

   if plot == true then 在(plotx,ploty)處畫點(diǎn) 
這就是計(jì)算機(jī)圖形學(xué)中流行的布蘭森漢姆(Bresenham)算法,他的意圖就是采用離散的整數(shù)增量來代替斜率增量計(jì)算,學(xué)習(xí)這個(gè)算法,最好的方法不是看多少理論,而是按照上面的偽代碼自己完成一條直線的繪制工作,你就能心領(lǐng)神會(huì)了——不是小弟我偷懶。 

所有的計(jì)算都是簡(jiǎn)單得整數(shù)計(jì)算,代碼效率自然不用小弟我羅嗦哈。
怎樣在點(diǎn)陣屏上繪圖——基于LCD12864
俗語說,巧婦難為無米之炊,有了點(diǎn)再有了直線算法,距離窗體的繪制不遠(yuǎn)了,But Stop! “沒有最好,但求更好”這是我們做系統(tǒng)開發(fā)應(yīng)該謹(jǐn)記的一條準(zhǔn)則。 
有了上面的算法還不夠,畢竟,他們只是一些偽代碼,針對(duì)不同的屏幕——準(zhǔn)確地說,是針對(duì)不同的顯存映射方式,有不同的算法優(yōu)化方法。究竟有哪些優(yōu)化方法暫且不論,其實(shí)他們都是一個(gè)原理,我想先解釋一下,為什么我們需要優(yōu)化算法,或者說,我們需要先弄清楚是什么地方產(chǎn)生了冗余。 

還記得黑白點(diǎn)陣屏幕的顯存映射方式么?它簡(jiǎn)單的使用1個(gè)字節(jié)表示8個(gè)坐標(biāo)點(diǎn),同時(shí)這1個(gè)字節(jié)是沿著屏幕的短邊方向映射的,所以當(dāng)我們想畫一條垂直的直線時(shí),對(duì)于每一個(gè)牽涉到的字節(jié)都有可能要重復(fù)的操作8次之多,這種操作不是簡(jiǎn)單的畫線,而是要先讀取再計(jì)算最后再寫這樣的復(fù)合操作,重復(fù)8次只是為了把整個(gè)字節(jié)變黑顯然是一種超級(jí)不可容忍的冗余——大家都知道,直接把這個(gè)字節(jié)讀取一次,計(jì)算一次,再寫一次就完成了?;谶@種思想,我們需要把這種特殊情況單獨(dú)提取出來,重新優(yōu)化代碼……具體優(yōu)化代碼就留給大家做作業(yè)了哈。 

同時(shí)補(bǔ)充一下,這樣做,不是只對(duì)畫線作了優(yōu)化,事實(shí)上,在后面,矩形的填充里面,這種優(yōu)化會(huì)極大地提高速度,因?yàn)樘畛涞谋举|(zhì)就是畫線(點(diǎn))…… 
 

?

群創(chuàng)液晶屏 友達(dá)液晶屏 京東方液晶屏 京瓷液晶屏 龍騰液晶屏 天馬液晶屏 奇美液晶屏 三菱液晶屏