使用STM32 HAL庫 驅動ST7789 顯示屏
這是驅動好的效果圖,我買的是中景園電子的一塊IPS顯示屏, 它的像素密度很高,顯示非常細膩。
今天我用stm32 HAL庫來驅動它。
使用STM32CubeMX生成代碼
使用STM32CubeMX 生成功能, 其中主要設置了SPI和 驅動引腳
主要代碼所示:
//引腳設置
#define LCD_D0_SCL_Pin GPIO_PIN_5
#define LCD_D0_SCL_GPIO_Port GPIOA
#define LCD_D1_SDA_Pin GPIO_PIN_7
#define LCD_D1_SDA_GPIO_Port GPIOA
#define LCD_RES_Pin GPIO_PIN_0
#define LCD_RES_GPIO_Port GPIOB
#define LCD_DC_Pin GPIO_PIN_1
#define LCD_DC_GPIO_Port GPIOB
#define LCD_CS_Pin GPIO_PIN_10
#define LCD_CS_GPIO_Port GPIOB
/* SPI1 init function */
static void MX_SPI1_Init(void)
{
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; //主機模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; //只使能發送,兩線制,因為買到的模塊只能設置, 不能讀數據。
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; //默認時鍾位, 應當為低
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; //上升沿采集數據
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; //SPI時鍾,使用72M主頻,4分頻
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LCD_RES_Pin|LCD_DC_Pin|LCD_CS_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : LCD_RES_Pin LCD_DC_Pin LCD_CS_Pin */
GPIO_InitStruct.Pin = LCD_RES_Pin|LCD_DC_Pin|LCD_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = LCD_D0_SCL_Pin|LCD_D1_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
}
移植官方例程
中景園官方給的資料全是使用標准庫的,很無奈, 不過看了一下,改動應該非常簡單。
首先是改動驅動包里面的lcd.c
文件:
#include "lcd.h"
#include "oledfont.h"
#include "delay.h"
#include "bmp.h"
u16 BACK_COLOR; //背景色
/******************************************************************************
函數說明:LCD串行數據寫入函數
入口數據:dat 要寫入的串行數據
返回值: 無
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{
u8 i;
OLED_CS_Clr();
for(i=0;i<8;i++)
{
OLED_SCLK_Clr();
if(dat&0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat<<=1;
}
OLED_CS_Set();
}
/*把上面的函數改成下面這種, 因為中景園給的例程是使用模擬spi的時序的,刷新非常慢,
我們改成如下這種,在使用的時候要事先初始化單片機SPI模塊*/
void LCD_Writ_Bus(u8 dat)
{
u8 i;
OLED_CS_Clr();
HAL_SPI_Transmit(&hspi1, &dat, 1, 0xffff);
OLED_CS_Set();
}
再改動lcd.h
文件:
//-----------------OLED端口定義----------------
#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_5)
#define OLED_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_5)
#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_7)//DIN
#define OLED_SDIN_Set() GPIO_SetBits(GPIOA,GPIO_Pin_7)
#define OLED_RST_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_0)//RES
#define OLED_RST_Set() GPIO_SetBits(GPIOB,GPIO_Pin_0)
#define OLED_DC_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_1)//DC
#define OLED_DC_Set() GPIO_SetBits(GPIOB,GPIO_Pin_1)
#define OLED_CS_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_4)//CS
#define OLED_CS_Set() GPIO_SetBits(GPIOA,GPIO_Pin_4)
#define OLED_BLK_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_10)//BLK
#define OLED_BLK_Set() GPIO_SetBits(GPIOB,GPIO_Pin_10)
/*上面是原來例程里面的程序,我改成下面這種的, 因為已經使用了硬件SPI ,所以去掉了時鍾線與數據線的設置,
其他的仍保留,使用固件庫HAL_GPIO_WritePin() 函數來設置引腳電平*/
//-----------------OLED端口定義----------------
#define OLED_RES_Clr() HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_RESET)//RES
#define OLED_RES_Set() HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_SET)
#define OLED_DC_Clr() HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET)//DC
#define OLED_DC_Set() HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET)
#define OLED_CS_Clr() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET)///CS
#define OLED_CS_Set() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET)
// #define OLED_BLK_Clr() HAL_GPIO_WritePin(, LCD_DC_Pin, GPIO_PIN_RESET)///BLK
// #define OLED_BLK_Set() HAL_GPIO_WritePin(, LCD_DC_Pin, GPIO_PIN_SET)
接着,再把初始化函數里面的引腳初始化部分注釋掉,也把里面的延時函數更改成HAL庫的:
至此,程序移植已經可以了,在main里面執行初始化屏幕的函數就可以了。
/*=================IPS顯示屏初始化=============*/
Lcd_Init();
LCD_Clear(GREEN);
BACK_COLOR = GREEN;
如圖,成功驅動屏幕。