tag 标签: LCD12864

相关博文
  • 热度 15
    2013-6-7 13:11
    1337 次阅读|
    0 个评论
      本文针对LCD12864 特性,完成了数字示波器显示必须的绘图驱动程序设计,这个教程定位给初学者使用,我立足从简单到复杂一步一步介绍设计过程,甚至是调试的过程,还包括一些经验总结,特别是提供了完整的keil 工程附件。希望读者立足示波器项目,学到更多软硬件设计经验技巧。   一、简易数字示波器原理   数字示波器基本原理可以简单理解为:数据采集+ 图形显示,该过程循环进行,如图1 所示。 图1 简易数字示波器流程图   LCD 图形显示需要根据LCD 特性设计,不同LCD驱动程序不同,本篇将结合不带字库的LCD12864 设计显示程序。   二、图形液晶LCD12864绘图驱动设计基础   关于LCD 的硬件接口电路,在其他教程中有详细介绍,涉及单片机总线知识和CPLD 内部电路,需要认真学习,这里借助现成的驱动函数,重点讲解LCD绘图程序设计。   LCD12864 的电路接口在头文件中定义:   #define LCD_LCW XBYTE   // 左屏命令写入   #define LCD_LDW XBYTE   // 左屏数据写入   #define LCD_LCR XBYTE   // 左屏命令读出   #define LCD_LDR XBYTE   // 左屏数据读出   #define LCD_RCW XBYTE   // 右屏命令写入   #define LCD_RDW XBYTE   // 右屏数据写入   #define LCD_RCR XBYTE   // 右屏命令读出   #define LCD_RDR XBYTE   // 右屏数据读出   后面所有对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;i8;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;j64;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(); // 执行清屏,非必须操作   }   该函数用来初始化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 到15 点为字节1,依此类推对应8 字节。 图3 LCD“点”显示示例   第一点y 轴为30,应该对应垂直哪个字节的哪个比特呢?   实际30 点应该在第4 字节(24 到31)的Bit 6 上,拿30/8 取整为3,刚好是应该跳过的前3 字节(对应0 到23),那么30%8(30 除8 取余数)呢,余数是6,不是刚好是Bit 位吗?所以可以这样将y 值映射到某字节的某点上,如果y 轴64 点对应8 字节变量Da ,n从0 到7,则:   da = 1 《 (y%8);或da =0x01《(y0x07);后一种算法更优。   通过总结规律,用以上算法可以将任意0 到63 之间的数据作为坐标描点到对应的8 个字节中,然后将8个字节全部写入LCD,则通过刚才算法就会有一点与所给坐标一致。   第一点:da = 1 《 30%8; 即da = 0x40;   第二点:da = 1 《10%8; 即da = 0x04;    首先给出列显示子函数,在任意列显示y 值对应点。   {   unsigned char j;   if(x64) { // 根据列坐标选择左右半屏   for(j=0;j8;j++) { // 写左半屏   lcd_cmd_wr(ORGY+j,0);   lcd_cmd_wr(ORGX+x,0);   lcd_data_wr(da ,0);   }   }   else {   x-=64;// 坐标调整   for(j=0;j8;j++) { // 写右半屏   lcd_cmd_wr(ORGY+j,1);   lcd_cmd_wr(ORGX+x,1);   lcd_data_wr(da ,1);   }   }   }   有了列显示函数,LCD 任何坐标位置上描点绘图函数为:   void lcd_disp(unsigned char x,y) //x 水平坐标,y 垂直坐标   {   unsigned char dat ;   unsigned char j;   y=63-y;// 使xy 坐标符合习惯   for(j=0;j8;j++) dat = 0x0;   dat |= 0x01《(y0x07);   lcd_row_wr(x,dat);   }   以上函数能够在指定坐标(x,y)上描点,下面尝试将ADC 的值采集后送LCD 显示。再按时间轴x 轴顺序将不同时刻采集到的y 值顺序写入LCD,这是我们就可以在LCD 上看到随时间变化的电压曲线了。主程序为:   void main()   {   unsigned char i;   lcd12864_init();   for(i=0;i128;i++) {   lcd_disp(i,read_adc(0)/16);// 从10bit 映射到6bit,要除16   }   while(1);   }   调整输入给ADC 的信号频率,可以得到满意的波形图了,效果如图4 所示。 图4 LCD实时显示ADC图   如果你成功做到了这一步,可喜可贺,已经掌握了绘图基础了,不过程序还要继续完善。   三、图形液晶LCD12864绘图驱动设计提高   如何在现实波形显示的基础上,同时将定标网格也显示出来呢?   首先我们看一种C 语法“A = 0x05; A |= 0x50;”运行以上指令后,A = 0x55 ;也可以说第二个数据0x50 是叠加到第一个数据上的,我们可以用这种算法把需要显示的亮点(也就是“1”)按一定的算法叠加在一起,送LCD 显示,就出现了我们希望的在波形上增加背景网格的效果。   因为网格与水平x 轴是严格关联的,所以我们可以对x 轴数据进行判断,有规律的将边框和背景格点加入。   改进带背景格的lcd_disp() 函数。   void lcd_disp(unsigned char x,unsigned char y)   {   unsigned char da ;   unsigned char j;   y = 63-y;   for(j=1;j7;j++) da = 0x0;   da =0x01;   da =0x80;   if(x%5==0) {   da |= 0x01《(21%8);   da |= 0x01《(42%8);   }   if((x==0)||(x==127)) {// 加两端边框   for(j=0;j8;j++) da = 0xff;   }   da |= 0x01《(y%8);   lcd_row_wr(x,da);   }   效果如图5 所示。 图5 带网格的LCD显示图   四、图形液晶LCD12864移动游标线绘图驱动设计   声明控制水平线的变量“unsigned charpointY="0";” 范围0 到63, 声明控制垂直线的变量“unsigned char pointX="0";”范围0 到127。   void lcd_disp(unsigned char x,unsigned char y)   {   unsigned char da ;   unsigned char j;   y = 63-y;   for(j=1;j7;j++) da = 0x0;   {// 绘制边框   da =0x01;   da =0x80;    if((x==0)||(x==127)) {    for(j=0;j8;j++) da = 0xff;   }   }   if(x%5==0) da |= 0x01 《 (pointY0x07);   // 绘制由变量pointY 控制的水平游标线   if(x==pointX) // 绘制由变量pointX 控制的垂直游标线   for(j=0;j64;j++)   if(j%5==0) da |= 0x01 《(j0x07);   da |= 0x01《(y%8); // 绘制信号波形   lcd_row_wr(x,da);   }   运行效果如图6 所示。 图6 水平垂直移动游标线示例   五、图形液晶LCD12864数字符号显示   图形点阵LCD 显示数字,原理是把数字以点阵的形式取模,再把点阵模写入特定的LCD 空间即可,首先来看数字取模,如图7 所示,对数字“0”按8×5点取模。 图7 数字取模示例图   纵向看,8 点一列,从上至下对应bit0 到bit7,我们用1 表示“亮”,0 表示“暗”,从左至右,依次确定为0111 1100,即0x7c ;1000 0010,即0x82 ;10000010, 即0x82 ;1000 0010, 即0x82 ;0111 1100,即0x7c ;如果我们依次将这5 个字节写入LCD 某页连续5个地址空间,LCD 上就会显示“0”。   下面我们把数字变量在LCD 上动态显示,就是数值变了,显示跟着变。   字符显示LCD 驱动函数,实现8×n 点阵字符写入函数。   void lcd_put_xyns(unsigned char x,y,n,unsigned char *s)   {   unsigned char i;   for(i=0;in;i++) {   if((x+i)63) {   lcd_cmd_wr(ORGY+y,1);   lcd_cmd_wr(ORGX+x+i-64,1);   lcd_dat_wr(s ,1);   }   else {   lcd_cmd_wr(ORGY+y,0);   lcd_cmd_wr(ORGX+x+i,0);   lcd_dat_wr(s ,0);   }   }   }   参数:“x, y”是坐标,这里y 是页坐标,取值从0 到7,“n”是点阵模字节数,“*s”是点阵模起始地址。   将字模生成字模表:   unsigned char code number dam) if(++i (DATA_SIZE/2)) break;   while(da_buffer = dam) if(++i (DATA_SIZE/2)) break;   while(da_buffer dam) if(++i (DATA_SIZE/2)) break;   这里的dam 就是信号交流部分的中值。   程序用几个while 语句,看上去很呆板,实际运行效果很好喔。第一句把比设定值大的数据过滤,如图10 中的1、2、3 点,如果数据是从4 开始的,第一句会直接跳过;第二句把比设定值小的数据跳过,找出过零点的上升沿5 点。   9. 矢量绘图   前面我们介绍的LCD 描点绘图不是矢量绘图,图形由一系列的“点”组成,在波形绘图区,每列只有1个点,拿方波绘图来看,描点绘图图形如图12 所示,矢量绘图在点与点之间填充“直线”,方波绘图效果如图11 所示。对比两种绘图效果,最好选择矢量绘图,LCD 波形显示效果较点绘图好很多。 图11 点绘图 图12 矢量绘图   矢量绘图需要按时间轴连续两点同时考虑,根据两点之间的差值补点,这就是绘图程序disp(x, y, l)中参数l 的作用。   七、数字示波器程序流程图设计分析   表达程序设计思想的关键就是程序流程图,下面将重点分析本程序设计的几个关键流程图。   主程序流程图如图13 所示,初始化完成系统初始化设置,包括全局变量初始化,红外按键中断、定时器中断初始化,在主循环程序中,处理外部按键输入,由于数据采集是在定时中断中完成的,主循环中需要等待一帧数据采集完成后,才能对数据进行同步处理,包括直流滤波,数据到LCD 映射,调用LCD 显示函数完成波形绘图,一帧数据处理完成后,重新开中断,等待下一帧数据采集。   图13 主程序流程图图   LCD 波形显示流程图如图14 所示,LCD 波形显示区需要根据新采集到的数据不断刷新,这里以LCD列为单位,一次绘图一个(x, y)坐标点,这里的编程思想是定义7 字节内存变量,与LCD 的第x 列对应,首先对参数进行检查,例如y 参数就不能超过LCD 显示去最大值,超过需要修正,确保点到点映射不出错,需要显示的内容除了波形信号外,还有窗口边框,背景格,游标线等,都要同时考虑。这里的l 参数是两点之间的间隔,采用矢量显示,两点之间用直线矢量绘图代替描点,显示效果要好很多。 图14 LCD波形显示   数据采集流程图如图15 所示,数据采集需要严格等时,而且根据不同频率的信号,从低频到高频需要用不同的采样率,所以这里用定时器控制采样时间间隔。 图15 数据采集流程图   由于定时器中断任务调用需要额外时间,对于高速中断是有一定时间间隔限制的,通过计算,100μs 周期采样用定时器实现不了,所以这里定时数据采样分高速和低速两档,高速档一次一帧,低速档一次一点,一帧数据采集完成后,回到主程序对数据进行处理。   按键任务流程图如图16 所示,由于示波器控制需要很多按键,涉及电压档位,采样时间档位,游标线等,这些档位都由一个全局变量控制,在按键任务模块,就是根据有效按键,对这些档位全局变量进行加减调整,变量调整后,有些效果会在波形显示刷新中体现出来,还有的需要单独刷新显示。 图16 按键任务流程图   八、经验总结与心得体会   STC89C52RC 内部扩展RAM 只有256 字节,不像数据手册上介绍的512 字节,外部RAM 超量使用会导致意想不到的后果,经常莫名其妙的死机。   窗口波形显示有两种模式,逐点显示(采集一个数据马上刷新显示)和逐帧显示(采集完成一帧数据后刷新显示),经过测试论证,低频逐点视觉效果好,高频没区别,但是逐点没办法同步。   初学者在学习他人程序时,不要仅仅对程序代码下功夫看懂,其实真正学习的捷径是看懂程序流程图,学习他人的程序设计思想,在吸收他人程序设计思想的前提下,具体编程实现特定的功能,程序可以有多种“写法”。   作为终端输出显示装置,并不需要很高的刷新速度,因为它是给“人”看的,每秒超过10 次的变化,对人眼睛产生不了有用的效果。   我写这篇教程,特别注重解决问题方法的总结,我认为掌握一种解决问题的方法比掌握一种具体的知识要重要得多。
  • 热度 33
    2011-6-3 17:44
    5342 次阅读|
    13 个评论
    这是一款自己开发的视频音频输入输出自动切换的控制板!它采用S52为单片机。12846做中文显示!可实现1路视频和音频输入,4路视频和4路音频的单路通道轮流输出和四路视频音频通道的同时输出功能!可切换对讲LINE IN ,支持串口与PC通讯!同时可将所有的视频切换信息随时随地通过串口传给电脑,电脑可通过软件接收信息存到服务器中保存!以备查询!在切换的同时LED灯实时显示目前的通道数!12864也以中文的方式显示目前正处在哪个通道!以方便巡查!   该控制板还可以控制24V电压的输入!以方便控制大电器的开关!   开发这款控制板的目的是为了测试视频通道和音频通道的单独输入自动化检测,比如多路DVR,视频服务器或者是多路监视器,或者是其他多路视频音频设备的检测!提高检测输入,实现防呆(防漏检),防错检,智能化测试的提高!为公司或为检测机构提高 了效率!如果大批量检测更能体现出这款产品的实用性!   从技术上将,开发这款产品着重在于芯片的选择,对于视频放大,视频选通等功能的芯片选择上需要满足芯片的高带宽,高频率的要求。   现发此资料以供大家分享!谢谢支持     电路原理图截图!   PCB设计图截图   PCB板正面截图   PCB板反面截图 感谢支持!未完待续……            
  • 热度 28
    2011-5-30 16:51
    3330 次阅读|
    3 个评论
    由于项目所需,所以这段时间,抽空学了一下LPC2134,它是基于ARM7核的微处理器,内部有128K的flash与16k的RAM,所以一般的处理程序,内部空间就够用了,当然你要上想在上面跑跑操作系统什么的,那就另当别论了。关于这个处理器其它方面的内部资料,如果你想了解,建议你好好翻翻它的数据手册,如果你说英文太难啃,网上有大把中文的资料,当然懒猫还是建议你看英文原版,一它是厂家的资料,比较真实可靠一般不会有什么大错,二你还可以凑这个空档学学英语,真学好了这也是你要工资的筹码。   今天只是实验一下它的IO端口功能,如何实验,懒猫就不再从流水灯开始了,懒猫选择从LCD12864开始,说实在看着这么大一块屏,挺吓人的,其实LCD也没有那么可怕,处理好时序就能让它乖乖的显示,所以想写好LCD12864的驱动首先还是要好好翻看它的数据手册,这里懒猫就不再详述数据手册上的内容了。不过在这里懒猫要先啰嗦一句,想让LCD12864正确显示,一定要记住先清屏,其实也就是清它内部寄存器,否则初始化时它内部的RAM中不知道是什么乱七八糟的东东,一旦你没有清屏,很可能在显示时会出现乱码或显示不正常,如下图所示: 图1-1 初始化时没有加清屏函数 其实懒猫在上大学时就试着用51写LCD12864的驱动程序,所以这次使用还算顺利,记得当时初次使用LCD12864出现这种情况,懒猫非常郁闷,以为自己的驱动程序没有写好,于是使劲翻看数据手册,仔细的看时序,最后还单步调试,发现问题还是没有解决,最后懒猫看到LCD12864中RAM时,突然想到单片机的设置变量时,初值也是随机的,于是就想着清一下RAM,结果问题还真解决了,呵呵,当时那个兴奋呀,无以言表。现在想想那时真的有点傻的可爱,网上有好多现成的程序,自己却一个人死扣自己的程序。可惜时光如梭,转眼间懒猫毕业就要两年了,那些激情燃烧的岁月已渐渐远去,却永远无法抹去我美好的记忆……   好了,不费话,说一说这次测试的电路,外围电路很简单,没有接什么东东,就接了一块LCD12864,2134的晶振是12MHz的,实时时钟频率是32.768KHz,下面给出仿真电路图,上面省略了很多东东,这次仿真用的是proteus7.5的版本,仿真不能代替实物,懒猫的程序都是通过实物测试通过的,仿真只是为了调试之用,如果你真想学到真本领,做项目是最好的途径。 图2 电路仿真图 注意,这是仿真电路图,实际设计中要加上电源,晶振,电位器等部件,这个电路图只说明一下LCD与LPC2134的数据接口。   说一下程序,程序包括main.c与display.c两个C源程序代码,只是简单的测试一下lpc2134与LCD12864为后面的实验做一个铺垫,以后的实验可能会用到这个驱动,由于程序东东比较多,所以就只贴出display.c这个源程序,其它的程序在附件中,如果有兴趣可以下载下来查看: /*************************************************************************/ //文件名称:display.c //功    能:LCD12864驱动函数 //作    者:懒猫爱飞 //备    注:MCU      -- LPC2134 //          Crystal  -- 12MHz //          RTC      -- 32.768KHz   //          开发环境 -- RealView MDK-ARM Verxion 4.12 /*************************************************************************/ #define IN_DISPLAY   #include "config.h" #include "display.h"   //LCD12864引脚配置 #define LCD_CS1 4     /*-- P0.4 --*/ #define LCD_CS2 3     /*-- P0.3 --*/ #define LCD_RST 5     /*-- P0.5 --*/ #define LCD_DI  21    /*-- P0.21 --*/ #define LCD_RW  11    /*-- P0.11 --*/ #define LCD_EN  10    /*-- P0.10 --*/   //LCD12864操作宏定义 #define LCD_DE() IO0SET |= 1     #define LCD_IE() IO0CLR |= 1     #define LCD_RE() IO0SET |= 1     #define LCD_WE() IO0CLR |= 1     #define LCD_EH() IO0SET |= 1     #define LCD_EL() IO0CLR |= 1         //LCD12864命令宏定义 #define LCDSTARROW 0xC0    /*-- 设置起始行指令 --*/ #define LCDPAGE    0xB8    /*-- 设置页指令 --*/ #define LCDLINE    0x40    /*-- 设置列指令 --*/   /********************************************************************************** //函数名称:void delay_us(void) //功    能:简短微秒级延时 //入口参数:uint32 t -- 延时长度 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void delay_us(uint32 us) {     while(us--);      }   /********************************************************************************** //函数名称:void Out_Data(uint8 Odata) //功    能:向端口输出数据 //入口参数:uint8 Odata -- 要输出的数据 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Out_Data(uint8 Odata) {     IO1CLR |= (uint32)(0xFF16);  // 将输出端口置0     IO1SET |= (uint32)(Odata16); // 输出要输出的数据Odata }   /********************************************************************************** //函数名称:void Write_Data(uint8 Wdata) //功    能:向LCD12864端口写入数据 //入口参数:uint8 Wdata -- 要写入的数据 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Write_Data(uint8 Wdata) {     LCD_DE();        // 写数据使能     delay_us(1);     // 延时等待端口电平稳定        LCD_WE();        // 写命令使能     delay_us(1);     // 延时等待数据写进端口寄存器     Out_Data(Wdata); // 输出要写入LCD12864的数据     delay_us(1);     // 延时等待端口电平稳定     LCD_EH();        // 数据在EN下降沿写入LCD12864中     delay_us(3);     // 延时     LCD_EL();        // EN下降沿     delay_us(3);     // 延时一下 }   /********************************************************************************** //函数名称:void Write_Cmd(uint8 Wcmd) //功    能:向LCD12864端口写入命令 //入口参数:uint8 Wcmd -- 要写入的命令 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Write_Cmd(uint8 Wcmd) {     LCD_IE();        // 写命令使能     delay_us(1);     LCD_WE();        // 写命令使能     delay_us(1);       Out_Data(Wcmd);  // 写入命令     delay_us(1);     LCD_EH();        // 数据在EN下降沿写入LCD12864中     delay_us(3);         LCD_EL();        // EN下降沿     delay_us(3);                                      }   /********************************************************************************** //函数名称:void Init_LCDIO(void) //功    能:LCD端口初始化函数 //入口参数:NULL //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Init_LCDIO(void) {     IO0DIR |=  (1 )                    |(1 )                                   |(1 )                                   |(1 )                                   |(1 )                                   |(1 );     IO0SET |= (1 )|(1     IO0CLR |= 1     IO0CLR |= 1 ;                    delay_us(50);     IO0SET |= 1 ;                    delay_us(50);     IO0SET |= (1 )|(1     Write_Cmd(0x3F);                     //开显示, 关显示为 -- 0x3e     Write_Cmd(0x38);                                        // 8位形式,两行字符     Write_Cmd(0x0F);                     // 开显示     Write_Cmd(0x01);                     // 清屏     Write_Cmd(0x06);                     // 画面不动,光标右移     Write_Cmd(0xC0);                     // 设置起始行 }   /********************************************************************************** //函数名称:void Show_Row(uint8 ucPage,uint8 ucLine,uint8 ucWidth,uint8 const *ucaRow) //功    能:在8×128的格子里显示自定义长度的一行 //入口参数:uint8 ucPage   -- 取值范围0~7 //          uint8 ucLine   -- 取值范围0~127 //          uint8 ucWidth  -- 取值范围0~127 //          ucLine+ucWidth1128 //          uint8 const *ucaRow    -- 要显示的数组 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Show_Row(uint8 ucPage,uint8 ucLine,uint8 ucWidth,uint8 const *ucaRow) {     uint8 ucCount = 0;     if(ucLine64)     {         IO0SET |= 1 ;                              IO0CLR |= 1 ;                   Write_Cmd(LCDPAGE+ucPage);     // 设定页号                   Write_Cmd(LCDLINE+ucLine);     // 设定列号                   Write_Cmd(0x34);                   if(ucLine+ucWidth64)          // 位于左半屏                   {                                 for(ucCount = 0;ucCount ;uccount++)                                 {                                               Write_Data(*(ucaRow+ucCount));   // 写入数据                                 }                               }                   else                                    // 跨越两个半屏 先写完左半屏                   {                                 for(ucCount=0;ucCount64-ucLine;ucCount++)                                 {                                                Write_Data(*(ucaRow+ucCount));              // 写入数据                                 }                                   IO0CLR |= 1 ;                                                IO0SET |= 1 ;                       Write_Cmd(LCDPAGE+ucPage);          // 设定页号                       Write_Cmd(LCDLINE);                 // 设定列号                                 Write_Cmd(0x34);                                  for(ucCount=64-ucLine;ucCount ;uccount++)                                 {                                                 Write_Data(*(ucaRow+ucCount));// 写入数据                                 }                                                                                                                   }     }     else                                    // 位于右半屏     {                   IO0CLR |= 1 ;                                            IO0SET |= 1 ;                   Write_Cmd(LCDPAGE+ucPage);          // 设定页号                   Write_Cmd(LCDLINE+ucLine-64);       // 设定列号                   Write_Cmd(0x34);                   for(ucCount=0;ucCount ;uccount++)                   {                                 Write_Data(*(ucaRow+ucCount));  // 写入数据                              }     } }    /********************************************************************************** //函数名称:void Show_Onehz(uint8 ucPage,uint8 ucLine,uint8 const *ucaChinMap) //功    能:将16×16汉字显示在8×128的格子里 //入口参数:uint8 ucPage -- 取值范围 0~7 //          uint8 ucLine -- 取值范围 0~127 //          int8 const *ucaChinMap -- 要显示的汉字数组 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Show_Word(uint8 ucPage,uint8 ucLine,uint8 const *ucaChinMap) {     Show_Row(ucPage,ucLine,16,ucaChinMap);                                      // 汉字上半部分     Show_Row(ucPage+1,ucLine,16,ucaChinMap+16);                          // 汉字下半部分 }   /********************************************************************************** //函数名称:void Display_HZ(uint8 pagenum,uint8 colnum,uint8 num) //功    能:LCD显示汉字 //入口参数:uint8 pagenum -- 页码 //          uint8 colnum  -- 列数 //          uint8 num     -- 第几个汉字 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Display_HZ(uint8 pagenum,uint8 colnum,uint8 num) {   //uint8 k;   uint8 const *p1;   //k=colnum*16;   p1=hz_mode ;   Show_Word(pagenum,colnum,p1); } /********************************************************************************** //函数名称:void Show_Char(uint8  ucPage,uint8  ucLine,uint8  const *ucaCharMap) //功    能:将8×16字符显示在8×128的格子里。 //入口参数:uint8  ucPage – 要写入的页 //           uint8  ucLine – 要写入的列 //           uint8  const *ucaCharMap – 要写入的数值 //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Show_Char(unsigned char ucPage,unsigned char ucLine,unsigned char const *ucaCharMap) {     Show_Row(ucPage,ucLine,8,ucaCharMap);     Show_Row(ucPage+1,ucLine,8,ucaCharMap+8); } /********************************************************************************** //函数名称:void Clear_Screen() //功    能:清屏函数 //入口参数:NULL //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Clear_Screen() {    uint8 i,j;    for(i=0;i8;i+=2)   //共8页    {       for(j=0;j128;j+=8)     //共128列       {         Show_Char(i,j,CHAR_B);       }    } } /********************************************************************************** //函数名称:void Init_LCD(void) //功    能:LCD初始化函数 //入口参数:NULL //出口参数:NULL //备    注:NULL ***********************************************************************************/ void Init_LCD(void) {     Init_LCDIO();    // 初始化LCD接口     Clear_Screen();  // 要先清屏,不然会显示不正常       /*-- 以下显示函数显示“懒猫爱飞,学习日志” --*/     Display_HZ(2,0,10);     // 懒     Display_HZ(2,16,11);    // 猫     Display_HZ(2,32,12);    // 爱     Display_HZ(2,48,13);    // 飞       Display_HZ(3,64,14);    // 学     Display_HZ(3,80,15);    // 习     Display_HZ(3,96,16);    // 日     Display_HZ(3,112,17);   // 志 } 当然这个程序还不完善,还没显示图片的函数,以后会慢慢加上的,现在还只是在LPC2134中裸奔,主要是为了了解一下它内部结构与内部资源,以后的资料会涉及到ucos可其它嵌入式系统,这个慢慢再总结。 好了,今天说就先到这吧 最后再吼一下懒猫的口号:   每天进步一点点,开心多点 ^_^  
