本文所有的硬件基础以及工程参考来自魏坤示波仪,重新实现驱动并重构工程。
version 0.2 界面动态显示功能
界面显示功能原理
显示波形有如下两个方案:
- 每一帧直接重绘显示界面,再显示下一帧图形
- 用背景色覆盖上一帧图形,再显示被毁坏的坐标,最后显示下一帧图形
第一种解决方案代码比较简单,但是实际测试刷新缓慢(以肉眼可测的速度刷新),故选择第二种方案。
其中有几点需要注意的部分:
- 两个点直接需要连接起来,可以按照显示芯片写的顺序,依次填充y轴,来达到连线。
- 规划将波形数据保存在DISP数组中,再绘制的同时写入CLR数组中,供下一轮清理波形使用。
清波形函数如下:
/*
* 函数名:CLR_WAVE_CH1
* 功能:清除CH1波形
* 日期:2017-02-16
*/
void CLR_WAVE_CH1() {
unsigned int i, k;
for (i = 0; i < 400; i++) {
//确认CLR中有波形数据(在有效区域内)
if (CLR_DATA_CH1[i] > 60 && CLR_DATA_CH1[i] < 300) {
//清除这个点
set_addr(i + 11, CLR_DATA_CH1[i]);
send_data(WAVE_BACK_COLOR);
set_addr(i + 11, CLR_DATA_CH1[i] + 1);
send_data(WAVE_BACK_COLOR);
set_addr(i + 11, CLR_DATA_CH1[i] - 1);
send_data(WAVE_BACK_COLOR);
//下面清除连接两个点的线
if (i < 399) {
if (CLR_DATA_CH1[i] < CLR_DATA_CH1[i + 1]) {
set_addr(i + 11, CLR_DATA_CH1[i]);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, WAVE_BACK_COLOR);
for (k = CLR_DATA_CH1[i]; k < CLR_DATA_CH1[i + 1]; k++) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
}
} else {
set_addr(i + 11, CLR_DATA_CH1[i + 1]);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, WAVE_BACK_COLOR);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, WAVE_BACK_COLOR);
for (k = CLR_DATA_CH1[i + 1]; k < CLR_DATA_CH1[i]; k++) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
}
}
}
}
}
//显示坐标
display_area();
}
显示波形代码如下
void DISP_WAVE_CH1() {
unsigned int i, k;
//清除CH1波形
CLR_WAVE_CH1();
for (i = 0; i < 400; i++) {
//显示当前点
CLR_DATA_CH1[i] = DISP_DATA_CH1[i];
set_addr(i + 11, DISP_DATA_CH1[i]);
send_data(WAVE_COLOR_CH1);
// set_addr(i+11,DISP_DATA_CH1[i]+ 1);
set_y(DISP_DATA_CH1[i] + 1);
send_data(WAVE_COLOR_CH1);
set_addr(i + 11, DISP_DATA_CH1[i] - 1);
set_y(DISP_DATA_CH1[i] - 1);
// send_data(WAVE_COLOR_CH1);
//画连线
if (i < 399) {
if (DISP_DATA_CH1[i] < DISP_DATA_CH1[i + 1]) {
set_y(DISP_DATA_CH1[i]);
// set_addr(i+11,DISP_DATA_CH1[i]);
send_data(WAVE_COLOR_CH1);
for (k = DISP_DATA_CH1[i]; k < DISP_DATA_CH1[i + 1]; k++) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
// set_addr(i+11,k);
// send_data(WAVE_COLOR_CH1);
}
} else {
set_y(DISP_DATA_CH1[i + 1]);
send_data(WAVE_COLOR_CH1);
for (k = DISP_DATA_CH1[i + 1]; k < DISP_DATA_CH1[i]; k++) {
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
// set_addr(i+11,k);
// send_data(WAVE_COLOR_CH1);
}
}
}
}
}
类似的可以写出CH2
的波形显示函数以及触发线等显示函数。
而其他的数据显示利用0.1
版本的显示驱动即可轻松实现。
version 0.2.1 显示功能优化
在动态测试的过程中,发现这样通过调用打包中间层函数的方法,速度跟不上来,会出现频繁闪动的问题。
分析一个有以下几种可能
- 函数调用导致速度过慢
- 中间抽象层中有部分可以通过更少的时钟周期完成(利用像素的局部性)
将函数展开,以及部分不需要重新传输坐标的部分优化后解决了刷新的问题:
void CLR_WAVE_CH1() {
unsigned int i, k;
for (i = 0; i < 400; i++){
LCD_ILI9481_CMD(0x002b);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, (i + 11) >> 8);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, (i + 11) & 0x00ff);
//... 其余类似
}
}