基于LCD12864显示器的数字示波器设计
发布时间:2011-9-10 08:47
发布者:1046235000
关键词:
LCD12864显示器 , 数字示波器
来自:中国计量测控网 本文针对LCD12864 特性,完成了数字示波器显示必须的绘图驱动程序设计,这个教程定位给初学者使用,立足从简单到复杂一步一步介绍设计过程,甚至是调试的过程,还包括一些经验总结,特别是提供了完整的keil 工程附件。希望读者立足示波器项目,学到更多软硬件设计经验技巧。 一、简易数字示波器原理 数字示波器基本原理可以简单理解为:数据采集+ 图形显示,该过程循环进行,如图1 所示。 图1 简易数字示波器流程图 LCD 图形显示需要根据LCD 特性设计,不同LCD驱动程序不同,本篇将结合不带字库的LCD12864 设计显示程序。 二、图形液晶LCD12864绘图驱动设计基础 LCD12864 的电路接口在头文件中定义: #define LCD_LCW XBYTE[0xf4ea] // 左屏命令写入 #define LCD_LDW XBYTE[0xf5ea] // 左屏数据写入 #define LCD_LCR XBYTE[0xf6ea] // 左屏命令读出 #define LCD_LDR XBYTE[0xf7ea] // 左屏数据读出 #define LCD_RCW XBYTE[0xf8ea] // 右屏命令写入 #define LCD_RDW XBYTE[0xf9ea] // 右屏数据写入 #define LCD_RCR XBYTE[0xfaea] // 右屏命令读出 #define LCD_RDR XBYTE[0xfbea] // 右屏数据读出 后面所有对LCD 的编程操作都是基于以上接口定义进行的各种读写操作。 首先来看LCD12864 的点阵结构图,如图2 所示。 图2 LCD点阵分布结构图 此LCD 屏由水平128 列,垂直64 行组成。水平128 列分左右各64 列两个半屏构成。垂直64 行又分8 页,每页8 行(1 列8 点刚好1 字节)。程序每次对LCD 的绘图操作就是以最小单位1 字节进行操作的。 理解这点至关重要。也就是每次只能针对8 点进行操作,而不是1 点进行操作。左右屏由单独地址线控制(前面的接口定义就是分左右屏定义的)。实际打点只需往指定“位置”写入数据,“1”亮,“0”暗。 LCD 驱动忙检测函数void loop_lcd12864_is_busy(unsigned char right)。 void loop_lcd12864_is_busy(unsigned char right) { unsigned char tmp,counter=0; do { if(right) tmp = LCD_RCR; else tmp = LCD_LCR; if(counter++>50) break; // 超时跳出 } while ((tmp|0x7f)==0xff); //bit7 为1 则表示LCD 内部执行命令,处于“忙”状态 } 对LCD 进行读写操作时,需要进行“忙”检测,LCD 内部也是由控制器来完成一系列刷屏操作的,执行各种操作都是需要一定的时间,也就是说不是任何时候外部控制器都可以对LCD 发操作指令的,只有LCD为空闲状态时才可以操作,忙检测就是循环读取LCD状态标志位,判断是否空闲,关于命令的细节请参考数据手册。 命令写入函数void lcd_cmd_wr(unsigned char cmd,right)。 void lcd_cmd_wr(unsigned char cmd, right) { loop_lcd12864_is_busy(right); // 忙检测 if(right) LCD_RCW = cmd; // 右屏命令写入 else LCD_LCW = cmd; // 左屏命令写入 } 数据写入函数void lcd_dat_wr(unsigned char data,right)。 void lcd_dat_wr(unsigned char data,right) { loop_lcd12864_is_busy(right); if(right) LCD_RDW = data; else LCD_LDW = data; } lcd_cmd_wr() 和lcd_dat_wr() 两个函数分别是给LCD 写命令和写数据函数,通过写命令函数设定地址。每个函数都分左右屏,“right”参数选择,“0”选左屏,“非0”选右屏。 读数据函数unsigned char lcd_dat_rd(unsigned char right)。 unsigned char lcd_dat_rd(unsigned char right) { loop_LCD12864_is_busy(right); if(right) return(LCD_RDR); else retuen(LCD_LDR); } 该函数可以读出LCD 当前显示的数据,首次操作需要读2次才有效。 LCD 清屏函数void lcd12864_clr(void)。 void lcd12864_clr(void) { unsigned char i,j; for(i=0;i<8;i++) { // 从0 到7 共8 页 lcd_cmd_wr(ORGX,0); // 分页设定左屏0 点地址 lcd_cmd_wr(ORGY+i,0); lcd_cmd_wr(ORGX,1); // 分页设定右屏0 点地址 lcd_cmd_wr(ORGY+i,1); for(j=0;j<64;j++) { lcd_data_wr(0,0); lcd_data_wr(0,1); } } } 该函数对LCD 所有点阵写0,完成一次清屏操作。这里的ORGY,PRGX 是设定光标的命令,光标指向(0,0)字节,是一个固定值。实际在执行数据写入的时,x 坐标范围从0 到63,在连续写入过程中能够实现自动加1,y 轴页地址范围从0 到7,需要逐页设定。 LCD 初始化函数void lcd12864_init(void)。 void lcd12864_init(void) { lcd_cmd_wr(DISPON,0); // 显示开启 lcd_cmd_wr(DISPFIRST,0); // 设定显示首行地址,修改首行地址可以实现屏幕滚动显示效果 lcd_cmd_wr(ORGY,0); // 设定初始光标 lcd_cmd_wr(ORGX,0); lcd_cmd_wr(DISPON,1); // 初始另外一半 lcd_cmd_wr(DISPFIRST,1); lcd_cmd_wr(ORGY,1); lcd_cmd_wr(ORG,1); lcd12864_clr(); // 执行清屏,非必须操作 }
|
网友评论