【GD32】06 - SPI (含ST7735S TFT-LCD屏幕驱动)

这篇文章我们看看GD32中如何实现SPI,软件SPI的话可以参考我之前的文章,把对应操作GPIO口的代码从STM32改成GD32就可以使用了。

【快速上手STM32】SPI通信协议&&1.8寸TFT-LCD(ST7735S)_tftlcdst7735和stm32-CSDN博客文章浏览阅读3.7k次,点赞46次,收藏60次。SPI,英文全称Serial Peripheral Interface,即串行外围设备接口,是一种高速、全双工、同步的串行通信总线。我们之前说过I2C,那么我们就拿I2C和SPI做个对比。SPI和I2C对比,优势在于SPI的传输速率比I2C快得多,劣势在于SPI需要用的通信线比较多。_tftlcdst7735和stm32https://blog.csdn.net/m0_63235356/article/details/136977377?spm=1001.2014.3001.5501这边就来看看硬件SPI如何使用。

和之前不一样,我这篇文章使用的GD32是GD32F407VET6,其实大体上没差别,因为我们使用的是固件库。要注意的就是两种型号的单片机的引脚SPI资源不一样,不同的SPI对应的引脚是不一样的,这个要查手册去对应上,不过相同的SPI资源好像引脚是一样的,比如说GD32E230的SPI0和GD32F407的引脚是一样的。那么我们接下来就使用SPI0来做示范,这样不管是哪个型号的板子都可以兼容。

 

流程上都是先配置好GPIO为复用模式,接着是初始化SPI,然后就直接可以用了,GD32的硬件SPI还是非常方便的。

第一步先配置时钟。

要配置的有硬件SPI0,以及对应的引脚所在的GPIO端口,因为SPI0对应的引脚都在GPIOA,因此我们只需要使能GPIOA的时钟,如果是其他的SPI资源的话可能就要使能多个端口了。

rcu_periph_clock_enable(RCU_GPIOA);    // 使能GPIOA
rcu_periph_clock_enable(RCU_SPI0);     // 使能SPI0

接下来我们要开启引脚复用,SPI一共是四个引脚,MISO,MOSI,SS,SCK,其中SS一般来说我们不让他硬件控制,通常我们会另外软件控制,因为硬件SPI的SS是固定死的,这样可能会和我们其他要用的引脚冲突,而且使用硬件SPI就是为了速度更快,而SS软件另外控制并不会影响多少速度,因此我们就算使用硬件SPI,也会让SS引脚使用软件控制。

所以开启引脚复用只需要开启另外三个即可。

#define Z_SPI_PORT  GPIOA
#define Z_SPI_SS    GPIO_PIN_4
#define Z_SPI_SCK   GPIO_PIN_5
#define Z_SPI_MISO  GPIO_PIN_6
#define Z_SPI_MOSI  GPIO_PIN_7

上面是宏定义,但是其实好像没什么必要,因为硬件SPI的引脚是固定死的,留着宏定义是因为代码是之前软件SPI的代码,懒得改了就留下来了。大家看下面示例代码的时候看见“Z_”开头的知道是SPI引脚的宏定义就可以了。 

    //开启引脚复用
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_SCK);
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_MISO);
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_MOSI);

接下来就是配置GPIO口的模式了。

SS引脚我们不用硬件SPI的,我们单独控制,直接配置为输出模式即可,因为默认我们不选中,所以加个上拉电阻。

其他三个引脚我们选择复用模式(GPIO_MODE_AF),因为是交给硬件SPI了,所以我们不加电阻。

    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, Z_SPI_SS);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_SCK);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_MISO);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_MOSI);

接下来就是配置输出模式了。

都配置为输出模式即可,速度选择50MHz就够用了,一般用于通信的引脚的输出频率为两倍传输速率就可以了。

    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_SS);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_SCK);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_MISO);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_MOSI);

配置完引脚,接下来就可以配置SPI了。

这是从GD32F407固件库手册里截取的,如果是GD32E230的话SPI就只有0和1,没有2345了,其他是一样的。

device_mode :一般我们就选择主机模式SPI_MASTER

trans_mode : 选择全双工模式SPI_TRANSMODE_FULLDUPLEX,说实话,除了仅接受之外的其他两个选项没看懂。

