在我们嵌入式开发中,有时候有些调试环境、流程比较复杂/繁杂。比如有些bug需要跑很长的一段流程才可以复现,这时候如果按照正常的流程来调试,单单是复现问题估计都需要话不少时间。
这时候应该要多思考需要怎么去模拟一个相同的环境,可以更方便地进行调试,一个好的仿真环境可以大大地提高工作效率。比如数据的模拟、流程的模拟、通信收发的模拟等方面,或是用一些网上现成的模拟器。
本次就来给大家分享一个实用的LCD模拟器:VirtLCD。这个模拟器在我们的工作中有用到,觉得挺实用,分享给大家。
这个模拟器的代码是开源的,大家感兴趣的话可以自己去下载来研究。地址:
❝https://gitee.com/kerndev/VirtualLCD
❞
下面进行实践演示。先看一个图:
使用VirtLCD时,我们同样需要一个demo(VirtSTM32)工程编写我们的界面设计代码,调试好之后可以很快地移到STM32工程上。
我们在使用STM32做LCD显示时,常常会封装一些基础的绘制函数,如画点、画线等函数。同样的,使用VirtSTM32与VirtLCD做调试时,也要封装类似函数,作者也给我们提供了一些参考,如:
- //画点
- 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 < x2; x1++)
- {
- *mem++ = color;
- }
- }
-
- //画垂直直线
- void LCD_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上,如:
- 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;
- }
-
运行结果:
这就是模拟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
-
- //定义像素类型
- typedef unsigned long 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))
-
- //响应鼠标事件
- static void on_mouse_input(int event, int x, int y)
- {
-
- }
-
- //响应键盘事件
- 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 < x2; x1++)
- {
- *mem++ = color;
- }
- }
-
- //画垂直直线
- void LCD_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)
- 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); //得到字体一个字符对应点阵集所占的字节数
- num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
- for(t=0;t<csize;t++)
- {
- if(size==12)temp=ascii_1206[num][t]; //调用1206字体
- else if(size==16)temp=ascii_1608[num][t]; //调用1608字体
- else if(size==24)temp=ascii_2412[num][t]; //调用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; //超区域了
- if((y-y0)==size)
- {
- y=y0;
- x++;
- if(x>=LCD_WIDTH)return; //超区域了
- break;
- }
- }
- }
- }
-
- //显示字符串
- //x,y:起点坐标
- //width,height:区域大小
- //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我已经打包好了,点击下载。