LX12864P1屏幕显示(ST7567驱动)

可编辑12864液晶模组,也就是液晶显示屏是有128*64个点阵组成。12864是一种图形点阵液晶显示器,它主要采用动态驱动原理由行驱动—控制器和列驱动器两部分组成了128(列)×64(行)的全点阵液晶显示此显示器采用了COB的软封装方式,通过导电橡胶和压框连接LCD,使其寿命长,连接可靠。

产品特性编辑工作电压为+5V±10%,可自带驱动LCD所需的负电压,全屏幕点阵,点阵数为128(列)×64(行),可显示8(行)×4(行)个(16×16点阵)汉字,字符16(行)x8(行)个(8 .x 8)也可完成图形字符的显示,与CPU接口采用SPI通讯方式,驱动ST7567

LCD12864DDRAM示意图

驱动芯片ST7567 DDRAM示意图

ST7567芯片可写入的页有0 ~ 8 共9页,列有132列,但LCD12864只用到了8页和64列

写入数据的点阵显示效果

主控芯片与ST7567的通信方式

通信方式有并行的6800和8080,以及串行的4线方式,本次实验使用了4线串行通信,CSB为片选引脚,数据传输前拉低CSB,A0引脚说明传输的是数据还是指令,如果A0为0,说明是指令,如果为1,说明是数据,SCL为时钟线,SDA为数据/指令线,SCL为低电平时放数据或指令,SCL为高电平是ST7567读取SDA上的电平信号

LX12864官方手册(带参考代码):https://download.csdn.net/download/weixin_46251230/86731882

参考代码说明

1、LCD初始化函数中行扫描顺序的指令是0xC0,指令说明从上到下扫描,从屏幕上看则最下面是Page0,从下往上直到Page7

2、默认的g_ucComTable数组控制页的访问顺序,默认从Page3开始,若调用 LX12864_ShowChar(0,0,‘A’);函数显示一个字符时,因为字符A高16位,所以占两页,会在Page3开始显示,到Page2结束

3、若想Page0在屏幕的最上边,则初始化时行扫描顺序指令要改为0xC8

4、如果此时g_ucComTable数组不变,则也是从Page3开始显示,再往上显示到Page2,再调用LX12864_ShowChar(0,0,‘A’);则会显示倒着的A

5、如果把g_ucComTable数组改为{0,1,2,3,4,5,6,7},若调用LX12864_ShowChar(3,0,‘A’),则字符A也会倒着显示,并且字符A的上半部分倒着显示在Page3,下半部分倒着显示在Page4,不是想要的效果

6、重新用取模软件取模字符A,则会正常显示

对参考代码进行修改:

1、初始化函数中写入0xC8指令,控制Page0是在屏幕的最上面(根据屏幕实际摆放)

2、将g_ucComTable数组改为{0,1,2,3,4,5,6,7},或者后续可以把函数中的g_ucComTable操作去掉

3、把ASCII码全部重新取模一遍,因为参考代码的字模数组要用特定的数组来显示的,通用性不太好,自己进行修改

代码

GPIO要先初始化

/*** @name   gpio_Init* @brief  GPIO初始化* @param  None* @retval None*/
void gpio_Init(void)
{GPIO_InitTypeDef        GPIO_InitStructure;/* GPIOB Periph clock enable */RCC_AHBPeriphClockCmd(CLK_GPIO, ENABLE);/*Configure GPIO_PIN*/GPIO_InitStructure.GPIO_Pin = BL|SI|SCL|A0|RS|CS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(PORT, &GPIO_InitStructure);GPIO_SetBits(PORT,CS);GPIO_SetBits(PORT,SCL);GPIO_SetBits(PORT,SI);
}

BL:背光

SI(SDA):数据/指令线

SCL:时钟线

A0:说明是数据还是指令

RS:复位

CS:片选

写命令

