STM32 LCD12864 AIP31020 基础指令集 调试显示字符

求点赞谢谢啦ovo 关注就太感激啦! 歇歇支持啦
下一章写关于LCD12864实现绘制图像功能。

引言

在嵌入式开发中,LCD 显示屏广泛用于图形界面和文字显示。今天,我们来介绍如何用 STM32 微控制器驱动一个常见的 128x64 分辨率的 LCD 显示屏(LCD12864)。LCD12864 采用串行接口,并使用基本的命令和数据通信方式。本文将详细解析如何在 STM32 环境中驱动 LCD12864,包括引脚配置、命令发送、以及显示数据的具体实现。

LCD12864 模块简介

LCD12864 是一种字符型和图形型显示屏,支持 128x64 的显示分辨率。它使用 3 根主要控制引脚:

  • CS (Chip Select):选择 LCD 模块。
  • SID (Serial Data):串行数据输入线,负责传送数据。
  • CLK (Serial Clock):串行时钟线,用于同步数据传输。

1. LCD 显示模式

LCD12864 支持基本指令集和扩展指令集,可以进行文字显示,也可以通过扩展指令绘制图形。通过串行通信传送的每个字节需要分为 3 个数据包进行传输,且有特定的时序要求。
具体参考说明书,设置在h文件中有说明

2. STM32 GPIO 初始化

在 STM32 微控制器中,我们需要对控制 LCD 的 GPIO 引脚进行初始化。以 STM32F1xx 为例,本次我以
//PA5 CS
//PA6 SID
//PA7 SCLK
宏定义如下

#define LCD_CS_GPIO_PIN   GPIO_PIN_5   // PA5 - Chip Select
#define LCD_SID_GPIO_PIN  GPIO_PIN_6   // PA6 - Serial Data (MOSI)
#define LCD_CLK_GPIO_PIN GPIO_PIN_7   // PA7 - Serial Clock

#define LCD_GPIO_PORT GPIOA

/* 12864使用的引脚定义,CS:PB13 CLK:PB15, SID:PB14 */
#define LCD_CS(a)         HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_CS_GPIO_PIN, (a) ? GPIO_PIN_SET : GPIO_PIN_RESET)
#define LCD_CLK(a)        HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_CLK_GPIO_PIN, (a) ? GPIO_PIN_SET : GPIO_PIN_RESET)
#define LCD_SID(a)        HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_SID_GPIO_PIN, (a) ? GPIO_PIN_SET : GPIO_PIN_RESET)

/* 功能设置指令 */
#define LCD_FUNCTION_SET_BASIC   0x30  // 8位接口,基本指令集 (DL=1, RE=0) 0011 0000
#define LCD_FUNCTION_SET_EXTEND  0x34  // 8位接口,扩展指令集 (DL=1, RE=1) 0011 0100
#define LCD_FUNCTION_SET_DRAWPIC 0x36  // 拓展指令集下打开绘画显示

/* 显示控制指令 */
#define LCD_DISPLAY_OFF          0x08  // 关闭整体显示 (D=0, C=0, B=0) 0000 1000
#define LCD_DISPLAY_ON           0x0C  // 打开整体显示,不显示游标 (D=1, C=0, B=0) 0000 1100
#define LCD_DISPLAY_CURSOR_ON    0x0E  // 显示游标 (D=1, C=1, B=0) 0000 1110
#define LCD_DISPLAY_CURSOR_BLINK 0x0F  // 显示游标 + 反白闪烁 (D=1, C=1, B=1) 0000 1111

/* 清除显示 */
#define LCD_DISPLAY_CLEAR        0x01  // 清除显示 0000 0001

只有一块LCD ,故CS 我直接保持高,
我们需要启用 GPIOA 时钟,并配置适当的引脚模式为推挽输出模式。以下是相关的 GPIO 初始化代码:

void LCD_GPIO_Init(void) {
    // 启用 GPIO 端口时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 配置 CS、SID(MOSI)、SCLK 为推挽输出模式
    GPIO_InitStruct.Pin = LCD_CS_GPIO_PIN | LCD_SID_GPIO_PIN | LCD_CLK_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速输出
    HAL_GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStruct);

    // 默认拉高 CS,使 LCD 处于选中状态
    HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_CS_GPIO_PIN, GPIO_PIN_SET);
    
    // 默认 SCLK 置低,SID 数据线默认置低
    HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_SID_GPIO_PIN, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_GPIO_PORT, LCD_CLK_GPIO_PIN, GPIO_PIN_RESET);
}

3.延迟函数说明

LCD 通信要求精确的时序,因此需要延时函数来控制时钟和数据传输的速度。但是延迟函数有很多种不同的显示形式,根据不同的显示形式,会有不同的设定,故最后留一个函数指针结构,需要在LCD 初始化时候对他进行指向。

typedef void(*delayus)(uint32_t us); //在h文件

extern delayus Sys_Delayus; //在h文件
//以下为c文件
delayus Sys_Delayus =NULL;
void LCD_DelayUs(uint32_t us)
{
    if (Sys_Delayus != NULL) {
        Sys_Delayus(us);  // 调用外部的延时函数
    }
}
void LCD_DelayMs(uint32_t ms)
{
    while (ms--) {
        LCD_DelayUs(1000);  // 1 毫秒 = 1000 微秒
    }
}
void LCD_Init(delayus sys_delay){
	
	LCD_GPIO_Init();
    // 确保 Sys_Delayus 指向外部的延迟函数
    Sys_Delayus = sys_delay;  // 将 Sys_Delayus 指向 }
}
//在main中实现
	LCD_Init(My_DelayUs);
	//需要根据自己的delay设定,注意是uint32 ,
	//因为uint8 只支持到256,而uint16 66535 us级如果直接1ms的话直接超过了  我就用uint32 了

