在应用液晶屏做仪器控制界面的时候常常会遇到绘制测量曲线的问题综合分析这些问题大体可以分为两类:
(多年前写的东西,整理好放在CSDN,本人原创转载请注明出处)
一. 波形显示很糟糕曲线的周围出现不可预计的白点
二. 因为曲线数据量的离散使波形看上去不是连续的曲线采用了补点的办法却使波形相对于实际的测量结果严重失真
第一种问题出在对液晶屏的显示RAM和实际显示点阵的关系理解不透彻而第二种问题是因为没有从数学和美观的角度综合分析曲线的趋势找出合理的补点算法下面就根据这两个问题结合现在市面上流行的单色液晶控制器 Sed1335针对320*240 的点阵液晶具体说明这两种问题的解决办法并提供简单的C51 模块程序实际上这种方法对所有的液晶和曲线都是通用希望能给刚刚从事液晶屏开发的朋友一点启发SED133/SED1335 是日本SEIKOEPSON 公司出品的液晶显示控制器笔者认为其最大的优点就是它可以以图形和文本方式分层显示这给界面菜单和曲线的绘制都带来了很大的方便在文本显示的方式下显示位为 FX*FY点阵块在图形方式下显示位为8*1点阵块。
笔者建议画曲线的时候最好在图形方式下( 文本方式下相对复杂的多 )其中显示RAM是从左向右从上到下地址递增的而每一个byte 对应8 个点如果我们采用的是8 位单片机(这里以51 系列为例) 每次访问一次显示RAM必须是一个字节那么要轻松的在屏幕的任意一个位置画一个点就必须要对显示的RAM进行位操作Sed1335 的指令集中提供了对显示RAM读写的操作指令因此我们只要在每次写入显示RAM的时候读取原来的状态在根据具体的需要对RAM进行操作就很容易的可以在屏幕的任意一个位置画一个点同时不会删除画点之前这个点周围的点这样我们的第一个问题就解决了。
再来看第二个问题我们分析如图1 的曲线 ( 这是一个RC 电路中电感在高压脉冲经过以后出现的振荡波形 ) 我们把曲线的走势分类设Q(t)是曲线在时间t 时刻的导数那么可以把曲线的趋势分成五类
(1) Q(t) > 1 快速递增
(2) 0 < Q(t) ≤ 1 缓慢递增
(3) Q(t) < -1 快速递减
(4) 0 > Q(t)≥ -1 缓慢递减
(5) Q(t) = 0 幅值不便
对于需要绘制实时曲线的系统来说 几乎所有采样系统都是按照系统时间的推移来采样的同样我们要绘制的曲线也必须时按照同样的规律变化因此我们有必要把液晶屏幕上曲线的X轴等价于实际的时间轴为了能充分的反应出被测对象的特性我们把液晶屏幕X轴方向每一个点的变化定义为一次AD采样这样的曲线该是个什么样子呢我们可以想象如果我们的AD采样一直不变的情况下这个曲线刚好是一个连续的水平直线(因为X坐标是连续的)但是如果AD采样的值发生变化以后Y值(应该反应被测对象的幅值特性)就会发生变化而这样的变化是必使曲线呈现离散的状态下面我们就根据我们把曲线(指实际的曲线可以理解为AD数据的变化趋势)分类好的趋势来分5 种情况对曲线进行补点因为我们的X坐标对于点阵来说是连续的因此我们只要讨论Y变化后的补点就可以了
(1) Q(t) > 1 快速递增
左图是一对典型的Q(t) > 1的离散点为了满足快速递增的特性我们只要按
照右图的方法补点就可以了
(2) 0 < Q(t) ≤ 1 缓慢递增(如果X轴连续这个情况不用考虑)
我们同样保持这个缓慢递增的特性
(3) Q(t) < -1 快速递减
(4) 0 > Q(t)≥ -1 缓慢递减(如果X轴连续这个情况不用考虑)
(5) Q(t) = 0 幅值不便(如果X轴连续这个情况不用考虑)
笔者给出部分程序供参考 注释就不写了如果读者还有其他方面的问题可以来信
extern void drawdots_e(int dot_x,int dot_y,Byte layer);
是在屏幕上画点的函数
extern void draw_wave(Byte value1,float yamplify,Word value2,Byte value3,Byte layer,Bool value4);
是在屏幕上画波形的函数 包括了横纵坐标的放大倍数
extern void wave_lineto(int x1,int y1,int x2,int y2,Byte layer);
是连线函数
void wave_lineto(int x1,int y1,int x2,int y2,Byte layer){ int d_x,d_y; float k; d_x=x2-x1; d_y=y2-y1; k=d_y/d_x; if(k==0){ for(x1=x1+1;x1<=x2;x1++){ drawdots_e(x1,y1,layer); } } if((k>0)&&(k<=1)){ for(x1=x1+1;x1<=x2;x1++){ y1++; drawdots_e(x1,y1,layer); } } if(k>1){ x1++; for(y1=y1+1;y1<=y2;y1++){ drawdots_e(x1,y1,layer); } } if((k<0)&&(k>=-1)){ for(x1=x1+1;x1<=x2;x1++){ y1--; drawdots_e(x1,y1,layer); } } if(k<-1){ for(y1=y1-1;y1>y2;y1--){ drawdots_e(x1,y1,layer); } x1++; drawdots_e(x1,y1,layer); } } void draw_wave(Byte value1,float value5,Word value2,Byte value3,Byte layer,Bool value4){ int x1,y1,x2,y2; int pdata temp; dot_lineflag=FALSE; dot_line=value4; //处理X轴平移的问题 x1=0; y1=sram_r(value2)-value3; drawdots_e(x1,y1,layer); for(x2=1;x2<300;x2++){ temp=value2+(value1+1)*x2; y2=sram_r(temp)-value3; if(temp>0x7f00) break; y2=y2*value5; wave_lineto(x1,y1,x2,y2,layer); x1=x2; y1=y2; } dot_lineflag=FALSE; dot_line=FALSE; } void drawdots_e(int dot_x,int dot_y,Byte layer){ int x,y; Byte temp,dotbyte,dotbyteago; long zuobiao1,zuobiao2; Byte OH,OL; if(dot_line){ dot_lineflag=~dot_lineflag; } if(!dot_lineflag){ temp=0x80; dot_x+=20; x=dot_x/8; y=dot_y; y=112-y; dotbyte=dot_x%8; temp=temp>>dotbyte; dotbyte=temp; zuobiao1=y*40+x; zuobiao2=zuobiao1; OH=zuobiao1>>8; OL=zuobiao2; //comm_w(0x4c); comm_w(0x46); data_w(OL); data_w(OH+layer); comm_w(0x43); dotbyteago=0; dotbyteago=data_r(); _nop_(); _nop_(); dotbyte=dotbyte|dotbyteago; //comm_w(0x4c); comm_w(0x46); data_w(OL); data_w(OH+layer); comm_w(0x42); data_w(dotbyte); } }