frame_size : 数据帧格式我们都是选择8bit的SPI_FRAMESIZE_8BIT,如果要发送16bit的时候发送两次8bit就行了。

nss : 前面说了,我们SS就软件控制就行了SPI_NSS_SOFT,因此这边选择软件控制。

endian : 大端小端就是高位在前在后的区别,我们SPI基本上都是高位在前,因此选择大端模式SPI_ENDIAN_MSB

spi_init_struct.clock_polarity_phase : 相位和极性配置,说通俗一点就是选择SPI的模式。

一般来说有四种模式。

时序图可以参考下面的。

不懂要通信的模块支持哪种模式的话就默认选模式0就行SPI_CK_PL_LOW_PH_1EDGE,一般来说模式0是都支持的,实在不行就四种模式都试一遍(但是得保证其他环节不出错)。

prescale : 这是预分频器,这就要看看SPI的速率以及时钟频率了。

我们先来看看SPI的时钟频率。

SPI0挂载在APB2上,频率是84MHz。那么我们分频可以分个8,也就是差不多10MHz的速率。

因为我问的科大讯飞的大模型,它说ST7735S支持的速率是12MHz,当然了,仅供参考。因为我2分频之后也是可以正常使用ST7735S的。

综上,我们安装下面这样配置就可以了。

    spi_parameter_struct spi_init_struct;
    spi_init_struct.trans_mode        		= SPI_TRANSMODE_FULLDUPLEX;  // 传输模式全双工
    spi_init_struct.device_mode       		= SPI_MASTER;                // 配置为主机
    spi_init_struct.frame_size         		= SPI_FRAMESIZE_8BIT;        // 8位数据
    spi_init_struct.clock_polarity_phase 	= SPI_CK_PL_LOW_PH_1EDGE;    // 模式0  
    spi_init_struct.nss               		= SPI_NSS_SOFT;              // 软件cs
    spi_init_struct.prescale           		= SPI_PSC_8;                 // 8分频
    spi_init_struct.endian            		= SPI_ENDIAN_MSB;            // 高位在前

    spi_init(SPI0, &spi_init_struct);

接下来就是使能。

spi_enable(SPI0);

配置完上面之后我们就可以直接发送数据了。

因为我们之前配置的是8bit,因此第二个参数传入8位的数据就可以了,这边形参类型是16bit是为了兼容两种传输格式。

spi_i2s_data_transmit(SPI0, data);

然后我们注意到了函数的名称是SPI_i2s开头的,因此i2s发送数据的函数也是用的这个。

接收数据的话我们用另外一个函数。

在发送和接收之前,我们需要检查缓冲区是否满足要求——发送的时候缓冲区是否为空,接收的时候缓冲区是否有数据。

常用的标志我用红框框出来了,完整的标志可以到固件库手册里查看。

因此我们发送一次数据可以封装起来。也就是在发送数据之前先检测发送缓冲区为空,在接收之前检测接收缓冲区非空。而且SPI它通信是类似于交换的,所以我们发送和接收放在一起。

uint8_t Z_SPI_SwapByte(uint8_t data){
    //等待发送缓冲区为空
    while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE)); 
    spi_i2s_data_transmit(SPI0, data);
    //等待接收缓冲区不空
    while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));
    return spi_i2s_data_receive(SPI0);
}

有了上面这些函数,我们就可以使用硬件SPI了,完整的配置代码可以参考下面。

#define Z_SPI_PORT  GPIOA
#define Z_SPI_SS    GPIO_PIN_4
#define Z_SPI_SCK   GPIO_PIN_5
#define Z_SPI_MISO  GPIO_PIN_6
#define Z_SPI_MOSI  GPIO_PIN_7

void Z_SPI_SetSS(uint8_t val){        //封装一下选中SS
    gpio_bit_write(Z_SPI_PORT, Z_SPI_SS,val);
}

