STM32驱动ST7735彩色屏幕(任意分辨率),驱动不了你来打我

使用STM32轻松驱动ST7735屏幕

驱动方式

硬件SPI

适用STM32型号

带SPI的任意型号,驱动不了你来打我(内心OS:HAL真好)

特别提醒

以下内容介绍如何使用HAL方式驱动ST7735,所以默认你已经了解并且会使用STM32CubeMX软件(如果没有接触过的话建议先安装尝试一下再继续以下内容,不然有种囫囵吞枣的意思了)。

开始进行

第0步:STM32CubeMX创建工程

不再赘述。

第1步:SPI配置

在STM32CubeMX的Connectivity选项中选择SPI1(选哪个都行,看你的心情),Mode选择Transmit Only Master,意思是SPI作为主机且只有发送功能(因为数据是仅通过SPI发送到屏幕,并不会从屏幕读取数据)。

在Parameter中调整Prescaler来确定SPI的速度,根据每个人的时钟配置来灵活调整,Baud Rate调整到5-20M之间就行,没有严格要求,因为目标是屏幕正常显示就行(实测低于5M或者高于20M也能正常显示)

剩余项默认即可,以下是我测试时的配置截图。

第2步:SPI其它引脚配置

第一步仅配置了SPI的SCK和MOSI,驱动ST7735还需要RST、DC、CS三个引脚,在STM32CubeMX的pinout中挑选三个你喜欢的引脚,均设置为GPIO_Output,分别设置Label为:SPI1_RST、SPI1_DC、SPI1_CS(建议这么命名,按自己的心情命名也行)。

此时配置完毕,生成工程。

第3步:编写ST7735驱动

打开工程,先编译一下看有没有报错,正常情况下是0错误0警告。

新建两个文件:st7735.c和st7735.h,然后在main.c中include “st7735.h”(写到这里我咋有一种手把手教的感觉嘞。。。啥也不说了,毕竟驱动不了你要来打我的。。。)

在st7735.c中 复制粘贴 编写以下代码:

#include "st7735.h"

#define ST7735_SLPOUT   0x11
#define ST7735_FRMCTR1  0xB1
#define ST7735_FRMCTR2  0xB2
#define ST7735_FRMCTR3  0xB3
#define ST7735_INVCTR   0xB4
#define ST7735_PWCTR1   0xC0
#define ST7735_PWCTR2   0xC1
#define ST7735_PWCTR3   0xC2
#define ST7735_PWCTR4   0xC3
#define ST7735_PWCTR5   0xC4
#define ST7735_VMCTR1   0xC5
#define ST7735_COLMOD   0x3A
#define ST7735_GMCTRP1  0xE0
#define ST7735_GMCTRN1  0xE1
#define ST7735_NORON    0x13
#define ST7735_DISPON   0x29
#define ST7735_CASET    0x2A
#define ST7735_RASET    0x2B
#define ST7735_RAMWR    0x2C
#define ST7735_INVOFF   0x20

#define ST7735_MADCTL     0x36
#define ST7735_MADCTL_MX  0x40
#define ST7735_MADCTL_MY  0x80
#define ST7735_MADCTL_MV  0x20
#define ST7735_MADCTL_RGB 0x00

void ST7735_Reset(void)
{
  HAL_GPIO_WritePin(ST7735_RST_GPIO_Port, ST7735_RST_Pin, GPIO_PIN_RESET);
  HAL_Delay(100);
  HAL_GPIO_WritePin(ST7735_RST_GPIO_Port, ST7735_RST_Pin, GPIO_PIN_SET);
  HAL_Delay(100);
}

void ST7735_WriteCommand(uint8_t cmd)
{
  HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&ST7735_SPI_INSTANCE, &cmd, 1, 100);
  HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_SET);
}

void ST7735_WriteData(uint8_t data)
{
  HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&ST7735_SPI_INSTANCE, &data, 1, 100);
  HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_SET);
}

