大家好,我是张巧龙,在嵌入式开发中,有时候有些调试环境、流程比较复杂/繁杂。比如有些bug需要跑很长的一段流程才可以复现,这时候如果按照正常的流程来调试,单单是复现问题估计都需要花不少时间。
这时候应该要多思考需要怎么去模拟一个相同的环境,可以更方便地进行调试,一个好的仿真环境可以大大地提高工作效率。比如数据的模拟、流程的模拟、通信收发的模拟等方面,或是用一些网上现成的模拟器。
本次就来给大家分享一个实用的LCD模拟器:VirtLCD这个模拟器在我们的工作中有用到,觉得挺实用,分享给大家。
这个模拟器的代码是开源的,大家感兴趣的话可以自己去下载来研究。
地址:
https://gitee.com/kerndev/VirtualLCD

下面进行实践演示

先看一个图:
使用VirtLCD时,我们同样需要一个demo(VirtSTM32)工程编写我们的界面设计代码,调试好之后可以很快地移到STM32工程上。
我们在使用STM32做LCD显示时,常常会封装一些基础的绘制函数,如画点、画线等函数。同样的,使用VirtSTM32与VirtLCD做调试时,也要封装类似函数,作者也给我们提供了一些参考,如:
//画点
voidLCD_DrawPoint(int x, int y, PIXEL color)
{

    PIXEL *mem;

    mem = GET_FRAMEBUFFER(x, y);

    *mem = color;

}


//画水平直线
voidLCD_DrawHLine(int x1, int y1, int x2, PIXEL color)
{

    PIXEL *mem;

    mem = GET_FRAMEBUFFER(x1, y1);

for
(; x1 < x2; x1++)

    {

        *mem++ = color;

    }

}


//画垂直直线
voidLCD_DrawVLine(int x1, int y1, int y2, PIXEL color)
{

    PIXEL *mem;

    mem = GET_FRAMEBUFFER(x1, y1);

for
(; y1 < y2; y1++)

    {

        *mem = color;

        mem -= LCD_WIDTH;

    }

}

下面我们新建一个VirtSTM32工程(VS2019控制台程序)进行验证,然后把这些函数加到我们的VirtSTM32工程里。
同时,VirtSTM32需要依赖于VirtLCD.lib,导入即可,这个库可以在VirtLCD SDK包里找到(文末统一发给大家)。
有了这三个基础函数,我们可以就可以做很多的事情了,显示字符串、显示图片等函数都是以画点函数为基础的,这些函数可以在各种开发板的lcd相关例程里找到,拿过来修改一下就可以。接下来我们显示一些字符串到Virtlcd上,如:
左右滑动查看全部代码>>>
intmain(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
);

return0
;

}

运行结果:
这就是模拟STM32裸机显示字符串到VirtLCD中,调试好之后我们可以很快地移到真正的STM32工程中。
这里只是进行简单的演示,当然,感兴趣的话,还可以移植LVGL、emwin等GUI进去。
附VirtSTM32主要代码:
#include"virtlcd.h"
#include"font.h"
#include<stdio.h>

#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

//定义像素类型
typedefunsignedlong
   PIXEL;


//帧缓存指针
static
 PIXEL* m_pFrameBuffer;


//计算在X,Y坐标的帧缓存指针
#define GET_OFFSET(x, y)        (( LCD_WIDTH * ( LCD_HEIGHT - (y) - 1) ) + (x) )
#define GET_FRAMEBUFFER(x, y)   ( m_pFrameBuffer + GET_OFFSET(x, y))

//响应鼠标事件
staticvoidon_mouse_input(int event, int x, int y)
{


}


//响应键盘事件
staticvoidon_keybd_input(int event, int key)
{


}


//初始化LCD
intLCD_Init(void)
{

int
 ret;

    ret = VirtLCD_Init(LCD_FILENAME, LCD_WIDTH, LCD_HEIGHT, LCD_BPP);

if
 (!ret)

    {

return0
;

    }

    m_pFrameBuffer = VirtLCD_GetFrameBuffer();

    VirtLCD_SetMouseProc(on_mouse_input);

    VirtLCD_SetKeybdProc(on_keybd_input);

return1
;

}


//画点
voidLCD_DrawPoint(int x, int y, PIXEL color)
{

    PIXEL* mem;

    mem = GET_FRAMEBUFFER(x, y);

    *mem = color;

}


//画水平直线
voidLCD_DrawHLine(int x1, int y1, int x2, PIXEL color)
{

    PIXEL* mem;

    mem = GET_FRAMEBUFFER(x1, y1);

for
 (; x1 < x2; x1++)

    {

        *mem++ = color;

    }

}


//画垂直直线
voidLCD_DrawVLine(int x1, int y1, int y2, PIXEL color)
{

    PIXEL* mem;

    mem = GET_FRAMEBUFFER(x1, y1);

for
 (; y1 < y2; y1++)

    {

        *mem = color;

        mem -= LCD_WIDTH;

    }

}


//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
voidLCD_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
);  
//得到字体一个字符对应点阵集所占的字节数 
  num=num-
' '
;
//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
for
(t=
0
;t<csize;t++)

 {   

if
(size==
12
)temp=ascii_1206[num][t];    
//调用1206字体
elseif
(size==
16
)temp=ascii_1608[num][t]; 
//调用1608字体
elseif
(size==
24
)temp=ascii_2412[num][t]; 
//调用2412字体
elsereturn
;        
//没有的字库
for
(t1=
0
;t1<
8
;t1++)

  {       

if
(temp&
0x80
)LCD_DrawPoint(x,y,FRONT_COLOR);

elseif
(mode==
0
)LCD_DrawPoint(x,y,BACK_COLOR);

   temp<<=
1
;

   y++;

if
(y>=LCD_HEIGHT)
return
;  
//超区域了
if
((y-y0)==size)

   {

    y=y0;

    x++;

if
(x>=LCD_WIDTH)
return
//超区域了
break
;

   }

  }    

 }                

}  


//显示字符串
//x,y:起点坐标
//width,height:区域大小  
//size:字体大小
//*p:字符串起始地址    
voidLCD_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++;

    }

}


intmain(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
);

return0
;

}

以上就是本次的分享。如果文章对你有帮助,麻烦三连支持一下

代码下载

VirtLCD SDK包及本文的VirtSTM32工程demo我已经打包好了,大家可以点击下方卡片关注,后台回复关键词:LCD 即可获取。
继续阅读
阅读原文