文档详情

基于LCD12864显示器的数字示波器设计

gg****m
实名认证
店铺
DOCX
247.11KB
约21页
文档ID:227189484
基于LCD12864显示器的数字示波器设计_第1页
1/21

本文针对LCD12864特性,完成了数字示波器显示必须的绘图驱动程序设计,这个教程定 位给初学者使用,我立足从简单到复杂一步一步介绍设计过程,甚至是调试的过程,还包括 一些经验总结,特别是提供了完整的keil工程附件希望读者立足示波器项目,学到更多 软硬件设计经验技巧一、简易数字示波器原理数字示波器基本原理可以简单理解为:数据采集+图形显示,该过程循环进行,如图1 所示图1简易数字示波器流程图LCD图形显示需要根据LCD特性设计,不同LCD驱动程序不同,本篇将结合不带字 库的LCD12864设计显示程序二、图形液晶LCD1 2864绘图驱动设计基础关于LCD的硬件接口电路,在其他教程中有详细介绍,涉及单片机总线知识和CPLD 内部电路,需要认真学习,这里借助现成的驱动函数,重点讲解LCD绘图程序设计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[ Oxfaea]//右屏命令读出# define LCD_RDR XBYTE[ Oxfbea]//右屏数据读出后面所有对LCD的编程操作都是基于以上接口定义进行的各种读写操作。