void Z_SPI_Init(void){
    rcu_periph_clock_enable(RCU_GPIOA);    // 使能GPIOA外设时钟
    rcu_periph_clock_enable(RCU_SPI0);     // 使能SPI0外设时钟
    
    //配置引脚复用
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_SCK);
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_MISO);
    gpio_af_set(Z_SPI_PORT, GPIO_AF_5, Z_SPI_MOSI);
    //配置引脚模式
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, Z_SPI_SS);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_SCK);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_MISO);
    gpio_mode_set(Z_SPI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, Z_SPI_MOSI);
    //配置输出模式
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_SS);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_SCK);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_MISO);
    gpio_output_options_set(Z_SPI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Z_SPI_MOSI);
   
    Z_SPI_SetSS(1);        //默认不选中
    
    spi_parameter_struct spi_init_struct;
    spi_init_struct.trans_mode        		= SPI_TRANSMODE_FULLDUPLEX;  // 传输模式全双工
    spi_init_struct.device_mode       		= SPI_MASTER;                // 配置为主机
    spi_init_struct.frame_size         		= SPI_FRAMESIZE_8BIT;        // 8位数据
    spi_init_struct.clock_polarity_phase 	= SPI_CK_PL_LOW_PH_1EDGE;    // SPI模式0  
    spi_init_struct.nss               		= SPI_NSS_SOFT;              // 软件SS
    spi_init_struct.prescale           		= SPI_PSC_8;                 // 8分频
    spi_init_struct.endian            		= SPI_ENDIAN_MSB;            // 高位在前
 
    spi_init(SPI0, &spi_init_struct);
    
    //使能SPI
    spi_enable(SPI0);
    
}

uint8_t Z_SPI_SwapByte(uint8_t data){
    //等待发送缓冲区为空
    while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE)); 
    spi_i2s_data_transmit(SPI0, data);
    //等待接收缓冲区非空
    while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));
    return spi_i2s_data_receive(SPI0);
}

有了SPI,我们就可以直接封装ST7735S的驱动了,具体ST7735S的指令什么的我就不在这边啰嗦了,之前的文章有小小地介绍一下,文章链接在本文的开头。下面就直接把驱动代码贴出来了(需要包含上面的示例代码)。

/*
ST7725S驱动代码
*/
#define Z_ST7735S_RST_GPIO  GPIO_PIN_0
#define Z_ST7735S_DC_GPIO   GPIO_PIN_1
#define Z_ST7735S_PORT      GPIOA
#define Z_ST7735S_WIDTH     128
#define Z_ST7735S_HIGH      160


void Z_ST7735S_SetRST(uint8_t val){
    gpio_bit_write(Z_ST7735S_PORT,Z_ST7735S_RST_GPIO,val);
}

void Z_ST7735S_SetDC(uint8_t val){
    gpio_bit_write(Z_ST7735S_PORT,Z_ST7735S_DC_GPIO,val);
}

//发送指令,需要把DC拉低
void Z_ST7735S_SendCommand(uint8_t command){
    Z_SPI_SetSS(0);
    Z_ST7735S_SetDC(0);
    Z_SPI_SwapByte(command);
    Z_SPI_SetSS(1);
}

//发送数据,需要把DC拉高
void Z_ST7735S_SendData(uint8_t data){
    Z_SPI_SetSS(0);
    Z_ST7735S_SetDC(1);
    Z_SPI_SwapByte(data);
    Z_SPI_SetSS(1);
}

//发送16位的数据
void Z_ST7735S_Send16bitsRGB(uint16_t rgb)
{
    Z_ST7735S_SendData(rgb >> 8);
    Z_ST7735S_SendData(rgb);
}

