完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
第十四节:液晶屏第二大类定律—横向显示八个点(T6963C驱动240128屏)
第二大类定律:横向显示八个点的类型。 这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。 (1) 开场白: 这节 我以驱动芯片为T6963C的240128液晶屏为例子,来继续深入了解第二大类定律:横向显示八个点的类型。T6963C驱动芯片的驱动范围很大,它可以直接驱动一块240128的液晶屏,因此240128液晶屏实际上就是由一块240128液晶屏组成的,没有分屏合并的概念。240128屏在横向上是240个点,纵向上是128个点,也就是一个长方形的屏。因为它属于第二大类的屏,所以X轴坐标数值的最大范围是(240/8)-1=29,而纵向坐标数值的最大范围是128-1=127. 正常的操作思路是这样的,先发送X轴与Y轴的位置数据,确定位置后,就发送一个字节(八个点)的显示数据。这类屏还有一个特征,连续发送显示数据时,在横向(X轴上)的位置数据会自动加一,因此如果在不换行的情况下,只要设定一次位置,就可以从左到右连续发送显示的数据。当换行显示数据时,必须重新设定一下坐标位置。 横向取模,字节正序与倒序的概念解释:当我们一次在横向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从左到右的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。240128这个屏是属于正序的屏。 取模软件是必须的,读者可以在网上自己下载,资料很多。 (2)功能需求: 在240128屏上分别显示8X16的字符,16X16的汉字,24X24的汉字。 (3)硬件原理: 液晶屏的VEE接20K可调电阻的左边端口,VO接可调电阻的中间端口,VSS接可调电阻的右边端口,此可调电阻在这里用来调节液晶屏的对比度。模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。这个大家都懂。 (4)源码适合的单片机:SST89E516RD,晶振为11.0592MHz。 (5)源代码讲解如下: #include #include #define LcmXPixel 240 //横向宽度 #define LcmYPixel 128 //纵向高度 #define Uchar unsigned char #define Uint unsigned int //补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus #define LcmDataBus P1 //数据总线 ***it CSP_dr = P3^2; ***it RSP_dr = P3^3; ***it WRP_dr = P3^0; ***it RDP_dr = P3^1; ***it RES_dr = P3^4; //IO口操作低电平复位,也可以用硬件复位电路,可以省一个IO口 ***it FS_dr = P3^5; //字体选择,一般在硬件接口直接接电源或地,可以省一个IO口 void delay(unsigned int t); //时序延时函数声明 void chk_busy() ; //忙检测,液晶驱动时序的一部分 void chk_busy_auto_write();//自动写的忙闲检查,驱动液晶程序的一部分 void write_com(unsigned char cmdcode); //往液晶模块写入指令 void write_data(unsigned char Di_drspdata); //往液晶模块写入数据 void write_data_data_com(unsigned char Di_drspdata1,unsigned char Di_drspdata2,unsigned char cmdcode3);//写两个数据与一个指令,驱动液晶程序的一部分 void LocateXY240128(unsigned char x,unsigned char y);//设定显示地址函数,驱动液晶程序的一部分 void screen_clear(); //清空屏的内容 void ***_display816(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示8X16的字符函数,本节的核心内容 void hz_display1616(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示16X16的汉字函数,本节的核心内容 void hz_display2424(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示24X24的汉字函数,本节的核心内容 void init_lcd(); //初始化液晶模块 //补充说明:吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用***,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。如果有重复的,则多加一个序列号标识。如果是汉字,则前缀用hz,其它的一样。 unsigned char code ***816_V[]=//从取模软件中复制的字库,横向取模,字节正序 { /*-- 文字: V --*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/ 0x00,0x00,0x00,0xE7,0x42,0x42,0x44,0x24,0x24,0x28,0x28,0x18,0x10,0x10,0x00,0x00, }; unsigned char code ***816_5[]= { /*-- 文字: 5 --*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/ 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00, }; unsigned char code hz1616_hong[]= { /*-- 文字: 鸿 --*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x40,0x20,0x20,0x40,0x20,0xFC,0x0E,0xC4,0x84,0xA4,0x54,0xA4,0x54,0x8C,0x24,0x80, 0x24,0xFE,0x26,0x02,0xD8,0x02,0x43,0xFA,0x40,0x02,0x40,0x02,0x40,0x0A,0x00,0x04, }; unsigned char code hz1616_ge[]= { /*-- 文字: 哥 --*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x00,0x00,0x7F,0xFC,0x00,0x10,0x1F,0x90,0x10,0x90,0x1F,0x90,0x10,0x90,0x00,0x04, 0xFF,0xFE,0x00,0x10,0x1F,0x90,0x10,0x90,0x1F,0x90,0x10,0x90,0x00,0x50,0x00,0x20, }; unsigned char code hz2424_hong[]= { /*-- 文字: 鸿 --*/ /*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0xC0,0x08,0x00,0x80,0x0C,0x01,0x00,0x00, 0x17,0xF8,0x03,0xFC,0x18,0x44,0x44,0x98,0x24,0x44,0xD0,0x34,0x44,0x10,0x14,0x44, 0x10,0x08,0x44,0x70,0x08,0x44,0x20,0x08,0x44,0x04,0x08,0x57,0xFC,0x08,0xE0,0x0C, 0x33,0x00,0x0C,0x10,0x00,0x6C,0x10,0x3F,0x98,0x10,0x00,0x08,0x10,0x00,0x08,0x18, 0x00,0xF8,0x18,0x00,0x30,0x00,0x00,0x00, }; unsigned char code hz2424_ge[]= { /*-- 文字: 哥 --*/ /*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x1F,0xFF,0xF8,0x00,0x00,0x40,0x02, 0x08,0x40,0x03,0xF8,0x40,0x02,0x08,0x40,0x02,0x08,0x40,0x03,0xF8,0x40,0x00,0x00, 0x40,0x00,0x00,0x0C,0x1F,0xFF,0xF0,0x00,0x00,0x40,0x07,0xF8,0x40,0x06,0x08,0x40, 0x06,0x08,0x40,0x06,0x08,0x40,0x07,0xF8,0x40,0x06,0x08,0x40,0x00,0x00,0x40,0x00, 0x03,0xC0,0x00,0x00,0xC0,0x00,0x00,0x00, }; //主程序 void main(void) { init_lcd(); //初始化液晶屏 screen_clear ();//清空整屏显示内容 //左边,正显,16X16的汉字,鸿哥V5,X轴的范围是0到29 hz_display1616(0, 0,hz1616_hong,0); hz_display1616(2, 0,hz1616_ge,0); ***_display816(4, 0,***816_V,0); ***_display816(5, 0,***816_5,0); //右边,反显,24X24的汉字,鸿哥,X轴的范围是0到29 hz_display2424(20, 0,hz2424_hong,1); hz_display2424(23, 0,hz2424_ge,1); while(1) { ; } } //------------------时序延时子程序----------------------------- void delay(unsigned int t) { unsigned int i; for(i=0;i } //------------------忙闲检查,驱动液晶程序的一部分------------------------------ void chk_busy() { CSP_dr = 0; WRP_dr = 1; RSP_dr = 1; LcmDataBus = 0xff; RDP_dr = 0; while((LcmDataBus & 0x03) != 0x03); RDP_dr = 1; CSP_dr = 1; } //------------------自动写的忙闲检查,驱动液晶程序的一部分------------------------------ void chk_busy_auto_write() { CSP_dr = 0; WRP_dr = 1; RSP_dr = 1; LcmDataBus = 0xff; RDP_dr = 0; while((LcmDataBus & 0x08) ==0 ); RDP_dr = 1; CSP_dr = 1; } //------------------写命令到LCD,,驱动液晶程序的一部分------------------------------ void write_com(unsigned char cmdcode) { chk_busy(); //忙检测 CSP_dr = 0; RDP_dr = 1; RSP_dr = 1; LcmDataBus = cmdcode; WRP_dr = 0; WRP_dr = 1; CSP_dr = 1; LcmDataBus = 0xff; } //-------------------写数据到LCD,,驱动液晶程序的一部分---------------------------- void write_data(unsigned char Di_drspdata) { CSP_dr = 0; RDP_dr = 1; RSP_dr = 0; LcmDataBus = Di_drspdata; WRP_dr = 0; WRP_dr = 1; CSP_dr = 1; LcmDataBus = 0xff; } //-----写两个数据与一个指令,驱动液晶程序的一部分---------------------------- void write_data_data_com(unsigned char Di_drspdata1,unsigned char Di_drspdata2,unsigned char cmdcode3) { write_data(Di_drspdata1); write_data(Di_drspdata2); write_com(cmdcode3); } //设定显示地址函数,驱动液晶程序的一部分---------------------------- void LocateXY240128(unsigned char x,unsigned char y) //内部到底什么含义,我也是看得两眼冒星星。只要我们会用就行 { unsigned int temp; temp= LcmXPixel/8*y + x; temp+=0x0800; //图形模式要加上图形区首地址0x0800 write_data_data_com(temp&0xff,temp/256,0x24); } //*------------------清空屏幕的内容,内部的时序细节可以不管,因为我也没仔细去研究过,知道是用来干什么的就行---------------*/ void screen_clear () { unsigned char i=8192; write_data_data_com(0x00,0x00,0x24); //驱动芯片的一种固有指令,具体含义我也没有研究过 write_com(0xB0); //进入自动写 while(i--) { chk_busy_auto_write(); //自动写的忙闲检查 write_data(0x00); //清零就等于清屏 } write_com(0xB2); //退出自动写 } //显示8X16的字符函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相对//应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 void ***_display816(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag) { unsigned char j=0,i=0; for(j=0;j<16;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个8X16字符只占用16行 { LocateXY240128(col,pag+j); write_com(0xB0); //进入自动写 for(i=0;i<1;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴地址会自动加一,横向类的屏,8X16字符的宽度是8个点阵,范围是(只有一个0),(8/8)-1=0. { if(opposite_flag ==1) //反显 { write_data(~zk [1*j+i]); //发送显示的字节数据,一行1个字节,因此1*j } else //正显 { write_data(zk [1*j+i]); //发送显示的字节数据,一行1个字节,因此1*j } } write_com(0xB2); //退出自动写 } } //显示16X16的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 void hz_display1616(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag) { unsigned char j=0,i=0; for(j=0;j<16;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个16X16汉字只占用16行 { LocateXY240128(col,pag+j); write_com(0xB0); //进入自动写 for(i=0;i<2;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴地址会自动加一,横向类的屏,16X16汉字的宽度是16个点阵,范围是(0到1),(16/8)-1=1. { if(opposite_flag ==1) //反显 { write_data(~zk [2*j+i]); //发送显示的字节数据,一行2个字节,因此2*j } else //正显 { write_data(zk [2*j+i]); //发送显示的字节数据,一行2个字节,因此2*j } } write_com(0xB2); //退出自动写 } } //显示24X24的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 void hz_display2424(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag) { unsigned char j=0,i=0; for(j=0;j<24;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个24X24汉字只占用24行 { LocateXY240128(col,pag+j); write_com(0xB0); //进入自动写 for(i=0;i<3;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴地址会自动加一,横向类的屏,24X24汉字的宽度是24个点阵,范围是(0到2),(24/8)-1=2. { if(opposite_flag ==1) //反显 { write_data(~zk [3*j+i]); //发送显示的字节数据,一行3个字节,因此3*j } else //正显 { write_data(zk [3*j+i]); //发送显示的字节数据,一行3个字节,因此3*j } } write_com(0xB2); //退出自动写 } } //*------------------初始化LCD屏--------------------------*/ void init_lcd() { FS_dr = 0; //选择字体模式,具体含义我也不同,也是当使用内部字库时候的选项,我的程序都不用内部字库的 RES_dr = 0; //复位 delay(4920); RES_dr = 1; delay(14760); write_data_data_com(0x00,0x00,0x40); //设置文本显示区首地址 write_data_data_com(LcmXPixel/8,0x00,0x41); //设置文本显示区宽度 write_data_data_com(0x00,0x08,0x42); //设置图形显示区首地址0x0800 write_data_data_com(LcmXPixel/8,0x00,0x43); //设置图形显示区宽度 write_com(0xA7); //设置光标形状 8x8方块 write_com(0x81); //显示方式设置 文本xor图形(异或) write_com(0x9C); //显示开关设置 文本开,图形开,光标闪烁关 } (6)小结: 读者要重点弄清楚void ***_display816, void hz_display1616, void hz_display2424这三个函数他们之间的联系与规律,即可掌握本节内容的精髓。 自从我首次提出“鸿哥单色液晶屏三大类定律”之后,以后任何单色液晶屏的驱动程序都可以遵照此定律的思路来编写,一切显得很有规律,很有整齐的“队形”感。 (未完待续,下节更精彩,不要走开哦) |
|
|
|
|
|
|
|
|
|
|
|
|
|
学习了
|
|
|
|
|
|
楼主的风格不错
我的风格是 将 #define Unsigned char BYTE 然后用BYTE 去定义 对于IO #deifine ########_HOP 输出 高电平有效 #deifine ########_LOP 输出 低电平有效 #deifine ########_HIP 输入 高电平有效 #deifine ########_LIP 输入 低电平有效 #deifine ########_AIP AD Pin .. |
|
|
|
|
|
|
|
|
|
|
|
|
|
期待实战技巧
|
|
|
|
|
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
求解外围电路实现的是4脚给持续低电平复位并正常工作,高电平不工作的原因
2076 浏览 1 评论
3489 浏览 3 评论
PIC1946程序有一个变量在运行过程中恢复初始值其他变量保持不变
2329 浏览 2 评论
2754 浏览 0 评论
PIC16F1825的RC5引脚,在主程序中操作无效,在中断中可以改变是为什么?
4012 浏览 5 评论
960浏览 0评论
用XC8编译PIC18F25K80时提示下面Error,求怎么解决这个问题
6345浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-23 23:40 , Processed in 0.934043 second(s), Total 91, Slave 81 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号