實用 | 手頭上無LCD卻又急著開發(fā)UI?LCD模擬器了解一下~
LCD模擬器

在我們嵌入式開發(fā)中,有時候有些調(diào)試環(huán)境、流程比較復(fù)雜/繁雜。比如有些bug需要跑很長的一段流程才可以復(fù)現(xiàn),這時候如果按照正常的流程來調(diào)試,單單是復(fù)現(xiàn)問題估計都需要話不少時間。
這時候應(yīng)該要多思考需要怎么去模擬一個相同的環(huán)境,可以更方便地進行調(diào)試,一個好的仿真環(huán)境可以大大地提高工作效率。比如數(shù)據(jù)的模擬、流程的模擬、通信收發(fā)的模擬等方面,或是用一些網(wǎng)上現(xiàn)成的模擬器。
本次就來給大家分享一個實用的LCD模擬器:VirtLCD。這個模擬器在我們的工作中有用到,覺得挺實用,分享給大家。
這個模擬器的代碼是開源的,大家感興趣的話可以自己去下載來研究。地址:
https://gitee.com/kerndev/VirtualLCD
下面進行實踐演示。先看一個圖:
使用VirtLCD時,我們同樣需要一個demo(VirtSTM32)工程編寫我們的界面設(shè)計代碼,調(diào)試好之后可以很快地移到STM32工程上。
//畫點
void??LCD_DrawPoint(int?x,?int?y,?PIXEL?color)
{
PIXEL?*mem;
mem?=?GET_FRAMEBUFFER(x,?y);
*mem?=?color;
}
//畫水平直線
void??LCD_DrawHLine(int?x1,?int?y1,?int?x2,?PIXEL?color)
{
PIXEL?*mem;
mem?=?GET_FRAMEBUFFER(x1,?y1);
for(;?x1?
{
*mem++?=?color;
}
}
//畫垂直直線
void??LCD_DrawVLine(int?x1,?int?y1,?int?y2,?PIXEL?color)
{
PIXEL?*mem;
mem?=?GET_FRAMEBUFFER(x1,?y1);
for(;?y1?
{
*mem?=?color;
mem?-=?LCD_WIDTH;
}
}
下面我們新建一個VirtSTM32工程(VS2019控制臺程序)進行驗證,然后把這些函數(shù)加到我們的VirtSTM32工程里。同時,VirtSTM32需要依賴于VirtLCD.lib,導(dǎo)入即可,這個庫可以在VirtLCD SDK包里找到(文末統(tǒng)一發(fā)給大家)。
有了這三個基礎(chǔ)函數(shù),我們可以就可以做很多的事情了,顯示字符串、顯示圖片等函數(shù)都是以畫點函數(shù)為基礎(chǔ)的,這些函數(shù)可以在各種開發(fā)板的lcd相關(guān)例程里找到,拿過來修改一下就可以。接下來我們顯示一些字符串到Virtlcd上,如:
左右滑動查看全部代碼>>>
int?main(void)
{
LCD_Init();
printf("hello?virtlcd,?i?am?ZhengN");
LCD_DrawHLine(10,?10,?350,?WHITE);
LCD_ShowString(10,?30,?LCD_WIDTH,?LCD_HEIGHT,?12,?"hello?virtlcd,?i?am?ZhengN");
LCD_ShowString(10,?50,?LCD_WIDTH,?LCD_HEIGHT,?16,?"hello?virtlcd,?i?am?ZhengN");
LCD_ShowString(10,?70,?LCD_WIDTH,?LCD_HEIGHT,?24,?"hello?virtlcd,?i?am?ZhengN");
LCD_DrawHLine(10,?110,?350,?WHITE);
while(1);
return?0;
}
運行結(jié)果:
這就是模擬STM32裸機顯示字符串到VirtLCD中,調(diào)試好之后我們可以很快地移到真正的STM32工程中。這里只是進行簡單的演示,當(dāng)然,感興趣的話,還可以移植LVGL、emwin等GUI進去。
附VirtSTM32主要代碼:
#include?"virtlcd.h"
#include?"font.h"
#include?
#pragma?comment(lib,?"virtlcd.lib")
#define?LCD_FILENAME????"virtlcd.exe"
#define?LCD_WIDTH???????480
#define?LCD_HEIGHT??????320
#define?LCD_BPP?????????32
#define?WHITE???????????0xFFFFFFFF
#define?BLACK???????????0x00000000
#define?FRONT_COLOR?WHITE
#define?BACK_COLOR?BLACK
//定義像素類型
typedef?unsigned?long???PIXEL;
//幀緩存指針
static?PIXEL*?m_pFrameBuffer;
//計算在X,Y坐標(biāo)的幀緩存指針
#define?GET_OFFSET(x,?y)????????((?LCD_WIDTH?*?(?LCD_HEIGHT?-?(y)?-?1)?)?+?(x)?)
#define?GET_FRAMEBUFFER(x,?y)???(?m_pFrameBuffer?+?GET_OFFSET(x,?y))
//響應(yīng)鼠標(biāo)事件
static?void?on_mouse_input(int?event,?int?x,?int?y)
{
}
//響應(yīng)鍵盤事件
static?void?on_keybd_input(int?event,?int?key)
{
}
//初始化LCD
int?LCD_Init(void)
{
int?ret;
ret?=?VirtLCD_Init(LCD_FILENAME,?LCD_WIDTH,?LCD_HEIGHT,?LCD_BPP);
if?(!ret)
{
return?0;
}
m_pFrameBuffer?=?VirtLCD_GetFrameBuffer();
VirtLCD_SetMouseProc(on_mouse_input);
VirtLCD_SetKeybdProc(on_keybd_input);
return?1;
}
//畫點
void??LCD_DrawPoint(int?x,?int?y,?PIXEL?color)
{
PIXEL*?mem;
mem?=?GET_FRAMEBUFFER(x,?y);
*mem?=?color;
}
//畫水平直線
void??LCD_DrawHLine(int?x1,?int?y1,?int?x2,?PIXEL?color)
{
PIXEL*?mem;
mem?=?GET_FRAMEBUFFER(x1,?y1);
for?(;?x1?
{
*mem++?=?color;
}
}
//畫垂直直線
void??LCD_DrawVLine(int?x1,?int?y1,?int?y2,?PIXEL?color)
{
PIXEL*?mem;
mem?=?GET_FRAMEBUFFER(x1,?y1);
for?(;?y1?
{
*mem?=?color;
mem?-=?LCD_WIDTH;
}
}
//在指定位置顯示一個字符
//x,y:起始坐標(biāo)
//num:要顯示的字符:"?"--->"~"
//size:字體大小?12/16/24
//mode:疊加方式(1)還是非疊加方式(0)
void?LCD_ShowChar(int?x,?int?y,?int?num,?int?size,?int?mode)
{
int?temp,t1,t;
int?y0=y;
int?csize=(size/8+((size%8)?1:0))*(size/2);??//得到字體一個字符對應(yīng)點陣集所占的字節(jié)數(shù)
num=num-'?';//得到偏移后的值(ASCII字庫是從空格開始取模,所以-'?'就是對應(yīng)字符的字庫)
for(t=0;t { if(size==12)temp=ascii_1206[num][t];????//調(diào)用1206字體 else?if(size==16)temp=ascii_1608[num][t];?//調(diào)用1608字體 else?if(size==24)temp=ascii_2412[num][t];?//調(diào)用2412字體 else?return;????????//沒有的字庫 for(t1=0;t1<8;t1++) { if(temp&0x80)LCD_DrawPoint(x,y,FRONT_COLOR); else?if(mode==0)LCD_DrawPoint(x,y,BACK_COLOR); temp<<=1; y++; if(y>=LCD_HEIGHT)return;??//超區(qū)域了 if((y-y0)==size) { y=y0; x++; if(x>=LCD_WIDTH)return;?//超區(qū)域了 break; } } } } //顯示字符串 //x,y:起點坐標(biāo) //width,height:區(qū)域大小 //size:字體大小 //*p:字符串起始地址 void?LCD_ShowString(int?x,?int?y,?int?width,?int?height,?int?size,?char*?p) { int?x0?=?x; width?+=?x; height?+=?y; while?((*p?<=?'~')?&&?(*p?>=?'?'))//判斷是不是非法字符! { if?(x?>=?width)?{?x?=?x0;?y?+=?size;?} if?(y?>=?height)break;//退出 LCD_ShowChar(x,?y,?*p,?size,?0); x?+=?size?/?2; p++; } } int?main(void) { LCD_Init(); printf("hello?virtlcd,?i?am?ZhengN"); LCD_DrawHLine(10,?10,?350,?WHITE); LCD_ShowString(10,?30,?LCD_WIDTH,?LCD_HEIGHT,?12,?"hello?virtlcd,?i?am?ZhengN"); LCD_ShowString(10,?50,?LCD_WIDTH,?LCD_HEIGHT,?16,?"hello?virtlcd,?i?am?ZhengN"); LCD_ShowString(10,?70,?LCD_WIDTH,?LCD_HEIGHT,?24,?"hello?virtlcd,?i?am?ZhengN"); LCD_DrawHLine(10,?110,?350,?WHITE); while(1); return?0; } 以上就是本次的分享。如果文章對你有幫助,麻煩三連支持一下 代碼下載 VirtLCD SDK包及本文的VirtSTM32工程demo我已經(jīng)打包好了放在后臺,大家可以在本公眾號后臺回復(fù)關(guān)鍵詞:VLCD ,即可獲取。 基礎(chǔ)很重要!elf和map文件有不同? 為什么 128 KB 的魂斗羅可以塞下這么長的劇情? 100元都不到的樹莓派Zero 2 W正式發(fā)布! API/SDK
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。