//初始化ST7735S,其中一段初始化序列厂家会提供
void Z_ST7735S_Init(void){
    Z_SPI_Init();
    
    // 除了上面SPI初始化的GPIO口,还需要额外初始化RST和DC
    if(Z_ST7735S_PORT==GPIOA)  rcu_periph_clock_enable(RCU_GPIOA);
    else if(Z_ST7735S_PORT==GPIOB) rcu_periph_clock_enable(RCU_GPIOB);
    else if(Z_ST7735S_PORT==GPIOC) rcu_periph_clock_enable(RCU_GPIOC);
    
    gpio_mode_set(Z_ST7735S_PORT,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,Z_ST7735S_RST_GPIO);
    gpio_output_options_set(Z_ST7735S_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,Z_ST7735S_RST_GPIO);
    
    gpio_mode_set(Z_ST7735S_PORT,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,Z_ST7735S_DC_GPIO);
    gpio_output_options_set(Z_ST7735S_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,Z_ST7735S_DC_GPIO);
    
    Z_ST7735S_SetRST(0);
    delay_ms(1);
    Z_ST7735S_SetRST(1);
    delay_ms(120);
    
    
    // 厂家提供的固定的初始化代码
    Z_ST7735S_SendCommand(0x11); // Sleep out
    delay_ms(120);               // Delay 120ms
    //------------------------------------ST7735S Frame Rate-----------------------------------------//
    Z_ST7735S_SendCommand(0xB1);
    Z_ST7735S_SendData(0x05);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendCommand(0xB2);
    Z_ST7735S_SendData(0x05);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendCommand(0xB3);
    Z_ST7735S_SendData(0x05);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendData(0x05);
    Z_ST7735S_SendData(0x3C);
    Z_ST7735S_SendData(0x3C);
    //------------------------------------End ST7735S Frame Rate---------------------------------//
    Z_ST7735S_SendCommand(0xB4); // Dot inversion
    Z_ST7735S_SendData(0x03);
    //------------------------------------ST7735S Power Sequence---------------------------------//
    Z_ST7735S_SendCommand(0xC0);
    Z_ST7735S_SendData(0x28);
    Z_ST7735S_SendData(0x08);
    Z_ST7735S_SendData(0x04);
    Z_ST7735S_SendCommand(0xC1);
    Z_ST7735S_SendData(0XC0);
    Z_ST7735S_SendCommand(0xC2);
    Z_ST7735S_SendData(0x0D);
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendCommand(0xC3);
    Z_ST7735S_SendData(0x8D);
    Z_ST7735S_SendData(0x2A);
    Z_ST7735S_SendCommand(0xC4);
    Z_ST7735S_SendData(0x8D);
    Z_ST7735S_SendData(0xEE);
    //---------------------------------End ST7735S Power Sequence-------------------------------------//
    Z_ST7735S_SendCommand(0xC5); // VCOM
    Z_ST7735S_SendData(0x1A);
    Z_ST7735S_SendCommand(0x36); // MX, MY, RGB mode
    Z_ST7735S_SendData(0xC0);
    //------------------------------------ST7735S Gamma Sequence---------------------------------//
    Z_ST7735S_SendCommand(0xE0);
    Z_ST7735S_SendData(0x04);
    Z_ST7735S_SendData(0x22);
    Z_ST7735S_SendData(0x07);
    Z_ST7735S_SendData(0x0A);
    Z_ST7735S_SendData(0x2E);
    Z_ST7735S_SendData(0x30);
    Z_ST7735S_SendData(0x25);
    Z_ST7735S_SendData(0x2A);
    Z_ST7735S_SendData(0x28);
    Z_ST7735S_SendData(0x26);
    Z_ST7735S_SendData(0x2E);
    Z_ST7735S_SendData(0x3A);
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(0x01);
    Z_ST7735S_SendData(0x03);
    Z_ST7735S_SendData(0x13);
    Z_ST7735S_SendCommand(0xE1);
    Z_ST7735S_SendData(0x04);
    Z_ST7735S_SendData(0x16);
    Z_ST7735S_SendData(0x06);
    Z_ST7735S_SendData(0x0D);
    Z_ST7735S_SendData(0x2D);
    Z_ST7735S_SendData(0x26);
    Z_ST7735S_SendData(0x23);
    Z_ST7735S_SendData(0x27);
    Z_ST7735S_SendData(0x27);
    Z_ST7735S_SendData(0x25);
    Z_ST7735S_SendData(0x2D);
    Z_ST7735S_SendData(0x3B);
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(0x01);
    Z_ST7735S_SendData(0x04);
    Z_ST7735S_SendData(0x13);
    //------------------------------------End ST7735S Gamma Sequence-----------------------------//
    Z_ST7735S_SendCommand(0x3A); // 65k mode
    Z_ST7735S_SendData(0x05);
    Z_ST7735S_SendCommand(0x29); // Display on
}

// 指定范围
void Z_ST7735S_SpecifyScope(uint8_t xs, uint8_t xe, uint8_t ys, uint8_t ye)
{
    Z_ST7735S_SendCommand(0x2A); // 指定列范围
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(xs);
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(xe);

    Z_ST7735S_SendCommand(0x2B); // 指定行范围
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(ys);
    Z_ST7735S_SendData(0x00);
    Z_ST7735S_SendData(ye);

    Z_ST7735S_SendCommand(0x2C); // 开始内存写入
}