/*** @name   LX12864_WrCmd* @brief  写命令串口模式下只能写不能读,也不能查忙,因此用户要控制好速度不要太快* @param  ucCmd:命令字节* @retval None*/
void LX12864_WrCmd(uint8_t ucCmd)
{uint8_t i;GPIO_ResetBits(PORT,CS);                                            /* CS片选引脚输出低电平 */GPIO_ResetBits(PORT,A0);                                            /* A0引脚输出低电平,说明是指令 */for(i=0;i<8;i++){GPIO_ResetBits(PORT,SCL);if(ucCmd&0x80){GPIO_SetBits(PORT,SI);}else{GPIO_ResetBits(PORT,SI);}        GPIO_SetBits(PORT,SCL);delay_us(10);ucCmd=(ucCmd<<1);}GPIO_SetBits(PORT,CS);
}

写数据

/*** @name   LX12864_WrData* @brief  写数据* @param  ucData:数据字节* @retval None   */
void LX12864_WrData(uint8_t ucData)
{   uint8_t i;GPIO_ResetBits(PORT,CS);                                            /* CS片选引脚输出低电平 */GPIO_SetBits(PORT,A0);                                              /* A0引脚输出高电平,说明是数据 */for(i=0;i<8;i++){GPIO_ResetBits(PORT,SCL);if(ucData&0x80){GPIO_SetBits(PORT,SI);}else{GPIO_ResetBits(PORT,SI);}GPIO_SetBits(PORT,SCL);delay_us(10);ucData=(ucData<<1);}GPIO_SetBits(PORT,CS);
}

初始化

/*** @name   LX12864_Init* @brief  LX12864初始化* @param  None* @retval None   */
void LX12864_Init(void)
{GPIO_ResetBits(PORT,RS);                                            /* 硬复位 */delay_us(20);GPIO_SetBits(PORT,RS);delay_us(20);LX12864_WrCmd(0xE2);                                              /* 软复位 */delay_us(50);LX12864_WrCmd(0x2C);                                              /* 升压步骤1 */delay_us(50);LX12864_WrCmd(0x2E);                                                /* 升压步骤2 */delay_us(50);LX12864_WrCmd(0x2F);                                                /* 升压步骤3 */delay_us(50);LX12864_WrCmd(0x24);                                                /* 调整对比度,设置范围0x20~0x27 */LX12864_WrCmd(0x81);                                             /* 微调对比度 */LX12864_WrCmd(0x1B);                                             /* 微调对比度的值 */LX12864_WrCmd(0xA3);                                               /* 偏压比(bias),0xA2:1/9   0xA3:1=1/7  */LX12864_WrCmd(0xA6);                                               /* 正常显示 */LX12864_WrCmd(0xA4);                                              /* 全部点阵打开   */LX12864_WrCmd(0xC8);                                              /* 行扫描顺序:从上到下 */LX12864_WrCmd(0xA0);                                             /* 列扫描顺序:从左到右 */LX12864_WrCmd(0x40);                                             /* 起始行:第一行开始 */LX12864_WrCmd(0xAF);                                              /* 开显示 */LX12864_Open_BL();                                                  /* 显示背光 */
}

LCD初始化指令

初始化命令中,设置对比度由两条指令组成,一定要先发送指令0x81,告诉ST7567接下来的一条指令是设置对比度的,再发送对比度的值,例如0x1B,由6位来控制;

设置行扫描顺序或者列扫描顺序时需要根据屏幕来设定,因为屏幕摆放的方向不同,则行列的显示也会不同

填充屏幕


/*** @name   LX12864_FillScreen* @brief  填充屏幕* @param  ucFillData:填充的数据* @retval None   */
void LX12864_FillScreen(uint8_t ucFillData)
{uint16_t i,j;for(i=0;i<8;i++){LX12864_WrCmd(0xB0|i);                                         /* 设置页地址 */LX12864_WrCmd(0x10);                                         /* 设置列地址的高位 */LX12864_WrCmd(0x00);                                          /* 设置列地址的低位 */for(j=0;j<128;j++){LX12864_WrData(ucFillData);}}
}

填充一页

