【STM32】SPI屏幕刷图总结:GPIO模拟,硬件SPI,DMA+硬件SPI

news2024/10/5 14:43:45

文章目录

  • 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模拟SPI220ms4.5 fps
硬件SPI188ms5.3 fps
DMA+硬件SPI60ms16.6 fps

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&am…

PageObject+Python+Appium

目录 前言&#xff1a; 简介 功能 常用目录 配置 实例 - 第一次启动 app 实例 - 登录 代码入口实例 结果展示 前言&#xff1a; Page Object模式是一种常用的设计模式&#xff0c;用于组织和管理自动化测试脚本中的页面对象。它将页面的元素和操作封装在一个独立的类…

数据质量相关问题系列

数据质量问题是什么&#xff1f; 数据质量&#xff0c;是指在业务环境下&#xff0c;数据符合数据消费者的使用目的&#xff0c;能满足业务场景具体需求的程度。而数据质量问题是指数据集中存在无法容忍的缺陷&#xff0c;从而降低该数据的可靠性和可信度。简单理解就是数据很脏…

【JAVA】云HIS系统功能菜单知识(一)

一、云HIS特色 云HIS滚动消息栏&#xff1a;质控消息、住院时长、药库结转、患者入院、医嘱停止、新开医嘱、门诊用药不良、出院审核、药品调拨、排班提醒、药品库存、药品过期、药品临期等帮助医生、护士和相关管理人员实时接收院内消息并作出处理。 二、云HIS功能菜单 【预约…

【MySQL】MySQL事务保姆级教程(适合MySQL初学者学习)

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;重…

桥接模式——连接抽象维度和实现维度

桥接模式 bridge pattern 一 定义 桥接模式&#xff0c;是将抽象部分与它的具体实现部分分离&#xff0c;使它们都可以独立地变化。它是将两个不同的维度建立联系。这两个维度通常是指&#xff1a;抽象维度和实现维度。 使用场景 在抽象和具体实现之间需要增加更多的灵活性…

找不到dll的问题解决,loadlibrary 126错误

症状&#xff1a;loadlibrary时&#xff0c;getlasterror返回126&#xff0c;表示是找不到模块错误。来到目录下看到依赖所需的dll均存在 解决办法&#xff1a; 1.下载ProcmonProcmom-监视进程所有的动作资源-CSDN文库https://download.csdn.net/download/gergul/880597622.运…

RocketMQ第四节(部署模式、监控面板等)

1&#xff1a;mq的部署模式 部署方式 | RocketMQ 参考官网。 单机模式&#xff1a;抗风险能力差&#xff0c;单机挂机没服务&#xff0c;单机硬盘损坏&#xff0c;丢失数据 多机&#xff08;多master没有Slave副本&#xff09;: 多个master采用RAID10磁盘&#xff0c;不会丢…

[java安全]类加载器CommonsCollections3

文章目录 【java安全】类加载器&CommonsCollections3前言java类加载器URLClassLoader利用ClassLoader#defineClass()直接加载字节码 使用TemplatesImpl加载字节码TemplatesImpl中字节码实现AbstractTranslet类 构造未完成POCTrAXFilter类调用newTransformer()InstantiateTr…

【AI绘画Stable Diffusion】高清图像放大+面部修复+一键抠图,谈谈你可能不知道的优化技巧!

一提起后期处理&#xff0c;我猜你可能立马想到的就是图像放大。 今天&#xff0c;我要向你展示的后期处理手法&#xff0c;以及优化技巧。 图片放大算法 如果你常用的是秋叶大佬的整合包&#xff0c;那么你对"R-ESRGAN 4x"和"R-ESRGAN 4x Anime6B"应该…

FPGA单端口RAM——IP核

文章目录 前言一、RAM简介1、随机存储器IP核分类1、RAM IP核2、ROM IP核 2、RAM IP核 二、IP核配置步骤三、源码1、ram_rw驱动文件2、ip_1port_ram顶层文件3、仿真文件4、仿真波形 四、SignalTap II在线调试五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.1 2、vsco…

Leetcode-每日一题【1019.链表中的下一个更大结点】

题目 给定一个长度为 n 的链表 head 对于列表中的每个节点&#xff0c;查找下一个 更大节点 的值。也就是说&#xff0c;对于每个节点&#xff0c;找到它旁边的第一个节点的值&#xff0c;这个节点的值 严格大于 它的值。 返回一个整数数组 answer &#xff0c;其中 answer[…

Servlet的监听器

Servlet常用的监听器 ServletContextAttributeListener 用来感知ServlerContext对象属性变化&#xff0c;比如添加或删除属性变化 ServletContextListener 用来感知ServlerContext对象的创建和销毁的 ServletRequestListener 可以用来监听感知ServletRequest对象的创建和销毁的…

大语言模型(LLM)评估综述

论文地址&#xff1a;https://arxiv.org/abs/2307.03109 Github地址&#xff1a;https://github.com/MLGroupJLU/LLM-eval-survey 一 、背景 随着ChatGPT和GPT-4的推出&#xff0c;大型语言模型&#xff08;LLM&#xff09;在学术界和工业界的热度日益升高&#xff0c;这主要…

优雅的设计测试用例

⭐️前言⭐️ 入职以后接触到了公司的具体业务&#xff0c;提升了设计测试用例的能力&#xff0c;于是沉淀出这篇文档与大家分享。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&…

Acwing.905 区间选点(贪心)

题目 给定N个闭区间[a,bi]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数N&#xff0c;表示区间数。 接下来N行&#xff0c;每行包含两个整数…

Linux内核《CPU负载计算》

目录 前言一、什么是CPU负载&#xff1f;二、如何计算CPU负载三、计算CPU负载的一个脚本四、top命令详解 前言 在实际的产品开发中&#xff0c;我们往往需要关注CPU的负载&#xff0c;确保程序可以长久稳定的运行&#xff0c;并且能够重复发挥SOC的性能。Linux中提供了一些命令…

ArrayList和LinkedList

ArrayList的注意事项 1、在ArrayList中可以放任意元素&#xff0c;包括空值&#xff0c;任何元素&#xff0c;且可重复添加。 2、ArrayList底层是由数组来实现数据存储的 3、ArrayList基本等同于Vector&#xff0c;除了ArrayList是线程不安全(执行效率高),看源码 在多线程的…

【Linux系列P7】进度条小程序的深度解剖(细节满满)

​​​​​ ​ 前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过Linux的老铁&#xff0c;主要内容含 欢迎订阅 YY滴Linux专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 订阅专栏阅读&am…

SpringBoot项目中MVC使用--【SB系列之010】

SpringBoot系列文章目录 SpringBoot 的项目编译即报错处理–SB系列之001 —第一部的其它章节可以通过001链接 SpringBoot项目中WEB页面放哪里–【SB系列之008】 SpringBoot项目中WEB与Controller的联系–【SB系列之009】 ———————————————— 文章目录 SpringBoo…