打印
[程序源码]

实验成功5110lcd显示四行中文可以错列显示同时内存占用小

[复制链接]
3581|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 wishriver 于 2015-7-21 10:59 编辑

从学校的时候对器件成本不敏感,凡是显示,基本都用12864,一来不用花钱买,二来是操作简单,(串行模式)占用io少,显示内容还多,
前段时间偶然从废品站买了几十片5110的lcd,虽然成色很烂,但是价格便宜,5块钱一个,个个都能显示,有点占小便宜的感觉,哈哈
之前就看到很多人玩5110的屏,屏倒是不贵,10元不到,运费却要10元了,一直也没买过,
刚好这两天很闲,而且做得转接板也到手了,就把5110的文字显示学了一下

带字库的12864 面积大,使用方便,

5110价格便宜,价格便宜,价格便宜


对于单片机来说,存储较小,51的话,内置64k,存放3种ASCII点阵,加上 16x16和12x12的中文就基本可以满足一般的显示需要,比如上面diy的激光测,
标题用16的字体,其他用12的字体,感觉不算违和,
至于6x8的ASCII可以显示不太重要的数据或者比较长的数据,
最后一行的8x12的ascii则可以用来显示重要一点的数据,第一样就能看到,比如测距状态,OK还是ERROR等等


5110的lcd控制器的y地址寻址是以字节为单位的,而不是像x一样以位为单位,这就导致了,显示英文比较方便,可以在某一行任意地址显示,y方向就固定6行好了,
显示16点阵的字体也方便,因为一个汉字刚好占据两个y地址,不过实际来看,16的字体显得太大,和这块小屏幕不太和谐,而且显示内容少,所以可以选用比较秀气的12像素字体,效果也很好,但是有个小问题,12像素字体有的笔画会缺失,但是没有什么太大影响,比如下图,顺序都不会影响,缺个点之类的更不用担心啦

来看5110的控制器y地址寻址和12像素字体的关系,第0,2,4行显示是没问题到只不过 1 3 5行会空出来4个像素,比较常见的取模软件都是不足8位补足8位的,所以,y1的下半部分就是0,
显示两行12的汉字,需要用3个y地址,把第二行的汉字上移4就可以了,

单独来看y1,它包含了第一行汉字的下半部分,还包含了第二行汉字的上半部分,而且,第二行汉字的上半部分显示在了y1的下半部分(比较绕口)看图可以看得出来

不过这样看好像就比较清楚了,其实第二行中文的y方向起始地址还是y1,和第一行汉字的y地址重合,数据移位处理即可

那就可以使用单片机的xdata内存区存放交叉区的缓存数据,
显示12像素的汉字,可以显示4行,
我们把第一行的汉字的y1区0-83个地址都存下来,叫做y0ram,
第二行中文的y1区0-83个地址都存下来叫做 y1ram  
每当显示到这两个地址的时候,就把这两个ram缓存保存下来,
再显示下一行的时候进行移位没然后数据或运算在写到控制器里,就可以了,
当然也可以按照控制器的地址来划分,y1就叫y1ram,y3就叫y3ram,这样在数据保存的时候进行移位,而且还节约了84*2字节的内存,效果是一样的,
可以用一张图来表示

在程序中

然后再从主函数里调用

再说一下字库吧,因为毕竟不是完整真正的字库,所以显示不知寻址来的,是查表来的,字库呢,分为两部分呢,一部分是索引,放在后面,一部分是点阵数据,放前面,比如我查找到"滚"是结构体中第0个元素索引中
那就调取播放图标进行显示
其他同理


实际效果如下




5110的驱动部分源码,写的不好大家批评
/*
显示12*12的字体,任意地址,上下错开也解决了
*/
#include<reg51.h>
#include"Nokia5110Lcd.h"
#include "lcd5110font.c"

#include<intrins.h>
#define   nop() _nop_()
#define uchar unsigned char
#define uint unsigned int

