260 lines
8.9 KiB
C
260 lines
8.9 KiB
C
#include "lcd.h"
|
||
#include "lcd_font.h"
|
||
#include <stdlib.h> // 添加标准库以使用 malloc 和 free
|
||
|
||
// 写命令到LCD
|
||
static void LCD_WriteCommand(uint8_t cmd) {
|
||
LCD_DC_LOW();
|
||
LCD_CS_LOW();
|
||
HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
|
||
LCD_CS_HIGH();
|
||
}
|
||
|
||
// 写数据到LCD
|
||
static void LCD_WriteData(uint8_t data) {
|
||
LCD_DC_HIGH();
|
||
LCD_CS_LOW();
|
||
HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY);
|
||
LCD_CS_HIGH();
|
||
}
|
||
|
||
// // 写多个数据到LCD
|
||
// static void LCD_WriteDataBuffer(uint8_t *data, uint16_t size) {
|
||
// LCD_DC_HIGH();
|
||
// LCD_CS_LOW();
|
||
// HAL_SPI_Transmit(&hspi1, data, size, HAL_MAX_DELAY);
|
||
// LCD_CS_HIGH();
|
||
// }
|
||
|
||
// 使用 DMA 写多个数据到 LCD
|
||
static void LCD_WriteDataBuffer_DMA(uint8_t *data, uint16_t size) {
|
||
LCD_DC_HIGH();
|
||
LCD_CS_LOW();
|
||
HAL_SPI_Transmit_DMA(&hspi1, data, size); // 使用 DMA 传输
|
||
while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); // 等待传输完成
|
||
LCD_CS_HIGH();
|
||
}
|
||
|
||
// 修改原来的 LCD_WriteDataBuffer,增加 DMA 支持
|
||
static void LCD_WriteDataBuffer(uint8_t *data, uint16_t size) {
|
||
if (size > 64) { // 如果数据量较大,使用 DMA
|
||
LCD_WriteDataBuffer_DMA(data, size);
|
||
} else { // 否则使用普通传输
|
||
LCD_DC_HIGH();
|
||
LCD_CS_LOW();
|
||
HAL_SPI_Transmit(&hspi1, data, size, HAL_MAX_DELAY);
|
||
LCD_CS_HIGH();
|
||
}
|
||
}
|
||
|
||
// 初始化LCD
|
||
void LCD_Init(void) {
|
||
LCD_RST_LOW();
|
||
HAL_Delay(50);
|
||
LCD_RST_HIGH();
|
||
HAL_Delay(50);
|
||
|
||
LCD_WriteCommand(0x36); // Memory Data Access Control
|
||
LCD_WriteData(0x60); // 横屏模式,向右旋转90度
|
||
|
||
LCD_WriteCommand(0x3A); // Interface Pixel Format
|
||
LCD_WriteData(0x05); // 16位色
|
||
|
||
LCD_WriteCommand(0xB2); // Porch Setting
|
||
uint8_t porch[] = {0x0C, 0x0C, 0x00, 0x33, 0x33};
|
||
LCD_WriteDataBuffer(porch, sizeof(porch));
|
||
|
||
LCD_WriteCommand(0xB7); // Gate Control
|
||
LCD_WriteData(0x35);
|
||
|
||
LCD_WriteCommand(0xBB); // VCOM Setting
|
||
LCD_WriteData(0x19);
|
||
|
||
LCD_WriteCommand(0xC0); // LCM Control
|
||
LCD_WriteData(0x2C);
|
||
|
||
LCD_WriteCommand(0xC2); // VDV and VRH Command Enable
|
||
LCD_WriteData(0x01);
|
||
|
||
LCD_WriteCommand(0xC3); // VRH Set
|
||
LCD_WriteData(0x12);
|
||
|
||
LCD_WriteCommand(0xC4); // VDV Set
|
||
LCD_WriteData(0x20);
|
||
|
||
LCD_WriteCommand(0xC6); // Frame Rate Control
|
||
LCD_WriteData(0x0F);
|
||
|
||
LCD_WriteCommand(0xD0); // Power Control 1
|
||
LCD_WriteData(0xA4);
|
||
LCD_WriteData(0xA1);
|
||
|
||
LCD_WriteCommand(0xE0); // Positive Voltage Gamma Control
|
||
uint8_t gamma_pos[] = {0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23};
|
||
LCD_WriteDataBuffer(gamma_pos, sizeof(gamma_pos));
|
||
|
||
LCD_WriteCommand(0xE1); // Negative Voltage Gamma Control
|
||
uint8_t gamma_neg[] = {0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23};
|
||
LCD_WriteDataBuffer(gamma_neg, sizeof(gamma_neg));
|
||
|
||
LCD_WriteCommand(0x21); // Display Inversion On
|
||
LCD_WriteCommand(0x11); // Sleep Out
|
||
HAL_Delay(120);
|
||
LCD_WriteCommand(0x29); // Display On
|
||
}
|
||
|
||
// 设置显示窗口
|
||
static void LCD_SetAddressWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||
uint16_t x_start = x + X_OFFSET;
|
||
uint16_t x_end = x_start + w - 1;
|
||
uint16_t y_start = y + Y_OFFSET;
|
||
uint16_t y_end = y_start + h - 1;
|
||
|
||
LCD_WriteCommand(0x2A); // Column Address Set
|
||
uint8_t data_x[] = {x_start >> 8, x_start & 0xFF, x_end >> 8, x_end & 0xFF};
|
||
LCD_WriteDataBuffer(data_x, sizeof(data_x));
|
||
|
||
LCD_WriteCommand(0x2B); // Row Address Set
|
||
uint8_t data_y[] = {y_start >> 8, y_start & 0xFF, y_end >> 8, y_end & 0xFF};
|
||
LCD_WriteDataBuffer(data_y, sizeof(data_y));
|
||
|
||
LCD_WriteCommand(0x2C); // Memory Write
|
||
}
|
||
|
||
// 清屏
|
||
// void LCD_Clear(uint16_t color) {
|
||
// uint8_t color_data[] = {color >> 8, color & 0xFF};
|
||
// LCD_SetAddressWindow(0, 0, LCD_WIDTH, LCD_HEIGHT);
|
||
|
||
// for (uint32_t i = 0; i < LCD_WIDTH * LCD_HEIGHT; i++) {
|
||
// LCD_WriteDataBuffer(color_data, 2);
|
||
// }
|
||
// }
|
||
|
||
void LCD_Clear(uint16_t color) {
|
||
uint8_t color_data[] = {color >> 8, color & 0xFF};
|
||
LCD_SetAddressWindow(0, 0, LCD_WIDTH, LCD_HEIGHT); // 设置整个屏幕为绘制窗口
|
||
|
||
// 创建一个缓冲区,用于存储一行的颜色数据
|
||
uint32_t row_size = LCD_WIDTH * 2; // 每行像素占用 2 字节
|
||
uint8_t *row_buffer = (uint8_t *)malloc(row_size);
|
||
if (row_buffer == NULL) return; // 分配失败,直接返回
|
||
|
||
// 填充缓冲区为目标颜色
|
||
for (uint32_t i = 0; i < row_size; i += 2) {
|
||
row_buffer[i] = color_data[0];
|
||
row_buffer[i + 1] = color_data[1];
|
||
}
|
||
|
||
// 按行传输数据,覆盖整个屏幕
|
||
for (uint32_t y = 0; y < LCD_HEIGHT; y++) {
|
||
LCD_WriteDataBuffer_DMA(row_buffer, row_size);
|
||
}
|
||
|
||
free(row_buffer); // 释放缓冲区
|
||
}
|
||
|
||
// 绘制像素
|
||
void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
|
||
LCD_SetAddressWindow(x, y, 1, 1);
|
||
uint8_t color_data[] = {color >> 8, color & 0xFF};
|
||
LCD_WriteDataBuffer(color_data, 2);
|
||
}
|
||
|
||
// // 绘制字符(旋转90度)
|
||
// void LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgColor) {
|
||
// const unsigned char *font = ascii_1206[ch - ' '];
|
||
// for (uint8_t i = 0; i < FONT_WIDTH; i++) { // 遍历字体宽度
|
||
// for (uint8_t j = 0; j < FONT_HEIGHT; j++) { // 遍历字体高度
|
||
// if (font[j] & (1 << i)) { // 行列交换,旋转90度
|
||
// LCD_DrawPixel(x + i, y + j, color);
|
||
// } else {
|
||
// LCD_DrawPixel(x + i, y + j, bgColor);
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// 绘制字符(逆时针旋转90度)
|
||
// void LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgColor) {
|
||
// const unsigned char *font = ascii_1206[ch - ' '];
|
||
// for (uint8_t i = 0; i < FONT_WIDTH; i++) { // 遍历字体宽度
|
||
// for (uint8_t j = 0; j < FONT_HEIGHT; j++) { // 遍历字体高度
|
||
// if (font[j] & (1 << i)) { // 行列交换,逆时针旋转90度
|
||
// LCD_DrawPixel(x + j, y - i, color); // 注意坐标变换
|
||
// } else {
|
||
// LCD_DrawPixel(x + j, y - i, bgColor);
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// 绘制字符
|
||
// void LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgColor) {
|
||
// const unsigned char *font = ascii_1206[ch - ' '];
|
||
// uint8_t char_buffer[FONT_WIDTH * FONT_HEIGHT * 2]; // 每个像素 2 字节
|
||
// uint32_t index = 0;
|
||
|
||
// // 将字符数据按行存储到缓冲区
|
||
// for (uint8_t j = 0; j < FONT_HEIGHT; j++) { // 遍历字体高度(行)
|
||
// for (uint8_t i = 0; i < FONT_WIDTH; i++) { // 遍历字体宽度(列)
|
||
// if (font[j] & (1 << i)) { // 判断像素是否为前景色
|
||
// char_buffer[index++] = color >> 8;
|
||
// char_buffer[index++] = color & 0xFF;
|
||
// } else { // 背景色
|
||
// char_buffer[index++] = bgColor >> 8;
|
||
// char_buffer[index++] = bgColor & 0xFF;
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// // 设置显示窗口
|
||
// LCD_SetAddressWindow(x, y, FONT_WIDTH, FONT_HEIGHT);
|
||
|
||
// // 使用 DMA 传输字符像素数据
|
||
// LCD_WriteDataBuffer_DMA(char_buffer, sizeof(char_buffer));
|
||
// }
|
||
void LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bgColor) {
|
||
const unsigned char *font = ascii_1206[ch - ' '];
|
||
uint8_t char_buffer[FONT_WIDTH * FONT_HEIGHT * 2]; // 每个像素 2 字节
|
||
uint32_t index = 0;
|
||
|
||
// 将字符数据按列存储到缓冲区(逆时针旋转 90 度 + 左右镜像)
|
||
for (uint8_t i = 0; i < FONT_WIDTH; i++) { // 遍历字体宽度(列)
|
||
for (uint8_t j = 0; j < FONT_HEIGHT; j++) { // 遍历字体高度(行)
|
||
// 左右镜像:将列索引从 FONT_WIDTH - 1 - i 开始
|
||
if (font[j] & (1 << (FONT_WIDTH - 1 - i))) { // 判断像素是否为前景色
|
||
char_buffer[index++] = color >> 8;
|
||
char_buffer[index++] = color & 0xFF;
|
||
} else { // 背景色
|
||
char_buffer[index++] = bgColor >> 8;
|
||
char_buffer[index++] = bgColor & 0xFF;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置显示窗口(注意旋转后宽高互换)
|
||
LCD_SetAddressWindow(x, y, FONT_HEIGHT, FONT_WIDTH);
|
||
|
||
// 使用 DMA 传输字符像素数据
|
||
LCD_WriteDataBuffer_DMA(char_buffer, sizeof(char_buffer));
|
||
}
|
||
|
||
|
||
|
||
// 绘制字符串(沿y轴绘制)
|
||
void LCD_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bgColor) {
|
||
y = LCD_HEIGHT-7 -y;
|
||
while (*str) {
|
||
LCD_DrawChar(x, y, *str, color, bgColor);
|
||
y -= FONT_WIDTH; // 每个字符向下移动一个字符宽度
|
||
str++;
|
||
}
|
||
}
|
||
// void LCD_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bgColor) {
|
||
|
||
// while (*str) {
|
||
// LCD_DrawChar(x, y, *str, color, bgColor); // 使用 DMA 绘制字符
|
||
// x += FONT_WIDTH; // 每个字符向右移动一个字符宽度
|
||
// str++;
|
||
// }
|
||
// }
|