03 SPI驱动TFT液晶屏
前言
上文已经实现MCU的IO口、定时器、外部中断等操作,在此基础上我们来实现TFT液晶屏的驱动,用于后边测试的状态张氏。
目标
软硬件驱动TFT液晶屏,实现页面展示。
实现
本次使用的液晶屏是1.54吋,IPS高清显示,分辨率240*240,驱动芯片为ST7789,支持MCU和SPI两种通信方式,本次通过SPI方式驱动液晶屏,相对来说分辨率不低,所以通过软硬件两种方式可以轻松看出来比较明显的区别,液晶屏SPI通信时只能作为从机接收数据,所以只用到了MOSI和SCK,CS和RS通过软件控制,复位和背光控制通过软件控制。
相应宏定义
#define MOSI_OUT0 gpio_bits_reset(GPIOB,GPIO_PINS_15)
#define MOSI_OUT1 gpio_bits_set(GPIOB,GPIO_PINS_15)
#define CLK_OUT0 gpio_bits_reset(GPIOB,GPIO_PINS_13)
#define CLK_OUT1 gpio_bits_set(GPIOB,GPIO_PINS_13)
#define CS_OUT0 gpio_bits_reset(GPIOA,GPIO_PINS_4)
#define CS_OUT1 gpio_bits_set(GPIOA,GPIO_PINS_4)
#define TFT_RS_reset gpio_bits_reset(GPIOA,GPIO_PINS_5)
#define TFT_RS_set gpio_bits_set(GPIOA,GPIO_PINS_5)
#define TFT_RESET_reset gpio_bits_reset(GPIOA,GPIO_PINS_3)
#define TFT_RESET_set gpio_bits_set(GPIOA,GPIO_PINS_3)
#define TFT_BL_SET gpio_bits_set(GPIOA,GPIO_PINS_2)
#define TFT_BL_RESET gpio_bits_reset(GPIOA,GPIO_PINS_2)
软件模拟SPI控制:
void SPI_IOInit(void)
{
gpio_init_type gpio_init_struct;
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_13|GPIO_PINS_15;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_pins = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_3;
gpio_init(GPIOA, &gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
gpio_init_struct.gpio_pins = GPIO_PINS_2;
gpio_init(GPIOA, &gpio_init_struct);
CLK_OUT0;
MOSI_OUT0;
CS_OUT0;
TFT_RS_reset;
TFT_RESET_reset;
TFT_BL_RESET;
}
void SPI_Send_Data(uint8_t Data)
{
CS_OUT0; //选中该从机
delay_us(2);
uint8_t i;
for (i = 0;i < 8;i++)
{
if ((Data << i) & 0x80)
{
MOSI_OUT1;
CLK_OUT0;//rising edge
CLK_OUT1;
}
else
{
MOSI_OUT0;
CLK_OUT0;//rising edge
CLK_OUT1;
}
}
CS_OUT1;
}
硬件SPI控制:
void SPI_IOInit(void)
{
gpio_init_type gpio_initstructure;
spi_init_type spi_init_struct;
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* software cs, pa4 as a general io to control flash cs */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_3;
gpio_init(GPIOA, &gpio_initstructure);
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pull = GPIO_PULL_DOWN;
gpio_initstructure.gpio_pins = GPIO_PINS_2;
gpio_init(GPIOA, &gpio_initstructure);
CS_OUT0;
TFT_RS_reset;
TFT_RESET_reset;
TFT_BL_RESET;
/* sck */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_13;
gpio_init(GPIOB, &gpio_initstructure);
/* mosi */
gpio_initstructure.gpio_pull = GPIO_PULL_DOWN;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_15;
gpio_init(GPIOB, &gpio_initstructure);
crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
spi_default_para_init(&spi_init_struct);
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8;
spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
spi_init(SPI2, &spi_init_struct);
spi_enable(SPI2, TRUE);
}
void SPI_Send_Data(uint8_t Data)
{
CS_OUT0; //选中该从机
delay_us(1);
spi_i2s_data_transmit(SPI2, Data);
while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
delay_us(1);
CS_OUT1;
}
在软件模拟驱动成功后切换到硬件SPI时出现了一个小插曲,居然驱动失败了,通过不断的修改测试发现出现在了CS_OUT1;这个操作,可能上升太快导致异常,在之前加了一个delay_us(1);后驱动正常。
直接使用#if + #elif + #endif进行选择性代码编写,方便切换。
具体的tft的驱动代码可以结合实际使用的屏进行设计,这块一般都是使用的厂家提供的驱动代码。
驱动成功:
只看到背光亮了,没见有显示,是不是上传图片有误?