深入理解SPI协议,TFT显示屏实战

1.硬件介绍

本期介绍一下智能家居项目中用到的TFT显示屏。此模块在项目中用于温湿度、光度、陀螺仪角度等数据的显示。

2.SPI协议

SPI(Serial Peripheral Interface,串行外设接口) 是一种高速的、全双工、同步的串行通信协议,主要用于单片机与各种外设之间进行数据传输,下面为你详细介绍:

2.1.基本组成

SPI 通信通常由主设备(Master)和从设备(Slave)组成 ,一个主设备可以连接多个从设备。SPI 接口一般使用 4 根线进行通信:
时钟线(SCK,Serial Clock)
由主设备产生,用于同步主设备和从设备之间的数据传输,就像大家一起跟着节拍器打拍子一样,保证数据传输节奏一致。
主机输出 / 从机输入线(MOSI,Master Output, Slave Input)
主设备通过这条线向从设备发送数据。比如主设备是单片机,从设备是显示屏,单片机要给显示屏发送显示内容的数据,就通过 MOSI 线传输。
主机输入 / 从机输出线(MISO,Master Input, Slave Output)
从设备通过这条线向主设备发送数据。比如从设备是温度传感器,要把采集到的温度数据发送给主设备单片机,就经由 MISO 线。
从机选择线(SS,Slave Select,有的也叫 CS,Chip Select )
由主设备控制,用来选择与哪个从设备进行通信。因为一个主设备可能连接多个从设备,当主设备要和某个从设备通讯时,就把对应从设备的 SS 线拉低,相当于告诉这个从设备 “该你干活啦” ,其他从设备的 SS 线保持高电平,处于非工作状态。

2.2.通信过程

选择从设备
主设备先将目标从设备的 SS 线拉低,选中要通信的从设备。比如主设备要和连接在 SPI 总线上的 Flash 存储芯片通讯,就把 Flash 芯片对应的 SS 线拉低。
时钟同步
主设备通过 SCK 线产生时钟信号,确定数据传输的节拍。数据在时钟信号的上升沿或者下降沿进行传输,具体是上升沿还是下降沿传输,由主设备和从设备事先约定好的 SPI 模式决定(SPI 有 4 种工作模式 ,主要区别在于时钟极性 CPOL 和时钟相位 CPHA 的不同组合)。
数据传输
在时钟信号的驱动下,主设备通过 MOSI 线发送数据给从设备,从设备通过 MISO 线发送数据给主设备,两者的数据传输是同时进行的,这就是全双工的体现。
比如主设备给从设备发送一个控制指令,同时从设备把自己的状态数据反馈给主设备。数据通常以字节(8 位)为单位进行传输 ,主设备和从设备在每一个时钟周期内,各自发送和接收 1 位数据,经过 8 个时钟周期完成一个字节的传输(数据传输可以高位先行MSB或者低位先行LSB)。
结束通信
主设备将从设备的 SS 线拉高,结束与该从设备的通信 。此时,从设备进入等待状态,直到下一次被主设备选中。

2.3.CPOL 和 CPHA 的作用

SPI 通信中,主从设备通过时钟线(SCL) 同步数据传输,而CPOL 和 CPHA 共同决定了:
  • 时钟线在空闲时的电平(CPOL);
  • 数据在时钟的哪个边沿被采样(CPHA)。
两者组合形成 SPI 的 4 种工作模式(模式 0~3),理解这两个参数是掌握 SPI 工作模式的基础。

2.3.1.CPOL(时钟极性):定义时钟线的空闲电平

  • 定义:当 SPI 没有数据传输(空闲状态)时,时钟线(SCL)的电平状态。
    • 若空闲时 SCL 为高电平,则 CPOL=1
    • 若空闲时 SCL 为低电平,则 CPOL=0
  • 举例:比如一个 SPI 设备设定 CPOL=1,那么在不传输数据时,SCL 线一直保持高电平,直到开始传输时才会跳变。

2.3.2.CPHA(时钟相位):定义数据的采样时刻

核心:数据在时钟的 “第几个边沿” 被采样(采集),分为两种情况:
CPHA=0:在 “第 1 个边沿”(奇数边沿)采样
  • 时钟从 “空闲状态” 开始跳变的第一个边沿(上升沿或下降沿)就是采样时刻。
  • 边沿极性由 CPOL 决定:
    • 若 CPOL=0(空闲低电平),第一个边沿是上升沿(低→高),此时采样;
    • 若 CPOL=1(空闲高电平),第一个边沿是下降沿(高→低),此时采样。
CPHA=1:在 “第 2 个边沿”(偶数边沿)采样
  • 数据采样发生在时钟的第二个边沿(即偶数次跳变),此时的边沿极性与 CPHA=0 相反:
    • 若 CPOL=0(空闲低电平):第一个边沿是上升沿(低→高,奇数),第二个边沿是下降沿(高→低,偶数),此时采样;
    • 若 CPOL=1(空闲高电平):第一个边沿是下降沿(高→低,奇数),第二个边沿是上升沿(低→高,偶数),此时采样。

2.4.SPI的4种工作模式

参数组合
空闲电平(CPOL)
采样边沿(CPHA)
对应的边沿极性示例
CPOL=0, CPHA=0
低电平
第 1 个边沿(上升沿)
低→高时采样
CPOL=0, CPHA=1
低电平
第 2 个边沿(下降沿)
高→低时采样
CPOL=1, CPHA=0
高电平
第 1 个边沿(下降沿)
高→低时采样
CPOL=1, CPHA=1
高电平
第 2 个边沿(上升沿)
低→高时采样
CPHA=0时,CPOL=1与CPOL=0时的时序
CPHA=1时,CPOL=1与CPOL=0时的时序

