电子产业一站式赋能平台

PCB联盟网

搜索
查看: 62|回复: 0
收起左侧

基于STM32 HAL库硬件SPI的ST7789驱动(TFT-LCD 240*320)

[复制链接]

208

主题

208

帖子

1635

积分

三级会员

Rank: 3Rank: 3

积分
1635
发表于 2021-4-4 12:36:00 | 显示全部楼层 |阅读模式
点击上方「嵌入式实验基地」,选择「置顶公众号」第一时间查看嵌入式笔记!

sul4tpmcmit64047053639.png

sul4tpmcmit64047053639.png

??在日常开发项目中,显示屏是经常使用的一个部件,显示屏的种类也是多种多样,但对于开发者来说,主要关心的是显示屏所用到的驱动芯片,本次给小伙伴们带来的是 STM32 下的 HAL 库硬件 SPI 驱动 320*240 分辨率的 TFT-LCD,LCD 显示屏驱动芯片为 ST7789,一步步实现如何驱动此类驱动芯片的 LCD 屏幕,话不多说,上干货!
  • 完成目标1、cubemx配置硬件SPI
    2、驱动240*320分辨率LCD显示屏(驱动芯片为ST7789)
  • 硬件环境1、STM32F103C8T6(自设计)
    2、ST7789驱动LCD显示屏
  • 软件环境1、cubemx
    2、keil5
    一、cubemx配置硬件SPI及LCD相关引脚1.1 时钟配置
    ??第一步仍然是时钟配置,由于板子上设计没有预留外部晶振,我使用的是内部RC振荡器,内部RC振荡器只能配置到64MHZ,如下,如果你使用的是外部晶振,最大到72MHZ

    s5vuyshfdjg64047053740.png

    s5vuyshfdjg64047053740.png

    1.2 LCD与STM32硬件连接关系
    LCDMCULCD-RSTPB1LCD-CSPB0LCD-DCPA4LCD-MOSIPA7LCD-CLKPA5LCD-LDE+VCC-3.3(可接IO控制)LCD-LDE-GNDLCD-VCCVCC-3.3VLCD-GNDGND1.3 LCD相关引脚配置
    ??本次使用的是SPI1,对SPI1的引脚及参数进行配置,相关IO初始化状态可以根据需要进行配置u,比如CS引脚,拉低有效,初始化我们可以配置为高,根据自己需要进行配置即可

    mntl1p30ixy64047053840.png

    mntl1p30ixy64047053840.png

    lvcsqi24kln64047053940.png

    lvcsqi24kln64047053940.png


    0npskxjrzus64047054040.png

    0npskxjrzus64047054040.png

    ??小伙伴们有没有遇到过配置完发现不能仿真,这里需要设置一下,根据自己的仿真器接口进行配置,是SWD模式还是JTAG模式

    lpepn34m0du64047054140.png

    lpepn34m0du64047054140.png

    生成工程配置,配置完之后,直接点击生成即可,注意工程路径不要有中文,记得以前可以有,不知道什么时候有的臭毛病...只能按照做了

    kkgf3v2xelc64047054240.png

    kkgf3v2xelc64047054240.png

    zgxrpugd5ri64047054340.png

    zgxrpugd5ri64047054340.png

    二、代码编写??先定义LCD相关引脚,CS、RST、DC
    #define LCD_REST_LOW()   HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET);
    #define LCD_REST_HIGH()  HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
    #define LCD_DC_LOW()     HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET);
    #define LCD_DC_HIGH()    HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
    #define LCD_CS_LOW()     HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
    #define LCD_CS_HIGH()    HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
    #define LCD_WR_RS(n) (n?HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_RESET))
    ??定义用到的几个基本函数
    /**
    * @brief  写16位的数据(两个字节)到LCD
    * @param   dat —— 需要发送的16bit数据
    * @return  none
    */
    void LCD_Write_2Bytes(const uint16_t dat)
    {
        uint8_t data[2] = {0};
        data[0] = dat >> 8;
        LCD_data_write(data[0]);
        data[1] = dat;
        LCD_data_write(data[1]);
        // LCD_SPI_Send(data, 2);
    }
    void LCD_command_write(uint8_t command)
    { // 写命令
        LCD_DC_LOW();
        LCD_CS_LOW();
        lcd_SendBytes(command);
        LCD_CS_HIGH();
    }
    void LCD_data_write(uint8_t data)
    { //写数据
        LCD_DC_HIGH();
        LCD_CS_LOW();
        lcd_SendBytes(data);
        LCD_CS_HIGH();
    }
    void delay_lcd(unsigned int time)
    {
        while (time)
        {
            time--;
            time--;
            time--;
            time--;
        }
    }
    void LCD_Reset(void)
    {
        LCD_REST_HIGH();
        delay_lcd(1000);
        LCD_REST_LOW();
        delay_lcd(10000);
        LCD_REST_HIGH();
        delay_lcd(10000);
        LCD_CS_HIGH();
    }
    LCD行列设置
    //========================================================
    //CASET (2Ah): Column Address Set
    //RASET (2Bh): Row Address Set
    //x1,y1:起始地址,x2,y2:终点地址
    //========================================================
    void lcd_set_address(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
    {
        LCD_command_write(0x2a);
        LCD_data_write(x1 >> 8);
        LCD_data_write(x1);
        LCD_data_write(x2 >> 8);
        LCD_data_write(x2);
        LCD_command_write(0x2b);
        LCD_data_write(y1 >> 8);
        LCD_data_write(y1);
        LCD_data_write(y2 >> 8);
        LCD_data_write(y2);
        LCD_command_write(0x2C); // write_ram
    }
    LCD初始化代码,这部分主要是参考网上已经完成的,相关配置可以在手册具体查看
    void lcd_init(void)
    {
        LCD_CS_HIGH();
        LCD_Reset();
        /************* display Setting *************/
        LCD_command_write(0x01);
        delay_lcd(10000);
        LCD_command_write(LCD_CMD_SLPOUT);
        delay_lcd(10000);

      //修改此处,可以改变屏幕的显示方向,横屏,竖屏等
        LCD_command_write(LCD_CMD_MADCTL); // 0x36  ///
        LCD_data_write(0x00);              //50//40//C0
        LCD_command_write(LCD_CMD_COLMOD); //  0x3A     ///
        LCD_data_write(0x05);              /// 16bit/pixel
        /*********** Frame Rate Setting ***********/
        LCD_command_write(LCD_CMD_PORCTRL); //0xB2     ///
        LCD_data_write(0x0c);               ///
        LCD_data_write(0x0c);               ///
        LCD_data_write(0x00);               ///
        LCD_data_write(0x33);               ///
        LCD_data_write(0x33);               ///
        LCD_command_write(LCD_CMD_GCTRL); //  0xB7     ///
        LCD_data_write(0x72);             ///
        LCD_command_write(LCD_CMD_VCOMS); // 0xBB     ///
        LCD_data_write(0x3d);             ///
        LCD_command_write(LCD_CMD_LCMCTRL); ///0xC0     ///
        LCD_data_write(0x2c);
        LCD_command_write(LCD_CMD_VDVVRHEN); //0xC2     ///
        LCD_data_write(0x01);
        LCD_data_write(0xFF);
        /* VRH Set */
        LCD_command_write(LCD_CMD_VRHS); //0xC3
        LCD_data_write(0x19);
        /* VDV Set */
        LCD_command_write(LCD_CMD_VDVS); //0xC4
        LCD_data_write(0x20);
        LCD_command_write(LCD_CMD_FRCTRL2); //  0xC6     ///
        LCD_data_write(0x0f);               ///
        LCD_command_write(LCD_CMD_PWCTRL1); // 0xD0     ///
        LCD_data_write(0xa4);
        LCD_data_write(0xa1); ///
        /* Positive Voltage Gamma Control */
        LCD_command_write(0xE0);
        LCD_data_write(0xD0);
        LCD_data_write(0x04);
        LCD_data_write(0x0D);
        LCD_data_write(0x11);
        LCD_data_write(0x13);
        LCD_data_write(0x2B);
        LCD_data_write(0x3F);
        LCD_data_write(0x54);
        LCD_data_write(0x4C);
        LCD_data_write(0x18);
        LCD_data_write(0x0D);
        LCD_data_write(0x0B);
        LCD_data_write(0x1F);
        LCD_data_write(0x23);
        /* Negative Voltage Gamma Control */
        LCD_command_write(0xE1);
        LCD_data_write(0xD0);
        LCD_data_write(0x04);
        LCD_data_write(0x0C);
        LCD_data_write(0x11);
        LCD_data_write(0x13);
        LCD_data_write(0x2C);
        LCD_data_write(0x3F);
        LCD_data_write(0x44);
        LCD_data_write(0x51);
        LCD_data_write(0x2F);
        LCD_data_write(0x1F);
        LCD_data_write(0x1F);
        LCD_data_write(0x20);
        LCD_data_write(0x23);
        // LCD_command_write( 0x21);     ///
        //LCD_command_write( 0x13);
        //LCD_InitSequence();
        //Display_logo();
        // lcd_clear(LCD_DISP_RED);
      lcd_clear(LCD_DISP_WRITE);
        LCD_command_write(LCD_CMD_DISPON); ///
    }
    常用颜色定义,为RGB565格式,其他颜色可以自己改变配比
    /************** 颜色(RGB 5,6,5) **************/
    #define LCD_DISP_RED                    0xF800       //先高字节,后低字节      
    #define LCD_DISP_GREEN                  0x07E0
    #define LCD_DISP_BLUE                   0x001F
    #define LCD_DISP_WRITE                  0xFFFF
    #define LCD_DISP_BLACK                  0x0000
    #define LCD_DISP_GRAY                   0xEF5D
    #define LCD_DISP_GRAY75                 0x39E7
    #define LCD_DISP_GRAY50                 0x7BEF
    #define LCD_DISP_GRAY25                 0xADB5
    LCD清屏,可以填充指定的颜色
    //========================================================
    //LCD清屏  color:要写入的颜色
    //先关显示,等所有的数据写入到RAM后,再打开显示
    //========================================================
    void lcd_clear(uint16_t color)
    {
        uint16_t i, j;
        LCD_command_write(0x2A);
        LCD_data_write(0);
        LCD_data_write(0);
        LCD_data_write(0);
        LCD_data_write(240);
        LCD_command_write(0X2B);
        LCD_data_write(0);
        LCD_data_write(0);
        LCD_data_write(0X01);
        LCD_data_write(0X40);
        LCD_command_write(0X2C);
        for (i = 0; i 240; i++)
        {
            for (j = 0; j 320; j++)
            {
                LCD_data_write(color >> 8);
                LCD_data_write(color);
            }
        }
        lcd_display_on(); /* 开LCD显示 */
    }
    ??还有一些打点、划线、画圆等函数,就不再一一介绍了,编写测试代码,刷屏,画圆、画矩形、显示汉字,一气呵成,直接来看演示视频吧~

            后面会分享更多有意思的显示小项目,包括界面等的设计,敬请期待吧!
    本次的介绍就到这里啦,后面有更精彩的内容,欢迎大家持续关注嵌入式实验基地!
    ??如果你觉得对自己有帮助的话,给个赞,点个关注,点个在看,感谢前进的道路上有你的陪伴!

    2lxs3idwa4a64047054440.jpg

    2lxs3idwa4a64047054440.jpg

    推荐阅读
    ?开源电路のSTM32最小系统设计
    ?一种你值得拥有的简单易实现的开关电路
    ?无线通讯之红外通讯?DIY一个离线语音控制器
    ?HAL库us延时的3种实现方式?逻辑分析仪的简单使用介绍(附带iic,uart,spi数据波形分析)
    ?ART-PI重力感应无线智能小车第一弹----ART-PI扩展板设计?ART-PI重力感应无线智能小车第二弹----Onenet+wifi+L298N电机驱动?ART-PI重力感应无线智能小车第三弹----RT-Studio+MPU6050+MQTT发布订阅?STM32 DAC音频输出
    ?pcb设计基础?OLED+ESP8266网络小时钟
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表