//将整个屏幕都填充上相同的颜色
void Z_ST7735S_RefreshAll(uint16_t rgb)
{
    Z_ST7735S_SpecifyScope(0, Z_ST7735S_WIDTH, 0, Z_ST7735S_HIGH);
    for (uint16_t j = 0; j < Z_ST7735S_HIGH; ++j)
    {
        for (uint16_t i = 0; i < Z_ST7735S_WIDTH; ++i)
        {
            Z_ST7735S_Send16bitsRGB(rgb);
        }
    }
}

//将指定区域的屏幕填充上相同的颜色
void Z_ST7735S_RefreshArea(uint8_t start_x,uint8_t end_x,uint8_t start_y,uint8_t end_y,uint16_t rgb){
    if(start_x>Z_ST7735S_WIDTH||start_y>Z_ST7735S_HIGH||end_x>Z_ST7735S_WIDTH||end_y>Z_ST7735S_HIGH)    return ;
    Z_ST7735S_SpecifyScope(start_x,end_x,start_y,end_y);
    for (uint16_t j = start_y; j <= end_y; ++j){
        for (uint16_t i = start_x; i <= end_x; ++i){
            Z_ST7735S_Send16bitsRGB(rgb);
        }
    }
}

//将指定区域填充上颜色数组(可以不同)
void Z_ST7735S_DrawArea(uint8_t start_x,uint8_t end_x,uint8_t start_y,uint8_t end_y,uint16_t* rgb){
    if(start_x>Z_ST7735S_WIDTH||start_y>Z_ST7735S_HIGH||end_x>Z_ST7735S_WIDTH||end_y>Z_ST7735S_HIGH)    return ;
    Z_ST7735S_SpecifyScope(start_x,end_x,start_y,end_y);
    for (uint16_t j = start_y; j <= end_y; ++j){
        for (uint16_t i = start_x; i <= end_x; ++i){
            Z_ST7735S_Send16bitsRGB(*rgb);
            rgb++;
        }
    }
}


//const unsigned char number[10][10] = {
//    {0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}, /*"0",0*/
//    {0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, /*"1",1*/
//    {0x00, 0x00, 0x3C, 0x42, 0x02, 0x0C, 0x10, 0x20, 0x7E, 0x00}, /*"2",2*/
//    {0x00, 0x00, 0x3C, 0x46, 0x04, 0x0C, 0x02, 0x42, 0x3C, 0x00}, /*"3",3*/
//    {0x00, 0x00, 0x0C, 0x14, 0x24, 0x44, 0x7C, 0x04, 0x0C, 0x00}, /*"4",4*/
//    {0x00, 0x00, 0x3E, 0x40, 0x58, 0x66, 0x02, 0x42, 0x3C, 0x00}, /*"5",5*/
//    {0x00, 0x00, 0x3C, 0x40, 0x58, 0x66, 0x42, 0x42, 0x3C, 0x00}, /*"6",6*/
//    {0x00, 0x00, 0x7E, 0x44, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00}, /*"7",7*/
//    {0x00, 0x00, 0x3C, 0x42, 0x62, 0x3C, 0x42, 0x42, 0x3C, 0x00}, /*"8",8*/
//    {0x00, 0x00, 0x3C, 0x42, 0x42, 0x66, 0x1A, 0x04, 0x78, 0x00}, /*"9",9*/
//};

//void Z_ST7735S_ShowChar(uint8_t x, uint8_t y, uint8_t ch, uint16_t rgb)
//{
//    if (ch >= 10)
//        return;
//    Z_ST7735S_SpecifyScope(x, x + 7, y, y + 9);
//    for (uint8_t i = 0; i < 10; ++i)
//    {
//        uint8_t temp = number[ch][i];
//        for (uint8_t j = 0; j < 8; ++j)
//        {
//            if ((temp & 0x80) != 0)
//                Z_ST7735S_Send16bitsRGB(rgb);
//            else
//                Z_ST7735S_Send16bitsRGB(0x0000);
//            temp <<= 1;
//        }
//    }
//}

接下来小小演示一下。

#include "board.h"
#include "Z_TFT.h"