uchar xdata Y0Ram[84]; //第0行汉字的临时缓存
uchar xdata Y1Ram[84];
uchar xdata Y2Ram[84];
uchar xdata Y3Ram[84];
void delay(int t)
{
        uchar i;
        while (t--)
        {
                for (i=0;i<125;i++)
                        {}
        }
}
void Lcd5110WriteDta(uchar dat)
{
        unsigned char i;
        sce=0;
        dc=1;
        for (i=0;i<8;i++)
        {
                if (dat&0x80)
                        sdin=1;
                else
                        sdin=0;
                dat=dat<<1;
                sclk=0;
                nop();
                sclk=1;
        }
        dc=1;
        sce=1;
        sdin=1;
}
void Lcd5110WriteCMD(uchar dat)
{
        unsigned char i;
        sce=0;
        dc=0;
        for (i=0;i<8;i++)
        {
                if (dat&0x80)
                        sdin=1;
                else
                        sdin=0;
                dat=dat<<1;
                sclk=0;
                nop();
                sclk=1;

        }
        dc=1;
        sce=1;
        sdin=1;
}
/*---------------------------------------
LCD_init: 3310LCD初始化
编写日期:20080918
-----------------------------------------  */
void Lcd5110Init(void)
{
        char i;
        // res=0;
        // delay(10);
        // res=1; //以上三句 不用也行
        Lcd5110WriteCMD(0x21 );//初始化Lcd,功能设定使用扩充指令
        Lcd5110WriteCMD(0xb2 );//设定液晶偏置电压
        //Lcd5110WriteCMD(0xc0);//设定液晶偏置电压 //调试用 显示全黑
        Lcd5110WriteCMD(0x02 );//温度校正
        Lcd5110WriteCMD(0x13 );//1:48
        Lcd5110WriteCMD(0x20 );//使用基本指令
        Lcd5110WriteCMD(0x0C );//设定显示模式,正常显示
        for (i=0;i<84;i++)
        {
                Y0Ram[i]=Y1Ram[i]=Y2Ram[i]=Y3Ram[i]=0;
        }
}
/*-------------------------------------------
LCD_set_XY: 设置LCD坐标函数
输入参数:X:0-83  Y:0-5
编写日期:20080918
---------------------------------------------*/
void Lcd5110SetXY(uchar X,Y)
{
        Lcd5110WriteCMD(0x40 | Y  );// 垂直方向 0-5
        Lcd5110WriteCMD(0x80 | X  );// 水平方向0-83
}
/*------------------------------------------
LCD_clear: LCD清屏函数
编写日期:20080918
--------------------------------------------*/
void Lcd5110Clear(void)
{
        unsigned char t;
        unsigned char k;
        Lcd5110SetXY(0,0);
        for (t=0;t<6;t++)
        {
                for (k=0;k<84;k++)
                        Lcd5110WriteDta(0x00);
        }
}
/*---------------------------------------------
LCD_write_shu: 显示8(宽)*16(高)点阵列数字字母符号等半角类

addr:写入地址
row: 第几行 对于6*8点阵 实际5*7留有空边,字高8个点, 屏幕一共6行  竖着48个点
dd:字符
-----------------------------------------------*/
void Lcd5110Write6x8AtAddr(uchar row, addr, dat)
{
        unsigned char i;

        dat=dat-32; //ascii转换为字库偏移地址
        Lcd5110SetXY(addr, row-1);// 某行的某个地址 行1-6地址0-83
        for (i=0; i<6;i++)
        {
                Lcd5110WriteDta(Ascii6x8[dat*6+i]);
        }

}
void Lcd5110show6x8AscWithNoAddr(uchar  dat)//显示一个6*8点阵
{
        uchar i;
        dat-=32;
        for (i=0; i<6;i++)
                Lcd5110WriteDta(Ascii6x8[dat*6+i]);
}


void Lcd5110String6x8(uchar row , addr, uchar *p)
{

        Lcd5110SetXY(addr, row);// 列,页

        while (*p!='\0')
        {
                Lcd5110show6x8AscWithNoAddr(*p++);
        }

}
void Lcd5110show8x16AscAtAddr(uchar row,addr,  dat)
{
        uchar i ;
        dat-=32;
        Lcd5110SetXY(addr,row);
        for (i=0; i<8;i++)
                Lcd5110WriteDta(Ascii8x16[dat*16+i]);
        Lcd5110SetXY(addr,row+1);
        for (i=8; i<16;i++)
                Lcd5110WriteDta(Ascii8x16[dat*16+i]);
}


/*
行 范围 1-6一共6行,但在行=6的时候会显示不全
*/
void Lcd5110String8x16(uchar row , addr, uchar *p)
{
        //不再用8*16的ascii了,直接屏蔽掉,想用的时候在解除屏蔽即可
        uchar dat;
        while (*p!='\0')
        {
                dat =*p;
                Lcd5110show8x16AscAtAddr(row-1 ,addr, dat);
                *p++;
                addr+=8;
        }
}

