jssd 发表于 2020-4-20 11:51:15

【开源】LCD12864 ST7920带中文字库屏驱动程序

刚调通了LCD12864 芯片为ST7920带中文字库的屏的驱动,串行驱动,贴出来让大家挑挑刺,顺便开源备份一下
功能:说白了,其实就3个
        1、显示字符串
        2、显示数字
        3、反白显示
说明:
        1、先说字符串,因为屏幕自带了字库16*16的,支持中文,只能显示4行,每行16字节,特别是中英文混合显示,处理不好会乱码,所以这部分也没特别好的办法,直接由用户控制了。支持反白显示
        2、数字显示支持十进制和十六进制,左对齐、右对齐和中间对齐,支持全部显示或者只显示一部分空白部分支持自定义字符(当然是字库要有才行),支持反白显示。
        3、反白显示可以单独控制,用0x00和0xff就可以适应大部分应用,也就是透明和不透明之分。当然,改一下也可以支持图形,这个目前没做。。
效果:        LCD_ShowNumber(2,0,0x567890,FORMAT_H|DISP_ALL,' ',0xff);
                LCD_ShowNumber(2,1,-12345,FORMAT_D|ALIGN_R|10,'*',0x00);
                LCD_ShowNumber(2,2,12345,FORMAT_D|ALIGN_M|7,' ',0xff);
                LCD_ShowNumber(5,3,tick,FORMAT_D|ALIGN_M|DISP_ALL,' ',0xff);

以上。。

以下是头文件
#ifndef __LCD12864_ZK_H
#define __LCD12864_ZK_H

#include "main.h"

//数据显示长度
#defineDISP_MASK           0x1F
#defineDISP_ALL           0x00

//进制格式
#defineFORMAT_MASK           0x80
#defineFORMAT_D           0x00 //十进制Decimal
#defineFORMAT_H           0x80 //十六进制Hexadecimal

//对齐方式
#defineALIGN_MASK           0x60
#defineALIGN_R                   0x00 //右对齐
#defineALIGN_L                   0x20 //左对齐
#defineALIGN_M               0x40 //中间对齐

void LCD_Init(void);
void LCD_ShowString(unsigned char x,unsigned char y,const char *pStr,unsigned char bg);
void LCD_ShowNumber(unsigned char x,unsigned char y,long num,unsigned char param,char fill,unsigned char bg);
void LCD_SetWhite(unsigned char x,unsigned char y,unsigned char width);
void LCD_SetBG(unsigned char x,unsigned char y,unsigned char w,unsigned char bg);
void LCD_Process(void);
       

#endif



以下是C文件
#include "main.h"

#define LCD_RST_1                P20 = 1
#define LCD_RST_0                P20 = 0

#define LCD_CS_1                P26 = 1
#define LCD_CS_0                P26 = 0

#define LCD_CLK_1                P24 = 1
#define LCD_CLK_0                P24 = 0

#define LCD_SID_1                P25 = 1
#define LCD_SID_0                P25 = 0



static void write(char cmd, unsigned char dat) //写指令或数据数据cmd=1:0xfa 命令cmd=0:0xf8
{        unsigned char i,j,Temp;
       
        LCD_CS_1;
        LCD_CLK_0;
       
        for(j=0;j<3;j++){             
                       if (j==0){ Temp =( cmd? 0xfa:0xf8);}
                else if (j==1){ Temp =((dat<<0) & 0xf0);}
                else if (j==2){ Temp =((dat<<4) & 0xf0);}
                for(i=0;i<8;i++){
                        (Temp&0x80)?(LCD_SID_1):(LCD_SID_0);Temp<<=1; delay_us(1); //左移
                        LCD_CLK_1; //delay_us(1);   //_nop_();_nop_();//移入
                        LCD_CLK_0; //delay_us(1);   //_nop_();_nop_();_nop_(); //读出
                }
        }
        LCD_CS_0;
}       

unsigned char SetWdat;//反白显示缓存
unsigned char SetWdat_bak;//反白显示缓存

