驱动ST77893P2.25寸屏幕
·
驱动ST77893P2.25寸屏幕 参考示例
特别值得注意的是 LCD_Address_Set 根据 ST7789的demo你要计算偏移了多少
留了一个timer方便lvgl移植
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
if (USE_HORIZONTAL == 0)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+82);
LCD_WR_DATA(x2+82);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+18);
LCD_WR_DATA(y2+18);
LCD_WR_REG(0x2c); // 储存器写
}
else if (USE_HORIZONTAL == 1)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+82);
LCD_WR_DATA(x2+82);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+18);
LCD_WR_DATA(y2+18);
LCD_WR_REG(0x2c); // 储存器写
}
else if (USE_HORIZONTAL == 2)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+18);
LCD_WR_DATA(x2+18);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+82);
LCD_WR_DATA(y2+82);
LCD_WR_REG(0x2c); // 储存器写
}
else
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+18);
LCD_WR_DATA(x2+18);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+82);
LCD_WR_DATA(y2+82);
LCD_WR_REG(0x2c); // 储存器写
}
}
SPI2 c文件
/*********************************************************************
* INCLUDES
*/
#include "bsp_spi.h"
/*********************************************************************
* LOCAL DEFINES
*/
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef HdmaCh1;
/*********************************************************************
* LOCAL FUNCTIONS
*/
/**
* @brief Initialize SPI related MSP
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (hspi->Instance == SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE(); /* Enable DMA clock */
__HAL_RCC_SYSCFG_CLK_ENABLE(); /* Enable SYSCFG clock */
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF3_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = GPIO_PIN_14;
// GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
// GPIO_InitStruct.Alternate = GPIO_AF3_SPI2;
// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*GPIO configured as SPI:MISO/MOSI*/
GPIO_InitStruct.Pin = GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF3_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Interrupt configuration */
HAL_NVIC_SetPriority(SPI2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
/* DMA_CH1 configuration */
HdmaCh1.Instance = DMA1_Channel1;
HdmaCh1.Init.Direction = DMA_MEMORY_TO_PERIPH;
HdmaCh1.Init.PeriphInc = DMA_PINC_DISABLE;
HdmaCh1.Init.MemInc = DMA_MINC_ENABLE;
if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
{
HdmaCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
HdmaCh1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
}
else
{
HdmaCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
HdmaCh1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
}
HdmaCh1.Init.Mode = DMA_NORMAL;
HdmaCh1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
/* Initialize DMA */
HAL_DMA_Init(&HdmaCh1);
/* DMA handle is associated with SPI handle */
__HAL_LINKDMA(hspi, hdmatx, HdmaCh1);
/* Set DMA channel map. */
HAL_DMA_ChannelMap(&HdmaCh1, DMA_CHANNEL_MAP_SPI2_WR); /* SPI2_TX DMA1_CH1 */
/* DMA interrupt configuration*/
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
}
/**
* @brief Deinit SPI MSP
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI2)
{
/* USER CODE BEGIN SPI2_MspDeInit 0 */
/* USER CODE END SPI2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI2_CLK_DISABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
HAL_NVIC_DisableIRQ(SPI2_IRQn);
HAL_DMA_DeInit(&HdmaCh1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
}
}
/*********************************************************************
* @fn bsp_spi2_init
*
* @brief Initialize SPI2 peripheral.
*
* @return none
*/
void bsp_spi2_init(void)
{
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
// hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
// hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
APP_ErrorHandler();
}
/* Initialize SPI peripheral */
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
APP_ErrorHandler();
}
}
/****************************************************END OF FILE****************************************************/
SPI2 h文件
// Copyright (c) RealCoolEngineer. 2025. All rights reserved.
// Author: ClingYang
// https://clingyang.github.io/
// Date: 2025-06-30
// Version: 1.0
#ifndef __BSP_SPI_H__
#define __BSP_SPI_H__
#ifdef __cplusplus
extern "C" {
#endif
/*********************************************************************
* INCLUDES
*/
#include "main.h"
/*********************************************************************
* API FUNCTIONS
*/
extern DMA_HandleTypeDef HdmaCh1;
extern SPI_HandleTypeDef hspi2;
void bsp_spi2_init(void);
void bsp_spi2_transmit_dma(uint8_t *pTxData, uint16_t Size);
#ifdef __cplusplus
}
#endif
#endif /*__BSP_SPI_H__*/
LCD.c
#include "lcd.h"
void LCD_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PB12 PB14 */
GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : REST PA8 BLCK PA9 */
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin Output Level CS PB12 DC PB14 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_14, GPIO_PIN_SET);
/*Configure GPIO pin Output Level REST PA8 BLCK PA9 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); // 背光默认关闭
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{
LCD_CS_Clr();
HAL_SPI_Transmit(&usr_lcd_spi, &dat, 1, 1000);
// bsp_spi2_transmit_dma(uint8_t *pTxData, uint16_t Size)
LCD_CS_Set();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
LCD_Writ_Bus(dat >> 8);
LCD_Writ_Bus(dat & 0xff);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
LCD_DC_Clr(); // 写命令
LCD_Writ_Bus(dat);
LCD_DC_Set(); // 写数据
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
if (USE_HORIZONTAL == 0)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+82);
LCD_WR_DATA(x2+82);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+18);
LCD_WR_DATA(y2+18);
LCD_WR_REG(0x2c); // 储存器写
}
else if (USE_HORIZONTAL == 1)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+82);
LCD_WR_DATA(x2+82);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+18);
LCD_WR_DATA(y2+18);
LCD_WR_REG(0x2c); // 储存器写
}
else if (USE_HORIZONTAL == 2)
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+18);
LCD_WR_DATA(x2+18);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+82);
LCD_WR_DATA(y2+82);
LCD_WR_REG(0x2c); // 储存器写
}
else
{
LCD_WR_REG(0x2a); // 列地址设置
LCD_WR_DATA(x1+18);
LCD_WR_DATA(x2+18);
LCD_WR_REG(0x2b); // 行地址设置
LCD_WR_DATA(y1+82);
LCD_WR_DATA(y2+82);
LCD_WR_REG(0x2c); // 储存器写
}
}
void LCD_Init(void)
{
LCD_GPIO_Init(); // 初始化GPIO/SPI接口(需你自己实现)
LCD_RES_Clr(); // 拉低复位引脚
HAL_Delay(30); // 延时 >10ms
LCD_RES_Set(); // 拉高复位引脚
HAL_Delay(100); // 等待芯片稳定
LCD_BLK_Set(); // 打开背光
HAL_Delay(100);
// 软件复位
LCD_WR_REG(0x01);
HAL_Delay(120);
// 退出睡眠
LCD_WR_REG(0x11);
HAL_Delay(120);
// 设置内存数据访问控制
LCD_WR_REG(0x36);
if (USE_HORIZONTAL == 0) LCD_WR_DATA8(0x00); // 竖屏
else if (USE_HORIZONTAL == 1) LCD_WR_DATA8(0xC0); // 横屏180
else if (USE_HORIZONTAL == 2) LCD_WR_DATA8(0x70); // 竖屏180
else LCD_WR_DATA8(0xA0); // 横屏
// 设置像素格式为16位色(RGB565)
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
// 设置Porch控制
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
// 设置Gate控制
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0x35);
// VCOM设置
LCD_WR_REG(0xBB);
LCD_WR_DATA8(0x35);
// LCM控制
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x2C);
// VDV和VRH命令使能
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x01);
// VRH设置
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x13);
// VDV设置
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x20);
// 帧率控制(60Hz)
LCD_WR_REG(0xC6);
LCD_WR_DATA8(0x0F);
// 电源控制1
LCD_WR_REG(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
// 电源控制2
LCD_WR_REG(0xD6);
LCD_WR_DATA8(0xA1);
// 正极性伽马校正
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3E);
LCD_WR_DATA8(0x38);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
// 负极性伽马校正
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3E);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x32);
// 设置窗口(可选)
LCD_Address_Set(0, 0, LCD_W - 1, LCD_H - 1);
// 清屏为黑色
LCD_Fill(0, 0, LCD_W, LCD_H, 0x0000);
// 打开显示
LCD_WR_REG(0x29);
}
#define COLOR_FILL_BUFFER_SIZE 240 // 定义缓冲区大小,可根据实际情况调整
static uint16_t color_fill_buffer[COLOR_FILL_BUFFER_SIZE * 2]; // 静态缓冲区
// GC9307
void Lcd_SendByte(uint8_t dat, LCD_DCType DC)
{
LCD_CS_Clr();
if (DC == LCD_DATA)
{
LCD_DC_Set();
}
else
{
LCD_DC_Clr();
}
while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
;
LCD_CS_Set();
}
void Lcd_SendHalfWord(uint16_t dat)
{
uint8_t tempdat[2];
LCD_CS_Clr();
tempdat[0] = dat >> 8;
tempdat[1] = dat & 0xFF;
HAL_SPI_Transmit_DMA(&usr_lcd_spi, tempdat, 2);
while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
;
LCD_CS_Set();
}
void Lcd_SendMulitiByte(uint8_t *dat, uint16_t len)
{
LCD_CS_Clr();
LCD_DC_Set();
HAL_SPI_Transmit_DMA(&usr_lcd_spi, dat, len);
while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
;
LCD_CS_Set();
}
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{
uint32_t total_pixels = (xend - xsta) * (yend - ysta);
// 设置地址范围
LCD_Address_Set(xsta, ysta, xend - 1, yend - 1);
// 填充缓冲区(高低字节交换)
uint16_t swapped_color = (color >> 8) | (color << 8);
for (uint32_t i = 0; i < COLOR_FILL_BUFFER_SIZE * 2; i++) {
color_fill_buffer[i] = swapped_color;
}
// 批量传输数据
LCD_DC_Set(); // 确保处于数据写入模式
LCD_CS_Clr();
while (total_pixels > 0) {
uint32_t chunk_size = (total_pixels > COLOR_FILL_BUFFER_SIZE * 2) ? COLOR_FILL_BUFFER_SIZE * 2 : total_pixels;
// 使用 DMA 传输数据
HAL_SPI_Transmit_DMA(&usr_lcd_spi, (uint8_t *)color_fill_buffer, chunk_size * 2);
// 等待 DMA 传输完成
while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX);
total_pixels -= chunk_size;
}
LCD_CS_Set();
}
/******************************************************************************
函数说明:显示图片
入口数据:x,y起点坐标
length 图片长度
width 图片宽度
pic[] 图片数组
返回值: 无
******************************************************************************/
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])
{
u16 i,j;
u32 k=0;
LCD_Address_Set(x,y,x+length-1,y+width-1);
for(i=0;i<length;i++)
{
for(j=0;j<width;j++)
{
LCD_WR_DATA8(pic[k*2]);
LCD_WR_DATA8(pic[k*2+1]);
k++;
}
}
}
#define PIC_DMA_BUFFER_SIZE 512 // 定义缓冲区大小(可根据实际情况调整)
static uint8_t pic_dma_buffer[PIC_DMA_BUFFER_SIZE * 2]; // 静态缓冲区
void LCD_ShowPicture_DMA(u16 x, u16 y, u16 length, u16 width, const u8 pic[])
{
u32 total_pixels = (u32)length * width; // 总像素数
u32 k = 0; // 当前像素索引
// 设置地址范围
LCD_Address_Set(x, y, x + length - 1, y + width - 1);
// 确保处于数据写入模式
LCD_DC_Set();
LCD_CS_Clr();
while (total_pixels > 0)
{
u32 chunk_size = (total_pixels > PIC_DMA_BUFFER_SIZE) ? PIC_DMA_BUFFER_SIZE : total_pixels;
// 填充缓冲区
for (u32 i = 0; i < chunk_size; i++)
{
pic_dma_buffer[i * 2] = pic[k * 2];
pic_dma_buffer[i * 2 + 1] = pic[k * 2 + 1];
k++;
}
// 使用 DMA 传输数据
HAL_SPI_Transmit_DMA(&usr_lcd_spi, pic_dma_buffer, chunk_size * 2);
// 等待 DMA 传输完成
while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX);
total_pixels -= chunk_size;
}
// 传输完成,关闭片选信号
LCD_CS_Set();
}
LCD.h
#ifndef __LCD_H
#define __LCD_H
#include "main.h"
#include "bsp_spi.h"
/* Description
LTS225KP-PF09 is a 76RGBX284 dot-matrix TFT LCD module. This module is composed of a TFT LCD
Panel, driver ICs, FPC and a Backlight unit.
ST7789P3
*/
#define usr_lcd_spi hspi2
#define USE_HORIZONTAL 0
#if USE_HORIZONTAL == 0 || USE_HORIZONTAL == 1
#define LCD_W 76
#define LCD_H 284
#else
#define LCD_W 284
#define LCD_H 76
#endif
// 命令还是数据
typedef enum
{
LCD_CMD,
LCD_DATA,
} LCD_DCType;
// RESET PA 8
#define LCD_RES_Clr() GPIOA->ODR &= ~(0x01 << 8);
#define LCD_RES_Set() GPIOA->ODR |= (0x01 << 8);
// PB 14
#define LCD_DC_Clr() GPIOB->ODR &= ~(0x01 << 14);
#define LCD_DC_Set() GPIOB->ODR |= (0x01 << 14);
// PB12
#define LCD_CS_Clr() GPIOB->ODR &= ~(0x01 << 12);
#define LCD_CS_Set() GPIOB->ODR |= (0x01 << 12);
// PA 9 背光
#define LCD_BLK_Set() GPIOA->ODR &= ~(0x01 << 9);
#define LCD_BLK_Clr() GPIOA->ODR |= (0x01 << 9);
void LCD_GPIO_Init(void);
void LCD_Init(void);
void LCD_Fill(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color);
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[]);
void LCD_ShowPicture_DMA(u16 x, u16 y, u16 length, u16 width, const u8 pic[]);
#endif
参考代码
更多推荐



所有评论(0)