void ST7735_SetRotation(uint8_t rotation)
{
    uint8_t madctl = 0;

    switch (rotation)
    {
        case 0:
            madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_RGB;
            break;
        case 1:
            madctl = ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_RGB;
            break;
        case 2:
            madctl = ST7735_MADCTL_RGB;
            break;
        case 3:
            madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_RGB;
            break;
    }

    ST7735_WriteCommand(ST7735_MADCTL);
    ST7735_WriteData(madctl);
}

void ST7735_Init(void) {
  // Initialize the display
  ST7735_Reset();
  ST7735_WriteCommand(ST7735_SLPOUT);
  HAL_Delay(120);
  ST7735_WriteCommand(ST7735_FRMCTR1);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_FRMCTR2);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_FRMCTR3);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x2D);
  ST7735_WriteCommand(ST7735_INVCTR);
  ST7735_WriteData(0x07);
  ST7735_WriteCommand(ST7735_PWCTR1);
  ST7735_WriteData(0xA2);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x84);
  ST7735_WriteCommand(ST7735_PWCTR2);
  ST7735_WriteData(0xC5);
  ST7735_WriteCommand(ST7735_PWCTR3);
  ST7735_WriteData(0x0A);
  ST7735_WriteData(0x00);
  ST7735_WriteCommand(ST7735_PWCTR4);
  ST7735_WriteData(0x8A);
  ST7735_WriteData(0x2A);
  ST7735_WriteCommand(ST7735_PWCTR5);
  ST7735_WriteData(0x8A);
  ST7735_WriteData(0xEE);
  ST7735_WriteCommand(ST7735_VMCTR1);
  ST7735_WriteData(0x0E);
  ST7735_WriteCommand(ST7735_INVOFF);
  ST7735_WriteCommand(ST7735_COLMOD);
  ST7735_WriteData(0x05);
  ST7735_WriteCommand(ST7735_CASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x7F);
  ST7735_WriteCommand(ST7735_RASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x9F);
  ST7735_WriteCommand(ST7735_GMCTRP1);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x1C);
  ST7735_WriteData(0x07);
  ST7735_WriteData(0x12);
  ST7735_WriteData(0x37);
  ST7735_WriteData(0x32);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x25);
  ST7735_WriteData(0x2B);
  ST7735_WriteData(0x39);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x01);
  ST7735_WriteData(0x03);
  ST7735_WriteData(0x10);
  ST7735_WriteCommand(ST7735_GMCTRN1);
  ST7735_WriteData(0x03);
  ST7735_WriteData(0x1D);
  ST7735_WriteData(0x07);
  ST7735_WriteData(0x06);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x2C);
  ST7735_WriteData(0x29);
  ST7735_WriteData(0x2D);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x2E);
  ST7735_WriteData(0x37);
  ST7735_WriteData(0x3F);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x00);
  ST7735_WriteData(0x02);
  ST7735_WriteData(0x10);
  ST7735_WriteCommand(ST7735_NORON);
  HAL_Delay(10);
  ST7735_WriteCommand(ST7735_DISPON);
  HAL_Delay(10);
  
  ST7735_SetRotation(ST7735_ROTATION);
  ST7735_FillScreen(ST7735_BLACK);
}

void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
  x0 += ST7735_XSTART;
  y0 += ST7735_YSTART;

  x1 += ST7735_XSTART;
  y1 += ST7735_YSTART;
  
  ST7735_WriteCommand(ST7735_CASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(x0 + ST7735_XSTART);
  ST7735_WriteData(0x00);
  ST7735_WriteData(x1 + ST7735_XSTART);
  
  ST7735_WriteCommand(ST7735_RASET);
  ST7735_WriteData(0x00);
  ST7735_WriteData(y0 + ST7735_YSTART);
  ST7735_WriteData(0x00);
  ST7735_WriteData(y1 + ST7735_YSTART);
}

void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
  ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);
  ST7735_WriteCommand(ST7735_RAMWR);
  // Write the color data
  for (uint16_t i = 0; i < width * height; i++)
  {
    ST7735_WriteData(color >> 8);
    ST7735_WriteData(color & 0xFF);
  }
}

void ST7735_FillScreen(uint16_t color)
{
  ST7735_DrawRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
}

