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显示不会丢失颜色信息)。