LX12864P1屏幕使用介绍(ST7567驱动),显示横线、字符、图形
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驱动),显示横线、字符、图形相关推荐
- HAL库的STM32单片机LTDC驱动显示LCD屏幕
本文基于STM32H750核心,学习使用LTDC外设,用CubeMX创建HAL库工程,驱动显示LCD屏幕.LCD屏采用AT070TN83. 文末有工程链接. 目录 一.CubeMX生成工程 LCD屏的 ...
- ESP8266+0.96OLED驱动显示(I2C)
文章目录 ESP8266 一.简介 二.管脚定义 三.代码 ESP8266 一.简介 这篇我们说一下ESP8266来驱动OLED显示屏显示,这里使用的是I2C的屏幕,像Arduino中有好几个库可以驱 ...
- 看这篇就够了——ubuntu扩展屏幕及装显卡驱动后黑屏问题
1.问题说明 首先说明为什么外接屏幕需要装显卡驱动,显卡由GPU和显存构成,又称为显示适配器,与数据的输出有密切关系. 在ubuntu系统中,外接显示器是用的独立显卡驱动,而内置屏幕用的是集显驱动,也 ...
- 8051单片机Proteus仿真与开发实例-OLED显示屏(SSD1306控制器)I2C驱动显示中文及图片仿真
OLED显示屏(SSD控制器)I2C驱动显示中文及图片仿真 1.OLED显示屏介绍 在前面的实例中,已经介绍了OLED显示屏,在这里就不展开介绍了,请参考: OLED显示屏(SSD1306控制器)I2 ...
- NVidia 3060/1650S 独显笔记本 HDMI外接屏幕有输出,笔记本屏幕无输出/ubuntu 更改显卡驱动后无法进入图形界面的处理方法 以及禁止内核自动更新
这里写自定义目录标题 NVidia 3060/1650S 独显笔记本 HDMI外接屏幕有输出,笔记本屏幕无输出/ubuntu 更改显卡驱动后无法进入图形界面的处理方法 结论 关于操作系统 deepin ...
- 轩逸车联网功能怎么用_2020款轩逸中控屏幕按键功能介绍
全新2020款轩逸仅高配奢享版上才配备有双区自动空调,其他的车型都是配备手动空调的,空调怎么使用呢?下面笔者来介绍一下. 轩逸空调面板上的按键从左到右依次是自动空调开关,旋钮主驾驶温度调节.前风挡除雾 ...
- Arduino框架下ESP32+合宙1.54“ 电子墨水屏(e-paper)驱动显示示例
Arduino框架下ESP32+合宙1.54" 电子墨水屏(e-paper)驱动显示示例 显示效果展示; 合宙1.54" 电子墨水屏 有关合宙1.54"电子墨水屏的介绍资 ...
- 【MicroPython ESP32】1.8“tft ST7735带中文驱动显示示例
[MicroPython ESP32]1.8"tft ST7735带中文驱动显示示例 本实例基于Thonny平台开发 效果演示 驱动屏幕和开发板 驱动屏幕采用的是合宙1.8"tft ...
- 51单片机 IIC OLED驱动显示通用程序模板
51单片机 IIC OLED驱动显示通用程序模板 本模板是通过中景园OLED屏幕资料中提取保留ASCII字符集,点阵大小:6x8和8X16. 汉字取模方式 取模软件:pctolcd2002 /汉字取模 ...
最新文章
- SAP MM初阶之采购信息记录里的Prior Supplier栏位
- 安防行业巨头都是如何布局无人机的?
- 文件系统与NoSQL分布式存储技术对比
- java applet配置_配置Java Applet的运行环境
- 理解JavaScript中的原型继承(2)
- 使用keil建立标准STM32工程模版(图文详细版!)
- 前后端分离Java后端跨越问题解决
- DownloadManager不好用?试试ZlsamDownloadService
- Linux服务器挂死案例分析
- linux 文件读写 加速,MMAP文件加速读写小技俩
- 数据清洗的主要类型及步骤
- 数据库连接池连接耗尽,导致tomcat请求无响应,呈现出假死状态
- 奥克兰计算机科学专业世界排名,新西兰计算机专业大学排名
- C++几个常用的排序
- 腾讯云 Debian11 bullseye 源
- 面向全球用户的Teams app之时区篇
- 大数据行业怎么样?工资可观么?
- Vulnhub-Earth
- 快来使用HTTPS吧
- 计算机财务管理技术pdf,计算机财务管理技术在财务管理方面的应用研究.pdf
热门文章
- 关于Ontimer()函数
- (五)本地镜像发布到阿里云仓库以及私有库
- 省钱指南:何为物联卡流量池?
- h5页面如何预览excel文件_H5 app实现文件预览下载(包括图片、pdf、word、excel、txt格式)...
- 【OpenGL】透视投影矩阵推导
- 转:实验3 地理空间数据可视化
- HTML文档可以输入在标记之间,【单选题】在数控加工程序中,下列可以省略的是( )...
- wiki上卷积神经网络(CNN)的理解
- 模型7——多元线性回归分析
- 最新代手机号段整理[用于判断]