文章目录
- GPIO模拟SPI
- 硬件SPI外设
- DMA+硬件SPI外设
- 总结
代码工程:https://github.com/liefyuan/stm32-spi-st7789-tft.git

前言
我的屏幕的分辨率是:240*320
 驱动是:ST7789V
 线驱动方式:四线SPI(CS,DC,SDA,SCL)
 以下分别使用了三种方式来实现刷图。
头文件:
#ifndef __ST7789_DRIVER_H__
#define __ST7789_DRIVER_H__
#include "stdint.h"
#include "stm32f4xx.h"
#include "system_stm32f4xx.h"
#define ST7789_LCD_WIDTH             240
#define ST7789_LCD_HEIGHT            320
// System Function Command Table 1
#define ST7789_CMD_NOP               0x00 // No operation
#define ST7789_CMD_SWRESET           0x01 // Software reset
#define ST7789_CMD_RDDID             0x04 // Read display ID
#define ST7789_CMD_RDDST             0x09 // Read display status
#define ST7789_CMD_RDDPM             0x0a // Read display power
#define ST7789_CMD_RDDMADCTL         0x0b // Read display
#define ST7789_CMD_RDDCOLMOD         0x0c // Read display pixel
#define ST7789_CMD_RDDIM             0x0d // Read display image
#define ST7789_CMD_RDDSM             0x0e // Read display signal
#define ST7789_CMD_RDDSDR            0x0f // Read display self-diagnostic result
#define ST7789_CMD_SLPIN             0x10 // Sleep in
#define ST7789_CMD_SLPOUT            0x11 // Sleep out
#define ST7789_CMD_PTLON             0x12 // Partial mode on
#define ST7789_CMD_NORON             0x13 // Partial off (Normal)
#define ST7789_CMD_INVOFF            0x20 // Display inversion off
#define ST7789_CMD_INVON             0x21 // Display inversion on
#define ST7789_CMD_GAMSET            0x26 // Gamma set
#define ST7789_CMD_DISPOFF           0x28 // Display off
#define ST7789_CMD_DISPON            0x29 // Display on
#define ST7789_CMD_CASET             0x2a // Column address set
#define ST7789_CMD_RASET             0x2b // Row address set
#define ST7789_CMD_RAMWR             0x2c // Memory write
#define ST7789_CMD_RAMRD             0x2e // Memory read
#define ST7789_CMD_PTLAR             0x30 // Partial start/end address set
#define ST7789_CMD_VSCRDEF           0x33 // Vertical scrolling definition
#define ST7789_CMD_TEOFF             0x34 // Tearing line effect off
#define ST7789_CMD_TEON              0x35 // Tearing line effect on
#define ST7789_CMD_MADCTL            0x36 // Memory data access control
#define ST7789_CMD_VSCRSADD          0x37 // Vertical address scrolling
#define ST7789_CMD_IDMOFF            0x38 // Idle mode off
#define ST7789_CMD_IDMON             0x39 // Idle mode on
#define ST7789_CMD_COLMOD            0x3a // Interface pixel format
#define ST7789_CMD_RAMWRC            0x3c // Memory write continue
#define ST7789_CMD_RAMRDC            0x3e // Memory read continue
#define ST7789_CMD_TESCAN            0x44 // Set tear scanline
#define ST7789_CMD_RDTESCAN          0x45 // Get scanline
#define ST7789_CMD_WRDISBV           0x51 // Write display brightness
#define ST7789_CMD_RDDISBV           0x52 // Read display brightness value
#define ST7789_CMD_WRCTRLD           0x53 // Write CTRL display
#define ST7789_CMD_RDCTRLD           0x54 // Read CTRL value display
#define ST7789_CMD_WRCACE            0x55 // Write content adaptive brightness control and Color enhancemnet
#define ST7789_CMD_RDCABC            0x56 // Read content adaptive brightness control
#define ST7789_CMD_WRCABCMB          0x5e // Write CABC minimum brightness
#define ST7789_CMD_RDCABCMB          0x5f // Read CABC minimum brightness
#define ST7789_CMD_RDABCSDR          0x68 // Read Automatic Brightness Control Self-Diagnostic Result
#define ST7789_CMD_RDID1             0xda // Read ID1
#define ST7789_CMD_RDID2             0xdb // Read ID2
#define ST7789_CMD_RDID3             0xdc // Read ID3
// System Function Command Table 2
#define ST7789_CMD_RAMCTRL           0xb0 // RAM Control
#define ST7789_CMD_RGBCTRL           0xb1 // RGB Control
#define ST7789_CMD_PORCTRL           0xb2 // Porch control
#define ST7789_CMD_FRCTRL1           0xb3 // Frame Rate Control 1
#define ST7789_CMD_GCTRL             0xb7 // Gate control
#define ST7789_CMD_DGMEN             0xba // Digital Gamma Enable
#define ST7789_CMD_VCOMS             0xbb // VCOM Setting
#define ST7789_CMD_LCMCTRL           0xc0 // LCM Control
#define ST7789_CMD_IDSET             0xc1 // ID Setting
#define ST7789_CMD_VDVVRHEN          0xc2 // VDV and VRH Command enable
#define ST7789_CMD_VRHS              0xc3 // VRH Set
#define ST7789_CMD_VDVSET            0xc4 // VDV Setting
#define ST7789_CMD_VCMOFSET          0xc5 // VCOM Offset Set
#define ST7789_CMD_FRCTR2            0xc6 // FR Control 2
#define ST7789_CMD_CABCCTRL          0xc7 // CABC Control
#define ST7789_CMD_REGSEL1           0xc8 // Register value selection 1
#define ST7789_CMD_REGSEL2           0xca // Register value selection 2
#define ST7789_CMD_PWMFRSEL          0xcc // PWM Frequency Selection
#define ST7789_CMD_PWCTRL1           0xd0 // Power Control 1
#define ST7789_CMD_VAPVANEN          0xd2 // Enable VAP/VAN signal output
#define ST7789_CMD_CMD2EN            0xdf // Command 2 Enable
#define ST7789_CMD_PVGAMCTRL         0xe0 // Positive Voltage Gamma Control
#define ST7789_CMD_NVGAMCTRL         0xe1 // Negative voltage Gamma Control
#define ST7789_CMD_DGMLUTR           0xe2 // Digital Gamma Look-up Table for Red
#define ST7789_CMD_DGMLUTB           0xe3 // Digital Gamma Look-up Table for Blue
#define ST7789_CMD_GATECTRL          0xe4 // Gate control
#define ST7789_CMD_PWCTRL2           0xe8 // Power Control 2
#define ST7789_CMD_EQCTRL            0xe9 // Equalize Time Control
#define ST7789_CMD_PROMCTRL          0xec // Program Control
#define ST7789_CMD_PROMEN            0xfa // Program Mode Enable
#define ST7789_CMD_NVMSET            0xfc // NVM Setting
#define ST7789_CMD_PROMACT           0xfe // Program Action
#define ST7789_CMDLIST_END           0xff // End command (used for command list)
#define RED  	0xf800
#define GREEN	0x07e0
#define BLUE 	0x001f
#define WHITE	0xffff
#define BLACK	0x0000
#define YELLOW  0xFFE0
#define GRAY0   0xEF7D   	    //灰色0 3165 00110 001011 00101
#define GRAY1   0x8410      	//灰色1      00000 000000 00000
#define GRAY2   0x4208      	//灰色2  1111111111011111
//#define LCD_SDA        	//PB15    	// SPI 数据引脚
//#define LCD_SCL        	//PB13    	// SPI 时钟引脚
//#define LCD_CS        	//PB12    	// SPI片选引脚
//#define LCD_DC         	//PB11    	// SPI 数据/命令引脚
//#define LCD_RST           //PB10    	// 屏幕复位引脚 
//#define LCD_BLK           //PB1    	// 背光控制引脚
//液晶控制口置1操作语句宏定义
#define	LCD_SDA_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define	LCD_SCL_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_13)
#define	LCD_CS_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_12)   
#define	LCD_DC_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_11)
#define LCD_RST_SET     GPIO_SetBits(GPIOB, GPIO_Pin_10)
#define	LCD_BLK_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_1)   
//液晶控制口置0操作语句宏定义
#define	LCD_SDA_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_15)    
#define	LCD_SCL_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_13)  
#define	LCD_CS_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_12)  
#define	LCD_DC_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_11) 
#define LCD_RST_CLR     GPIO_ResetBits(GPIOB, GPIO_Pin_10)
#define	LCD_BLK_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_1)
void LCD_GPIO_Init(void);
void Lcd_Init(void);
void Lcd_Test(void);
void Lcd_Full(uint16_t color);
void Lcd_Dma_Full(uint16_t color);
#endif // __ST7789_DRIVER_H__
GPIO模拟SPI
//液晶控制口置1操作语句宏定义
#define	LCD_SDA_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define	LCD_SCL_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_13)
#define	LCD_CS_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_12)   
#define	LCD_DC_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_11)
#define LCD_RST_SET     GPIO_SetBits(GPIOB, GPIO_Pin_10)
#define	LCD_BLK_SET  	GPIO_SetBits(GPIOB, GPIO_Pin_1)   
//液晶控制口置0操作语句宏定义
#define	LCD_SDA_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_15)    
#define	LCD_SCL_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_13)  
#define	LCD_CS_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_12)  
#define	LCD_DC_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_11) 
#define LCD_RST_CLR     GPIO_ResetBits(GPIOB, GPIO_Pin_10)
#define	LCD_BLK_CLR  	GPIO_ResetBits(GPIOB, GPIO_Pin_1)
//液晶IO初始化配置
void LCD_GPIO_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_1 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//向SPI总线传输一个8位数据
void  SPI_WriteData(uint8_t Data)
{
    uint8_t i;
    for(i = 0; i < 8; i++)    // 295 ms 1 frame
    {
        if((Data&0x80) != 0)
        {
            LCD_SDA_SET;
        }
        else
            LCD_SDA_CLR;
        LCD_SCL_CLR;
        LCD_SCL_SET;
        Data <<= 1;
    }
}
//向液晶屏写一个8位指令
void Lcd_WriteIndex(uint8_t Index)
{
    //SPI 写命令时序开始
    LCD_CS_CLR;
    LCD_DC_CLR;
    SPI_WriteData(Index);
    LCD_CS_SET;
}
//向液晶屏写一个8位数据
void Lcd_WriteData(uint8_t Data)
{
    LCD_CS_CLR;
    LCD_DC_SET;
    SPI_WriteData(Data);
    LCD_CS_SET;
}
//向液晶屏写一个16位数据
void LCD_WriteData_16Bit(uint16_t Data)
{
//    LCD_CS_CLR;
//    LCD_DC_SET;
    SPI_WriteData(Data>>8); 	//写入高8位数据
    SPI_WriteData(Data); 		//写入低8位数据
//    LCD_CS_SET;
}
void Lcd_WriteReg(uint8_t Index,uint8_t Data)
{
    Lcd_WriteIndex(Index);
    Lcd_WriteData(Data);
}
void Lcd_Reset(void)
{
    LCD_RST_CLR;//RST引脚输出为低
    delay_ms(100);
    LCD_RST_SET;//RST引脚输出为高
    delay_ms(100);
}
/***********************************************************************/
void Lcd_Init(void)
{
    LCD_GPIO_Init();
    LCD_RST_CLR;
    delay_ms(1000);
    LCD_RST_SET;
    /********************************************************/
    delay_ms(1000);
    Lcd_WriteIndex(ST7789_CMD_SLPOUT); 	//Sleep Out
    delay_ms(120);
    //-----------------------ST7789V Frame rate setting-----------------//
    //************************************************
    Lcd_WriteIndex(ST7789_CMD_COLMOD);       //65k mode
    Lcd_WriteData(0x05);
    Lcd_WriteIndex(ST7789_CMD_VCMOFSET); 	//VCOM
    Lcd_WriteData(0x1A);
    Lcd_WriteIndex(ST7789_CMD_MADCTL);       // 屏幕显示方向设置
    Lcd_WriteData(0x00);
    //-------------ST7789V Frame rate setting-----------//
    Lcd_WriteIndex(ST7789_CMD_PORCTRL);		//Porch Setting
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x00);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x33);
    Lcd_WriteIndex(ST7789_CMD_GCTRL);		//Gate Control
    Lcd_WriteData(0x05);			//12.2v   -10.43v
    //--------------ST7789V Power setting---------------//
    Lcd_WriteIndex(ST7789_CMD_VCOMS);//VCOM
    Lcd_WriteData(0x3F);
    Lcd_WriteIndex(ST7789_CMD_LCMCTRL); //Power control
    Lcd_WriteData(0x2c);
    Lcd_WriteIndex(ST7789_CMD_VDVVRHEN);	//VDV and VRH Command Enable
    Lcd_WriteData(0x01);
    Lcd_WriteIndex(ST7789_CMD_VRHS);		//VRH Set
    Lcd_WriteData(0x0F);		//4.3+( vcom+vcom offset+vdv)
    Lcd_WriteIndex(ST7789_CMD_VDVSET);		//VDV Set
    Lcd_WriteData(0x20);				//0v
    Lcd_WriteIndex(ST7789_CMD_FRCTR2);		//Frame Rate Control in Normal Mode
    Lcd_WriteData(0X01);			     //111Hz
    Lcd_WriteIndex(ST7789_CMD_PWCTRL1);		//Power Control 1
    Lcd_WriteData(0xa4);
    Lcd_WriteData(0xa1);
    Lcd_WriteIndex(ST7789_CMD_PWCTRL2);		//Power Control 1
    Lcd_WriteData(0x03);
    Lcd_WriteIndex(ST7789_CMD_EQCTRL);		//Equalize time control
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    //---------------ST7789V gamma setting-------------//
    Lcd_WriteIndex(ST7789_CMD_PVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x3F);
    Lcd_WriteData(0x07);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x30);
    Lcd_WriteIndex(ST7789_CMD_NVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x03);
    Lcd_WriteData(0x24);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x3B);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x2F);
    Lcd_WriteIndex(ST7789_CMD_INVON);		//反显
    Lcd_WriteIndex(ST7789_CMD_DISPON);		//开启显示
}
/*************************************************
函数名:LCD_Set_Region
功能:设置lcd显示区域,在此区域写点数据自动换行
入口参数:xy起点和终点,Y_IncMode表示先自增y再自增x
返回值:无
*************************************************/
void Lcd_SetRegion(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
{
    Lcd_WriteIndex(0x2a);
    Lcd_WriteData(0x00);
    Lcd_WriteData(x_start);
    Lcd_WriteData(0x00);
    Lcd_WriteData(x_end);
    Lcd_WriteIndex(0x2b);
    Lcd_WriteData(0x00);
    Lcd_WriteData(y_start);
    Lcd_WriteData(y_end>>8);
    Lcd_WriteData(y_end);
    Lcd_WriteIndex(0x2c); //开始写入GRAM
}
void Lcd_Full(uint16_t color)
{
	uint16_t row,column;
	Lcd_SetRegion(0, 0, ST7789_LCD_WIDTH, ST7789_LCD_HEIGHT);
	
    LCD_CS_CLR;
    LCD_DC_SET;
	for(row = 0;row < ST7789_LCD_WIDTH; row++)             //ROW loop
	{
		for(column = 0;column < ST7789_LCD_HEIGHT; column++) //column loop
		{
			LCD_WriteData_16Bit(color); // 180ms 1 frame
		}
	}
	LCD_CS_SET;
}
硬件SPI外设
SPI_InitTypeDef  SPI_InitStructure;
void SPI2_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    //SPI2的时钟来源是APB1 42MHz
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);	//使能GPIOB、SPI2时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	//使能GPIOB、SPI2时钟
    //PB13--SCL ,PB15--SDI初始化设置,
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;//PB13,PB15复用功能输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2
    //这里只针对SPI口初始化
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI2
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为低电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第一个跳变沿(上升或下降)数据被采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;		//定义波特率预分频的值:波特率预分频值为
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
    SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
    SPI_Cmd(SPI2, ENABLE); //使能SPI外设
    SPI2_ReadWriteByte(0xff);//启动传输
}
//液晶IO初始化配置
void LCD_Hal_Spi_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC,ENABLE);
    GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_10  | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB,GPIO_Pin_14);//MISO引脚输出为高
    SPI2_Init();//初始化硬件SPI2
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI2_ReadWriteByte(uint16_t TxData)
{
//    uint8_t retry=0;
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
//        retry++;
//        if(retry>200)return 0;
    }
    SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
