產品動態
全國統一服務熱線:
15382323032
客服QQ:3234659108
手機:15382323032
地址:浙江省杭州市西湖區文一西路830號蔣村商務中心B樓2-8007室
在點陣屏上面繪圖—LCD12864控制的詳解
怎樣在點陣屏上繪圖——基于LCD12864
LCD12864:
— 預備知識 —
其實,本文應該算是計算機圖形學中的一個具體分支,所以,計算機圖形學的最基本要求就是本文的基本要求了,由于考慮到各位大兄弟的胃口,我就多啰嗦下。
1、位操作
像LCD12864這一種二值屏幕,我們往往習慣于使用1個字節表示連續的8個點,1對應的對應位被點亮,0則表示不亮,所以對于圖形的操作最基本的手段那就是位操作了。
復習一下常用的位操作,假設Dis表示是某一個現存地址的內容
Dis = Dis~ 黑白顛倒
Dis &= ~(1<<n) 第n處被擦去,
Dis |= (1<<n) 第n處被畫了一個點
Dis ^= (1<<n) 如果n處是亮的,就變被擦掉;如果n處是空白的,就被點亮了……
…… 差不多也就是這些
2、作圖的原理
點是一切光柵顯示設備最基本的要素,所有的操作也都是以點為基礎的,所以要學會如何去利用點構成線、圓、填充就是必須要掌握的——幾何不能夠太差。
還有,結合屏幕硬件的特點,對于算法進行優化的一些方法也是需要去掌握的。比方說:如何填充之類的……后面還會針對于LCD12864來作詳細的介紹。
3、人機交互學
雖然說很多的人都沒有去實實在在的學過這門功課,但是多多少少還是對于界面應該都有些許了解。如何去利用手中的基本操作函數來做出一些特效?如何安排窗體?如何繪制圖形界面的一些基本元素,例如按鈕,
甚至如何的顯示漢字,都是人際交互學需要教會你的——總而言之,如果你是沒有學過這一門課程,你的產品 只有你自己一個人用的話——那就跟著感覺走,沒錯的。
4、最最重要的物質基礎
你需要掌握一種單片機,掌握到一種點陣屏幕。
怎樣在點陣屏上繪圖——基于LCD12864
Chapter One
— 從點滴開始 —
前面就已經說過了,對于柵格的顯示設備來說,點是一切圖形的基礎,說白了,不會在液晶屏幕的任意位置隨心所欲的畫點就不能夠說你已經掌握了某一種液晶屏幕的使用了。事實上,根據筆者的一些經驗,嘗試畫點
往往就能暴露出很多的問題。就拿LCD12864來說,一段時間,筆者經常發現,在片切換的地方就會有一點點錯誤……
在說明如何畫點之前我先說明一個概念:顯示緩沖區。
所謂的顯示緩沖區,顧名思義,它就是顯示數據的一個緩沖地帶罷了。在一般情況下,我們繪圖也是直接的對
這塊緩沖區域進行操作。
很多朋友現在就要提問了:我們為什么不直接的對屏幕進行操作呢?
事實上,LCD本身就存在著一塊顯示存儲器,也可以被認為是一個顯示緩存,直接寫在這個存儲器上的數據并非是直接顯示出來的,而多半是需要一個顯示指令來影射一下。我們有的時候也會通過這種類似的技術來實現很大的圖片顯示——先畫好,然后再拿給大家看,讓人以為你是一下就畫好了的,當然如果你刻意的需要那種圖片被“畫”出來的效果,則不在討論之列了。問題就在于,LCD是片外的資源,對其存儲器的訪問可以被認為是對片外存儲器的訪問,其速度顯然是沒有對片內SRAM的操作速度快。如果我們使用的是那種常用的串行方式來作圖(所謂串行方式作圖,就是繪圖指令的執行和系統的其他操作是串行的,指令不完成,其它的操作就不會被執行),那么對于一些實時性要求比較高的系統來說就會造成一些重大的隱患——甚至是不符合要求的;如果開辟一段片內存儲空間和LCD的存儲器一一對應,在相同的時間段之內,花費相同的資源來保持這兩個存儲空間的一致性,那么就可以保證實時系統的穩定和可靠了,保證畫面顯示的正常(因為允許跳幀嘛^_^ )。這就是我們為什么還需要另外在片內選取一個顯示緩沖區的原因了。
以后,我們的操作都是針對于顯示緩沖區的。顯示緩沖區將會成為一個概念,無論這個緩沖區位于SRAM內還是LCD的內部。比方說,我們現在需要一個低成本的游戲機 ——比如做一個貪食蛇游戲機送給老師作為課程設計,或者是送給小侄子,那么,M8甚至是M48將會成為首選,問題是,M8是絕對無法開辟出一個8 * 128 = 1K大小的數組,所以,在這個時候,認定LCD的片內存儲器作為顯示緩沖區就是不二的選擇——好在貪食蛇的速度太快了也沒有辦法玩哈。
繞了這么多的彎子,究竟如何去畫點呢?我還想多補充一個原因,關于,為什么需要顯示緩沖區,由于點陣屏使用的是1個字節來表示8個點的,如果你想使得其中一個字節中的某一個點被操作而不影響到別的點,你起碼要知道原來這個位置是顯示的什么內容,對于有一些使用595級聯的LCD設備來說,無法直接從LCD讀取現存的數據,所以開辟了一個緩沖區,從中獲得信息加以加工以后再放回去,是這種設備處理顯示圖形的唯一方法——當然我們還沒有那么慘,但是從LCD中獲取所需點所在字節的內容還是必須的,不然你畫一個點就會破壞其一條線上所有的數據。
好的,那么我們實際上已經明確了如何去畫一個點。
首先,根據用戶給出的坐標計算出所要畫的點所在現存內的地址偏移量;
然后,我們讀出該地址內的數據;
再次,根據用戶所需畫點的類型(擦除、畫點、反相點)來進行相應的操作獲得一個新的數據;
最后,將該數據寫回原來的地址。
不是很難吧?
---------------------------------------------
LCD12864補充知識
1、關于坐標系。很多人,包括筆者,一開始都看不懂LCD12864的內存影射方式,感覺X、Y似乎不是那么回事。后來才發現,只要把屏幕豎著放一切就好懂了。X還是橫軸,Y還是豎軸……但是這顯然不符合我們的習慣,我們習慣于長的那個邊作為橫軸,所以需要一點點坐標之間的轉換。
假設輸入的是正常習慣的坐標 X,Y DX DY就是LCD上的坐標,那么轉換關系是
char DX = (Y >> 3); //計算出屬于哪個字節
char BX = Y - (DX << 3); //屬于該字節的哪個位
char DY = X;
2、讀取12864的數據的時候,一定要注意,E信號要在一個下降延之后持續拉高,然后才能正常獨處數據;假設直接拉高,的確也能讀出數據,但是,等著抓頭皮,發帖子“[跪求]大俠幫忙關于12864——請使用明確的大標題……”^_^
---------------------------------------------
廢話少說(說的不少了),看源代碼:
# 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); //計算出屬于哪個字節
char BX = Y - (DX << 3); //計算出屬于字節哪一位
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);
}
怎樣在點陣屏上繪圖——基于LCD12864
特別說明一下,關于貪食蛇范例的問題,這篇文章里面只會簡單得提及一下。
作為嵌入式系統開發的一個范例,我會另外開一個帖子詳細說明開發過程。
這個范例將作為介紹嵌入式系統開發方法的一個很好的例子,用于解釋一個系統和一段表示您調通了某一個功能的代碼之間有什么區別,同時也將介紹嵌入式開發系統的幾種模式(超級循環、調度器),順便侃一侃時間驅動的系統RTOS (Real Time Operation System實時操作系統)和RTS(Real Time System)實時系統。
怎樣在點陣屏上繪圖——基于LCD12864
[本章導讀]
直線由點構成,更精確的說,直線是由靠近這條線的像素構成。這就引出一個問題,究近那些點算是靠近一條直線;哪些點不算是靠近一條直線,這必須使用一種算法作為依據。實際上,圖形學算法和純幾何算法還是有很大差別的,問題就出在一個離散化上面,說白了,你畫出的直線很可能是一組波動厲害的鋸齒象素群而不是一條看起來有規則變化的直線。
當然,太過于理論的東西對我們是沒有多少實際價值的。下面,我就介紹兩種常見的畫線思路,一種就是最容易被想到的直線方程計算的方法,另外一種則是被稱為布蘭森漢姆(Bresenham)的計算機圖形學主流算法。
在介紹完這兩種算法以后,我們會針對LCD12864的硬件結構為例子,介紹,具體算法的實現和優化。
怎樣在點陣屏上繪圖——基于LCD12864
首先,我們從最基本的數學算法說起。
如果我們使用公式y = kx + b來作為繪圖的依據,那么就需要分3種情況:水平直線,斜率為0;垂直直線,斜率為五窮達(或者說k不存在);普通直線。
假設我們已經知道直線的起始坐標點(Xbegin,Ybegin)和終點(Xend,Yend),x,y,是當前的坐標點,如果我們通過增加x反算出y的方法的話,這個公式就可以很容易轉換為偽代碼。
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處畫點
case 垂直
for y = Ybegin to Yend
在Ebegin,y處畫點
default:
for x = Xbegin to Xend
{
y = kx + b
在x,y處畫點
}
非常簡單,不是么?注意,大部分情況下,這個算法存在很多乘法和除法,對單片機系統來說,可能不是那么合適哦。畫出的點也基本令人滿意。
怎樣在點陣屏上繪圖——基于LCD12864
有了上面的代碼墊底,我想很多人都可以放心了,因為大不了跑一個高速晶振也能快速的畫出直線,否則你還需要耐心的閱讀下面的算法。
首先,我們給出這個算法的偽代碼。
在(x1,y1)到(x2,y2)之間畫一條直線
dx 是x到終點橫坐標的距離
dy 是y到終點縱坐標的距離
ix 是dx的絕對值
iy 是dy的絕對值
inc是dx和dy中較大的那個
plot是是否要畫一個點的標志位,boolean變量
plotx 是當前點所在的橫坐標
ploty 是當前點所在的縱坐標
plotx = x1
ploty = y1
x = 0
y = 0
在 plotx,ploty畫一個點——起點
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)處畫點
這就是計算機圖形學中流行的布蘭森漢姆(Bresenham)算法,他的意圖就是采用離散的整數增量來代替斜率增量計算,學習這個算法,最好的方法不是看多少理論,而是按照上面的偽代碼自己完成一條直線的繪制工作,你就能心領神會了——不是小弟我偷懶。
所有的計算都是簡單得整數計算,代碼效率自然不用小弟我羅嗦哈。
怎樣在點陣屏上繪圖——基于LCD12864
俗語說,巧婦難為無米之炊,有了點再有了直線算法,距離窗體的繪制不遠了,But Stop! “沒有最好,但求更好”這是我們做系統開發應該謹記的一條準則。
有了上面的算法還不夠,畢竟,他們只是一些偽代碼,針對不同的屏幕——準確地說,是針對不同的顯存映射方式,有不同的算法優化方法。究竟有哪些優化方法暫且不論,其實他們都是一個原理,我想先解釋一下,為什么我們需要優化算法,或者說,我們需要先弄清楚是什么地方產生了冗余。
還記得黑白點陣屏幕的顯存映射方式么?它簡單的使用1個字節表示8個坐標點,同時這1個字節是沿著屏幕的短邊方向映射的,所以當我們想畫一條垂直的直線時,對于每一個牽涉到的字節都有可能要重復的操作8次之多,這種操作不是簡單的畫線,而是要先讀取再計算最后再寫這樣的復合操作,重復8次只是為了把整個字節變黑顯然是一種超級不可容忍的冗余——大家都知道,直接把這個字節讀取一次,計算一次,再寫一次就完成了。基于這種思想,我們需要把這種特殊情況單獨提取出來,重新優化代碼……具體優化代碼就留給大家做作業了哈。
同時補充一下,這樣做,不是只對畫線作了優化,事實上,在后面,矩形的填充里面,這種優化會極大地提高速度,因為填充的本質就是畫線(點)……
最新資訊
- 2024-07-05 高亮液晶屏在工業和航空領域的應用
- 2024-07-05 低溫環境下工業液晶屏的性能差異分
- 2024-06-25 立煌的LH0255ZJ01條形屏的相關介紹
- 2024-06-14 高溫對工業液晶顯示屏封裝材料的影
- 2024-06-12 京東方MV238FHB-NG0的簡介
- 2024-06-12 深入探討寬屏分辨率的工作原理
- 2024-06-12 深入探討寬屏分辨率的工作原理
- 2024-06-06 如何選擇適合自己的寬屏觸摸屏產品
- 2024-06-06 極端環境挑戰下超寬溫液晶屏的應用
- 2024-06-05 條形屏是如何根據客戶的需求來進行