/*** @name   LX12864_FillPage* @brief  填充一页* @param  ucFillData:填充的数据* @retval None   */
void LX12864_FillPage(uint8_t ucPage,uint8_t ucFillData)
{uint16_t i;LX12864_WrCmd(0xB0|ucPage);                                         /* 设置页地址 */LX12864_WrCmd(0x10);                                             /* 设置列地址的高位 */LX12864_WrCmd(0x00);                                              /* 设置列地址的低位 */for(i=0;i<128;i++){LX12864_WrData(ucFillData);}
}

显示一条横线

/*** @name   LX12864_ShowHorLine* @brief  显示一条横线* @param  ucPage:页地址 范围:0 ~ 7* @param  ucCol:列地址 范围:0 ~ 127* @param  ucLen:长度 范围:0 ~ 127* @param  ucData:数据* @retval None   */
void LX12864_ShowHorLine(uint8_t  ucPage,uint8_t  ucCol,uint8_t  ucLen,uint8_t  ucData)
{uint8_t i;LX12864_WrCmd((ucPage&0x07)|0xB0);                                   /* 设置页地址 */LX12864_WrCmd((ucCol>>4)|0x10);                                        /* 设置列地址高位 */LX12864_WrCmd(ucCol&0x0F);                                          /* 设置列地址低位 */for(i=0;i<ucLen;i++){LX12864_WrData(ucData);}
}

显示一条竖线

/*** @name   LX12864_ShowVerLine* @brief  显示一条竖线* @param  ucStartPage:起始页地址 范围:0 ~ 7* @param  ucCol:列地址* @param  ucEndPage:结束页地址 范围:0 ~ 7 注意:结束页地址要大于或等于起始页地址* @retval None   */
void LX12864_ShowVerLine(uint8_t  ucStartPage,uint8_t  ucCol,uint8_t  ucEndPage)
{uint8_t i,ucTemp;ucTemp = (ucEndPage - ucStartPage)+1;for(i=0;i<ucTemp;i++){LX12864_WrCmd((ucStartPage&0x07)|0xB0);                            /* 设置页地址 */LX12864_WrCmd((ucCol>>4)|0x10);                                    /* 设置列地址高位 */LX12864_WrCmd(ucCol&0x0F);                                      /* 设置列地址低位 */LX12864_WrData(0xFF);ucStartPage++;}
}

显示字符

typedef enum
{g_enBigNumber,g_enSmallNumber,
}__ENCHARARRAY_T;/*** @name   LX12864_ShowChar* @brief  显示字符* @param  ucPage:页地址 范围:0 ~ 7* @param  ucCol:列地址 范围:0 ~ 127* @param  ucWidth:字体宽度* @param  ucHight:字体高度* @param  ucChar:字符* @param  ucCharArray:字模数组* @retval None   */
void LX12864_ShowChar(uint8_t ucPage, uint8_t ucCol, uint8_t ucWidth, uint8_t ucHight,uint8_t ucChar,__ENCHARARRAY_T ucCharArray)
{uint8_t i,j,ucNeedPage;uint16_t ucIndex = 0;ucNeedPage = ucHight / 8;if((ucHight%8) != 0){ucNeedPage = ucNeedPage+1;                                      /* 加上不够一页的部分 */}for(i=0;i<ucNeedPage;i++){LX12864_WrCmd((ucPage&0x07)|0xB0);                              /* 设置页地址 */LX12864_WrCmd((ucCol>>4)|0x10);                                    /* 设置列地址高位 */LX12864_WrCmd(ucCol&0x0F);                                      /* 设置列地址低位 */for(j=0;j<ucWidth;j++){if(ucCharArray == g_enBigNumber){LX12864_WrData(g_ucBigNumber[ucChar][ucIndex]);         /* 大字体字模显示字符 */ucIndex++;}else if(ucCharArray == g_enSmallNumber){LX12864_WrData(g_ucSmallNumber[ucChar][ucIndex]);       /* 小字体字模显示字符 */ucIndex++;}}ucPage++;}
}