3.软件设计

我们通过GPIO模拟SPI协议来对显示屏进行控制。

3.1.STM32Cubemx配置

SDA对应MOSI,DC引脚用于切换命令或者数据模式(0/1),SCK引脚为时钟引脚,CS引脚片选引脚,RES为复位引脚,都配置为推挽输出即可。

3.2.SPI驱动代码实现

3.2.1.SPI写一个字节

这段代码实现的是SPI 模式 0(CPOL=0, CPHA=0),是显示屏控制中最常见的模式之一。数据传输为MSB高位先行。
void LCD_Writ_Bus(char dat)   //串行数据写入
{	
    u8 i;			  
    
    for(i=0;i<8;i++)
    {			  
        OLED_SCLK_Clr();
        if(dat&0x80)
            OLED_SDIN_Set();
        else 
            OLED_SDIN_Clr();
        OLED_SCLK_Set();
        dat<<=1;   
    }			
}

3.2.2.写寄存器

DC引脚低电平,代表写寄存器。
void LCD_WR_REG(char da)	 
{	
    OLED_CS_Clr();
    OLED_DC_Clr();
    LCD_Writ_Bus(da);
    OLED_CS_Set();
}

3.2.3.写数据

DC引脚高电平,代表写数据。
void LCD_WR_DATA8(char da) //发送数据-8位参数
{	
    OLED_CS_Clr();
    OLED_DC_Set();
    LCD_Writ_Bus(da);  
    OLED_CS_Set();
}  

3.2.4.显示屏初始化

void Lcd_Init(void)
{
    HAL_GPIO_WritePin(GPIOA, TFT_DC_Pin|TFT_SCK_Pin|TFT_RES_Pin
                          |TFT_SDA_Pin, GPIO_PIN_SET);
    OLED_RST_Clr();
    delay_ms(20);
    OLED_RST_Set();
    delay_ms(20);
    OLED_BLK_Set();
    //************* Start Initial Sequence **********// 
    LCD_WR_REG(0x36); 
    LCD_WR_DATA8(0x00);
    
    LCD_WR_REG(0x3A); 
    LCD_WR_DATA8(0x05);
    
    LCD_WR_REG(0xB2);
    LCD_WR_DATA8(0x0C);
    LCD_WR_DATA8(0x0C);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(0x33);
    LCD_WR_DATA8(0x33);
    
    LCD_WR_REG(0xB7); 
    LCD_WR_DATA8(0x35);  
    
    LCD_WR_REG(0xBB);
    LCD_WR_DATA8(0x19);
    
    LCD_WR_REG(0xC0);
    LCD_WR_DATA8(0x2C);
    
    LCD_WR_REG(0xC2);
    LCD_WR_DATA8(0x01);
    
    LCD_WR_REG(0xC3);
    LCD_WR_DATA8(0x12);   
    
    LCD_WR_REG(0xC4);
    LCD_WR_DATA8(0x20);  
    
    LCD_WR_REG(0xC6); 
    LCD_WR_DATA8(0x0F);    
    
    LCD_WR_REG(0xD0); 
    LCD_WR_DATA8(0xA4);
    LCD_WR_DATA8(0xA1);
    
    LCD_WR_REG(0xE0);
    LCD_WR_DATA8(0xD0);
    LCD_WR_DATA8(0x04);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x11);
    LCD_WR_DATA8(0x13);
    LCD_WR_DATA8(0x2B);
    LCD_WR_DATA8(0x3F);
    LCD_WR_DATA8(0x54);
    LCD_WR_DATA8(0x4C);
    LCD_WR_DATA8(0x18);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x0B);
    LCD_WR_DATA8(0x1F);
    LCD_WR_DATA8(0x23);
    
    LCD_WR_REG(0xE1);
    LCD_WR_DATA8(0xD0);
    LCD_WR_DATA8(0x04);
    LCD_WR_DATA8(0x0C);
    LCD_WR_DATA8(0x11);
    LCD_WR_DATA8(0x13);
    LCD_WR_DATA8(0x2C);
    LCD_WR_DATA8(0x3F);
    LCD_WR_DATA8(0x44);
    LCD_WR_DATA8(0x51);
    LCD_WR_DATA8(0x2F);
    LCD_WR_DATA8(0x1F);
    LCD_WR_DATA8(0x1F);
    LCD_WR_DATA8(0x20);
    LCD_WR_DATA8(0x23);
    
    LCD_WR_REG(0x21); 
    
    LCD_WR_REG(0x11);
    
    LCD_WR_REG(0x29); 
    
    LCD_Clear(WHITE);
} 

3.2.5.main函数

int main()
{
    Lcd_Init();
    
    LCD_Clear(WHITE); //清屏
    BACK_COLOR=WHITE;
    POINT_COLOR=BLACK; 
    Set_Myhanzi(70, 10, "chuanganqi");
    Set_Myhanzi(20, 55, "guangdu");
    Set_Myhanzi(20, 105, "wendu");
    Set_Myhanzi(20, 155, "shidu");
    
    while(1){}
}

4.完整代码

我用夸克网盘给你分享了「SmartHom...iyun」,点击链接或复制整段内容,打开「夸克APP」即可获取。
/~1d17370YmM~:/
链接:夸克网盘分享
提取码:1KdH
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值