STM32F030 SPI驱动ST7735S LCD实现
一、硬件连接配置
1.1 引脚定义(STM32F030F4P6最小系统)
ST7735S LCD模块 STM32F030F4P6
─────────────────────────────────
VCC → 3.3V
GND → GND
SCL → PA5 (SPI1_SCK)
SDA → PA7 (SPI1_MOSI)
RES → PA2 (复位)
DC → PA3 (数据/命令)
CS → PA4 (SPI1_NSS)
BL → PA1 (背光控制)
1.2 硬件特性
- MCU: STM32F030F4P6(16KB Flash,4KB RAM)
- LCD: ST7735S 1.8寸TFT(128×160分辨率)
- SPI: 最高15MHz(实际设置8MHz)
- 颜色格式: RGB565(16位色)
二、完整源码实现
2.1 头文件(st7735s.h)
/**
* @file st7735s.h
* @brief ST7735S LCD驱动头文件
*/
#ifndef __ST7735S_H
#define __ST7735S_H
#include "stm32f0xx.h"
#include <stdint.h>
/* 屏幕尺寸定义 */
#define ST7735S_WIDTH 128
#define ST7735S_HEIGHT 160
/* 颜色定义(RGB565格式) */
#define COLOR_BLACK 0x0000
#define COLOR_WHITE 0xFFFF
#define COLOR_RED 0xF800
#define COLOR_GREEN 0x07E0
#define COLOR_BLUE 0x001F
#define COLOR_YELLOW 0xFFE0
#define COLOR_CYAN 0x07FF
#define COLOR_MAGENTA 0xF81F
/* 控制引脚定义 */
#define ST7735S_CS_PORT GPIOA
#define ST7735S_CS_PIN GPIO_PIN_4
#define ST7735S_DC_PORT GPIOA
#define ST7735S_DC_PIN GPIO_PIN_3
#define ST7735S_RST_PORT GPIOA
#define ST7735S_RST_PIN GPIO_PIN_2
#define ST7735S_BL_PORT GPIOA
#define ST7735S_BL_PIN GPIO_PIN_1
/* 命令定义 */
#define ST7735S_SWRESET 0x01
#define ST7735S_SLPOUT 0x11
#define ST7735S_DISPOFF 0x28
#define ST7735S_DISPON 0x29
#define ST7735S_CASET 0x2A
#define ST7735S_PASET 0x2B
#define ST7735S_RAMWR 0x2C
#define ST7735S_MADCTL 0x36
#define ST7735S_COLMOD 0x3A
#define ST7735S_FRMCTR1 0xB1
#define ST7735S_PWCTR1 0xC0
#define ST7735S_PWCTR2 0xC1
#define ST7735S_VMCTR1 0xC5
#define ST7735S_GMCTRP1 0xE0
#define ST7735S_GMCTRN1 0xE1
/* 函数声明 */
void ST7735S_Init(void);
void ST7735S_Clear(uint16_t color);
void ST7735S_DrawPixel(uint16_t x, uint16_t y, uint16_t color);
void ST7735S_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void ST7735S_DrawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);
void ST7735S_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);
void ST7735S_DrawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void ST7735S_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bg_color);
void ST7735S_ShowString(uint16_t x, uint16_t y, char *str, uint16_t color, uint16_t bg_color);
void ST7735S_Backlight(uint8_t on);
#endif /* __ST7735S_H */
2.2 SPI驱动实现(spi.c)
/**
* @file spi.c
* @brief STM32F030 SPI1驱动实现
*/
#include "spi.h"
#include "delay.h"
/* SPI初始化 */
void SPI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
/* 1. 使能时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* 2. 配置GPIO引脚 */
// PA5: SPI1_SCK, PA7: SPI1_MOSI, PA4: SPI1_NSS
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置控制引脚(普通GPIO输出)
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 3. 配置SPI参数 */
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // CPOL=0
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // CPHA=0
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // 软件控制NSS
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 8MHz (16MHz/2)
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);
/* 4. 使能SPI */
SPI_Cmd(SPI1, ENABLE);
/* 5. 默认拉高CS和DC */
GPIO_SetBits(GPIOA, GPIO_PIN_4); // CS高
GPIO_SetBits(GPIOA, GPIO_PIN_3); // DC高
}
/* SPI发送单字节 */
void SPI_SendByte(uint8_t data)
{
/* 等待发送缓冲区空 */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* 发送数据 */
SPI_SendData8(SPI1, data);
/* 等待接收完成(清除接收缓冲区) */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
SPI_ReceiveData8(SPI1); // 读取并丢弃接收到的数据
}
/* SPI发送多字节 */
void SPI_SendBytes(uint8_t *data, uint16_t len)
{
for (uint16_t i = 0; i < len; i++) {
SPI_SendByte(data[i]);
}
}
2.3 ST7735S驱动实现(st7735s.c)
/**
* @file st7735s.c
* @brief ST7735S LCD驱动实现
*/
#include "st7735s.h"
#include "spi.h"
#include "delay.h"
/* 私有函数 */
static void ST7735S_WriteCommand(uint8_t cmd);
static void ST7735S_WriteData(uint8_t data);
static void ST7735S_WriteData16(uint16_t data);
static void ST7735S_SetAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
static void ST7735S_DelayMs(uint32_t ms);
/* 写命令 */
static void ST7735S_WriteCommand(uint8_t cmd)
{
GPIO_ResetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS低
GPIO_ResetBits(ST7735S_DC_PORT, ST7735S_DC_PIN); // DC低(命令)
SPI_SendByte(cmd);
GPIO_SetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS高
}
/* 写数据 */
static void ST7735S_WriteData(uint8_t data)
{
GPIO_ResetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS低
GPIO_SetBits(ST7735S_DC_PORT, ST7735S_DC_PIN); // DC高(数据)
SPI_SendByte(data);
GPIO_SetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS高
}
/* 写16位数据 */
static void ST7735S_WriteData16(uint16_t data)
{
GPIO_ResetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS低
GPIO_SetBits(ST7735S_DC_PORT, ST7735S_DC_PIN); // DC高(数据)
SPI_SendByte(data >> 8); // 高字节
SPI_SendByte(data & 0xFF); // 低字节
GPIO_SetBits(ST7735S_CS_PORT, ST7735S_CS_PIN); // CS高
}
/* 设置显示区域 */
static void ST7735S_SetAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
/* 设置列地址 */
ST7735S_WriteCommand(ST7735S_CASET);
ST7735S_WriteData16(x0);
ST7735S_WriteData16(x1);
/* 设置行地址 */
ST7735S_WriteCommand(ST7735S_PASET);
ST7735S_WriteData16(y0);
ST7735S_WriteData16(y1);
/* 准备写GRAM */
ST7735S_WriteCommand(ST7735S_RAMWR);
}
/* 延时函数 */
static void ST7735S_DelayMs(uint32_t ms)
{
Delay_Ms(ms);
}
/* ST7735S初始化 */
void ST7735S_Init(void)
{
/* 1. 硬件复位 */
GPIO_SetBits(ST7735S_RST_PORT, ST7735S_RST_PIN);
ST7735S_DelayMs(100);
GPIO_ResetBits(ST7735S_RST_PORT, ST7735S_RST_PIN);
ST7735S_DelayMs(100);
GPIO_SetBits(ST7735S_RST_PORT, ST7735S_RST_PIN);
ST7735S_DelayMs(120);
/* 2. 软件复位 */
ST7735S_WriteCommand(ST7735S_SWRESET);
ST7735S_DelayMs(120);
/* 3. 退出睡眠模式 */
ST7735S_WriteCommand(ST7735S_SLPOUT);
ST7735S_DelayMs(120);
/* 4. 帧率控制 */
ST7735S_WriteCommand(ST7735S_FRMCTR1);
ST7735S_WriteData(0x01);
ST7735S_WriteData(0x2C);
ST7735S_WriteData(0x2D);
/* 5. 电源控制 */
ST7735S_WriteCommand(ST7735S_PWCTR1);
ST7735S_WriteData(0xA2);
ST7735S_WriteData(0x02);
ST7735S_WriteData(0x84);
ST7735S_WriteCommand(ST7735S_PWCTR2);
ST7735S_WriteData(0xC5);
/* 6. VCOM控制 */
ST7735S_WriteCommand(ST7735S_VMCTR1);
ST7735S_WriteData(0x0E);
/* 7. 内存访问控制(竖屏模式) */
ST7735S_WriteCommand(ST7735S_MADCTL);
ST7735S_WriteData(0xC8); // RGB顺序,竖屏
/* 8. 颜色格式(16位色) */
ST7735S_WriteCommand(ST7735S_COLMOD);
ST7735S_WriteData(0x05); // 16位色
/* 9. Gamma校正 */
ST7735S_WriteCommand(ST7735S_GMCTRP1);
ST7735S_WriteData(0x0F);
ST7735S_WriteData(0x1A);
ST7735S_WriteData(0x0F);
ST7735S_WriteData(0x18);
ST7735S_WriteData(0x2F);
ST7735S_WriteData(0x28);
ST7735S_WriteData(0x20);
ST7735S_WriteData(0x22);
ST7735S_WriteData(0x1F);
ST7735S_WriteData(0x1B);
ST7735S_WriteData(0x23);
ST7735S_WriteData(0x37);
ST7735S_WriteData(0x00);
ST7735S_WriteData(0x07);
ST7735S_WriteData(0x02);
ST7735S_WriteData(0x10);
ST7735S_WriteCommand(ST7735S_GMCTRN1);
ST7735S_WriteData(0x0F);
ST7735S_WriteData(0x1B);
ST7735S_WriteData(0x0F);
ST7735S_WriteData(0x17);
ST7735S_WriteData(0x33);
ST7735S_WriteData(0x2C);
ST7735S_WriteData(0x29);
ST7735S_WriteData(0x2E);
ST7735S_WriteData(0x30);
ST7735S_WriteData(0x30);
ST7735S_WriteData(0x39);
ST7735S_WriteData(0x3F);
ST7735S_WriteData(0x00);
ST7735S_WriteData(0x07);
ST7735S_WriteData(0x03);
ST7735S_WriteData(0x10);
ST7735S_DelayMs(120);
/* 10. 开启显示 */
ST7735S_WriteCommand(ST7735S_DISPON);
/* 11. 开启背光 */
ST7735S_Backlight(1);
/* 12. 清屏 */
ST7735S_Clear(COLOR_BLACK);
}
/* 清屏 */
void ST7735S_Clear(uint16_t color)
{
ST7735S_FillRect(0, 0, ST7735S_WIDTH, ST7735S_HEIGHT, color);
}
/* 画点 */
void ST7735S_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
if (x >= ST7735S_WIDTH || y >= ST7735S_HEIGHT) return;
ST7735S_SetAddress(x, y, x, y);
ST7735S_WriteData16(color);
}
/* 画线 */
void ST7735S_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
int16_t dx = abs(x2 - x1);
int16_t dy = abs(y2 - y1);
int16_t sx = (x1 < x2) ? 1 : -1;
int16_t sy = (y1 < y2) ? 1 : -1;
int16_t err = dx - dy;
while (1) {
ST7735S_DrawPixel(x1, y1, color);
if (x1 == x2 && y1 == y2) break;
int16_t e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x1 += sx;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
}
}
/* 画矩形 */
void ST7735S_DrawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
ST7735S_DrawLine(x, y, x + w - 1, y, color);
ST7735S_DrawLine(x, y + h - 1, x + w - 1, y + h - 1, color);
ST7735S_DrawLine(x, y, x, y + h - 1, color);
ST7735S_DrawLine(x + w - 1, y, x + w - 1, y + h - 1, color);
}
/* 填充矩形 */
void ST7735S_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
if (x >= ST7735S_WIDTH || y >= ST7735S_HEIGHT) return;
if (x + w > ST7735S_WIDTH) w = ST7735S_WIDTH - x;
if (y + h > ST7735S_HEIGHT) h = ST7735S_HEIGHT - y;
ST7735S_SetAddress(x, y, x + w - 1, y + h - 1);
uint32_t pixel_count = w * h;
for (uint32_t i = 0; i < pixel_count; i++) {
ST7735S_WriteData16(color);
}
}
/* 画圆 */
void ST7735S_DrawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
int16_t x = r;
int16_t y = 0;
int16_t err = 1 - r;
while (x >= y) {
ST7735S_DrawPixel(x0 + x, y0 + y, color);
ST7735S_DrawPixel(x0 - x, y0 + y, color);
ST7735S_DrawPixel(x0 + x, y0 - y, color);
ST7735S_DrawPixel(x0 - x, y0 - y, color);
ST7735S_DrawPixel(x0 + y, y0 + x, color);
ST7735S_DrawPixel(x0 - y, y0 + x, color);
ST7735S_DrawPixel(x0 + y, y0 - x, color);
ST7735S_DrawPixel(x0 - y, y0 - x, color);
y++;
if (err < 0) {
err += 2 * y + 1;
} else {
x--;
err += 2 * (y - x) + 1;
}
}
}
/* 显示字符(8x16字体) */
void ST7735S_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bg_color)
{
uint8_t font[16];
uint8_t temp;
/* 获取字符点阵(简化版,实际需要字库) */
// 这里使用简化的ASCII字符点阵
static const uint8_t ascii_font[][16] = {
// 空格(0x20)
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
// 'A'(0x41)
{0x00,0x00,0x00,0x18,0x3C,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
// 'B'(0x42)
{0x00,0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00},
// '0'(0x30)
{0x00,0x00,0x00,0x3C,0x66,0x66,0x6E,0x6A,0x6A,0x6E,0x66,0x66,0x3C,0x00,0x00,0x00}
};
if (ch < 0x20 || ch > 0x7E) ch = '?';
uint8_t index = 0;
if (ch == ' ') index = 0;
else if (ch == 'A') index = 1;
else if (ch == 'B') index = 2;
else if (ch == '0') index = 3;
for (uint8_t i = 0; i < 16; i++) {
temp = ascii_font[index][i];
for (uint8_t j = 0; j < 8; j++) {
if (temp & 0x80) {
ST7735S_DrawPixel(x + j, y + i, color);
} else {
ST7735S_DrawPixel(x + j, y + i, bg_color);
}
temp <<= 1;
}
}
}
/* 显示字符串 */
void ST7735S_ShowString(uint16_t x, uint16_t y, char *str, uint16_t color, uint16_t bg_color)
{
while (*str) {
ST7735S_ShowChar(x, y, *str, color, bg_color);
x += 8;
if (x > ST7735S_WIDTH - 8) {
x = 0;
y += 16;
}
str++;
}
}
/* 背光控制 */
void ST7735S_Backlight(uint8_t on)
{
if (on) {
GPIO_SetBits(ST7735S_BL_PORT, ST7735S_BL_PIN);
} else {
GPIO_ResetBits(ST7735S_BL_PORT, ST7735S_BL_PIN);
}
}
2.4 延时函数(delay.c)
/**
* @file delay.c
* @brief 延时函数实现
*/
#include "delay.h"
static uint32_t fac_us = 0;
/* 初始化延时函数 */
void Delay_Init(void)
{
SysTick_Config(SystemCoreClock / 1000000); // 1us中断
fac_us = SystemCoreClock / 1000000;
}
/* 微秒延时 */
void Delay_Us(uint32_t us)
{
uint32_t temp;
SysTick->LOAD = us * fac_us;
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do {
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
/* 毫秒延时 */
void Delay_Ms(uint32_t ms)
{
for (uint32_t i = 0; i < ms; i++) {
Delay_Us(1000);
}
}
2.5 主程序(main.c)
/**
* @file main.c
* @brief ST7735S LCD测试程序
*/
#include "stm32f0xx.h"
#include "st7735s.h"
#include "spi.h"
#include "delay.h"
int main(void)
{
/* 1. 系统初始化 */
SystemInit();
Delay_Init();
/* 2. SPI初始化 */
SPI_Init();
/* 3. LCD初始化 */
ST7735S_Init();
/* 4. 显示测试图案 */
ST7735S_Clear(COLOR_BLACK);
/* 显示字符串 */
ST7735S_ShowString(10, 10, "STM32F030", COLOR_WHITE, COLOR_BLACK);
ST7735S_ShowString(10, 30, "ST7735S LCD", COLOR_GREEN, COLOR_BLACK);
ST7735S_ShowString(10, 50, "128x160", COLOR_BLUE, COLOR_BLACK);
/* 绘制几何图形 */
ST7735S_DrawRect(10, 80, 50, 30, COLOR_RED); // 红色矩形
ST7735S_FillRect(70, 80, 50, 30, COLOR_GREEN); // 绿色填充矩形
ST7735S_DrawCircle(40, 130, 20, COLOR_BLUE); // 蓝色圆形
ST7735S_DrawCircle(100, 130, 20, COLOR_YELLOW); // 黄色圆形
/* 绘制线条 */
ST7735S_DrawLine(0, 0, 127, 159, COLOR_CYAN); // 对角线
ST7735S_DrawLine(127, 0, 0, 159, COLOR_MAGENTA); // 对角线
/* 动态刷新测试 */
uint16_t color = COLOR_RED;
while (1) {
ST7735S_FillRect(10, 160-20, 50, 20, color);
color += 100;
if (color > COLOR_WHITE) color = COLOR_RED;
Delay_Ms(500);
}
}
三、Keil工程配置
3.1 工程设置
Target:
- Device: STM32F030F4P6
- Clock: 8MHz HSI → 48MHz PLL
- RAM: 4KB
- Flash: 16KB
C/C++:
- Define: STM32F030
- Include Paths:
.\
..\Libraries\CMSIS\Include
..\User
..\User\drivers
Linker:
- IROM1: 0x08000000, 0x4000 (16KB Flash)
- IRAM1: 0x20000000, 0x1000 (4KB RAM)
3.2 编译优化
Optimization Level: -O1
One ELF Section per Function: ✓
四、测试与调试
4.1 常见问题排查
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 屏幕无显示 | 背光未开启 | 检查BL引脚电平 |
| 显示花屏 | SPI时序不对 | 降低SPI时钟频率 |
| 颜色异常 | 颜色格式错误 | 确认使用RGB565格式 |
| 部分显示 | 初始化序列错误 | 检查ST7735S初始化命令 |
4.2 测试输出
STM32F030 ST7735S LCD Test
=====================================
显示内容:
- 黑色背景
- 白色文字:"STM32F030"
- 绿色文字:"ST7735S LCD"
- 蓝色文字:"128x160"
- 红色矩形框
- 绿色填充矩形
- 蓝黄两个圆形
- 两条对角线
- 底部动态变色矩形
参考代码 实现stm32f030 spi驱动初始化及st7735s驱动 www.youwenfan.com/contentcnu/56459.html
五、性能优化建议
5.1 SPI优化
/* 使用DMA传输大量数据 */
void ST7735S_FillRect_DMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
// 配置DMA传输,减少CPU干预
}
5.2 显示缓存
/* 使用显存缓存减少SPI传输次数 */
static uint16_t frame_buffer[ST7735S_WIDTH * ST7735S_HEIGHT];
void ST7735S_UpdateScreen(void)
{
// 一次性将整个显存刷到LCD
}
5.3 字库优化
/* 使用压缩字库节省Flash空间 */
const uint8_t font_compressed[] = {...};
浙公网安备 33010602011771号