void Lcd5110DisplayAscii8x12AtAddr(uchar row,addr, dat)
{

        uchar i, LocalHalfWidth,LocalFullWidth; //半宽字体,全宽字体
        LocalHalfWidth=8;//8*12的字体,光看上面一半8字节
        LocalFullWidth=16;//8*12的字体,上下两行就是16字节

        dat-=32;
        if (row==0)//按照4行显示,首行为0,地址就是0-3行,不是控制器的地址
        {
                Lcd5110SetXY(addr, row);// 列,页
                for (i=0; i<LocalHalfWidth;i++) //上半部分 12个像素
                {
                        Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]);
                }
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12个像素
                {
                        Y0Ram[addr+i-LocalHalfWidth]=Ascii8x12[dat*LocalFullWidth+i]; //第0行的下半部分12个字节存起来
                        Lcd5110WriteDta(Y0Ram[addr+i-LocalHalfWidth] | Y1Ram[addr+i-LocalHalfWidth]<<4 );
                }

        }
        if (row==1)
        {
                Lcd5110SetXY(addr, row);// 列,页
                for (i=0; i<LocalHalfWidth;i++) //上半部分 12个像素
                {
                        Y1Ram[addr+i]=Ascii8x12[dat*LocalFullWidth+i];//第1行上半部分存起来
                        Lcd5110WriteDta(Y1Ram[addr+i]<<4 | Y0Ram[addr+i]);
                }
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12个像素
                {
                        Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]<<4 | Ascii8x12[dat*LocalFullWidth+i-LocalHalfWidth]>>4  );
                }

        }

        if (row==2)//按照4行显示,首行为0,地址就是0-3行,不是控制器的地址
        {
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=0; i<LocalHalfWidth;i++) //上半部分 12个像素
                {
                        Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]);
                }
                Lcd5110SetXY(addr, row+2);// 列,页
                for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12个像素
                {
                        Y2Ram[addr+i-LocalHalfWidth]=Ascii8x12[dat*LocalFullWidth+i]; //第0行的下半部分12个字节存起来
                        Lcd5110WriteDta(Y2Ram[addr+i-LocalHalfWidth] | Y3Ram[addr+i-LocalHalfWidth]<<4 );
                }

        }
        if (row==3)//按照4行显示的话,地址就是0-3行
        {
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=0; i<LocalHalfWidth;i++) //上半部分 12个像素
                {
                        Y3Ram[addr+i]=Ascii8x12[dat*LocalFullWidth+i];//第1行上半部分存起来
                        Lcd5110WriteDta(Y3Ram[addr+i]<<4 | Y2Ram[addr+i]);
                }
                Lcd5110SetXY(addr, row+2);// 列,页
                for (i=LocalHalfWidth; i<LocalFullWidth;i++) //下半部分 12个像素
                {
                        Lcd5110WriteDta(Ascii8x12[dat*LocalFullWidth+i]<<4 | Ascii8x12[dat*LocalFullWidth+i-LocalHalfWidth]>>4);
                }

        }
}

