基于STM32F103与LCD12864 绘制图片 深入解析LCD屏幕的地址映射与写入机制
在嵌入式开发中,液晶显示屏(LCD)作为一种常见的显示设备,广泛应用于各种应用场景。今天,我将分享一些关于LCD 128x64显示屏的地址映射和数据写入方式的心得体会,并深入探讨它的工作原理。我购买的主要是这一款产品**SMR12864-15A**
关于LCD12864我也走了很多坑ovo,也花了不少时间,看过不少文章,现在我也总结一下我的一些发现,求点赞求关注QWQ。
在嵌入式开发中,液晶显示屏(LCD)作为一种常见的显示设备,广泛应用于各种应用场景。今天,我将分享一些关于LCD 128x64显示屏的地址映射和数据写入方式的心得体会,并深入探讨它的工作原理。
我购买的主要是这一款产品SMR12864-15A
SMR12864-15A系列中文图形液晶模块的特性主要由其控制AIP31020决定。AIP31020同时作为控制器和驱动器,它可提供 33 路 com 输出和 64 路 seg 输出在驱动器 AIP31021的配合下,最多可以驱动256×32 点阵液晶。备注:AIP31020控制器的 128×64 点阵液晶其实原理上等同 256×32 点阵,
LCD 128x64 显示屏的地址映射
| Y\X | 第0列 | 第2列 | 第3列 | 第4列 | ~ | 第7列 |
|---|---|---|---|---|---|---|
| 第0行 | 16位像素数据 | 16位 | 16位 | 16位 | 16位 | 16位 |
| 第2行 | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| 第3行 | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| ~ | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| 第31行 | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| Y\X | 第8列 | 第9列 | 第10列 | 第11列 | ~ | 第15列 |
| 第0行 | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| ~ | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
| 第31行 | 16位像素数据 | 数据 | 数据 | 数据 | 数据 | 数据 |
他其实更像是一块256X32 ,只不过另一半给搬到了屏幕下面。折合成128X64,所以在设定地址上要做出一点修改
如果要找第63行,其实应该是下半屏幕,那么63-32=31.对应的是31行,那么如何定位X轴,呢 ,如果我们需要定位的
比如说是第255位,实际上是第7列,255/16 =7 ;
如果是在下半屏幕的255,只需要在7+8;
提供 64×32 个字节的空间(由扩充指令设定绘图 RAM 地址),最多可以控制256×64 点阵的二维绘图缓冲空间,在更改绘图 RAM 是,由扩充指令设置 GDRAM地址先垂直地址后水平地址(连续 2 个字节的数据来定义垂直和水平地址),再2 个字节的数据给绘图 RAM(先高 8 位后低 8 位)。
设定 GDRAM 地址到地址计数器(AC),先设置垂直位置再设置水平位置(连续写入 2 字节数据来完成垂直与水平坐标的设置)。
垂直地址范围:AC6~AC0 (0~63)
水平地址范围:AC3~AC0 (0~15)
因为他的地址格式实际上是这样子的
| 水平地址 | 1 | 0 | 0 | 0 | A3 | A2 | A1 | A0 |
| 垂直地址 | 1 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
在理解了这个映射关系后,你可以通过设置坐标来控制显示内容。通常我们会使用LCD_SetGDRAMAddress函数来设置像素点的坐标,代码示例如下:
/**
* @brief 设置 GDRAM 地址
* @param x: X 方向起始地址
* @param y: Y 方向起始地址
* @retval 无
* @note
*/
void LCD_SetGDRAMAddress(uint8_t x, uint8_t y)
{
uint8_t verticalAddr, horizontalAddr;
if (y >= 32) // 下半屏
{
verticalAddr = 0x80 | (y - 32); // 处理下半屏,Y 坐标减去 32
horizontalAddr = 0x88 | (x >> 4); // horizontalAddr = 0x80 | 0x08 | (x / 16):
}
else // 上半屏
{
verticalAddr = 0x80 | y; // 上半屏,直接使用 Y 坐标
horizontalAddr = 0x80 | (x >> 4); // x/16
}
LCD_WriteCommand(verticalAddr); // 先写入垂直地址
LCD_WriteCommand(horizontalAddr); // 再写入水平地址
}
通过这段代码,我们可以清晰地控制每个像素点的显示,确保无论是上半屏还是下半屏,都能够正确地映射到LCD的显示区域。
地址映射细节
实际上,LCD 128x64屏幕的地址映射更像是一块256x32的屏幕,只不过下半部分被映射到屏幕的下方。为了正确地访问每个像素,我们必须注意到下半屏的地址偏移。
例如,如果你需要定位第63行,你应该将其映射到下半屏的第31行(63 - 32 = 31)。此外,x轴的地址是按列分配的,每列对应16个像素,因此每次需要跳转16个位置(也就是每次写两个字节)。这就意味着,写入一个字节将影响8个像素,而每两个字节写入将覆盖16个像素。
清屏与绘图
在得到了正确的地址映射后,我们可以轻松地实现清屏和绘图等功能。以下是一个简单的清屏实现,它将所有像素点的显示数据设置为0,清空屏幕:
void LCD_Draw_Clear(void)
{
uint8_t x, y;
for(y = 0; y < 32; y++) // 0~31
{
LCD_SetGDRAMAddress(0, y); // 设置显示坐标
for(x = 0; x < 16; x++) // 0~15
{
/* 因为x轴一个地址对应16个像素点,可以连续发送两个字节数据 */
LCD_WriteDisplayData(0x00);
LCD_WriteDisplayData(0x00);
}
}
}
这段代码遍历每一行,并设置每个像素点为0,从而清除屏幕上的所有内容。
绘制图片
在处理完屏幕清除后,我们可以绘制图像。这就需要将图片的数据转化为适合LCD显示的格式,通常是一个字节数组,每个字节代表8个像素。通过以下代码,我们能够将图片数据绘制到LCD屏幕上:
void LCD_Draw_Pic(const unsigned char *data){
uint8_t x, y;
for(y = 0; y < 64; y++)
{
LCD_SetGDRAMAddress(0, y);
for(x = 0; x < 8; x++)
{
LCD_WriteDisplayData(*data++);
LCD_DelayUs(10);
LCD_WriteDisplayData(*data++);
}
}
}
通过这种方式,我们能够在LCD屏幕上绘制出自定义图像。
绘制自定义尺寸的图片
void LCD_Draw_CustomPic(uint8_t startX, uint8_t startY, uint8_t width, uint8_t height, const unsigned char *data)
{
uint8_t x, y;
// 确保宽度和高度不超出显示屏的最大尺寸
if (startX + width > 128) startX = 128 - width;
if (startY + height > 64) startY = 64 - height;
for (y = 0; y < height; y++)
{
LCD_SetGDRAMAddress(startX, startY + y); // 设定起始地址
for (x = 0; x < width ; x += 8)
{
LCD_WriteDisplayData(*data++);
}
}
}
图片的取模方式
取模软件位:Pctolcd2002
取模参数调整为:
- 高位在前(MSB First)
- 横向取模(逐行扫描)
- 其他参数保持不变
- 可以修改输出格式
更多推荐



所有评论(0)