相关资源
  • 所需E币: 5
    时间: 2023-8-9 16:25
    大小: 29.33KB
    上传者: 物联创客
    本资源内容概要:这是基于51单片机的土壤温湿度检测LCD12864显示设计,包含了C语言程序源代码(keil软件打开)。本资源适合人群:单片机爱好者、电子类专业学生、电子diy爱好者。本资源能学到什么:可以通过查看电路学习电路设计原理,查看代码学习代码编写原理。本资源使用建议:建议使用者需要具备一定电子技术基础,掌握一些常用元器件原理,例如三极管、二极管、数码管、电容、稳压器等。了解C语言基础设计原理,能看懂基础的电路图,具备一定的电路图软件使用能力。
  • 所需E币: 5
    时间: 2023-5-22 11:17
    大小: 55.1KB
    上传者: 木头1233
    基于51单片机的LCD12864显示开机画面仿真设计
  • 所需E币: 1
    时间: 2022-7-31 11:13
    大小: 14.16MB
    上传者: xyzzyxaaa
    实验24:LCD12864液晶.zip
  • 所需E币: 1
    时间: 2022-7-31 11:06
    大小: 17.39KB
    上传者: xyzzyxaaa
    LCD12864液晶显示实验.zip
  • 所需E币: 0
    时间: 2022-7-28 22:00
    大小: 3.31MB
    上传者: ZHUANG
    基于51单片机LCD12864左右半屏交接处位置文字显示研究
  • 所需E币: 0
    时间: 2021-4-26 23:48
    大小: 15.25KB
    上传者: Argent
    AI产品层出不穷,手里收藏了有关电子通信,毕业设计等资料,方案诸多,可实施性强。单片机的应用开发,外设的综合运用,纵使智能产品设计多么复杂,但其实现的基本功能都离不开MCU的电路设计与驱动编程,无论是使用51单片机还是AVR单片机,其方案的选择因项目需求而定,需要这方面资料的工程师们,看过来吧。
  • 所需E币: 2
    时间: 2021-4-1 23:35
    大小: 2.86MB
    上传者: samewell
    2层LCD12864万年历(带原理图和PCB)
  • 所需E币: 0
    时间: 2020-9-1 23:42
    大小: 7.19KB
    上传者: Goodluck2020
    CC2530配套液晶驱动资料-LCD12864驱动文件
  • 所需E币: 3
    时间: 2019-12-25 06:01
    大小: 980.54KB
    上传者: rdg1993
    LCD12864在Spartan-3E实现教程和代码……
  • 所需E币: 3
    时间: 2019-12-25 00:10
    大小: 62.54KB
    上传者: 238112554_qq
    单片机读取1302中的时间信息,并在lcd12864中显示。1302有备用电源,掉电后时间依然运行。……
  • 所需E币: 5
    时间: 2019-12-24 18:22
    大小: 3.12MB
    上传者: wsu_w_hotmail.com
    该文档在工程模板上编写了12864液晶的驱动程序,测试没有问题,如果时钟不同的话,只需要再根据倍数大致修改一下延时函数即可。经测试没有问题。液晶的具体型号是FYD12864-0402C【是一款带字库的液晶】。……
  • 所需E币: 5
    时间: 2019-12-24 15:41
    大小: 467.21KB
    上传者: 978461154_qq
    lcd12864试验工程……
  • 所需E币: 3
    时间: 2019-12-24 15:41
    大小: 901.39KB
    上传者: 978461154_qq
    手把手教你学习FPGA_液晶篇……
  • 所需E币: 5
    时间: 2019-12-24 15:21
    大小: 530.38KB
    上传者: 978461154_qq
    作业LCD12864显示其他图片……