int main(void){
    
    board_init();
    Z_ST7735S_Init();
    
    while (1){
        for(uint16_t i=0;i<0xFFFF;i+=50){
            Z_ST7735S_RefreshAll(i);
            delay_ms(20);
        }
    }
}

board.h是立创开发板提供的模板,board_init里面是进行一些初始化。

然后我把上面ST7735S的驱动代码封装成Z_TFT.h了,这个代码就是每隔20ms刷新一次屏幕,就是看看能不能正常驱动屏幕的。

可以看的出来是可以正常驱动的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker部署skywalking

skywalking版本下载 1&#xff1a;拉取skywalking的oap镜像(可以选择自己的版本&#xff0c;最好与ui&#xff0c;agent版本一致) docker pull apache/skywalking-oap-server:9.5.02&#xff1a;启动oap docker run -d -p 11800:11800 -p 12800:12800 --name sw_oap apache/…

HCIE数通,为啥是网工的“黄金标准”?

作为网络工程师&#xff0c;你不可能没听说过HCIE&#xff0c;也不可能没听过数通&#xff0c;也可能曾经考虑过要不要挑战这个认证。 HCIE数通为何被誉为网工的黄金标准&#xff1f;聊聊 01 什么是HCIE数通&#xff1f; HCIE数通认证是华为技术有限公司推出的一项高级别认证…

深度学习-05-反向传播理论知识

深度学习-05-反向传播理论知识 本文是《深度学习入门2-自製框架》 的学习笔记&#xff0c;记录自己学习心得&#xff0c;以及对重点知识的理解。如果内容对你有帮助&#xff0c;请支持正版&#xff0c;去购买正版书籍&#xff0c;支持正版书籍不仅是尊重作者的辛勤劳动&#xf…

使用 IPSET 添加 CDN 节点 IP(IPv4/IPv6)到防火墙白名单

明月的服务器一直使用的是 iptables,随着近几年 IPv6 的普及&#xff0c;明月切身体会到还是 IPSET 最方便了&#xff0c;无论你是 IPv4 还是 IPv6 都可以方便的管理&#xff0c;无论你是加入白名单还是黑名单&#xff0c;都非常的简单高效&#xff01;今天就参照明月自己的实操…

PyQt5串口测试工具

笔者经常会遇到使用上位机进行相关测试的场景&#xff0c;但现成的上位机并不能完全满足自己的需求&#xff0c;或是上位机缺乏使用说明。所以&#xff0c;自己写&#xff1f; 环境说明 pycharm 2023.2.25 python 3.10 anaconda 环境配置 conda create -n envsram ##…

Proxmox Backup Server 命名空间使用

作者&#xff1a;田逸&#xff08;formyz&#xff09; Proxmox Backup Server&#xff08;一下统称PBS&#xff09;从2.2版本开始&#xff0c;新增了命名空间这样一个功能。这个功能大大便利了多Proxmox VE集群或者单节点备份&#xff0c;在以前PBS版本中&#xff0c;如果有多个…

Windows系统下DOS命令

Windows系统下DOS命令 1. 与文件操作相关1.1 mkdir&#xff0c;md命令1.2 rmdir、rd命令1.3 dir命令1.4 start命令1.5 echo命令1.6 type命令1.7 copy命令1.8 move命令1.9 copy和move的区别1.10 del命令1.11 rename命令1.12 attrib命令1.13 fsutil命令1.14 assoc命令 2. 与网络相…

DevOps生命周期的8个阶段和DevOps pipeline 详解

您可能也在探索DevOps pipeline或工作流的概念&#xff0c;这些术语可能会根据不同的解释者而有所交替使用。尽管如此&#xff0c;DevOps生命周期和DevOps pipeline这两个术语更常被提及。 本文将首先阐述DevOps生命周期的概念&#xff0c;然后深入介绍DevOps pipeline。 Dev…

基于4G工业路由器的信息发布系统物联网应用方案

随着物联网技术的快速发展&#xff0c;智能信息发布系统已成为城市管理和信息传播的重要工具。而4G工业路由器作为连接信息发布终端与云平台的关键设备&#xff0c;其在提升信息发布效率方面发挥着至关重要的作用。为了提升智能信息发布系统的效率和智能化水平&#xff0c;智联…

怎么在pdf上编辑文字?帮你解决这个头疼的问题!