设置页地址时,参数ucPage为想要显示字符的页数,因为页被分为了0 ~ 7页, 一共8页,只用3位二进制位即可遍历8页,28 = 3,所以&0x07是为了取出ucPage的低3位,再或上0xB0,就设置了想要显示的页

/* 小字体的字模数组 */
unsigned char g_ucSmallNumber[][24]={{0xC0,0xE0,0x70,0x30,0x30,0x70,0xE0,0xC0,0x3F,0x7F,0xE0,0xC0,0xC0,0xE0,0x7F,0x3F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"0",0*/
/* (8 X 17 , Arial, 加粗 )*/
{0x00,0x80,0xC0,0x60,0xF0,0xF0,0x00,0x00,0x00,0x01,0x00,0x00,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",1*/
/* (8 X 17 , Arial, 加粗 )*/
{0xC0,0xE0,0x70,0x30,0x30,0x30,0xE0,0xC0,0xC0,0xE0,0xF0,0xD8,0xDC,0xCE,0xC7,0xC1,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",2*/
…………………………
};

用PCtoLCD2002取模软件取出想要显示的字符,本次实验用二维数组保存字模数据,根据参数ucChar作为下标去找到要显示的字符的一位数组,再遍历数组写入数据

显示有符号整型数

 /*** @name     Pow* @brief    求sBase的sPower次方* @param    sBase:底数* @param    sPower:次方数* @retval 返回次方后的结果*/
int16_t Pow(int16_t sBase,int16_t sPower)
{uint8_t i;int16_t sResult = 1;for(i = 0; i < sPower; i++){sResult *= sBase;}return sResult;
}/*** @name   LX12864_ShowVariableNum* @brief  显示有符号的整型数* @param  ucPage:页地址,范围:0 ~ 7* @param  ucCol:列地址,范围:0 ~ 127* @param  ucWidth:字符宽度* @param  ucHight:字符高度* @param  ucNumLen:待显示数字的位数* @param  sNum:待显示的数字* @param  ucCharArray:字模数组* @retval None   */
void LX12864_ShowSignedNum(uint8_t  ucPage,uint8_t  ucCol,uint8_t  ucWidth,uint8_t  ucHight,uint8_t  ucNumLen,int16_t  sNum,__ENCHARARRAY_T ucCharArray)
{uint8_t i;int16_t sNumTemp,sResult;if(sNum >= 0){LX12864_ShowChar(ucPage,ucCol-(ucWidth+2),ucWidth,ucHight,11,ucCharArray);           /* 11对应空白,如果是正数则去掉负号 */sNumTemp = sNum;}else{LX12864_ShowChar(ucPage,ucCol-(ucWidth+2),ucWidth,ucHight,10,ucCharArray);           /* 10对应字符'-',负数则在前面加上负号 */sNumTemp = -sNum;}for(i=ucNumLen;i>0;i--){sResult = sNumTemp/Pow(10,i-1)%10;                                        /* 从高位开始,取出数字的每一位 */LX12864_ShowChar(ucPage,ucCol+((ucWidth+2)*(ucNumLen-i)),ucWidth,ucHight,sResult,ucCharArray);/*显示数字 */}
}

其中Pow函数的用法参考了之前写的LCD1602代码,可以参考
http://t.csdn.cn/mMBIA

显示图形

图形需要用取模软件生成

/*** @name   LX12864_ShowBmp* @brief  显示图形* @param  ucPage:页地址 范围:0 ~ 7* @param  ucCol:列地址 范围:0 ~ 127* @param  ucWidth:图形宽度* @param  ucHight:图形高度* @param  pucBmp:图形字模数组指针* @retval None   */
void LX12864_ShowBmp(uint8_t ucPage, uint8_t ucCol, uint8_t ucWidth, uint8_t ucHight,uint8_t* pucBmp)
{uint8_t i,j,ucNeedPage;uint16_t ucIndex = 0;ucNeedPage = ucHight / 8;                                           /* 所需页数 */if((ucHight%8) != 0){ucNeedPage = ucNeedPage+1;                                      /* 加上不够一页的部分 */}for(i=0;i<ucNeedPage;i++){LX12864_WrCmd((ucPage&0x07)|0xB0);                             /* 设置页地址 */LX12864_WrCmd((ucCol>>4)|0x10);                                    /* 设置列地址高位 */LX12864_WrCmd(ucCol&0x0F);                                      /* 设置列地址低位 */for(j=0;j<ucWidth;j++){LX12864_WrData(pucBmp[ucIndex]);                            /* 显示图形 */ucIndex++;}ucPage++;}
}

LCD实现显示亮一会,暗一会

实现亮一会,暗一会主要通过修改对比度来实现

在LCD_Init初始化函数中,有对比度的设置

LX12864_WrCmd(0x81);                                             /* 微调对比度 */
LX12864_WrCmd(0x1B);                                                /* 微调对比度的值 */

要先写入指令0x81,说明是后续的一个字节是修改对比度的

后续这个字节的是6位的,EV5和EV4的值会影响屏幕显示,有下面三种情况

0x1B:

正常显示(屏幕有点坏)

0x2B:

会显示填充整个128x64屏幕的黑点,“腾讯QQ”显示会比较暗,正面看看不清

如果从侧面看则可以看清

0x3B:

正面看看不到显示内容,屏幕全填充

侧面看也有黑点

所以调整对比度就只能设置EV3 ~ EV0这4位,高两位的EV4设置为1,EV5设置为0,才能正常显示

经过测试,0x1F对比度最高,显示内容很清晰,值越小则对比度越低,显示内容逐渐变暗,0x10时几乎看不见显示的内容

在主函数循环中,通过改变对比度的值,再加上适当的延时,就可以让显示内容亮一会,暗一会

/*
* @name   Run
* @brief  系统运行
* @param  None
* @retval None
*/
void Run(void)
{LX12864_WrCmd(0x81);                                               /* 微调对比度 */LX12864_WrCmd(0x1B);                                             /* 亮 */LCD_ShowBmp(g_ucBmp1);delay_ms(2000);delay_ms(2000);LX12864_WrCmd(0x81);                                             /* 微调对比度 */LX12864_WrCmd(0x15);                                             /* 微亮 */LCD_ShowBmp(g_ucBmp1);delay_ms(2000);delay_ms(2000);
}

LCD12864最终显示界面

右上角的WiFi显示一会亮,一会灭

实现思路:因为改变对比度是对一整个屏幕而言的,没发现有对某一部分屏幕改变对比度的方法,所以对WiFi显示的字模数组全部改为0x00,则WiFi图形这一部分就显示空白,WiFi图形显示1秒后再写入全是0x00的字模数组,则可以对WiFi图形擦除,擦除1秒后再显示,则可以达到闪烁的目标

LX12864P1屏幕使用介绍(ST7567驱动),显示横线、字符、图形相关推荐

  1. HAL库的STM32单片机LTDC驱动显示LCD屏幕

    本文基于STM32H750核心,学习使用LTDC外设,用CubeMX创建HAL库工程,驱动显示LCD屏幕.LCD屏采用AT070TN83. 文末有工程链接. 目录 一.CubeMX生成工程 LCD屏的 ...

  2. ESP8266+0.96OLED驱动显示(I2C)

    文章目录 ESP8266 一.简介 二.管脚定义 三.代码 ESP8266 一.简介 这篇我们说一下ESP8266来驱动OLED显示屏显示,这里使用的是I2C的屏幕,像Arduino中有好几个库可以驱 ...

  3. 看这篇就够了——ubuntu扩展屏幕及装显卡驱动后黑屏问题

    1.问题说明 首先说明为什么外接屏幕需要装显卡驱动,显卡由GPU和显存构成,又称为显示适配器,与数据的输出有密切关系. 在ubuntu系统中,外接显示器是用的独立显卡驱动,而内置屏幕用的是集显驱动,也 ...

  4. 8051单片机Proteus仿真与开发实例-OLED显示屏(SSD1306控制器)I2C驱动显示中文及图片仿真

    OLED显示屏(SSD控制器)I2C驱动显示中文及图片仿真 1.OLED显示屏介绍 在前面的实例中,已经介绍了OLED显示屏,在这里就不展开介绍了,请参考: OLED显示屏(SSD1306控制器)I2 ...

  5. NVidia 3060/1650S 独显笔记本 HDMI外接屏幕有输出,笔记本屏幕无输出/ubuntu 更改显卡驱动后无法进入图形界面的处理方法 以及禁止内核自动更新

    这里写自定义目录标题 NVidia 3060/1650S 独显笔记本 HDMI外接屏幕有输出,笔记本屏幕无输出/ubuntu 更改显卡驱动后无法进入图形界面的处理方法 结论 关于操作系统 deepin ...

  6. 轩逸车联网功能怎么用_2020款轩逸中控屏幕按键功能介绍

    全新2020款轩逸仅高配奢享版上才配备有双区自动空调,其他的车型都是配备手动空调的,空调怎么使用呢?下面笔者来介绍一下. 轩逸空调面板上的按键从左到右依次是自动空调开关,旋钮主驾驶温度调节.前风挡除雾 ...

  7. Arduino框架下ESP32+合宙1.54“ 电子墨水屏(e-paper)驱动显示示例

    Arduino框架下ESP32+合宙1.54" 电子墨水屏(e-paper)驱动显示示例 显示效果展示; 合宙1.54" 电子墨水屏 有关合宙1.54"电子墨水屏的介绍资 ...

  8. 【MicroPython ESP32】1.8“tft ST7735带中文驱动显示示例

    [MicroPython ESP32]1.8"tft ST7735带中文驱动显示示例 本实例基于Thonny平台开发 效果演示 驱动屏幕和开发板 驱动屏幕采用的是合宙1.8"tft ...

  9. 51单片机 IIC OLED驱动显示通用程序模板

    51单片机 IIC OLED驱动显示通用程序模板 本模板是通过中景园OLED屏幕资料中提取保留ASCII字符集,点阵大小:6x8和8X16. 汉字取模方式 取模软件:pctolcd2002 /汉字取模 ...

最新文章

  1. SAP MM初阶之采购信息记录里的Prior Supplier栏位
  2. 安防行业巨头都是如何布局无人机的?
  3. 文件系统与NoSQL分布式存储技术对比
  4. java applet配置_配置Java Applet的运行环境
  5. 理解JavaScript中的原型继承(2)
  6. 使用keil建立标准STM32工程模版(图文详细版!)
  7. 前后端分离Java后端跨越问题解决
  8. DownloadManager不好用?试试ZlsamDownloadService
  9. Linux服务器挂死案例分析
  10. linux 文件读写 加速,MMAP文件加速读写小技俩
  11. 数据清洗的主要类型及步骤
  12. 数据库连接池连接耗尽,导致tomcat请求无响应,呈现出假死状态
  13. 奥克兰计算机科学专业世界排名,新西兰计算机专业大学排名
  14. C++几个常用的排序
  15. 腾讯云 Debian11 bullseye 源
  16. 面向全球用户的Teams app之时区篇
  17. 大数据行业怎么样?工资可观么?
  18. Vulnhub-Earth
  19. 快来使用HTTPS吧
  20. 计算机财务管理技术pdf,计算机财务管理技术在财务管理方面的应用研究.pdf

热门文章

  1. 关于Ontimer()函数
  2. (五)本地镜像发布到阿里云仓库以及私有库
  3. 省钱指南:何为物联卡流量池?
  4. h5页面如何预览excel文件_H5 app实现文件预览下载(包括图片、pdf、word、excel、txt格式)...
  5. 【OpenGL】透视投影矩阵推导
  6. 转:实验3 地理空间数据可视化
  7. HTML文档可以输入在标记之间,【单选题】在数控加工程序中,下列可以省略的是( )...
  8. wiki上卷积神经网络(CNN)的理解
  9. 模型7——多元线性回归分析
  10. 最新代手机号段整理[用于判断]