这段时间在练习stm32上面的LCD画图,数据来源是实时接收的。因为屏幕尺寸限制,不可能把每个时间的数据全部打在屏幕上面,而且纯数字也不方便对比,所以很多时候都会画一个折线图啥的。
但是问题来了,我在网上面想搜一下有没有什么前人总结过的简单的方法,可是真的好难找啊,偶尔有几个标题差不多的点进去以后都是要积分的,甚至直接要钱。那就算了,我自己试吧,也就半小时的时间,我就用库里面的函数把图给画出来了,感觉还不错,在这里分享给大家,只说方法,不放大的程序,因为总程序我还有用。
stm32的库很强劲,而且基本功能几乎都有,就算一时间找不到自己想要的,用循环或判断语句改一改基本上都能达成目标。比如很久以前我在画实心圆的时候很简单就找到了空心圆环,一个for循环就把数量为半径的圆环全部显示出来,看起来就像是一个实心圆一样了。所以这一次我就在LCD的函数文件里面找。
有一个函数叫LCD_Color_Fill:
//在指定区域内填充指定颜色块
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-8x+l)*(ey-sy+1)
//color:要填充的颜色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{
u16 height,width;
u16 i,j;
width=ex-sx+1; //宽度
height=ey-sy+1; //高度
for(i=0;i<height;i++)
{
LCD_SetCursor(sx,sy+i);
LCD_WriteRAM_Prepare();
for(j=0;j<width;j++)LCD->LCD_RAM=color[i*width+j];
}
}
很显然,这个函数是画方框的,正好可以用来把数据点打出来。
但是这个函数有点复杂,我就又写了一个简单的把它引出来:
void plotdot(u16 t,u16 h,u16 *color)
{
LCD_Color_Fill(t-1,h-1,t+1,h+1,color);
}
这样,只要用plotdot后面加上横、纵坐标,再加上颜色就可以画长宽均为2像素的大点了。
带进去用实际数据试一下。
因为接收的是asc码,将它转换成十进制,然后用一个值减去它:
plotdot(i,300-((tem10-0x30)*10+tem1-0x30)*2,BLACK);
plotdot(i,410-((hum10-0x30)*10+hum1-0x30),LIGHTGREEN);
上面300和410的值是当tem和hum均为0时的纵坐标,之所以把待显示的数据放在除数的位置,是因为LCD的坐标原点在左上方,往右是x轴正方向,往下是y轴正方向,但是坐标轴的y轴正方向是向上,所以要把前面的正负改一下。
第一行*2是因为tem(在程序里面是温度的意思、temperature)变化幅度较小,在10-30中间的可能性较大,所以将它翻倍,容易看出来数值变化。
第二行是湿度,变化范围0%-100%,就没有翻倍了。
plotdot后面的i其实就是时间,这样,一个以时间为横轴,以接收数据为纵轴的散点图就设计好了。
烧写到板子上,结果让我很惊喜。
数据是我模拟的,取了比较极端的值——温度0-40摄氏度,湿度0-100%都涵盖了,看起来效果还是不错的,更为重要的是,因为每个点都连在一起,不需要再在点与点中间连线了!而且我的采样频率是1Hz,温度和湿度都是变化不会太剧烈的东西,一秒钟的时间它们很难改变1℃或1%,所以在纵向上它们也是连在一起的。
这部分的设计至此就结束了,这只是很小的一方面,在整个开发里面之占一点点,但是自我感觉还是不错的,运用的方法很巧妙。
来点拓展的:
前面因为有段代码是
LCD_Color_Fill(t-1,h-1,t+1,h+1,color);
所以每个小方块的边长都是三个像素,如果把每次横坐标也就是i都自增1或自增2,然后再画下一个点,点与点中间也是相连的,如果需要横向拉长图像可以考虑这个方法。
如果需要继续拉长,可能就要用线来连接了,这个我没有尝试,画线的函数是:
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
u16 t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1;
delta_y=y2-y1;
uRow=x1;
uCol=y1;
if(delta_x>0)incx=1;
else if(delta_x==0)incx=0;
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if(delta_y==0)incy=0;
else{incy=-1;delta_y=-delta_y;}
if( delta_x>delta_y)distance=delta_x;
else distance=delta_y;
for(t=0;t<=distance+1;t++ )
{
LCD_DrawPoint(uRow,uCol);
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
x1,y1是起点坐标,x2,y2是终点坐标。
大伙儿可以试试。