
最近在淘寶的店鋪上淘到了一塊ILI9341的彩色液晶屏,打算研究一下如何使用,
淘寶店鋪購買螢屏之后有附源代碼可供下載,代碼質量慘不忍睹,各種縮進不規范就不說了,先拿來試一下吧,
這是淘寶店鋪代碼的核心部分:
void setup() { Lcd_Init(); //LCD_Clear(0xf800); } void loop() { LCD_Clear(0xf800); LCD_Clear(0x07E0); LCD_Clear(0x001F); /* for(int i=0;i<1000;i++) { Rect(random(300),random(300),random(300),random(300),random(65535)); // rectangle at x, y, with, hight, color }*/ // LCD_Clear(0xf800); }
代碼里面的setup()和loop()是arduino特有的主函式,和普通C程式的main()函式一樣,
setup()函式在開機時只運行一次,運行完之后就開始回圈運行loop()函式,
程式先在setup()函式里做了一下初始化操作Lcd_Init(),接著開始連續用不同顏色清屏,
這里的LCD_Clear()就是清屏函式了,原型如下:
void LCD_Clear(unsigned int j) { unsigned int i,m; Address_set(0,0,240,320); //Lcd_Write_Com(0x02c); //write_memory_start //digitalWrite(LCD_RS,HIGH); digitalWrite(LCD_CS,LOW); for(i=0;i<240;i++) for(m=0;m<320;m++) { Lcd_Write_Data(j>>8); Lcd_Write_Data(j); } digitalWrite(LCD_CS,HIGH); }
縮進不規范就不吐槽了(;へ:),連變數名都起得亂七八糟,簡直慘不忍睹,稍微重寫了一下函式,長這樣:
void LCD_Clear(unsigned int color){ Address_set(0,0,240,320); digitalWrite(LCD_CS,LOW); for(int i=0;i<240;i++){ for(int m=0;m<320;m++){ Lcd_Write_Data(color>>8); Lcd_Write_Data(color); } } digitalWrite(LCD_CS,HIGH); }
這個函式先使用Address_set()設定了重繪區域,然后把LCD_CS針腳電壓拉低,之后回圈寫入color,
color分兩次寫入,一次寫入高八位(16位整形前面8個bit),一次寫入低八位,
看上去好像沒什么問題,但loop()函式中LCD_Clear()卻是直接用十六進制寫入的,
寫一個RGB()函式把RGB顏色轉換成十六進制,不是更人性化嗎?
讀了一遍源代碼,結果真的找到了店家的RGB函式:
int RGB(int r,int g,int b) {return r << 16 | g << 8 | b; }
還是不規范的縮進(╯︵╰),但有總比沒有好,輸出紅色試一下:
void setup() { Lcd_Init(); LCD_Clear(RGB(255,0,0)); } void loop() { //nothing }
出故障了,

Arduino重啟后,螢屏輸出了黑色!再試著排除一下故障,把RGB(255,0,0)改成RGB(0,255,0),輸出綠色試試:

結果輸出了橙色!
之后我又反復嘗試了,沒有一次輸出正確的顏色,莫非是這個RGB()函式有問題,淘寶店鋪才用十六進制數字?
再仔細推導了一下:return r << 16 | g << 8 | b;把紅色左移16位,綠色左移8位,藍色不動,所以合成的二進制應該是這樣的:
RRRRRRRRGGGGGGGGBBBBBBBB
R代表紅色位,G代表綠色位,B代表藍色位,每種顏色8位,總共24位,計算了一下可能性:

總共1677萬種可能,也就是1677萬種顏色,這就是普通電腦的真彩顏色,但LCD_Clear()函式是這么寫的:
Lcd_Write_Data(color>>8); Lcd_Write_Data(color);
總的只能寫入十六個bit,也就是16位,這和24位對不上號啊?
再回頭看了一下,店鋪代碼的setup()函式中有這樣一行白色清屏指令:
//LCD_Clear(0xf800);
0xf800換算成十進制,是63488,有沒有感覺很接近一個數?
沒錯,就是65535,單個16位無符號整數的最大儲存范圍,
16位整型變數,顧名思義就是用16個0和1組成的變數,可以儲存的整數范圍是-32768 ~ 32767,32768 + 32767剛好等于65535,換算到二進制,就是1111111111111111,16個1,

這時,真相出現了——這臺機器所采用的,是16位顏色,也被成為RGB565顏色模式,

早期的16位計算機由于架構的設計,一次只能處理一個16位二進制數,而圖形顯示對速度要求特別高,所以一個像素必須要用一個16進制數來表示,也就是16位顏色,
如果用采用24位顏色,就需要兩個16進制數,也就是2Bytes,速度就慢了一半,
而每個像素都是使用紅黃藍三基色來顯示的,所以一個16進制數必須分3份,來分別表示紅、黃、藍的資料,
這就出現了一個問題:
16 / 3 = 5.33333
紅黃藍三種顏色平均占用5.33333個bit,
可bit是計算機存盤的基本單位,要么是1,要么是0,不能再分割,必須要有一種顏色多用一個位,才能充分單個利用16進制整數,
人體的綠色視錐細胞比較敏感,正好,那綠色就用6位,紅色藍色就用5位吧,
這就是著名的RGB565模式,總共能存盤65535種顏色,
早期的游戲都采用這種模式,所以顏色不夠豐富,很有特色:

這塊ILI9341顯示屏模塊(注意不是ILI9341芯片本身)也剛好只有16根資料引腳,所以就采用了這種RGB565的顏色模式,
找到了問題,那就改一下程式吧:
int RGB(int r,int g,int b) { return r << 11 | g << 5 | b; }
光改RGB()函式還不夠,現在使用了RGB565模式,所以綠色范圍是從0-63,紅色、藍色的范圍是0-31,
所以還得改setup里面的清屏函式:
void setup() { Lcd_Init(); LCD_Clear(RGB(0,63,0)); }
重新下載了程式,螢屏成功顯示,輸出了正確的綠色!⁄(⁄⁄•⁄ω⁄•⁄⁄)⁄

那么問題來了,開頭店家給的LCD_Clear(0xf800)這條清屏指令,是怎么來的?畢竟他連RGB565都不知道呢!
這是我提供的一種可能性:
“0xf600試一下?”
“不行,太灰了!”
“那0xf700呢?”
“還是不行!老板,我們都試了一下午了,肯定是螢屏壞了!”
“加油,還差一點點了,肯定可以的!”
“0xf800好像還行,但是還是有點灰!”
“沒關系,反正買家能點亮螢屏就行,其他的我們不管!”
“……”
所以這家淘寶店鋪根本不知道自己在買什么,ヽ( ̄▽ ̄)?
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/24200.html
標籤:嵌入式
