1.3寸SPI通讯TFT LCD显示屏(驱动笔记)

本文详细介绍了如何使用STM32F103C6T6单片机通过SPI协议与ST7789V驱动的1.3寸TFTLCD显示屏进行通讯,包括硬件连接、程序编写中的GPIO模拟SPI输出、写数据和命令、初始化设置以及显示操作。此外,还展示了字符和数字的显示方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LCD的驱动为ST7789V,采用SPI协议单工进行通讯。正常SPI通讯拥有四根线片选先线、时钟线、输入线、输出线四根线配合进行输出,而LCD屏只需要写入数据显示即可,因此该显示屏引脚只有SPI通讯的时钟线和输入线。

一、硬件介绍

1.1 1.3寸SPI通讯TFT LCD显示屏

拥有GND、VCC、SCL、SDA、RES、DC、BLK四个引脚,分别为负极、正极(3.3V)、SCL(时钟信号线)、SDA(数据线)、RES(复位线)、DC(寄存器\数据写入选择线)、BLK(背光开启)。

驱动为ST7789V,最多能够驱动240*320分辨率的显示屏,而实际显示屏的分辨率只有240*240的分辨率。

1.2 单片机为STM32F103C6T6

单片机与LCD屏引脚的连接分别为:

BLK  ->  PB5
DC   ->  PB6
RES  ->  PB7
SDA  ->  PB8
SCL  ->  PB9

引脚设置均为推挽输出、上拉电阻;PB8与PB9的初始电压设置为高,其余三个引脚初始电压设置为低。

二、程序编写

2.1 GPIO模拟SPI输出

该模块时钟线和数据线初始状态均为高电平,时钟线由低电平变化为高电平的时刻,对信号线进行采样,传输时,高位在先,低位在后。

void LCD_Transport(char data)
{
    uint8_t i;
    // pull down the clock time
    for(i = 0; i < 8; i++)
    {
        LCD_CLK_Low();
        if(data&0x80) // OUTPUT Volt
             LCD_SDA_High();
        else
             LCD_SDA_Low();
        LCD_CLK_High(); //RESET
        data<<=1;
    }
}

2.2 写数据和写命令

写数据分成两个函数,一个是8位的发送函数,用来传输写入寄存器的指令,或者8位的数据;另一是16位的发送函数,一般用来传输颜色,颜色为16位;写命令之前,必须先发送寄存器的地址,当DC引脚为高电平时,LCD屏只接收数据;当DC引脚为低电平时,LCD屏只接收寄存器地址。

void LCD_Write_Data8(char data)
{
        LCD_DC_High();
        LCD_Transport(data);
}
void LCD_Write_Data(int data)
{
    // pull down CS,choose this machine
    // DC -> high  transport data
    LCD_DC_High();
    LCD_Transport(data>>8);
    LCD_Transport(data);
    // SPI hasn't reply mechanism
}

void LCD_Write_REG(char REG)
{
    // DC -> REG choose REG
    LCD_DC_Low();
    LCD_Transport(REG);
}

2.3初始化函数

初始化函数为重启、开启背光、配置寄存器等一些列操作。其中该型号显示屏能够配置12位、16位、18位的RGB等,显示屏分辨率为240*240,也就是240*240个像素点,而每个像素点都可以由12个、16个、18个小灯组成,每个像素点通过不同的RGB搭配方式可以显示出不同的颜色。一般24位以上的RGB显示才能称为真彩显示,因此该显示屏的显示效果比不上现在的手机屏的显示效果。