在信息爆炸的时代&#xff0c;PDF作为一种通用性极强的文件格式&#xff0c;广泛应用于各个领域。然而&#xff0c;对于许多用户来说&#xff0c;如何在PDF上编辑文字却是一个令人头疼的问题。今天&#xff0c;我们就来聊聊这个话题&#xff0c;并为大家推荐几款实用的PDF编辑软…

Python程序设计 身份证号的奥秘

第1关&#xff1a;判断性别 通过身份证的第17位也就是倒数第二位的数字可以辨别该身份证所属人的性别,奇数为男性,偶数为女性。 任务&#xff1a;输入身份证号&#xff0c;第17位若是偶数&#xff0c;输出男性&#xff0c;否则输出女性 如何截取字符串的一个字符 如何判断一个…

【YOLO 系列】基于YOLO V8的河道违规钓鱼检测识别系统【python源码+Pyqt5界面+数据集+训练代码】

前言&#xff1a; 随着社会发展和人口增长&#xff0c;对自然资源的保护和管理变得越来越重要。河流是重要的自然资源之一&#xff0c;对生态系统和人类社会都至关重要。然而&#xff0c;违规钓鱼等活动可能对河流生态环境造成严重破坏&#xff0c;并影响水域资源的可持续利用…

Codeforces Round 920 (Div. 3) E. Eat the Chip 题解 博弈论 贪心

Eat the Chip 题目描述 Alice and Bob are playing a game on a checkered board. The board has h h h rows, numbered from top to bottom, and w w w columns, numbered from left to right. Both players have a chip each. Initially, Alice’s chip is located at th…

回溯--字母迷宫

1.题目描述 字母迷宫游戏初始界面记作 m x n 二维字符串数组 grid&#xff0c;请判断玩家是否能在 grid 中找到目标单词 target。 注意&#xff1a;寻找单词时 必须 按照字母顺序&#xff0c;通过水平或垂直方向相邻的单元格内的字母构成&#xff0c;同时&#xff0c;同一个单…

SSM民宿在线预订平台的设计与实现-计算机毕业设计源码44449

摘 要 信息化社会内需要与之径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对民宿在线预订平台等问题&#xff0c;对民宿信息管理进行研究分…

【Qt知识】Qt窗口坐标系

Qt的窗口坐标体系遵循标准的计算机图形坐标系统规则 Qt窗口坐标体系特点 坐标原点&#xff1a;窗口坐标体系的原点位于窗口的左上角&#xff0c;即坐标(0, 0)位置。 轴方向&#xff1a; X轴&#xff1a;向右为正方向&#xff0c;随着X坐标值的增加&#xff0c;元素在窗口中从…

Honor of Kings 2024.06.03 50star (S35) AFK

Honor of Kings 2024.06.03 50star (S35) AFK 来个赛季S35总结吧&#xff0c;这个赛季结束以后&#xff0c;可能要和【魔兽世界】一样AFK了&#xff0c;手游来说肯定没法子和WOW相比&#xff0c;干啥都是有队友才好玩。 我玩的基本都是肉&#xff0c;爆发强的英雄&#xff0c;最…

重学java 57.哈希表结构存储过程

别焦虑&#xff0c;生活无非见招拆招 —— 24.6.3 哈希表存储数据去重复的过程: a.先比较元素的哈希值(重写hashCode),再比较内容(重写equals) b.如果哈希值不一样,证明内容不一样,存 c.如果哈希值一样,再比较内容 如果哈希值一样,内容不一样(哈希碰撞,哈希冲突),存 如果哈希值…

FASTGPT:可视化开发、运营和使用的AI原生应用

近年来&#xff0c;随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;AI的应用逐渐渗透到各行各业。作为一种全新的开发模式&#xff0c;AI原生应用正逐步成为行业的焦点。在这方面&#xff0c;FASTGPT无疑是一款颇具代表性的产品。本文将详细介绍FASTGPT的设…

再说零信任

什么是零信任&#xff1f; 2010年&#xff0c;由著名研究机构Forrester的首席分析师John Kindervag最早提出了零信任(Zero Trust)的概念&#xff0c; 并由Google在BeyondCorp项目中率先得到了应用&#xff0c;很好的解决了边界安全理念难以应对的安全问题。 我们的网络无时无…