//设置反白区域
void LCD_SetBG(unsigned char x,unsigned char y,unsigned char w,unsigned char bg)
{
        unsigned char i;
        if(x>15||y>3||w==0) return; //超出范围
        if(w+x>16) w = 16-x;
        for(i=0;i<w;i++){
                SetWdat[(y<<4)+x+i] = bg;
        }
}

//反白显示2字节
void LCD_ShowBG2Byte(unsigned char n)
{
        unsigned char Ax[] = {0x80,0x80,0x88,0x88};
        unsigned char Ay[] = {0x80,0x90,0x80,0x90};
        unsigned char j;
        unsigned char x = ((n&0x0f)>>1);
        unsigned char y = (n>>4);
       
        write(0,0x34); write(0,0x36); //打开GGRAM
        for(j=0;j<16;j++){
                write(0,Ay+j); //y
                write(0,Ax+x); //x
                write(1,SetWdat);
                write(1,SetWdat);
        }
        write(0,0x30); //关闭GGRAM
}

void LCD_BGProcess(void) //反白显示
{
        unsigned char i;
        for(i=0;i<64;i+=2){
                if((SetWdat_bak!=SetWdat)||(SetWdat_bak!=SetWdat)){ SetWdat_bak = SetWdat; SetWdat_bak = SetWdat;
                        LCD_ShowBG2Byte(i);
                }
        }
}


unsigned char LCDdat;//显示缓存
unsigned char LCDdat_bak;//显示缓存备份

void LCD_Process(void) //模拟刷屏12864
{       
        unsigned char Addr[] = {0x80,0x90,0x88,0x98};
        unsigned char i;
       
        for(i=0;i<64;i+=2){
                if((LCDdat_bak!=LCDdat)||(LCDdat_bak!=LCDdat)){LCDdat_bak = LCDdat;LCDdat_bak = LCDdat;
                        write(0,Addr+((i&0x0f)>>1)); //写地址 控制光标
                        write(1,LCDdat);   //数据一次要连写两个
                        write(1,LCDdat); //数据一次要连写两个
                }
        }
        LCD_BGProcess();
}

//void LCD_RefreshALL(void) //模拟刷屏12864
//{       
//        unsigned char Addr[] = {0x80,0x90,0x88,0x98};
//        unsigned char i,j;
//       
//        for(i=0;i<4;i++){ //送四行汉字 //一次送一个汉字 (两个字节)
//                write(0,Addr); //先送地址后送16个字符
//                for(j=0;j<16;j++){write(1,LCDdat[(i*16)+j]);}
//        }
//}




void LCD_ClearGM(void)
{
        unsigned char i,j;
        write(0,0x34);
        write(0,0x36);
        for(j=0;j<32;j++)
        {
                write(0,0x80+j);
                write(0,0x80);
                for(i=0;i<16;i++)
                {
                        write(1,0x00);
                }
        }
        for(j=0;j<32;j++)
        {
                write(0,0x80+j);
                write(0,0x88);
                for(i=0;i<16;i++)
                {
                        write(1,0x00);
                }
        }
        write(0,0x30);
}

//******************** 显示字符串 ***********************//
//**x:横坐标(0~15)y:纵坐标(0~3)显示中文时注意从x坐标偶数写,否则乱码
void LCD_ShowString(unsigned char x,unsigned char y,const char *pStr,unsigned char bg)
{
        unsigned char i;
        unsigned int strLen = strlen(pStr);        //字符串长度用 strlen(); 类型长度 sizeof();
        if(strLen<=0||x>15||y>3) return; //超出范围
       
        if(strLen+x>16) strLen = 16-x;
        for(i=0;i<strLen;i++){ //只在一行显示,超出部分丢弃
                LCDdat = pStr;
        }
        LCD_SetBG(x,y,strLen,bg);
}