void LCD_Init()
{
    // reset at first
    LCD_RST_Low();
    Delay_ms(20);
    LCD_RST_High();
    Delay_ms(20);
    LCD_BLK_High();  // open background 
    // set scan mode in screen memory and data form
    LCD_Write_REG(0x36);
    LCD_Write_Data8(0x00);
    //  set RGB form  color deep  16 bit R:5 G:6 B:5; RGB: 444 RGB: 666
    LCD_Write_REG(0x3A);
    LCD_Write_Data8(0x05);
    // porch set
    LCD_Write_REG(0xB2);
    LCD_Write_Data8(0x0C);
    LCD_Write_Data8(0x0C);
    LCD_Write_Data8(0x00);
    LCD_Write_Data8(0x33);
    LCD_Write_Data8(0x33);
    // Gate volt control  default setting   VGL=-8.87  VGH=14.06
    LCD_Write_REG(0xB7);
    LCD_Write_Data8(0x35);
    // Vcom volt 0.9v  default setting 
    LCD_Write_REG(0xBB);
    LCD_Write_Data8(0x19);
    // LCM control
    LCD_Write_REG(0xC0);
    LCD_Write_Data8(0x2C);
    // VDV and VRH Command Enable 
    LCD_Write_REG(0xC2);
    LCD_Write_Data8(0x01);
    // VRH Set 
    LCD_Write_REG(0xC3);
    LCD_Write_Data8(0x12);
    // VDV Set
    LCD_Write_REG(0xC4);
    LCD_Write_Data8(0x20);
    //Frame Rate Control in Normal Mode  60 Hz  00: 119Hz
    LCD_Write_REG(0xC6);
    LCD_Write_Data8(0x0F);
    // Power Control 1   default value
    LCD_Write_REG(0xD0);
    LCD_Write_Data8(0xA4);
    LCD_Write_Data8(0xA1);
    //Positive Voltage Gamma Control 
    LCD_Write_REG(0xE0);
    LCD_Write_Data8(0xD0);
    LCD_Write_Data8(0x04);
    LCD_Write_Data8(0x0D);
    LCD_Write_Data8(0x11);
    LCD_Write_Data8(0x13);
    LCD_Write_Data8(0x2B);
    LCD_Write_Data8(0x3F);
    LCD_Write_Data8(0x54);
    LCD_Write_Data8(0x4C);
    LCD_Write_Data8(0x18);
    LCD_Write_Data8(0x0D);
    LCD_Write_Data8(0x0B);
    LCD_Write_Data8(0x1F);
    LCD_Write_Data8(0x23);
    //Negative Voltage Gamma Control 
    LCD_Write_REG(0xE1);
    LCD_Write_Data8(0xD0);
    LCD_Write_Data8(0x04);
    LCD_Write_Data8(0x0C);
    LCD_Write_Data8(0x11);
    LCD_Write_Data8(0x13);
    LCD_Write_Data8(0x2C);
    LCD_Write_Data8(0x3F);
    LCD_Write_Data8(0x44);
    LCD_Write_Data8(0x51);
    LCD_Write_Data8(0x2F);
    LCD_Write_Data8(0x1F);
    LCD_Write_Data8(0x1F);
    LCD_Write_Data8(0x20);
    LCD_Write_Data8(0x23);
    // Display Inversion On 
    LCD_Write_REG(0x21);
    // turn off Sleep mode
    LCD_Write_REG(0x11);
    Delay_ms(20);
    // Display On
    LCD_Write_REG(0x29);
}

2.4 设置操作区域函数

LCD屏的显示操作就是先指定需要填充颜色的像素区域或像素点,分别在0x0a、0x2b、0x2c中操作即可。

void address_set(uint16_t x1,uint16_t y1,uint16_t x2, uint16_t y2)
{
    if(x2>wide-1|| y2>length-1)return;
    else
    {
        // choose x axle register
        LCD_Write_REG(0x2A);
        // write 16 bit 
        LCD_Write_Data8(x1>>8); 
        LCD_Write_Data8(x1); 
        LCD_Write_Data8(x2>>8);
        LCD_Write_Data8(x2); 
        // choose y axle register    
        LCD_Write_REG(0x2B);
        LCD_Write_Data8(y1>>8); 
        LCD_Write_Data8(y1); 
        LCD_Write_Data8(y2>>8); 
        LCD_Write_Data8(y2); 
        // reset to start colum / page position
        LCD_Write_REG(0x2C);
    }
}

