项目中,需要在屏幕上刷新波形。
原来的方式是通过两点之间画线,来描出曲线,但是刷新速度不理想,且时间不固定。
后来查阅LCD控制芯片手册,可以利用 “填充区域” 的方法提高刷新效率。
如下是2个LCD的基本通用的函数,设置范围和画点。
通过这两段代码可以分析:如果通过画线方式来刷新波形,由于点的所属区域不连贯,所以每画1个点,就需要设置1次行地址、列地址。
这里假设 LCD_SetCursor() 的耗时为n1,LCD_WR_DATA() 的耗时为n2 。
通过实测可以发现n1远大于n2。
void LCD_SetCursor(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
LCD_WR_REG(0x2A);
LCD_WR_DATA(x1 >> 8); //0x2A为列地址 所以注意当前模式下X坐标是列坐标,Y坐标为行坐标!!!
LCD_WR_DATA(x1); //起始地址
LCD_WR_DATA(x2 >> 8);
LCD_WR_DATA(x2); //结束地址
LCD_WR_REG(0x2B); //0x2B为行地址
LCD_WR_DATA(y1 >> 8); //起始地址
LCD_WR_DATA(y1);
LCD_WR_DATA(y2 >> 8); //结束地址
LCD_WR_DATA(y2);
LCD_WR_REG(0x2C);
}
void LCD_DrawPoint(uint16_t x,uint16_t y)
{
LCD_SetCursor(x, y, x, y);
LCD_WR_DATA( POINT_COLOR );
}
而且通过对比发现,刷新一个正弦波数据时,即使波形点只占据大约1/10屏幕时,也要大于刷整屏的时间(波形点的数量过半时更夸张,耗时远大于刷新整屏)。
所以我们可以借鉴 LCD_Fill() 函数的思路,来刷新我们的波形数据。
void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color)
{
uint16_t i,j;
LCD_SetCursor(sx,sy,ex,ey);
for(j = 0; j < (ey-sy+1); j++)
for(i = 0; i < (ex-sx+1); i++)
LCD_WR_DATA( color );
}
void LCD_FillColor_Buf(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t *color)
{
uint16_t i,j;
LCD_SetCursor(x1,y1,x2,y2);
for(j = 0; j < (y2-y1+1); j++)
for(i = 0; i < (x2-x1+1); i++)
LCD_WR_DATA( *color++ );
}
假设波形刷新区域大小为300*200(即宽度300个像素点,高度200个像素点),我们用一块内存区存储每个点的颜色,即需要300*200*2=117K字节大小的数组。
每次刷新之前,计算需要点亮哪些网格点,计算出需要刷新哪些像素点,等等,最后直接调用 LCD_FillColor_Buf() 函数刷新。
计算的方法,可参考如下代码
//设置默认颜色 即背景色
memset(WaveBufBit, List_c[OSC_M_WAVE].Back, OSC_WIDTH*OSC_HEIGHT*2);
//X轴、Y轴上,每25个点就点亮1个点,其它点不变
for(i = 1; i < 12; i++)
{
for(j = 1; j < 200 - 1; j++){
if(i!=6) j++;
WaveBufBit[j][25*i] = List_c[OSC_M_CELL].Point;
}
}
for(i = 1; i < 8; i++)
{
for(j = 1; j < 300 - 1; j++){
if(i!=4) j++;
WaveBufBit[25*i][j] = List_c[OSC_M_CELL].Point;
}
}
//从第2个点开始,每2个坐标点之间,可以计算出当前Y轴上需要点亮哪些点,然后依次计算出所有亮点
//#define OSC_PIXEL_GetMin(X1,X0) ((X1>=X0)?(OSC_HEIGHT-X1):(OSC_HEIGHT-X0))
//#define OSC_PIXEL_GetNum(X1,X0) ((X1>X0)?(X1-X0):((X1==X0)?1:X0-X1))
for(X = 2; X < OSC_WIDTH; X++)
{
LCD_Y_Min = OSC_PIXEL_GetMin(WaveBuf[X],WaveBuf[X-1]);//起始点亮点
LCD_Y_Num = OSC_PIXEL_GetNum(WaveBuf[X],WaveBuf[X-1]);//点亮数目
for(y = LCD_Y_Min; y < LCD_Y_Min + LCD_Y_Num; y++){
WaveBufBit[y][X] = List_c[OSC_M_WAVE].Point;
}
}
KD028FM屏幕(ST7789芯片)+STM32F429条件下,一次刷新时间固定在22ms。
这样,刷新时间就只取决于2个方面:1、像素点计算时间,2、LCD_Fill()刷新速度。
LCD刷新时间取决于硬件(芯片LCD接口的速率),软件提升空间不大。
像素点计算时间取决于代码执行效率,无非是空间换时间。
如果芯片无法支持117K字节大小的数组,也可以减半。不保存颜色(uint16_t类型)而保存颜色的枚举值,再到写入时根据枚举值填充不同的颜色。