#include "lcd.h" #include "lcd_font.h" #include // 添加标准库以使用 malloc 和 free #include "lv_port_disp.h" // 写命令到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(); } // 使用 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_DrawPixel(uint16_t x, uint16_t y, uint16_t color) { // 旋转 90° 的坐标映射 uint16_t new_x = y; uint16_t new_y = LCD_HEIGHT - 1 - x; LCD_SetAddressWindow(new_x, new_y, 1, 1); uint8_t color_data[] = {color >> 8, color & 0xFF}; LCD_WriteDataBuffer(color_data, 2); } // 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++; // } // }