2.5 像素点填充

以清屏函数为例,先指定全屏区域作为填充区域,后在每个像素点中逐个填入颜色。

void LCD_SPI_Clear(uint16_t color)
{
    int i,j;
    address_set(0,0, wide - 1, length - 1);  // choose total screen
    for(i = 0; i < wide; i++)
    {
        for(j = 0; j < length; j++)
        {
            LCD_Write_Data(color);
        }
    }

2.4 字符和数字的显示

每个字符占用的像素点为8*16个,因此需要配置8*16个像素点中的每个像素的颜色来显示字符串。字符在文件的存储形式为16个字节的数据,每个字节的8位代表8个像素点的像素值,0代表背景色,1代表显示颜色,这就比较简单,也就是通过二维数组来存储字符串,若要存储图片,那么就还需要存储每个像素点具体像素值,这就需要三维的数组,而数字显示则是将实际的数字进行加减乘除运算得到对应的字符串并显示。

void Draw_one_charater(uint8_t x, uint8_t y,char a, uint16_t color)
{
    uint8_t temp;
    // the show table only have value after space
    a = a - ' ';
    address_set(x,y,x + 7,y + 15);
    for(uint8_t i = 0; i < 16; i++)
    {
        temp = asc2_1608[a*16 + i];
        for(uint8_t j = 0; j < 8; j++) // write horizontal at first
        {
            if(temp&0x01)
            {
                LCD_Write_Data(color);
            }
            else
            {
                LCD_Write_Data(BLACK);
            }
            temp>>=1;
        }
    }
}

void Show_String(uint8_t x, uint8_t y, char *string,uint8_t String_long)
{
    // character occupy 8*16 position  0 or 1 reprensent pixel show black or wihte
    if(y+16>length)
    {
        return;
    }
    else
    {
        if(x + 8 * String_long<= wide) // normal Display
        {
            for(uint8_t i; i < String_long;i++)
            {
                Draw_one_charater(x + i *8, y,string[i], WHITE);
            }
        }
        else
        {
            return;
        }
    }
}

void Show_number(uint8_t x, uint8_t y, uint32_t number,uint8_t number_bit_in_ten)
{
    uint32_t temp;
    char Display_Number;
    // The MAX Display 10 bits in LCD uint32_t is 10 bit
    uint8_t memory_nuber[10]; 
    // ASCII: 0 -> 48 9 -> 57
    temp = number;
    if(x + number_bit_in_ten * 8 > wide)return;
    else
    {
        for(uint8_t i = 0; i < number_bit_in_ten; i++)
        {        
            memory_nuber[i] = temp % 10;
            temp = temp / 10;
        }
            for(uint8_t i = 0; i < number_bit_in_ten; i++)
        {        
            Display_Number = memory_nuber[number_bit_in_ten - i - 1] + 48;
            Draw_one_charater(x + i * 8, y,Display_Number, YELLOW);
        }
    } 
}

三、主函数和显示效果

主函数只需要添加初始化和清屏函数即可。

    LCD_Init();
    LCD_SPI_Clear(BLACK);
    LCD_Draw_Horizontal_Line(16,8,220);
    LCD_Draw_Horizontal_Line(16,16,220);
    LCD_Draw_Horizontal_Line(16,24,220);
    LCD_Draw_Horizontal_Line(16,32,220);
    LCD_Draw_Vetical_Line(16,8,32);
    LCD_Draw_Vetical_Line(116,8,32);
    LCD_Draw_Vetical_Line(220,8,32);
    Show_String(72, 48, "char:",5);
    Show_number(112,48,sizeof(char),1);
    Show_String(72, 64, "short int:",10);
    Show_number(152,64,sizeof(short int),1);
    Show_String(72, 80, "int:",4);
    Show_number(104,80,sizeof(int),1);

显示效果:

之前一直错误的以为int在电脑中占用4字节,在单片机中只占用1个字节,现在事实证明,和电脑中的一样;char-> 1bit  short int -> 2bit int -> 4bit

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值