//    retry=0;
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
//        retry++;
//        if(retry>200)return 0;
    }
    return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
//向SPI总线传输一个8位数据
void  SPI_WriteData(uint8_t Data)
{
    SPI2_ReadWriteByte(Data);
}
//向液晶屏写一个8位指令
void Lcd_WriteIndex(uint8_t Index)
{
    //SPI 写命令时序开始
    LCD_CS_CLR;
    LCD_DC_CLR;
    SPI_WriteData(Index);
    LCD_CS_SET;
}
//向液晶屏写一个8位数据
void Lcd_WriteData(uint8_t Data)
{
    LCD_CS_CLR;
    LCD_DC_SET;
    SPI_WriteData(Data);
    LCD_CS_SET;
}
//向液晶屏写一个16位数据
void LCD_WriteData_16Bit(uint16_t Data)
{
//    LCD_CS_CLR;
//    LCD_DC_SET;
    SPI_WriteData(Data>>8); 	//写入高8位数据
    SPI_WriteData(Data); 		//写入低8位数据
//    LCD_CS_SET;
}
void Lcd_WriteReg(uint8_t Index,uint8_t Data)
{
    Lcd_WriteIndex(Index);
    Lcd_WriteData(Data);
}
void Lcd_Reset(void)
{
    LCD_RST_CLR;//RST引脚输出为低
    delay_ms(100);
    LCD_RST_SET;//RST引脚输出为高
    delay_ms(100);
}
/***********************************************************************/
void Lcd_Init(void)
{
    LCD_Hal_Spi_Init();
    Lcd_Reset();
    /********************************************************/
    delay_ms(1000);
    Lcd_WriteIndex(ST7789_CMD_SLPOUT); 	//Sleep Out
    delay_ms(120);
    //-----------------------ST7789V Frame rate setting-----------------//
    //************************************************
    Lcd_WriteIndex(ST7789_CMD_COLMOD);       //65k mode
    Lcd_WriteData(0x05);
    Lcd_WriteIndex(ST7789_CMD_VCMOFSET); 	//VCOM
    Lcd_WriteData(0x1A);
    Lcd_WriteIndex(ST7789_CMD_MADCTL);       // 屏幕显示方向设置
    Lcd_WriteData(0x00);
    //-------------ST7789V Frame rate setting-----------//
    Lcd_WriteIndex(ST7789_CMD_PORCTRL);		//Porch Setting
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x00);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x33);
    Lcd_WriteIndex(ST7789_CMD_GCTRL);		//Gate Control
    Lcd_WriteData(0x05);			//12.2v   -10.43v
    //--------------ST7789V Power setting---------------//
    Lcd_WriteIndex(ST7789_CMD_VCOMS);//VCOM
    Lcd_WriteData(0x3F);
    Lcd_WriteIndex(ST7789_CMD_LCMCTRL); //Power control
    Lcd_WriteData(0x2c);
    Lcd_WriteIndex(ST7789_CMD_VDVVRHEN);	//VDV and VRH Command Enable
    Lcd_WriteData(0x01);
    Lcd_WriteIndex(ST7789_CMD_VRHS);		//VRH Set
    Lcd_WriteData(0x0F);		//4.3+( vcom+vcom offset+vdv)
    Lcd_WriteIndex(ST7789_CMD_VDVSET);		//VDV Set
    Lcd_WriteData(0x20);				//0v
    Lcd_WriteIndex(ST7789_CMD_FRCTR2);		//Frame Rate Control in Normal Mode
    Lcd_WriteData(0X01);			     //111Hz
    Lcd_WriteIndex(ST7789_CMD_PWCTRL1);		//Power Control 1
    Lcd_WriteData(0xa4);
    Lcd_WriteData(0xa1);
    Lcd_WriteIndex(ST7789_CMD_PWCTRL2);		//Power Control 1
    Lcd_WriteData(0x03);
    Lcd_WriteIndex(ST7789_CMD_EQCTRL);		//Equalize time control
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    //---------------ST7789V gamma setting-------------//
    Lcd_WriteIndex(ST7789_CMD_PVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x3F);
    Lcd_WriteData(0x07);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x30);
    Lcd_WriteIndex(ST7789_CMD_NVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x03);
    Lcd_WriteData(0x24);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x3B);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x2F);
    Lcd_WriteIndex(ST7789_CMD_INVON);		//反显
    Lcd_WriteIndex(ST7789_CMD_DISPON);		//开启显示
}
/*************************************************
函数名:LCD_Set_Region
功能:设置lcd显示区域,在此区域写点数据自动换行
入口参数:xy起点和终点,Y_IncMode表示先自增y再自增x
返回值:无
*************************************************/
void Lcd_SetRegion(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
{
    Lcd_WriteIndex(0x2a);
    Lcd_WriteData(0x00);
    Lcd_WriteData(x_start);
    Lcd_WriteData(0x00);
    Lcd_WriteData(x_end);
    Lcd_WriteIndex(0x2b);
    Lcd_WriteData(0x00);
    Lcd_WriteData(y_start);
    Lcd_WriteData(y_end>>8);
    Lcd_WriteData(y_end);
    Lcd_WriteIndex(0x2c); //开始写入GRAM
}
void Lcd_Full(uint16_t color)
{
	uint16_t row,column;
	Lcd_SetRegion(0, 0, ST7789_LCD_WIDTH, ST7789_LCD_HEIGHT);
	
    LCD_CS_CLR;
    LCD_DC_SET;
	for(row = 0;row < ST7789_LCD_WIDTH; row++)             //ROW loop
	{
		for(column = 0;column < ST7789_LCD_HEIGHT; column++) //column loop
		{
			LCD_WriteData_16Bit(color); // 180ms 1 frame
		}
	}
	LCD_CS_SET;
}
DMA+硬件SPI外设

 我使用的是SPI2,所以对应的DMA信息如上表。
void DMA_Config(u32 TX_Buff,u32 SENDBUFF_SIZE)
{
    // 中断结构体
    NVIC_InitTypeDef NVIC_InitStructure;		
    // DMA结构体
    DMA_InitTypeDef DMA_InitStructure;  		
    /* 使能DMA时钟 */  		
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);	
    /* 复位初始化DMA数据流 */  
    DMA_DeInit(DMA1_Stream4);								
    /* 确保DMA数据流复位完成 */  
    while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);	
    /* 配置 DMA Stream */
    /* 通道0,数据流4 */	  
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    /* 外设地址 */  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;	
    /* 内存地址(要传输的变量的指针) ,DMA存储器0地址*/  	
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)TX_Buff;	
    /* 方向:存储器到外设 */			
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    /* 数据传输量 ,可设置为0, 实际发送时会重新设置*/	    
    DMA_InitStructure.DMA_BufferSize = (uint32_t)SENDBUFF_SIZE;		
    /* 外设非增量模式 */		
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    /* 存储器增量模式 */  	
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    /* 外设数据长度:16位 */	 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    /* 内存数据长度:16位 */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    /* DMA模式:正常模式 */  		
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    /* 优先级:高 */	 		
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    /* 禁用FIFO */
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        		
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;   
    /* 外设突发单次传输 */  
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;    		
    /* 存储器突发单次传输 */  
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    /* 初始化DMA Stream */		
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
    /* 开启传输完成中断  */		
    DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);
    // 中断初始化 
    /* DMA发送中断源 */  
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;	
    /* 抢断优先级 */  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    /* 响应优先级 */  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;				
    /* 使能外部中断通道 */ 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;						 
    /* 配置NVIC */		
    NVIC_Init(&NVIC_InitStructure);
}
static uint8_t sendFlg = 0;
void DMA1_Stream4_IRQHandler(void)
{
    // DMA 发送完成
    if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))	
    {
        // 清除DMA发送完成标志
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);	
        // 片选拉高,数据发送完毕	
        LCD_CS_SET;	
		sendFlg = 1;
    }
}
void DMA_Write_buf(uint32_t SizeLen)
{   
	// 关闭发送 DMA		
	DMA_Cmd(DMA1_Stream4, DISABLE);	
	// 设置发送的数据量    
	DMA_SetCurrDataCounter(DMA1_Stream4, SizeLen);
	// 清空数据
	SPI2->DR;		
	// 擦除DMA标志位	
	DMA_ClearFlag(DMA1_Stream4, DMA_IT_TCIF4);
	// 片选拉低,接收数据
	LCD_CS_CLR;
	LCD_DC_SET;
	// 开启发送 DMA
	DMA_Cmd(DMA1_Stream4, ENABLE);
	
	while(!sendFlg); 
	sendFlg = 0;
}
#define SEND_BUF_SIZE 480*20
uint16_t SendBuff[SEND_BUF_SIZE];	//发送数据缓冲区
// 单颜色填满屏幕
void Lcd_Dma_Full(uint16_t color)
{
    int i = 0;
    for(i = 0 ; i < SEND_BUF_SIZE; i++)
    {
        SendBuff[i] = color; // 缓存区不够,分段来凑
    }
	for(i = 0; i < 16; i++)
	{
		SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE); // 60ms 1 frame
		DMA_Write_buf(SEND_BUF_SIZE);
	}
}
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init(168);      //初始化延时函数
    uart_init(115200);		//初始化串口波特率为115200
    LED_Init();					  //初始化LED
	
	Lcd_Init();
	
	Lcd_Full(RED);
	delay_ms(1000);
	uint16_t num = 0;
	
    while(1)
    {
	#if 1
		//num+=1;
		Lcd_Dma_Full(num++);
//		LED_ON;
		//delay_ms(10);
//		
//		Lcd_Dma_Full(WHITE);
//		LED_OFF;
		delay_ms(50);
//		
//		Lcd_Dma_Full(BLUE);
//		LED_ON;
		delay_ms(50);
//		
//		Lcd_Dma_Full(WHITE);
//		LED_OFF;
	#else
		Lcd_Full(GREEN);
		LED_ON;
//		delay_ms(50);
		
		Lcd_Full(WHITE);
		LED_OFF;
//		delay_ms(50);
		
		Lcd_Full(BLUE);
		LED_ON;
//		delay_ms(50);
		
		Lcd_Full(WHITE);
		LED_OFF;		
	#endif
//		delay_ms(50);
//		printf("Test \r\n");;
    }
}
总结
分辨率:240*320
 颜色:RGB565
| 方式 | 一帧耗时 | 帧率 | 
|---|---|---|
| GPIO模拟SPI | 220ms | 4.5 fps | 
| 硬件SPI | 188ms | 5.3 fps | 
| DMA+硬件SPI | 60ms | 16.6 fps | 








![[java安全]类加载器CommonsCollections3](https://img-blog.csdnimg.cn/img_convert/31c90ac0e2626e272f8982cadbccf139.png)










