PIC单片机 吴坚鸿单片机程序风格赏析2.docx
- 文档编号:7322035
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:114
- 大小:64.19KB
PIC单片机 吴坚鸿单片机程序风格赏析2.docx
《PIC单片机 吴坚鸿单片机程序风格赏析2.docx》由会员分享,可在线阅读,更多相关《PIC单片机 吴坚鸿单片机程序风格赏析2.docx(114页珍藏版)》请在冰豆网上搜索。
PIC单片机吴坚鸿单片机程序风格赏析2
第十一节:
鸿哥单色液晶屏三大类定律(KS0107驱动12864屏)
(1)开场白:
我曾经做过一年的液晶屏工程师,“出家”做自由职业者之后我又在很多项目上应用液晶屏。
深圳很多液晶模块公司都是用我帮他们做的测试程序。
不管什么品种的单色屏我都能玩得转。
谦虚一点说就是,在单色液晶驱动程序这方面,吴坚鸿在全国绝对排名在前三名之内(如果不谦虚地说我就号称第一了,呵呵)。
接下来我要介绍一下我的新发现,单色屏驱动程序的三大类定律。
市面上有各种各样的单色屏,什么点阵,段码等等,但是都逃不出我总结的三大类定律。
读者只要学会了鸿哥的三大类定律,以后任何单色屏对于你们来说都是浮云。
想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。
在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。
第一大类定律:
纵向显示八个点的类型。
这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。
而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
第二大类定律:
横向显示八个点的类型。
这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
第三大类定律:
任意位置显示一个点的类型。
这类液晶屏在任意位置上以一个点为基本单位,因此X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。
而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。
下面,我以驱动芯片为KS0107的12864液晶屏为例子,来介绍一下第一大类定律:
纵向显示八个点的类型。
12864液晶屏实际上是由左右两块6464液晶屏合并在一起的,然后通过两根IO口来片选不同的6464液晶屏。
因此,我们只要弄懂了一块6464液晶屏的显示方法就够了。
6464屏在横向上是64个点,纵向上是64个点,也就是一个正方形的屏。
因为它属于第一大类的屏,所以X轴坐标数值的最大范围是64-1=63,而纵向坐标数值的最大范围是(64/8)-1=7.正常的操作思路是这样的,先发送X轴与Y轴的位置数据,确定位置后,就发送一个字节(八个点)的显示数据。
这类屏还有一个特征,连续发送显示数据时,在横向(X轴上)的位置数据会自动加一,因此如果在不换行的情况下,只要设定一次位置,就可以从左到右连续发送显示的数据。
当换行显示数据时,必须重新设定一下坐标位置。
字节正序与倒序的概念解释:
当我们一次在纵向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从上到下的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。
12864这个屏是属于倒序的屏。
取模软件是必须的,读者可以在网上自己下载,资料很多。
(2)功能需求:
在12864屏上显示8X16的字符,16X16的汉字,24X24的汉字。
(3)硬件原理:
液晶屏的VEE接20K可调电阻的左边端口,VO接可调电阻的中间端口,VSS接可调电阻的右边端口,此可调电阻在这里用来调节液晶屏的对比度。
模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。
这个大家都懂。
(4)源码适合的单片机:
PIC18f4520,晶振为11.0592MHz。
(5)源代码讲解如下:
#include
#defineDisp_On0x3f//液晶模块的寄存器初始化的参数,抄网上的,我也从来没有
#defineDisp_Off0x3e//研究过它是什么含义,因为根本没必要知道,直接用就行
#defineCol_Add0x40
#definePage_Add0xb8
#defineStart_Line0xc0
//补充说明:
吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus
#defineLcd_busPORTB//液晶的数据总线
#defineBf_srRB7//芯片忙检查
#defineMcs_drLATD6//左右6464屏的片选
#defineScs_drLATD7//左右6464屏的片选
#defineEnable_drLATD5//类似时钟的数据线
#defineDi_drRC7//数据与指令的选择线
#defineRW_drRD4//读与写的选择线
voiddelay(unsignedintt);//时序延时函数声明
voidchk_busy();//忙检测,液晶驱动时序的一部分
voidwrite_com(unsignedcharcmdcode);//往液晶模块写入指令
voidwrite_data(unsignedcharDi_drspdata);//往液晶模块写入数据
voidscreen_clear();//清空屏的内容
voidzf_display816(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag);//显示8X16的字符函数,本节的核心内容
voidhz_display1616(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag);//显示16X16的汉字函数,本节的核心内容
voidhz_display2424(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag);//显示24X24的汉字函数,本节的核心内容
voidinit_lcd();//初始化液晶模块
//补充说明:
吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用zf,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。
如果有重复的,则多加一个序列号标////识。
如果是汉字,则前缀用hz,其它的一样。
constunsignedcharzf816_v[]=//从取模软件中复制的字库,纵向取模,字节倒序
{
/*--文字:
V--*/
/*--宋体12;此字体下对应的点阵为:
宽x高=8x16--*/
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,
};
constunsignedcharzf816_5[]=
{
/*--文字:
5--*/
/*--宋体12;此字体下对应的点阵为:
宽x高=8x16--*/
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,
};
constunsignedcharhz1616_hong[]=
{
/*--文字:
鸿--*/
/*--宋体12;此字体下对应的点阵为:
宽x高=16x16--*/
0x10,0x61,0x86,0x60,0x08,0xF8,0x08,0x00,0xFC,0x0E,0x35,0x04,0x44,0x7C,0x00,0x00,
0x04,0x7C,0x03,0x04,0x04,0x03,0x0A,0x08,0x09,0x09,0x09,0x09,0x49,0x81,0x7F,0x00,
};
constunsignedcharhz1616_ge[]=
{
/*--文字:
哥--*/
/*--宋体12;此字体下对应的点阵为:
宽x高=16x16--*/
0x00,0x02,0x02,0x7A,0x2A,0x2A,0x2A,0x2A,0x7A,0x02,0x02,0x7E,0x02,0x82,0x00,0x00,
0x01,0x01,0x01,0x3D,0x15,0x15,0x15,0x15,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00,
};
constunsignedcharhz2424_hong[]=
{
/*--文字:
鸿--*/
/*--宋体18;此字体下对应的点阵为:
宽x高=24x24--*/
0x00,0x80,0x00,0x04,0x18,0x90,0x40,0x40,0x40,0xC0,0x40,0x60,0x40,0xE0,0x20,0x30,
0xAC,0x24,0x20,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x03,0x06,0xF8,0x07,0x00,0x00,
0x80,0xFF,0x80,0x40,0x00,0x7F,0x40,0x40,0x41,0x49,0x58,0x4F,0xC0,0xE0,0x00,0x00,
0x00,0x00,0x01,0x7F,0x60,0x00,0x01,0x01,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,
0x24,0x22,0x62,0x64,0x3F,0x03,0x00,0x00,
};
constunsignedcharhz2424_ge[]=
{
/*--文字:
哥--*/
/*--宋体18;此字体下对应的点阵为:
宽x高=24x24--*/
0x00,0x00,0x00,0x08,0x08,0x08,0xE8,0x48,0x48,0x48,0x48,0x48,0xE8,0x08,0x08,0x08,
0x08,0xF8,0x08,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xD0,0xD3,0x52,
0x52,0x52,0x52,0x52,0xD3,0x10,0x10,0x10,0x10,0xF7,0x10,0x10,0x08,0x08,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x04,0x04,0x04,0x04,0x04,0x0F,0x00,0x20,0x20,
0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,
};
//主程序
main()
{
ADCON0=0x00;
ADCON1=0x0f;
ADCON2=0x00;
TRISA=0x02;
TRISE=0x00;
TRISC=0x7f;
TRISD=0x0f;
TRISB=0x00;
RBPU=0;
SSPEN=0;//决定RA5作为IO
TRISE2=1;
//补充说明,以上的内容为寄存器配置,每种不同的单片机会有点差异,
//大家不用过度关注以上寄存器的配置,只要知道有这么一回事即可
init_lcd();//初始化液晶屏
screen_clear();//清空整屏显示内容
Mcs_dr=1;Scs_dr=0;//左6464屏,正显,16X16的汉字,“鸿哥V5”
hz_display1616(0,0,hz1616_hong,0);
hz_display1616(16,0,hz1616_ge,0);
zf_display816(32,0,zf816_V,0);
zf_display816(40,0,zf816_5,0);
Mcs_dr=0;Scs_dr=1;//右6464屏,反显,24X24的汉字,“鸿哥V5”
hz_display2424(0,0,hz2424_hong,1);
hz_display2424(24,0,hz2424_ge,1);
zf_display816(48,0,zf816_V,1);
zf_display816(56,0,zf816_5,1);
while
(1)
{
CLRWDT();//喂看门狗,大家不用过度关注此行
}
}
//------------------时序延时子程序-----------------------------
voiddelay(unsignedintt)
{
unsignedinti,j;
for(i=0;i for(j=0;j<10;j++)CLRWDT(); } //------------------忙闲检查,驱动液晶程序的一部分------------------------------ voidchk_busy() { TRISB=0xff; Lcd_bus=0xff; Di_dr=0; RW_dr=1; delay(0); Enable_dr=1; while(Bf_sr==1); Enable_dr=0; TRISB=0x00; } //------------------写命令到LCD,,驱动液晶程序的一部分------------------------------ voidwrite_com(unsignedcharcmdcode) { chk_busy(); Di_dr=0; RW_dr=0; Lcd_bus=cmdcode; delay(0); Enable_dr=1; delay(0); Enable_dr=0; } //-------------------写数据到LCD,,驱动液晶程序的一部分---------------------------- voidwrite_data(unsignedcharDi_drspdata) { chk_busy(); Di_dr=1; RW_dr=0; Lcd_bus=Di_drspdata; delay(0); Enable_dr=1; delay(0); Enable_dr=0; } //*------------------清空屏幕的内容,本节的核心内容---------------*/ voidscreen_clear() { unsignedcharj,i; Mcs_dr=1;Scs_dr=0;//选择左屏6464 for(j=0;j<8;j++)//此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7. { write_com(Page_Add+j);//设定Y轴的起始位置,切换到下一行 write_com(Col_Add+0);//设定X轴的起始位置,每次换行都从0开始 for(i=0;i<64;i++)//此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63 { write_data(0x00);//都显示空内容,达到清空的目的 } } Mcs_dr=0;Scs_dr=1;//选择右屏6464 for(j=0;j<8;j++)//此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7. { write_com(Page_Add+j);//设定Y轴的起始位置,切换到下一行 write_com(Col_Add+0);//设定X轴的起始位置,每次换行都从0开始 for(i=0;i<64;i++)//此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63 { write_data(0x00);//都显示空内容,达到清空的目的 } } } //显示8X16的字符函数,本节的核心内容。 col代表X轴,pag代表Y轴,zk代表显示相对//应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 voidzf_display816(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag) { unsignedcharj=0,i=0; for(j=0;j<2;j++)//此处j代表Y轴的数据,也就是显示第几行了,一个8X16字符只占用//两行,每行8个点,两行的高度就是16个点, { write_com(Page_Add+pag+j);//换下一行Y轴的坐标 write_com(Col_Add+col);//每次换行都重新设定X轴的坐标, for(i=0;i<8;i++)//此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个字符的宽度是8个点,因此范围是(0到7),8-1=7. { if(opposite_flag==1)//反显 { write_data(~zk[8*j+i]);//发送显示的字节数据,纵向显示八个点,一行8个///点,因此8*j } else//正显 { write_data(zk[8*j+i]);//发送显示的字节数据,纵向显示八个点,一行8个点,//因此8*j } } } } //显示16X16的汉字函数,本节的核心内容。 col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 voidhz_display1616(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag) { unsignedcharj=0,i=0; for(j=0;j<2;j++)//此处j代表Y轴的数据,也就是显示第几行了,一个16X16汉字只占//用两行,每行8个点,两行的高度就是16个点, { write_com(Page_Add+pag+j);//换下一行Y轴的坐标 write_com(Col_Add+col);//每次换行都重新设定X轴的坐标, for(i=0;i<16;i++)//此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个16X16汉字的宽度是16个点,因此范围是(0到15),16-1=15. { if(opposite_flag==1)//反显 { write_data(~zk[16*j+i]);//发送显示的字节数据,纵向显示八个点,一行16个///点,因此16*j } else//正显 { write_data(zk[16*j+i]);//发送显示的字节数据,纵向显示八个点,一行16个点,//因此16*j } } } } //显示24X24的汉字函数,本节的核心内容。 col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显 voidhz_display2424(unsignedcharcol,unsignedcharpag,constunsignedchar*zk,unsignedcharopposite_flag) { unsignedcharj=0,i=0; for(j=0;j<3;j++)//此处j代表Y轴的数据,也就是显示第几行了,一个24X24汉字只占//用三行,每行8个点,三行的高度就是24个点, { write_com(Page_Add+pag+j);//换下一行Y轴的坐标 write_com(Col_Add+col);//每次换行都重新设定X轴的坐标, for(i=0;i<24;i++)//此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个24X24汉字的宽度是24个点,因此范围是(0到23),24-1=23. { if(opposite_flag==1)//反显 { write_data(~zk[24*j+i]);//发送显示的字节数据,纵向显示八个点,一行24///个点,因此24*j } else//正显 { write_data(zk[24*j+i]);//发送显示的字节数据,纵向显示八个点,一行24个/////点,因此24*j } } } } //*------------------初始化LCD屏--------------------------*/ voidinit_lcd() { Mcs_dr=1;//左6464屏初始化 Scs_dr=0; delay(100); write_com(Disp_Off); write_com(Page_Add+0); write_com(Start_Line+0); write_com(Col_Add+0); write_com(Disp_On); Mcs_dr=0;//右6464屏初始化 Scs_dr=1; delay(100); write_com(Disp_Off); write_com(Page_Add+0); write_com(Start_Line+0); write_com(Col_Add+0); write_com(Disp_On); } (6)小结: 读者要重点弄清楚voidscreen_clear,voidzf_display816,voidhz_display1616,voidhz_display2424这四个函数他们之间的联系与规律,即可掌握本节内容的精髓。 12864是由左右两个屏合并起来的,如果想一个汉字左边显示在左屏,右边显示在右屏,也就是跨屏显示的功能,或者如果想显示一副128X64的图像,根据本节的精髓,读者只要在程序上做一些改动处理,应该不难的。 这类液晶屏在纵向上只适合显示点阵数是8倍数的字体,如果不是8倍数的点阵字体,则需要在程序上做特殊处理,这种不是8倍数的字体不实用,同时,我认为跨屏显示的功能也不实用,读者也没必要逞强去尝试。 第十二节: 液晶屏第一大类定律--纵向显示八个点(KS0107驱动19264屏) (1)开场白: 在第十一节中介绍了我的新发现“吴坚鸿单色液晶屏三大类定律”,既然是定律就应该是放之四海而皆准,否则就是我吹牛。 为了证明它的真理性与普遍性,这节我将以驱动芯片为KS0107的19264屏为例子。 先补一下第十一节的基本知识。 想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。 在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。 第一大类定律: 纵向显示八个点的类型。 这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。 而X坐标数值的最大范
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- PIC单片机 吴坚鸿单片机程序风格赏析2 PIC 单片机 吴坚鸿 程序 风格 赏析