void Lcd5110String8x12(uchar row,addr,uchar *p)
{
        uchar dat;
        while (*p!='\0')
        {
                dat =*p;
                Lcd5110DisplayAscii8x12AtAddr(row ,addr, dat);
                *p++;
                addr+=8;
                //delay(6000); //调试用 慢动作
        }
}
/*---------------------------------------------
              在某行某地址显示中文字符,
-----------------------------------------------*/
void DispOneChs12x12(uchar row,addr,uchar *p)
{

        uchar i, LocalHalfWidth,LocalFullWidth; //半宽字体,全宽字体
        if (row==0)//按照4行显示,首行为0,地址就是0-3行,不是控制器的地址
        {
                Lcd5110SetXY(addr, row);// 列,页
                for (i=0; i<12;i++) //上半部分 12个像素
                {
                        Lcd5110WriteDta(p[i]);
                }
                Lcd5110SetXY(addr, row+1);

                /*字体的下半部分需要存储起来*/
                for (i=12; i<24;i++) //下半部分 12个像素
                {
                        Y0Ram[addr+i-12]=p[i]; //第0行的下半部分12个字节存起来,数组要保存文字的下半部分和这些数据在什么位置 0-83
                        Lcd5110WriteDta(Y0Ram[addr+i-12] | Y1Ram[addr+i-12]<<4 );
                }

        }
        if (row==1)
        {
                Lcd5110SetXY(addr, row);// 列,页
                for (i=0; i<12;i++) //上半部分 12个像素
                {
                        Y1Ram[addr+i]=p[i];//第1行上半部分存起来
                        Lcd5110WriteDta(Y1Ram[ addr+i]<<4 |Y0Ram[addr+i]);
                }
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=12; i<24;i++) //下半部分 12个像素
                {
                        Lcd5110WriteDta(p[i]<<4 | p[i-12]>>4  );
                }

        }
        if (row==2)//按照4行显示,首行为0,地址就是0-3行,不是控制器的地址
        {
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=0; i<12;i++) //上半部分 12个像素
                {
                        Lcd5110WriteDta(p[i]);
                }
                Lcd5110SetXY(addr, row+2);

                /*字体的下半部分需要存储起来*/
                for (i=12; i<24;i++) //下半部分 12个像素
                {
                        Y2Ram[addr+i-12]=p[i]; //第0行的下半部分12个字节存起来,数组要保存文字的下半部分和这些数据在什么位置 0-83
                        Lcd5110WriteDta(Y2Ram[addr+i-12] | Y3Ram[addr+i-12]<<4 );
                }

        }
        if (row==3)
        {
                Lcd5110SetXY(addr, row+1);// 列,页
                for (i=0; i<12;i++) //上半部分 12个像素
                {
                        Y3Ram[addr+i]=p[i];//第1行上半部分存起来
                        Lcd5110WriteDta(Y3Ram[ addr+i]<<4 |Y2Ram[addr+i]);
                }
                Lcd5110SetXY(addr, row+2);// 列,页
                for (i=12; i<24;i++) //下半部分 12个像素
                {
                        Lcd5110WriteDta(p[i]<<4 | p[i-12]>>4  );
                }

        }

}
void FindHZ12fromGBK12(uchar row ,addr ,uchar *dat)
{
        uchar i;
        for (i=0;i<LenthOfGbk12;i++) //索引
        {
                if ( (GBK12[i].Index[0] == dat[0]) && (GBK12[i].Index[1] == dat[1])) break;
        }

        DispOneChs12x12(row,addr,GBK12[i].Matrix);

}
void Lcd5110ChString12(uchar row,addr, uchar*dat)
{
        while (*dat)
        {
                FindHZ12fromGBK12(row,addr,dat);
                addr+=12;//12宽的字体,写完一个x地址加12
                dat+=2;        //dat是索引数据,一个汉字的索引由两个字节组成
        }
}
//显示一个 16*16的汉字,参数是指针,指向点阵数组
void DispOneChs16x16(uchar row,addr,uchar *dat)
{
        uchar i,j;
        for (j=0; j<2;j++)
        {
                Lcd5110SetXY(addr, row+j);// 列,页
                for (i=0; i<16;i++)
                        Lcd5110WriteDta(dat[16*j+i]);

        }
}
/*从字库里 用 汉字的指针 查找一个汉字 并显示出来   调用上面的函数 */
void FindHZ16fromGBK16(uchar row,addr, uchar *dat)
{
        uchar i;
        for (i=0;i<LenthOfGbk16;i++) //索引
        {
                if ( (GBK16[i].Index[0] == dat[0]) && (GBK16[i].Index[1] == dat[1])) break;
        }
        switch (row)
        {
        case 0:
                row=0;
                break;
        case 1:
                row=2;
                break;
        case 2:
                row=4;
                break;
        default:
                break;
        }
        DispOneChs16x16(row,addr,GBK16[i].Matrix);//把这个汉字显示出来,指向点阵区

}
//把数组的汉字显示出来,传入的参数是指针 双引号
void Lcd5110ChString16(uchar row,addr,uchar *dat)
{
        while (*dat)
        {
                FindHZ16fromGBK16(row,addr,dat);
                addr+=16;//16宽的字体,写完一个x地址加16
                dat+=2;        //dat是索引数据,一个汉字的索引由两个字节组成
        }
}
/*使用一个6x8的字体显示一个3位整数*/
void Lcd5110DispHundredIn6x8(uchar row,addr, int dat)
{
        Lcd5110SetXY(addr,row);
        Lcd5110show6x8AscWithNoAddr(48+dat/100);
        Lcd5110show6x8AscWithNoAddr(48+dat%100/10);
        Lcd5110show6x8AscWithNoAddr(48+dat%100%10);
}
//row,地址,传入
void Lcd5110DispHundredIn12x12(uchar row,addr,int dat)
{
        Lcd5110DisplayAscii8x12AtAddr(row,addr,48+dat/100);
        Lcd5110DisplayAscii8x12AtAddr(row,addr+8,48+dat%100/10);
        Lcd5110DisplayAscii8x12AtAddr(row,addr+16,48+dat%100%10);

}


评分
参与人数 1威望 +3 收起 理由
ningling_21 + 3 赞一个!

相关帖子

沙发
JY-DX-JY| | 2015-7-21 17:36 | 只看该作者
顶一个。。。。。。。。。。。

使用特权

评论回复
板凳
知识阅览者| | 2015-11-30 08:45 | 只看该作者
还不错!!!

使用特权

评论回复
地板
试一下看看能不能实现

使用特权

评论回复
5
冷雨♥| | 2017-8-8 18:49 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

84

帖子

4

粉丝