4. LCD 命令和数据发送

发送字节

LCD12864 通过串行接口接收命令和数据。每次传输需要 3 个字节的传输,其中包含命令的高 4 位和低 4 位。为了发送这些字节,我们需要定义一个函数来串行地将字节通过 SID 和 CLK 引脚发送出去。以下是发送字节的代码:
简单的通信 SCLK为低时变化SID,SID变化好了 将SCLK拉高
LCD_SID() 是宏定义,也可以用HAL 函数实现一样。

static void lcd_send_byte(uint8_t byte)
{
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
        LCD_CLK(0);  // 拉低时钟
        uint8_t bit = (byte >> (7 - i)) & 0x01;  // 获取每一位数据
        LCD_SID(bit);  // 按位发送数据
        LCD_DelayUs(5);  // 延迟
        LCD_CLK(1);  // 拉高时钟
    }
}

发送命令

LCD12864 有两类基本命令:功能设置和显示控制。我们通过串行接口发送命令来进行功能的切换和控制显示状态。
参考说明书中时序实现
以下是设置和发送命令的几个常见函数:

/**
 * @brief  发送 LCD12864 指令(带 RS 和 R/W 控制)
 * 
 * @param  RS   寄存器选择位 (0 = 命令, 1 = 数据)
 * @param  R_W  读写控制位 (0 = 写, 1 = 读)
 * @param  data 要发送的指令数据(8位)
 * 
 * @note   LCD 采用 3 字节格式进行串行通信:
 *         - 第一个字节: 11111 R/W RS 0
 *         - 第二个字节: D7 D6 D5 D4 0 0 0 0
 *         - 第三个字节: D3 D2 D1 D0 0 0 0 0
 * 
 * @note   LCD12864 需要连续发送三个字节完成一次指令传输。
 */
void LCD_SendCommand(uint8_t RS, uint8_t R_W, uint8_t data)
{
    uint8_t byte1, byte2, byte3;

    // 第一个字节: 11111 R/W RS 0
	byte1 = (0xf8) | (R_W << 2) | (RS << 1);  // 设置 RS 和 R/W 位
    // 第二个字节: D7 D6 D5 D4 0 0 0 0
    byte2 = (data & 0xF0);  // 提取 data 的高 4 位,低 4 位自动填 0

    // 第三个字节: D3 D2 D1 D0 0 0 0 0
    byte3 = (data << 4) & 0xF0;  // 提取 data 的低 4 位,并左移 4 位放入高 4 位

    // 发送三个字节
    lcd_send_byte(byte1);  // 发送第一个字节
    lcd_send_byte(byte2);  // 发送第二个字节
    lcd_send_byte(byte3);  // 发送第三个字节
}

发送指令与发送数据

/**
 * @brief  发送 LCD12864 指令(固定为写入命令)
 * 
 * @param  cmd  要发送的命令(8位)
 * 
 * @note   由于  R/W=0 RS=0,代表写入命令,此函数专门用于发送 LCD 命令。
 */
void LCD_WriteCommand(uint8_t cmd)
{
    LCD_SendCommand(0, 0, cmd);  //   RS=0 (命令), RW=0 (写)
}
void LCD_WriteDisplayData(uint8_t data)
{
    LCD_SendCommand(1, 0, data); 
}

显示字符串函数说明

在 LCD12864 中显示文本是通过设置显示位置后逐个写入字符的方式实现的。每个字符占用 16x16 像素,显示的文本通常是从特定的地址(行列)开始。

/* LCD12864内部字库显示的DDRAM地址,每个地址占16*16个像素点 */
static unsigned char lcd_str_addr[4][8] = {
	{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87},  		
	{0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97},		
	{0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F},		
	{0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}		
};

void LCD_Draw_Str(uint8_t column, uint8_t row, uint8_t *str)
{
    // 设置起始位置
    LCD_WriteCommand(lcd_str_addr[column][row]);
    while (*str) 
    {
        LCD_WriteDisplayData(*str++);  // 逐个字符显示
    }
}

LCD初始化

初始化 LCD12864 涉及多个步骤:首先配置引脚,然后初始化显示模式,最后执行一些基本的 LCD 设置。例如,选择功能集、开启显示、清屏等

void LCD_Init(delayus sys_delay)
{
    LCD_GPIO_Init();
    Sys_Delayus = sys_delay;  // 将延迟函数传入
    LCD_DelayMs(50);  // 延时 50ms 等待 LCD 准备
    LCD_WriteCommand(LCD_FUNCTION_SET_BASIC);  // 选择基本指令集
    LCD_WriteCommand(LCD_DISPLAY_ON);  // 打开显示
    LCD_WriteCommand(LCD_DISPLAY_CLEAR);  // 清除屏幕
    LCD_DelayMs(2);  // 延时,确保屏幕清除完成
}

文本显示

初始化完成后,我们可以通过 LCD_Draw_Str 函数在屏幕上显示文本。例如:

LCD_Draw_Str(0, 0, "Hello, World!");  // 在第一行显示 "Hello, World!"
LCD_Draw_Str(1, 0, "STM32 LCD Test");  // 在第二行显示 "STM32 LCD Test"

总结

通过 STM32 微控制器控制 LCD12864 显示屏,可以实现多种图形和文字显示功能。本文详细介绍了从引脚配置、命令发送到显示文本的完整实现流程。通过了解 LCD12864 的工作原理和 STM32 的控制方法,开发者可以根据项目需求灵活配置显示效果,满足不同应用的需求。

希望本文能够帮助大家快速上手 STM32 控制 LCD12864 显示屏的开发。如果有任何问题或建议,欢迎留言交流!

求点赞求关注谢谢啦ovo

下一章写关于LCD12864实现绘制图像功能。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