//******************** 显示数字 ***********************//
//**x:横坐标(0~15)y:纵坐标(0~3)
//**param:
//**(bit(7) 0:十进制显示 1:十六进制显示)
//**(bit(6~5) 00:右对齐 01:左对齐 10:中间对齐)
//**(bit(4~0)显示的长度0~31 0:显示全部)
//**fill: 空白处填充的字符,注意转义字符
void LCD_ShowNumber(unsigned char x,unsigned char y,long num,unsigned char param,char fill,unsigned char bg)
{
        unsigned char i;
        char strBuff;        //一行字符缓存
        char disBuff;        //一行字符缓存用于显示
        int strLen = 0;
        unsigned char disLen = (param&DISP_MASK);
       
        if((x>15)||(y>3)) return; //超出范围
       
        if(param&FORMAT_MASK){ //十六进制显示
                strLen = sprintf(strBuff,"%lX",num);
        }
        else{ //十进制显示
                strLen = sprintf(strBuff,"%ld",num);
        }
       
        if(strLen<=0) return; //错误
       
        if(disLen==DISP_ALL) disLen = strLen; //数据长度为0则全部显示
       
        if((param&ALIGN_MASK)==ALIGN_R){//右对齐
                for(i=0;i<disLen;i++){
                        if(i<strLen) disBuff = strBuff;
                        else disBuff = fill;
                }
        }
        else if((param&ALIGN_MASK)==ALIGN_L){//左对齐
                for(i=0;i<disLen;i++){
                        if(i<strLen) disBuff = strBuff;
                        else disBuff = fill;
                }
        }
        else if((param&ALIGN_MASK)==ALIGN_M){//中间对齐
                uint8_t disM = (disLen>>1); //显示窗口的中间位置
                uint8_t strM = (strLen>>1); //数据的中间位置
                for(i=0;i<disM;i++){ //前半部分右对齐
                        if(i<strM) disBuff = strBuff;
                        else disBuff = fill;
                }
                for(i=disM;i<disLen;i++){ //后半部分 左对齐
                        if(strM+i-disM<strLen) disBuff = strBuff;
                        else disBuff = fill;
                }
        }
        disBuff = '\0'; //末尾加结束符
        LCD_ShowString(x,y,disBuff,bg);
}

/**********************************
          LCD初始化
**********************************/

void LCD_Init(void)
{
        memset(LCDdat,' ',sizeof(LCDdat));
        memset(LCDdat_bak,0x00,sizeof(LCDdat_bak));
        memset(SetWdat,0x00,sizeof(SetWdat));       
        memset(SetWdat_bak,0x00,sizeof(SetWdat_bak));
       
        LCD_RST_0;         delay_ms(100);
        LCD_RST_1;         //delay_ms(100);//复位
        write(0,0x30);//8 位介面,基本指令集
        write(0,0x0c);//显示打开,光标关,反白关
        write(0,0x01);//清屏,将DDRAM的地址计数器归零
//        delay_ms(100);
        LCD_ClearGM();
       
//        LCD_SetBG(3,1,5,1);
}


angler12 发表于 2020-4-20 12:47:48

兄台,能丢到github或者gitee上吗?

flash3g 发表于 2020-4-20 15:58:12

谢谢分享,LCD12864不好用,绘图模式刷屏速度太慢了

jssd 发表于 2020-4-21 02:11:12

angler12 发表于 2020-4-20 12:47
兄台,能丢到github或者gitee上吗?

没有github或者gitee。。。真不好意思。不是专业的{:lol:}

jssd 发表于 2020-4-21 02:13:05

flash3g 发表于 2020-4-20 15:58
谢谢分享,LCD12864不好用,绘图模式刷屏速度太慢了

全屏刷是比较慢。但上面的程序不是全屏刷,而且速度已经飞快了。

lijianxing 发表于 2020-4-21 10:00:40

谢谢提供

pulan 发表于 2020-4-21 10:03:29

现在这种屏用的人少了吧?手里还有几十个全新的。

powerlabor001 发表于 2020-4-21 12:15:27

mark一下,看看有没有机会用上。

cctv02 发表于 2020-4-21 12:37:19

flash3g 发表于 2020-4-20 15:58
谢谢分享,LCD12864不好用,绘图模式刷屏速度太慢了

我都是开缓冲100ms刷一次。

foxpro2005 发表于 2020-4-21 14:57:00

以前也写过一个串口驱动的LCD12864 (记得用的是北京青云的LCD显示屏)

gmyu 发表于 2020-4-21 21:01:00

问一下,arduino的库可以直接放mdk下面用么?
页: [1]
查看完整版本: 【开源】LCD12864 ST7920带中文字库屏驱动程序