void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *image)
{
  ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);

  ST7735_WriteCommand(ST7735_RAMWR);
  for (uint32_t i = 0; i < width * height; i++)
  {
    ST7735_WriteData(image[i * 2]);
    ST7735_WriteData(image[i * 2 + 1]);
  }
}

在st7735.h中 复制粘贴 编写以下代码:

#ifndef ST7735_H
#define ST7735_H

#include "main.h"
#include "spi.h"

#define ST7735_RST_Pin SPI1_RST_Pin
#define ST7735_RST_GPIO_Port SPI1_RST_GPIO_Port
#define ST7735_DC_Pin SPI1_DC_Pin
#define ST7735_DC_GPIO_Port SPI1_DC_GPIO_Port
#define ST7735_CS_Pin SPI1_CS_Pin
#define ST7735_CS_GPIO_Port SPI1_CS_GPIO_Port

#define ST7735_SPI_INSTANCE hspi1

#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_WIDTH  160
#define ST7735_HEIGHT 128

#define ST7735_ROTATION 3

// Color definitions
#define ST7735_BLACK   0x0000
#define ST7735_BLUE    0x001F
#define ST7735_RED     0xF800
#define ST7735_GREEN   0x07E0
#define ST7735_CYAN    0x07FF
#define ST7735_MAGENTA 0xF81F
#define ST7735_YELLOW  0xFFE0
#define ST7735_WHITE   0xFFFF
#define ST7735_COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))

void ST7735_Init(void);
void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
void ST7735_FillScreen(uint16_t color);
void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *image);

#endif

第4步:调整SPI和引脚,均在头文件中进行

调整SPI:

如果你在STM32CubeMX中选择的SPI1,那么在st7735.h中#define ST7735_SPI_INSTANCE hspi1,
如果你在STM32CubeMX中选择的SPI2,那么在st7735.h中#define ST7735_SPI_INSTANCE hspi2,
如果你在STM32CubeMX中选择的SPI3,那么在st7735.h中#define ST7735_SPI_INSTANCE hspi3,

调整引脚:

#define ST7735_RST_Pin SPI1_RST_Pin
#define ST7735_RST_GPIO_Port SPI1_RST_GPIO_Port
#define ST7735_DC_Pin SPI1_DC_Pin
#define ST7735_DC_GPIO_Port SPI1_DC_GPIO_Port
#define ST7735_CS_Pin SPI1_CS_Pin
#define ST7735_CS_GPIO_Port SPI1_CS_GPIO_Port

看上面的宏定义,我想机智的同学已经知道该怎么做了。

第5步:调用显示

在main.c中调用ST7735_Init(); 然后编译,正常情况下是0错误0警告,下载进stm32后屏幕显示黑色。

调用ST7735_DrawRectangle可以在指定位置用指定颜色填充一个矩形;
调用ST7735_FillScreen可以用指定颜色填充屏幕;
调用ST7735_DrawImage可以在指定位置显示指定大小的图片;

以下是红绿蓝依次填充屏幕的代码

ST7735_FillScreen(ST7735_RED);
HAL_Delay(500);
ST7735_FillScreen(ST7735_GREEN);
HAL_Delay(500);
ST7735_FillScreen(ST7735_BLUE);
HAL_Delay(500);

可能会遇到的问题

问题1:显示正常,但是 方向 / 位置 / 尺寸 不对?

角度调整:
#define ST7735_ROTATION 3

位置调整:
#define ST7735_XSTART 0
#define ST7735_YSTART 0

尺寸调整:
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 128

上面的方法我相信机智的同学早已看穿了,哈哈哈。如果遇到问题,请在评论区提问哦~

问题2:怎么在屏幕上显示字符?

我在font.c中编写了3种尺寸的字体,代码量很大,粘贴到这里太占位置了,暂时先不放,需要的话请多多点赞评论,我再出一篇显示文字的教程。

问题3:rgb565是什么?

指的是用5位二级制代表red(红色)数据,6位二进制代表green(绿色)数据,5位二进制代表blue(蓝色)数据,加一起是16位数据,所以屏幕的颜色是用16位数据来指定(一些摄像头的输出也是rgb565,用st7735显示不会丢失颜色信息)。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32驱动ST7735彩色屏幕(任意分辨率),驱动不了你来打我

发表评论