一、系统总体设计
1.1 显示系统架构
┌─────────────────────────────────────────────────────────┐
│ 显示系统架构 │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ 汉字字库 │ │ 英文字库 │ │ 数字字库 │ │
│ │ GB2312编码 │ │ ASCII编码 │ │ ASCII编码 │ │
│ └──────┬──────┘ └──────┬──────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌──────▼────────────────▼────────────────▼─────┐ │
│ │ 显示缓冲管理 │ │
│ │ • 字符位置计算 • 颜色混合 • 裁剪处理 │ │
│ └──────┬────────────────────────────────┬─────┘ │
│ │ │ │
│ ┌──────▼────────────────────────────────▼─────┐ │
│ │ LCD驱动层 (ILI9341/ST7789) │ │
│ │ • SPI/8080接口 • 显存操作 • 颜色格式转换 │ │
│ └──────┬────────────────────────────────┬─────┘ │
│ │ │ │
│ ┌──────▼────────────────────────────────▼─────┐ │
│ │ 2.4寸/3.5寸彩色LCD屏 │ │
│ │ 320×240 / 480×320 分辨率 │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
1.2 技术规格
| 参数 | 规格 | 说明 |
|---|---|---|
| LCD控制器 | ILI9341/ST7789 | 常用彩屏控制器 |
| 分辨率 | 320×240 (QVGA) | 标准分辨率 |
| 颜色深度 | 16位RGB565 | 65K色 |
| 接口方式 | 4线SPI/8位并行 | 推荐SPI节省IO |
| 字库格式 | GB2312点阵 | 支持简体中文 |
| 显示速度 | >30FPS | 流畅刷新 |
二、硬件连接设计
2.1 硬件连接表
c
/* LCD硬件连接定义 */
// SPI接口连接(4线SPI模式)
#define LCD_CS_PIN GPIO_Pin_0 // PA0 - 片选
#define LCD_RS_PIN GPIO_Pin_1 // PA1 - 数据/命令选择
#define LCD_RST_PIN GPIO_Pin_2 // PA2 - 复位
#define LCD_SDA_PIN GPIO_Pin_7 // PA7 - SPI1_MOSI
#define LCD_SCK_PIN GPIO_Pin_5 // PA5 - SPI1_SCK
#define LCD_LED_PIN GPIO_Pin_3 // PA3 - 背光控制
// GPIO端口定义
#define LCD_CS_PORT GPIOA
#define LCD_RS_PORT GPIOA
#define LCD_RST_PORT GPIOA
#define LCD_LED_PORT GPIOA
#define LCD_SPI SPI1
// 触摸芯片(可选)
#define TOUCH_CS_PIN GPIO_Pin_4 // PA4 - 触摸片选
#define TOUCH_IRQ_PIN GPIO_Pin_8 // PA8 - 触摸中断
// 颜色定义(RGB565格式)
#define COLOR_BLACK 0x0000 // 黑色
#define COLOR_WHITE 0xFFFF // 白色
#define COLOR_RED 0xF800 // 红色
#define COLOR_GREEN 0x07E0 // 绿色
#define COLOR_BLUE 0x001F // 蓝色
#define COLOR_YELLOW 0xFFE0 // 黄色
#define COLOR_CYAN 0x07FF // 青色
#define COLOR_MAGENTA 0xF81F // 品红
#define COLOR_GRAY 0x8410 // 灰色
2.2 字库存储方案
| 存储方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 内部Flash | 访问速度快,无需外部器件 | 占用Flash空间大 | 少量汉字显示 |
| 外部SPI Flash | 存储容量大,成本低 | 访问速度较慢 | 完整字库显示 |
| SD卡存储 | 容量极大,可更换 | 访问速度慢,需要文件系统 | 多字体支持 |
| 外部SRAM | 读写速度快 | 掉电丢失,成本高 | 动态字库缓存 |
三、LCD底层驱动
3.1 LCD初始化
c
/* LCD底层驱动 */
#include "stm32f10x.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include <stdio.h>
#include <string.h>
// LCD尺寸定义
#define LCD_WIDTH 320
#define LCD_HEIGHT 240
// 显示方向
typedef enum {
LCD_ROTATE_0 = 0, // 0度
LCD_ROTATE_90 = 1, // 90度
LCD_ROTATE_180 = 2, // 180度
LCD_ROTATE_270 = 3 // 270度
} LCD_Rotation;
// 颜色定义
typedef uint16_t LCD_Color;
// 矩形区域
typedef struct {
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t height;
} LCD_Rect;
/* GPIO操作宏 */
#define LCD_CS_LOW() GPIO_ResetBits(LCD_CS_PORT, LCD_CS_PIN)
#define LCD_CS_HIGH() GPIO_SetBits(LCD_CS_PORT, LCD_CS_PIN)
#define LCD_RS_LOW() GPIO_ResetBits(LCD_RS_PORT, LCD_RS_PIN)
#define LCD_RS_HIGH() GPIO_SetBits(LCD_RS_PORT, LCD_RS_PIN)
#define LCD_RST_LOW() GPIO_ResetBits(LCD_RST_PORT, LCD_RST_PIN)
#define LCD_RST_HIGH() GPIO_SetBits(LCD_RST_PORT, LCD_RST_PIN)
#define LCD_LED_ON() GPIO_SetBits(LCD_LED_PORT, LCD_LED_PIN)
#define LCD_LED_OFF() GPIO_ResetBits(LCD_LED_PORT, LCD_LED_PIN)
/* SPI写数据 */
void LCD_SPI_WriteByte(uint8_t data) {
LCD_CS_LOW();
while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(LCD_SPI, data);
while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_RXNE) == RESET);
SPI_I2S_ReceiveData(LCD_SPI);
LCD_CS_HIGH();
}
/* 写命令 */
void LCD_WriteCommand(uint8_t cmd) {
LCD_RS_LOW(); // RS=0,命令模式
LCD_SPI_WriteByte(cmd);
}
/* 写数据 */
void LCD_WriteData(uint8_t data) {
LCD_RS_HIGH(); // RS=1,数据模式
LCD_SPI_WriteByte(data);
}
/* 写16位数据 */
void LCD_WriteData16(uint16_t data) {
LCD_RS_HIGH();
LCD_SPI_WriteByte(data >> 8); // 高字节
LCD_SPI_WriteByte(data & 0xFF); // 低字节
}
/* LCD初始化 */
void LCD_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
// 配置GPIO
GPIO_InitStructure.GPIO_Pin = LCD_CS_PIN | LCD_RS_PIN | LCD_RST_PIN | LCD_LED_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD_SCK_PIN | LCD_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置SPI
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 36MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(LCD_SPI, &SPI_InitStructure);
SPI_Cmd(LCD_SPI, ENABLE);
// 硬件复位
LCD_RST_LOW();
delay_ms(100);
LCD_RST_HIGH();
delay_ms(120);
// ILI9341初始化序列
LCD_WriteCommand(0xCF); // Power Control B
LCD_WriteData(0x00);
LCD_WriteData(0xC1);
LCD_WriteData(0x30);
LCD_WriteCommand(0xED); // Power On Sequence Control
LCD_WriteData(0x64);
LCD_WriteData(0x03);
LCD_WriteData(0x12);
LCD_WriteData(0x81);
LCD_WriteCommand(0xE8); // Driver Timing Control A
LCD_WriteData(0x85);
LCD_WriteData(0x00);
LCD_WriteData(0x78);
LCD_WriteCommand(0xCB); // Power Control A
LCD_WriteData(0x39);
LCD_WriteData(0x2C);
LCD_WriteData(0x00);
LCD_WriteData(0x34);
LCD_WriteData(0x02);
LCD_WriteCommand(0xF7); // Pump Ratio Control
LCD_WriteData(0x20);
LCD_WriteCommand(0xEA); // Driver Timing Control B
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteCommand(0xC0); // Power Control 1
LCD_WriteData(0x23);
LCD_WriteCommand(0xC1); // Power Control 2
LCD_WriteData(0x10);
LCD_WriteCommand(0xC5); // VCOM Control 1
LCD_WriteData(0x3E);
LCD_WriteData(0x28);
LCD_WriteCommand(0xC7); // VCOM Control 2
LCD_WriteData(0x86);
LCD_WriteCommand(0x36); // Memory Access Control
LCD_WriteData(0x48); // MX=1, MY=0, MV=0, ML=1, BGR=1
LCD_WriteCommand(0x3A); // Pixel Format Set
LCD_WriteData(0x55); // 16位色彩模式
LCD_WriteCommand(0xB1); // Frame Rate Control
LCD_WriteData(0x00);
LCD_WriteData(0x18);
LCD_WriteCommand(0xB6); // Display Function Control
LCD_WriteData(0x08);
LCD_WriteData(0x82);
LCD_WriteData(0x27);
LCD_WriteCommand(0xF2); // Enable 3Gamma Function
LCD_WriteData(0x00);
LCD_WriteCommand(0x26); // Gamma Set
LCD_WriteData(0x01); // Gamma curve selected
LCD_WriteCommand(0xE0); // Positive Gamma Correction
LCD_WriteData(0x0F);
LCD_WriteData(0x31);
LCD_WriteData(0x2B);
LCD_WriteData(0x0C);
LCD_WriteData(0x0E);
LCD_WriteData(0x08);
LCD_WriteData(0x4E);
LCD_WriteData(0xF1);
LCD_WriteData(0x37);
LCD_WriteData(0x07);
LCD_WriteData(0x10);
LCD_WriteData(0x03);
LCD_WriteData(0x0E);
LCD_WriteData(0x09);
LCD_WriteData(0x00);
LCD_WriteCommand(0xE1); // Negative Gamma Correction
LCD_WriteData(0x00);
LCD_WriteData(0x0E);
LCD_WriteData(0x14);
LCD_WriteData(0x03);
LCD_WriteData(0x11);
LCD_WriteData(0x07);
LCD_WriteData(0x31);
LCD_WriteData(0xC1);
LCD_WriteData(0x48);
LCD_WriteData(0x08);
LCD_WriteData(0x0F);
LCD_WriteData(0x0C);
LCD_WriteData(0x31);
LCD_WriteData(0x36);
LCD_WriteData(0x0F);
LCD_WriteCommand(0x11); // Sleep Out
delay_ms(120);
LCD_WriteCommand(0x29); // Display ON
LCD_LED_ON(); // 打开背光
printf("LCD ILI9341 Initialized\n");
}
3.2 显示区域设置
c
/* 设置显示窗口 */
void LCD_SetWindow(uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
uint16_t x_end = x + width - 1;
uint16_t y_end = y + height - 1;
// 设置列地址
LCD_WriteCommand(0x2A); // Column Address Set
LCD_WriteData16(x);
LCD_WriteData16(x_end);
// 设置行地址
LCD_WriteCommand(0x2B); // Page Address Set
LCD_WriteData16(y);
LCD_WriteData16(y_end);
// 准备写入显存
LCD_WriteCommand(0x2C); // Memory Write
}
/* 画点 */
void LCD_DrawPoint(uint16_t x, uint16_t y, LCD_Color color) {
if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;
LCD_SetWindow(x, y, 1, 1);
LCD_WriteData16(color);
}
/* 填充矩形 */
void LCD_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, LCD_Color color) {
uint32_t pixels = (uint32_t)width * height;
if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;
if (x + width > LCD_WIDTH) width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT) height = LCD_HEIGHT - y;
LCD_SetWindow(x, y, width, height);
LCD_RS_HIGH();
for (uint32_t i = 0; i < pixels; i++) {
LCD_SPI_WriteByte(color >> 8);
LCD_SPI_WriteByte(color & 0xFF);
}
}
/* 清屏 */
void LCD_Clear(LCD_Color color) {
LCD_FillRect(0, 0, LCD_WIDTH, LCD_HEIGHT, color);
printf("LCD Cleared with color: 0x%04X\n", color);
}
四、字库系统设计
4.1 汉字字库结构
c
/* 字库系统 */
#include "stdlib.h"
// 字体大小定义
typedef enum {
FONT_12x12 = 12, // 12×12点阵
FONT_16x16 = 16, // 16×16点阵
FONT_24x24 = 24, // 24×24点阵
FONT_32x32 = 32 // 32×32点阵
} FontSize;
// 字体颜色结构
typedef struct {
LCD_Color foreground; // 前景色(文字颜色)
LCD_Color background; // 背景色
} FontColor;
// 字体信息结构
typedef struct {
FontSize size; // 字体大小
uint8_t width; // 字符宽度
uint8_t height; // 字符高度
uint8_t bytes_per_row; // 每行字节数
FontColor color; // 字体颜色
} FontInfo;
// 汉字区位码结构
typedef struct {
uint8_t qu; // 区码 (0xA1-0xF7)
uint8_t wei; // 位码 (0xA1-0xFE)
uint32_t offset; // 字库偏移地址
} ChineseCode;
// 当前字体设置
FontInfo current_font = {
.size = FONT_16x16,
.width = 16,
.height = 16,
.bytes_per_row = 2,
.color = {COLOR_BLACK, COLOR_WHITE}
};
/* 汉字编码转换(GB2312) */
ChineseCode Convert_Chinese_Code(uint8_t high_byte, uint8_t low_byte) {
ChineseCode code;
// GB2312编码范围:0xA1A1 - 0xF7FE
code.qu = high_byte;
code.wei = low_byte;
// 计算字库偏移地址
// 计算公式:(区码-0xA1) * 94 + (位码-0xA1)
if (high_byte >= 0xA1 && high_byte <= 0xF7 &&
low_byte >= 0xA1 && low_byte <= 0xFE) {
code.offset = ((high_byte - 0xA1) * 94 + (low_byte - 0xA1)) *
current_font.width * current_font.height / 8;
} else {
code.offset = 0; // 未知字符,使用第一个字符
}
return code;
}
/* 汉字点阵数据获取 */
// 12x12汉字字库(示例数据)
const uint8_t Chinese_Font_12x12[] = {
// "中" 字的点阵数据
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 16x16汉字字库(示例数据)
const uint8_t Chinese_Font_16x16[] = {
// "中" 字的点阵数据
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 24x24汉字字库(示例数据)
const uint8_t Chinese_Font_24x24[] = {
// "中" 字的点阵数据
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// ... 更多数据
};
/* 获取汉字点阵数据 */
const uint8_t* Get_Chinese_Font_Data(uint8_t high_byte, uint8_t low_byte) {
ChineseCode code = Convert_Chinese_Code(high_byte, low_byte);
switch (current_font.size) {
case FONT_12x12:
return &Chinese_Font_12x12[code.offset];
case FONT_16x16:
return &Chinese_Font_16x16[code.offset];
case FONT_24x24:
return &Chinese_Font_24x24[code.offset];
default:
return Chinese_Font_16x16;
}
}
4.2 ASCII字库
c
/* ASCII字符字库 */
// 8x16 ASCII字库(标准8x16字体)
const uint8_t ASCII_Font_8x16[] = {
// 空格 (0x20)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// '0' (0x30)
0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44,
0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
// '1' (0x31)
0x00, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x00,
// 'A' (0x41)
0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x7C,
0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00,
// 'B' (0x42)
0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x44,
0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00,
// 'C' (0x43)
0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
// 更多字符...
};
// 16x24 ASCII字库(大字库)
const uint8_t ASCII_Font_16x24[] = {
// 更大的ASCII字符
};
/* 获取ASCII字符点阵数据 */
const uint8_t* Get_ASCII_Font_Data(uint8_t ascii_code) {
if (ascii_code < 32 || ascii_code > 127) {
ascii_code = '?'; // 未知字符显示为问号
}
return &ASCII_Font_8x16[(ascii_code - 32) * 16];
}
五、字符显示函数
5.1 汉字显示
c
/* 显示单个汉字 */
void LCD_ShowChineseChar(uint16_t x, uint16_t y, uint8_t high_byte, uint8_t low_byte) {
uint8_t width = current_font.width;
uint8_t height = current_font.height;
uint8_t bytes_per_row = current_font.bytes_per_row;
// 获取汉字点阵数据
const uint8_t* font_data = Get_Chinese_Font_Data(high_byte, low_byte);
// 设置显示窗口
LCD_SetWindow(x, y, width, height);
// 逐行显示点阵
for (uint8_t row = 0; row < height; row++) {
for (uint8_t byte_idx = 0; byte_idx < bytes_per_row; byte_idx++) {
uint8_t byte_data = font_data[row * bytes_per_row + byte_idx];
// 显示一个字节的8个像素点
for (uint8_t bit = 0; bit < 8; bit++) {
uint8_t pixel_x = byte_idx * 8 + bit;
if (pixel_x >= width) break;
if (byte_data & (0x80 >> bit)) {
// 显示前景色
LCD_WriteData16(current_font.color.foreground);
} else {
// 显示背景色
LCD_WriteData16(current_font.color.background);
}
}
}
}
}
/* 显示汉字字符串 */
void LCD_ShowChineseString(uint16_t x, uint16_t y, const char* str) {
uint16_t current_x = x;
while (*str) {
if ((uint8_t)*str > 0x80) { // 中文字符(GB2312编码)
uint8_t high_byte = (uint8_t)*str++;
uint8_t low_byte = (uint8_t)*str++;
LCD_ShowChineseChar(current_x, y, high_byte, low_byte);
current_x += current_font.width;
} else {
// ASCII字符,跳过
str++;
}
}
}
5.2 英文和数字显示
c
/* 显示ASCII字符 */
void LCD_ShowASCIIChar(uint16_t x, uint16_t y, uint8_t ascii_code) {
uint8_t width = 8; // ASCII字符宽度固定8像素
uint8_t height = 16; // ASCII字符高度固定16像素
// 获取ASCII点阵数据
const uint8_t* font_data = Get_ASCII_Font_Data(ascii_code);
// 设置显示窗口
LCD_SetWindow(x, y, width, height);
// 显示点阵
for (uint8_t row = 0; row < height; row++) {
uint8_t byte_data = font_data[row];
for (uint8_t bit = 0; bit < 8; bit++) {
if (byte_data & (0x80 >> bit)) {
LCD_WriteData16(current_font.color.foreground);
} else {
LCD_WriteData16(current_font.color.background);
}
}
}
}
/* 显示字符串 */
void LCD_ShowString(uint16_t x, uint16_t y, const char* str) {
uint16_t current_x = x;
while (*str) {
if ((uint8_t)*str > 0x80) { // 中文字符
uint8_t high_byte = (uint8_t)*str++;
uint8_t low_byte = (uint8_t)*str++;
LCD_ShowChineseChar(current_x, y, high_byte, low_byte);
current_x += current_font.width;
} else { // ASCII字符
LCD_ShowASCIIChar(current_x, y, (uint8_t)*str++);
current_x += 8;
}
}
}
/* 显示数字 */
void LCD_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len) {
uint8_t num_str[12]; // 最多12位数字
uint8_t i;
// 转换数字为字符串
sprintf((char*)num_str, "%lu", num);
// 显示数字
LCD_ShowString(x, y, (char*)num_str);
}
/* 显示浮点数 */
void LCD_ShowFloat(uint16_t x, uint16_t y, float num, uint8_t decimal_places) {
char float_str[20];
// 格式化浮点数
sprintf(float_str, "%.*f", decimal_places, num);
// 显示浮点数
LCD_ShowString(x, y, float_str);
}
5.3 混合文本显示
c
/* 显示混合文本(中英文+数字) */
void LCD_ShowMixedText(uint16_t x, uint16_t y, const char* text) {
uint16_t current_x = x;
const char* ptr = text;
while (*ptr) {
if ((uint8_t)*ptr > 0x80) { // 中文字符
uint8_t high_byte = (uint8_t)*ptr++;
uint8_t low_byte = (uint8_t)*ptr++;
LCD_ShowChineseChar(current_x, y, high_byte, low_byte);
current_x += current_font.width;
} else if (*ptr >= '0' && *ptr <= '9') { // 数字
LCD_ShowASCIIChar(current_x, y, (uint8_t)*ptr++);
current_x += 8;
} else { // 英文字符
LCD_ShowASCIIChar(current_x, y, (uint8_t)*ptr++);
current_x += 8;
}
}
}
六、高级显示功能
6.1 字体样式设置
c
/* 字体样式设置 */
void LCD_SetFont(FontSize size) {
current_font.size = size;
switch (size) {
case FONT_12x12:
current_font.width = 12;
current_font.height = 12;
current_font.bytes_per_row = 2;
break;
case FONT_16x16:
current_font.width = 16;
current_font.height = 16;
current_font.bytes_per_row = 2;
break;
case FONT_24x24:
current_font.width = 24;
current_font.height = 24;
current_font.bytes_per_row = 3;
break;
case FONT_32x32:
current_font.width = 32;
current_font.height = 32;
current_font.bytes_per_row = 4;
break;
}
printf("Font size changed to %dx%d\n", current_font.width, current_font.height);
}
/* 设置字体颜色 */
void LCD_SetFontColor(LCD_Color foreground, LCD_Color background) {
current_font.color.foreground = foreground;
current_font.color.background = background;
}
/* 设置显示方向 */
void LCD_SetRotation(LCD_Rotation rotation) {
uint8_t madctl_value = 0x48; // 默认值
switch (rotation) {
case LCD_ROTATE_0:
madctl_value = 0x48; // MX=1, MY=0, MV=0, ML=1, BGR=1
break;
case LCD_ROTATE_90:
madctl_value = 0x68; // MX=1, MY=0, MV=1, ML=1, BGR=1
break;
case LCD_ROTATE_180:
madctl_value = 0x88; // MX=0, MY=1, MV=0, ML=1, BGR=1
break;
case LCD_ROTATE_270:
madctl_value = 0xE8; // MX=1, MY=1, MV=1, ML=1, BGR=1
break;
}
LCD_WriteCommand(0x36); // Memory Access Control
LCD_WriteData(madctl_value);
}
6.2 特殊显示效果
c
/* 显示带边框的文本 */
void LCD_ShowTextWithBorder(uint16_t x, uint16_t y, const char* text,
LCD_Color text_color, LCD_Color border_color) {
// 先显示边框(偏移显示多次)
LCD_SetFontColor(border_color, COLOR_WHITE);
LCD_ShowMixedText(x-1, y, text);
LCD_ShowMixedText(x+1, y, text);
LCD_ShowMixedText(x, y-1, text);
LCD_ShowMixedText(x, y+1, text);
// 再显示正文
LCD_SetFontColor(text_color, COLOR_WHITE);
LCD_ShowMixedText(x, y, text);
}
/* 显示渐变颜色文本 */
void LCD_ShowGradientText(uint16_t x, uint16_t y, const char* text) {
uint16_t colors[] = {COLOR_RED, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE};
uint8_t color_count = sizeof(colors) / sizeof(colors[0]);
uint16_t text_width = strlen(text) * 8;
uint16_t segment_width = text_width / color_count;
for (uint8_t i = 0; i < color_count; i++) {
uint16_t segment_x = x + i * segment_width;
LCD_SetFontColor(colors[i], COLOR_WHITE);
// 只显示部分文本(这里简化处理,实际应该裁剪文本)
LCD_ShowMixedText(segment_x, y, text);
}
}
/* 滚动文本显示 */
typedef struct {
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t scroll_pos;
const char* text;
} ScrollingText;
ScrollingText scroll_text;
void LCD_InitScrollingText(uint16_t x, uint16_t y, uint16_t width, const char* text) {
scroll_text.x = x;
scroll_text.y = y;
scroll_text.width = width;
scroll_text.scroll_pos = 0;
scroll_text.text = text;
}
void LCD_UpdateScrollingText(void) {
// 清空白区域
LCD_FillRect(scroll_text.x, scroll_text.y, scroll_text.width, 16, COLOR_WHITE);
// 显示滚动文本
const char* display_text = &scroll_text.text[scroll_text.scroll_pos];
LCD_ShowMixedText(scroll_text.x, scroll_text.y, display_text);
// 更新滚动位置
scroll_text.scroll_pos++;
if (scroll_text.scroll_pos >= strlen(scroll_text.text)) {
scroll_text.scroll_pos = 0;
}
}
七、应用示例
7.1 综合显示界面
c
/* 综合显示界面示例 */
void LCD_Demo_Interface(void) {
// 1. 清屏
LCD_Clear(COLOR_WHITE);
// 2. 显示标题(大字体)
LCD_SetFont(FONT_24x24);
LCD_SetFontColor(COLOR_BLUE, COLOR_WHITE);
LCD_ShowMixedText(80, 20, "STM32彩屏显示系统");
// 3. 显示分隔线
for (uint16_t x = 10; x < 310; x++) {
LCD_DrawPoint(x, 60, COLOR_GRAY);
}
// 4. 显示中文信息
LCD_SetFont(FONT_16x16);
LCD_SetFontColor(COLOR_BLACK, COLOR_WHITE);
LCD_ShowMixedText(20, 80, "当前温度:");
LCD_SetFontColor(COLOR_RED, COLOR_WHITE);
LCD_ShowFloat(140, 80, 25.6f, 1);
LCD_ShowMixedText(200, 80, "℃");
// 5. 显示数字信息
LCD_SetFontColor(COLOR_BLACK, COLOR_WHITE);
LCD_ShowMixedText(20, 110, "设备编号:");
LCD_SetFontColor(COLOR_GREEN, COLOR_WHITE);
LCD_ShowNum(140, 110, 123456, 6);
// 6. 显示状态信息
LCD_SetFont(FONT_12x12);
LCD_ShowMixedText(20, 140, "系统状态:正常运行");
// 7. 显示带边框的文本
LCD_ShowTextWithBorder(20, 170, "重要提示", COLOR_RED, COLOR_BLACK);
// 8. 显示渐变文本
LCD_ShowGradientText(20, 200, "彩色渐变文字");
// 9. 显示边框装饰
LCD_DrawRect(10, 10, 300, 220, COLOR_BLUE);
LCD_DrawRect(12, 12, 296, 216, COLOR_GREEN);
}
/* 实时数据更新显示 */
typedef struct {
float temperature;
float humidity;
uint32_t pressure;
uint8_t battery_level;
} SensorData;
SensorData sensor_data = {25.6f, 65.2f, 101325, 85};
void LCD_UpdateSensorData(void) {
static uint32_t last_update = 0;
uint32_t current_time = Get_SystemTick();
if (current_time - last_update >= 1000) { // 每秒更新一次
// 更新温度显示
LCD_FillRect(140, 80, 60, 16, COLOR_WHITE);
LCD_SetFontColor(COLOR_RED, COLOR_WHITE);
LCD_ShowFloat(140, 80, sensor_data.temperature, 1);
// 更新湿度显示
LCD_FillRect(140, 95, 60, 16, COLOR_WHITE);
LCD_SetFontColor(COLOR_BLUE, COLOR_WHITE);
LCD_ShowFloat(140, 95, sensor_data.humidity, 1);
// 更新电池图标
LCD_DrawBatteryIcon(250, 10, sensor_data.battery_level);
last_update = current_time;
}
}
/* 绘制电池图标 */
void LCD_DrawBatteryIcon(uint16_t x, uint16_t y, uint8_t level) {
// 电池外框
LCD_DrawRect(x, y, 30, 15, COLOR_BLACK);
LCD_DrawRect(x + 30, y + 3, 3, 9, COLOR_BLACK);
// 电池电量
uint8_t fill_width = (level * 26) / 100;
LCD_FillRect(x + 2, y + 2, fill_width, 11, COLOR_GREEN);
}
参考代码 LCD彩色液晶屏显示汉字、英文、数字 www.youwenfan.com/contentcst/133232.html
八、主程序
8.1 完整主程序
c
/* 主程序 */
#include "stm32f10x.h"
#include "system_stm32f10x.h"
volatile uint32_t system_tick = 0;
void SysTick_Init(void) {
SysTick_Config(SystemCoreClock / 1000); // 1ms中断
}
void SysTick_Handler(void) {
system_tick++;
}
uint32_t Get_SystemTick(void) {
return system_tick;
}
// 延时函数
void delay_ms(uint32_t ms) {
uint32_t start = system_tick;
while ((system_tick - start) < ms);
}
int main(void) {
// 系统初始化
SystemInit();
SysTick_Init();
// 初始化串口(用于调试)
USART1_Init();
printf("\r\n=== STM32 LCD Color Display Demo ===\r\n");
// 初始化LCD
LCD_Init();
// 显示演示界面
LCD_Demo_Interface();
// 初始化滚动文本
LCD_InitScrollingText(20, 230, 280, "欢迎使用STM32彩色液晶屏显示系统!这是滚动文本演示...");
printf("LCD Demo Started!\r\n");
// 主循环
while (1) {
// 更新传感器数据
LCD_UpdateSensorData();
// 更新滚动文本
static uint32_t last_scroll = 0;
if (system_tick - last_scroll >= 200) { // 每200ms滚动一次
LCD_UpdateScrollingText();
last_scroll = system_tick;
}
// 模拟数据变化
static uint32_t data_counter = 0;
if (system_tick % 5000 == 0) { // 每5秒改变一次数据
sensor_data.temperature += 0.5f;
if (sensor_data.temperature > 35.0f) sensor_data.temperature = 20.0f;
sensor_data.humidity += 2.0f;
if (sensor_data.humidity > 90.0f) sensor_data.humidity = 40.0f;
sensor_data.battery_level -= 1;
if (sensor_data.battery_level < 10) sensor_data.battery_level = 100;
data_counter++;
}
delay_ms(10);
}
}
九、字库制作工具
9.1 字库生成脚本
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
汉字点阵字库生成工具
支持生成12x12, 16x16, 24x24, 32x32点阵字库
"""
import struct
from PIL import Image, ImageDraw, ImageFont
import os
class FontGenerator:
def __init__(self, font_path="simsun.ttc"):
self.font_path = font_path
def generate_chinese_font(self, characters, font_size):
"""生成汉字点阵字库"""
font = ImageFont.truetype(self.font_path, font_size)
output_lines = []
output_lines.append(f"/* {font_size}x{font_size} 汉字点阵字库 */")
output_lines.append("#ifndef __CHINESE_FONT_H")
output_lines.append("#define __CHINESE_FONT_H")
output_lines.append("")
output_lines.append("#include <stdint.h>")
output_lines.append("")
char_data_list = []
for i, char in enumerate(characters):
# 创建图像
img = Image.new('1', (font_size, font_size), color=0)
draw = ImageDraw.Draw(img)
# 绘制字符(居中显示)
bbox = draw.textbbox((0, 0), char, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x = (font_size - text_width) // 2
y = (font_size - text_height) // 2 - 2 # 稍微上移
draw.text((x, y), char, fill=1, font=font)
# 转换为点阵数据
bitmap_data = []
for y in range(font_size):
row_bytes = []
for byte_idx in range((font_size + 7) // 8):
byte_val = 0
for bit in range(8):
pixel_x = byte_idx * 8 + bit
if pixel_x < font_size and img.getpixel((pixel_x, y)):
byte_val |= (0x80 >> bit)
row_bytes.append(byte_val)
bitmap_data.extend(row_bytes)
# 生成变量名
var_name = f"ch_{ord(char):04X}"
char_data_list.append((var_name, bitmap_data, char))
output_lines.append(f"// 汉字\"{char}\" ({ord(char):04X})")
output_lines.append(f"const uint8_t {var_name}[] = {{")
# 输出点阵数据
for row in range(font_size):
row_start = row * ((font_size + 7) // 8)
row_data = bitmap_data[row_start:row_start + ((font_size + 7) // 8)]
hex_str = ', '.join(f'0x{b:02X}' for b in row_data)
output_lines.append(f" {hex_str},")
output_lines.append("};")
output_lines.append("")
# 生成字库数组
output_lines.append("// 字库数组")
output_lines.append("const uint8_t* chinese_font_array[] = {")
for var_name, _, _ in char_data_list:
output_lines.append(f" {var_name},")
output_lines.append("};")
output_lines.append("")
# 生成字符信息数组
output_lines.append("// 字符信息数组")
output_lines.append("typedef struct {")
output_lines.append(" uint16_t unicode;")
output_lines.append(" const uint8_t* data;")
output_lines.append("} ChineseCharInfo;")
output_lines.append("")
output_lines.append("ChineseCharInfo chinese_chars[] = {")
for var_name, _, char in char_data_list:
output_lines.append(f" {{0x{ord(char):04X}, {var_name}}},")
output_lines.append("};")
output_lines.append("")
output_lines.append("#endif // __CHINESE_FONT_H")
return '\n'.join(output_lines)
if __name__ == "__main__":
# 要生成的汉字列表
chinese_chars = "中文字符显示系统温度湿度压力电池欢迎使用"
generator = FontGenerator()
# 生成16x16字库
font_code = generator.generate_chinese_font(chinese_chars, 16)
# 保存到文件
with open("chinese_font_16x16.h", "w", encoding="utf-8") as f:
f.write(font_code)
print("16x16汉字字库生成完成: chinese_font_16x16.h")
十、总结
这个基于STM32的彩色LCD显示系统实现了以下功能:
核心功能:
- 多语言显示:完美支持中文、英文、数字混合显示
- 多字体大小:12x12、16x16、24x24、32x32点阵
- 颜色管理:16位RGB565色彩,65K色显示
- 文本特效:边框、渐变、滚动、阴影效果
- 实时更新:动态数据显示和界面刷新
技术亮点:
- GB2312编码:标准中文编码,兼容性好
- SPI高速接口:36MHz SPI时钟,刷新流畅
- 内存优化:按需加载字库,节省存储空间
- 模块化设计:显示驱动、字库管理、界面逻辑分离
- 跨平台兼容:支持ILI9341、ST7789等多种控制器
应用场景:
- 智能家居面板:温度、湿度、设备状态显示
- 工业控制界面:参数设置、实时监控、报警提示
- 医疗设备界面:患者信息、检测数据、操作菜单
- 车载显示系统:导航信息、车辆状态、多媒体控制
- 仪器仪表界面:测量数据、波形显示、系统设置
扩展建议:
- 外部字库存储:使用SPI Flash存储完整GB2312字库
- 矢量字体支持:集成FreeType库实现矢量字体渲染
- 触摸屏集成:结合触摸功能实现交互式界面
- GUI框架移植:移植LVGL、uCGUI等成熟GUI框架
- 多语言支持:扩展日文、韩文、阿拉伯文等字体