图2 LCD点阵分布结构图此LCD屏由水平128列,垂直64行组成水平128列分左右各64列两个半屏构 成垂直64行又分8页,每页8行(1列8点刚好1字节)程序每次对LCD的绘图操 作就是以最小单位1字节进行操作的理解这点至关重要也就是每次只能针对8点进行操作,而不是1点进行操作左右 屏由单独地址线控制(前面的接口定义就是分左右屏定义的)实际打点只需往指定“位置” 写入数据,“1”亮,“0”暗LCD 驱动忙检测函数 void Ioop_lcd12864_is_busy (unsigned char right)ovoid Ioop_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){Ioop_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){Ioop_lcd12864_is_busy (right);if (right) LCD_RDW = data;else LCD_LDW = data;}lcd_cmd_wr ()和lcd_dat_wr ()两个函数分别是给LCD写命令和写数据函数, 通过写命令函数设定地址每个函数都分左右屏,“right”参数选择,“(T选左屏,“非(T选 右屏读数据函数 unsigned char lcd_dat_rd (unsigned char right )ounsigned char lcd_dat_rd (unsigned char right)Ioop_lcd12864_is_busy (right);if (right) return (LCD_RDR);else retuen (LCD_LDR);}该函数可以读出LCD当前显示的数据,首次操作需要读2次才有效。

LCD 清屏函数void Icd12864_clr (void)void Icd1 2864_clr (void){unsigned char ij;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至i」63,在连续写入过程中能够实现自动加1, y轴页地址范围从0至U7,需要逐页设定LCD 初始化函数void Icd12864_init (void)void Icd12864_init (void){lcd_cmd_wr (DI SPON,0 ); // 显示开启led emd wr (DISPFI RS「0): //设定显示首行地址,修改首行地址可以实现屏幕 滚动显示效果lcd_cmd_wr (ORGY0); // 设定初始光标lcd_cmd_wr (ORGX,0);lcd_cmd_wr (DISPON,1 ); // 初始另外一半Icd_cmd_wr (DI SPFI RST, 1 );lcd_cmd_wr (ORGY 1 );lcd_cmd_wr (ORG, 1 );Icd1 2864_clr 0 ; //执行清屏,非必须操作}该函数用来初始化LCD,设置显示模式,光标位置等,在对LCD绘图时,最多的命令 就是设定当前光标位置,通过光标位置来指定将要操作的LCD显示点。

在对LCD编程操作以前,一定要执行此函数对LCD进行初始化操作从驱动函数可见,一次对LCD写入数据是以字节为单位,通过写命令设定坐标,y坐 标从0页到7页,x坐标从0列到63列,分左右屏,左上角为坐标(0, 0)点,这和我 们习惯的左下角为(0, 0)坐标轴是不一样的因为每次操作LCD是一个字节为单位,对应8点,如果我们希望以任意点为坐标显示, 还得另外寻找别的办法编程实现真正“点”显示如图3所示,在屏幕上指定位置画点,水平轴就是X,与LCD坐标一致,垂直轴需要 将点坐标变成字节为单位的坐标,我们先按习惯将y轴64点从下至上编号0到63,其中 0到7点为字节0, 8至灯5点为字节1,依此类推对应8字节LCD 128X64图3 LCD“点"显示示例第一点y轴为30,应该对应垂直哪个字节的哪个比特呢?实际30点应该在第4字节(24至031)的Bit 6上,拿30/8取整为3,刚好是应该 跳过的前3字节(对应0至IJ23),那么30%8 (30除8取余数)呢,余数是6,不是刚好 是Bit位吗?所以可以这样将y值映射到某字节的某点上,如果y轴64点对应8字节变 量 Da[n], n 从0 至!]7,贝I):da[y/8] = 1 《(y%8);或 da[y》3] = 0x01《(y&0x07);后一种算法更优。

通过总结规律,用以上算法可以将任意0到63之间的数据作为坐标描点到对应的8个字节 中,然后将8个字节全部写入LCD,则通过刚才算法就会有一点与所给坐标一致第一点:da[30/8] = 1 《30%8;即 da[3] = 0x40;第二点:da[10/8] = 1 《10%8;即 da[1] = 0x04;首先给出列显示子函数,在任意列显示y值对应点{unsigned char j;if (x<64) { //根据列坐标选择左右半屏for (j = 0;j<8;j++ ) { // 写左半屏lcd_cmd_wr (0RGY+j,0);lcd_cmd_wr (0RGX+ x,0);lcd_data_wr (da[j] ,0 );}}else {x-=64;//处标调整for (j= 0;j< 8;j++ ) { // 写右半屏lcd_cmd_wr (ORGY+j,1);lcd_cmd_wr (0RGX+ x, 1 );lcd_data_wr (da[j] ,1 );}}}有了列显示函数,LCD任何坐标位置上描点绘图函数为:void lcd_disp (unsigned char x,y) //x 水平坐标,y 垂直坐标{unsigned char dat[8];unsigned char j;y= 63-y;//使xy坐标符合习惯for (j= 0;j< 8;j++ ) dat[j] = 0x0;dat[y/8] |= 0x01《(y&0x07);Icd_row_wr (x,dat );}以上函数能够在指定坐标(x, y)上描点,下面尝试将ADC的值采集后送LCD显示。

再按时间轴x轴顺序将不同时刻采集到的y值顺序写入LCD,这是我们就可以在LCD上看到随时间变化的电压曲线了主程序为:void main ()unsigned char i;Icd12864_init 0 ;for (i= 0;i< 1 28;i+ + ) {lcd_disp (i,read_adc (0) /1 6); // 从 1 Obit 映射到6bit,要除 16}while (1 );}调整输入给ADC的信号频率,可以得到满意的波形图了,效果如图4所示如果你成功做到了这一步,可喜可贺,已经掌握了绘图基础了,不过程序还要继续完善三、图形液晶LCD1 2864绘图驱动设计提高如何在现实波形显示的基础上,同时将定标网格也显示出来呢?首先我们看一种C语法“A= 0x05; A |= 0x50;”运行以上指令后,A = 0x55 ;也 可以说第二个数据0x50是叠加到第一个数据上的,我们可以用这种算法把需要显示的亮点 (也就是“1”)按一定的算法叠加在一起,送LCD显示,就出现了我们希望的在波形上增 加背景网格的效果因为网格与水平X轴是严格关联的,所以我们可以对X轴数据进行判断,有规律的将 边框和背景格点加入。

改进带背景格的lcd_disp ()函数void lcd_disp (unsigned char x,unsigned cha。

下载提示
相似文档
正为您匹配相似的精品文档