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[] = {...};
posted @ 2026-05-08 12:46  小前端攻城狮  阅读(54)  评论(0)    收藏  举报