stm32F411ceu6标准库驱动ST7789屏幕

LCD驱动方式分为软件SPI和硬件SPI(具体的显示等函数就不展示了)

  起初SPI初始化函数和传输数据的函数是这样子的,但是屏幕就是不能显示东西。

/**@brief  LCD SPI初始化
 * @param  无
 * @retval 无
 */
void LCD_SPI_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.GPIO_Pin = SCLK_PIN | SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

    SPI_InitTypeDef SPI_InitStructure;
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 10;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}
/**@brief  LCD写数据(8位)
 * @param  dat:要发送的数据
 * @retval 无
 */
void LCD_WR_DATA8(u8 dat)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, dat);
}
/**@brief  LCD写数据(16位)
 * @param  dat:要发送的数据
 * @retval 无
 */
void LCD_WR_DATA(u16 dat)
{
    uint8_t temp[2];
    temp[0] = (dat >> 8)&0xFF;
    temp[1] = dat&0xFF;
    LCD_WR_DATA8(temp[0]);
    LCD_WR_DATA8(temp[1]);
}

/**@brief  LCD写命令
 * @param  dat:要发送的命令
 * @retval 无
 */
void LCD_WR_REG(u8 dat)
{
    LCD_DC_Clr();//写命令
    LCD_WR_DATA8(dat);
    LCD_DC_Set();//写数据
}

然后我无奈试了试软件SPI驱动看看屏幕能不能显示东西出来;

软件SPI代码

void LCD_GPIO_Init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.GPIO_Pin = RES_PIN | CS_PIN | DC_PIN | SDA_PIN | SCLK_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_SetBits(GPIOB, RES_PIN | CS_PIN | DC_PIN);
}

void LCD_WR_DATA8(u8 dat)
{
    //软件SPI驱动
     u8 i;
     LCD_SCLK_Set();  // 初始时钟高电平(CPOL=1)
     for (i = 0; i < 8; i++) {
         LCD_SCLK_Clr();          // 第一个边沿(下降沿)
         delay_us(1);             // 短暂延时
         if (dat & 0x80) {
             LCD_MOSI_Set();
         } else {
             LCD_MOSI_Clr();
         }
         LCD_SCLK_Set();         // 第二个边沿(上升沿,数据采样)
         delay_us(1);            // 短暂延时
         dat <<= 1;
     }
}

出乎我的意料,软件SPI居然能让屏幕显示东西出来,但是毕竟是软件模拟,速率肯定比不上硬件SPI而且还很占用CPU资源。于是我按照同学的指示去查SPI寄存器的值,发现DR寄存器是有值变化的,但就是点不亮屏幕,百思不得其解。

然后在第二天,我开始怀疑SPI速率的问题,把SPI时钟频率降低又把GPIO口的速率降低,但是这样依旧没有效果。实在没啥能改的我就在函数SPI_I2S_SendData(SPI1, dat);的后面加了一个delay_us(1);神奇的是屏幕能显示东西了,而且速率不算太慢,但是毕竟是delay还是会占用cpu资源,我把这个问题丢给AI,它建议我将delay换成

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)); 

得到的解答是  不等待 BSY 会导致 SPI 数据未完整发送 或 MOSI 信号不稳定,而 LCD 对时序极其敏感,因此必须等待 BSY=0 以确保可靠通信。那么应该可以理解为DR寄存器上的数据还没有传出去就又有新数据传进来了,导致数据没有稳定传到LCD,自然也就显示不了。

最后发现等待bsy标志位置位的方法要比delay得到的屏幕刷新快1倍左右。

硬件SPI代码

void LCD_SPI_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.GPIO_Pin = SCLK_PIN | SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

    SPI_InitTypeDef SPI_InitStructure;
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 10;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}

void LCD_WR_DATA8(u8 dat)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, dat);
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
}

还有硬件SPI+DMA的方法还在实现当中,这个方法速率更快而且CPU资源占用率很低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值