Files
STM32F103/STM32F103C8T6/Drivers/BSP/LCD/st7735s.c
2026-07-14 17:51:39 +08:00

390 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称ST7735S LCD驱动底层
* 模块功能提供ST7735S屏幕的硬件SPI通信、初始化、填充、画点、方向控制等底层操作
* 绘图函数见 lcd.c
* 适用平台STM32F103C8T6 + 硬件SPI2
* 作者:王建锋
* 创建日期2026-07-13
* 修改记录:
* 2026-07-13 王建锋 创建初始版本
* 2026-07-14 王建锋 软件SPI -> 硬件SPI2
* 2026-07-14 王建锋 拆分:绘图函数移入 lcd.c
*/
#include "st7735s.h"
#include "spi.h"
#include <stdio.h>
/*
* 部分屏幕厂家虽然标称128x160但实际使用132x162驱动晶片
* 左右各偏移2列上下偏移1行才能正确显示。
* 根据自己的屏幕实测调整这两个值。
*/
#define X_OFFSET 2
#define Y_OFFSET 1
uint16_t s_lcd_width = LCD_WIDTH;
uint16_t s_lcd_height = LCD_HEIGHT;
/*
* 函数功能硬件SPI写一个字节
* 入口参数data - 要发送的数据
* 返回值:无
* 函数说明使用SPI2外设发送一个字节
*/
void st7735s_spi_write_byte(uint8_t data)
{
HAL_SPI_Transmit(&hspi2, &data, 1, HAL_MAX_DELAY);
}
/*
* 函数功能硬件SPI批量写数据
* 入口参数data - 数据缓冲区
* len - 字节数
* 返回值:无
* 函数说明使用DMA批量发送
*/
void st7735s_spi_write_bulk(const uint8_t *data, uint32_t len)
{
HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)data, len);
while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
}
/*
* 函数功能写入命令CS+DC管理单字节
* 入口参数cmd - 命令字节
* 返回值:无
* 函数说明拉低DC发送命令
*/
void st7735s_write_cmd(uint8_t cmd)
{
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_RESET);
st7735s_spi_write_byte(cmd);
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能写入数据CS+DC管理单字节
* 入口参数data - 数据字节
* 返回值:无
* 函数说明拉高DC发送数据
*/
void st7735s_write_data(uint8_t data)
{
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
st7735s_spi_write_byte(data);
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能:设置显示窗口(框选区域)
* 入口参数x1 - 起始列(屏幕坐标,含偏移处理)
* y1 - 起始行
* x2 - 结束列
* y2 - 结束行
* 返回值:无
* 函数说明发送CASET(2Ah)+RASET(2Bh)+RAMWR(2Ch)
* 后续写入的数据将填充在此区域内
*/
void st7735s_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
st7735s_write_cmd(LCD_CMD_CASET);
st7735s_write_data(0x00);
st7735s_write_data(x1 + X_OFFSET);
st7735s_write_data(0x00);
st7735s_write_data(x2 + X_OFFSET);
st7735s_write_cmd(LCD_CMD_RASET);
st7735s_write_data(0x00);
st7735s_write_data(y1 + Y_OFFSET);
st7735s_write_data(0x00);
st7735s_write_data(y2 + Y_OFFSET);
st7735s_write_cmd(LCD_CMD_RAMWR);
}
/*
* 函数功能LCD初始化
* 入口参数:无
* 返回值:无
* 函数说明初始化ST7735S屏幕依赖MX_SPI2_Init()提前配置好SPI2
*/
void st7735s_init(void)
{
printf("LCD init start (HW SPI2)...\r\n");
/* CS初始高电平 */
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
/* 硬件复位 */
HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(20);
HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
HAL_Delay(150);
/* 软件复位 */
st7735s_write_cmd(LCD_CMD_SWRESET);
HAL_Delay(150);
/* 退出睡眠模式 */
st7735s_write_cmd(LCD_CMD_SLPOUT);
HAL_Delay(120);
/* 帧率控制 */
st7735s_write_cmd(LCD_CMD_FRMCTR1);
st7735s_write_data(0x05);
st7735s_write_data(0x3C);
st7735s_write_data(0x3C);
st7735s_write_cmd(LCD_CMD_FRMCTR2);
st7735s_write_data(0x05);
st7735s_write_data(0x3C);
st7735s_write_data(0x3C);
st7735s_write_cmd(LCD_CMD_FRMCTR3);
st7735s_write_data(0x05);
st7735s_write_data(0x3C);
st7735s_write_data(0x3C);
st7735s_write_data(0x05);
st7735s_write_data(0x3C);
st7735s_write_data(0x3C);
/* 显示反转控制(列反转) */
st7735s_write_cmd(LCD_CMD_INVCTR);
st7735s_write_data(0x03);
/* 功率控制 */
st7735s_write_cmd(LCD_CMD_PWCTR1);
st7735s_write_data(0xA2);
st7735s_write_data(0x02);
st7735s_write_data(0x84);
st7735s_write_cmd(LCD_CMD_PWCTR2);
st7735s_write_data(0xC5);
st7735s_write_cmd(LCD_CMD_PWCTR3);
st7735s_write_data(0x0D);
st7735s_write_data(0x00);
st7735s_write_cmd(LCD_CMD_PWCTR4);
st7735s_write_data(0x8D);
st7735s_write_data(0x2A);
st7735s_write_cmd(LCD_CMD_PWCTR5);
st7735s_write_data(0x8D);
st7735s_write_data(0xEE);
/* VCOM控制 */
st7735s_write_cmd(LCD_CMD_VMCTR1);
st7735s_write_data(0x0E);
/* 关闭反转显示 */
st7735s_write_cmd(0x20);
/* 关闭空闲模式 */
st7735s_write_cmd(0x38);
/* 正常模式(非部分模式) */
st7735s_write_cmd(0x13);
/* 存储器访问控制 (MADCTL)
* MY=0 MX=0 MV=0 ML=0 RGB=0 MH=0 → 0x00
* 左上角为坐标原点,列从左到右,行从上到下
*/
st7735s_write_cmd(LCD_CMD_MADCTL);
st7735s_write_data(0x00);
/* 像素格式16位 RGB565 */
st7735s_write_cmd(LCD_CMD_COLMOD);
st7735s_write_data(0x05);
/* Gamma校正 */
st7735s_write_cmd(LCD_CMD_GMCTRP1);
st7735s_write_data(0x0F);
st7735s_write_data(0x1A);
st7735s_write_data(0x0F);
st7735s_write_data(0x18);
st7735s_write_data(0x2F);
st7735s_write_data(0x28);
st7735s_write_data(0x22);
st7735s_write_data(0x26);
st7735s_write_data(0x31);
st7735s_write_data(0x1B);
st7735s_write_data(0x13);
st7735s_write_data(0x1E);
st7735s_write_data(0x13);
st7735s_write_data(0x11);
st7735s_write_data(0x06);
st7735s_write_cmd(LCD_CMD_GMCTRN1);
st7735s_write_data(0x0F);
st7735s_write_data(0x1B);
st7735s_write_data(0x0F);
st7735s_write_data(0x17);
st7735s_write_data(0x33);
st7735s_write_data(0x2C);
st7735s_write_data(0x29);
st7735s_write_data(0x2E);
st7735s_write_data(0x30);
st7735s_write_data(0x30);
st7735s_write_data(0x39);
st7735s_write_data(0x3F);
st7735s_write_data(0x34);
st7735s_write_data(0x14);
st7735s_write_data(0x06);
HAL_Delay(10);
/* 显示开启 */
st7735s_write_cmd(LCD_CMD_DISPON);
HAL_Delay(100);
printf("LCD init OK\r\n");
}
/*
* 函数功能:全屏填充
* 入口参数color - 填充颜色 (RGB565)
* 返回值:无
* 函数说明:用指定颜色填充整个屏幕
*/
void st7735s_fill_screen(uint16_t color)
{
uint32_t i;
uint32_t total = (uint32_t)s_lcd_width * s_lcd_height;
uint8_t buf[32];
uint8_t hi = (uint8_t)(color >> 8);
uint8_t lo = (uint8_t)(color & 0xFF);
for (i = 0; i < sizeof(buf) / 2; i++) {
buf[i * 2] = hi;
buf[i * 2 + 1] = lo;
}
st7735s_set_window(0, 0, s_lcd_width - 1, s_lcd_height - 1);
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
i = total * 2;
while (i > 0) {
uint32_t n = (i > sizeof(buf)) ? sizeof(buf) : i;
st7735s_spi_write_bulk(buf, n);
i -= n;
}
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能:填充矩形区域
* 入口参数x1 - 起始列
* y1 - 起始行
* x2 - 结束列
* y2 - 结束行
* color - 填充颜色 (RGB565)
* 返回值:无
* 函数说明:用指定颜色填充矩形区域
*/
void st7735s_fill_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
uint32_t i;
uint32_t total;
uint8_t buf[32];
uint8_t hi = (uint8_t)(color >> 8);
uint8_t lo = (uint8_t)(color & 0xFF);
if (x1 > x2) { uint16_t t = x1; x1 = x2; x2 = t; }
if (y1 > y2) { uint16_t t = y1; y1 = y2; y2 = t; }
for (i = 0; i < sizeof(buf) / 2; i++) {
buf[i * 2] = hi;
buf[i * 2 + 1] = lo;
}
total = (uint32_t)(x2 - x1 + 1) * (y2 - y1 + 1);
st7735s_set_window(x1, y1, x2, y2);
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
i = total * 2;
while (i > 0) {
uint32_t n = (i > sizeof(buf)) ? sizeof(buf) : i;
st7735s_spi_write_bulk(buf, n);
i -= n;
}
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能:画点
* 入口参数x - 列坐标
* y - 行坐标
* color - 颜色 (RGB565)
* 返回值:无
* 函数说明:在指定位置画一个点
*/
void st7735s_draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{
st7735s_set_window(x, y, x, y);
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
st7735s_spi_write_byte((uint8_t)(color >> 8));
st7735s_spi_write_byte((uint8_t)(color & 0xFF));
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能:设置屏幕方向
* 入口参数rotation - 方向 (0-3)
* 返回值:无
* 函数说明通过修改MADCTL(36h)寄存器控制显示方向
* 0: 竖屏 1: 横屏 2: 竖屏反转 3: 横屏反转
*/
void st7735s_set_rotation(uint8_t rotation)
{
uint8_t madctl = 0xC0;
switch (rotation) {
case 0:
madctl = 0xC0;
s_lcd_width = LCD_WIDTH;
s_lcd_height = LCD_HEIGHT;
break;
case 1:
madctl = 0xA0;
s_lcd_width = LCD_HEIGHT;
s_lcd_height = LCD_WIDTH;
break;
case 2:
madctl = 0x00;
s_lcd_width = LCD_WIDTH;
s_lcd_height = LCD_HEIGHT;
break;
case 3:
madctl = 0x60;
s_lcd_width = LCD_HEIGHT;
s_lcd_height = LCD_WIDTH;
break;
default:
break;
}
st7735s_write_cmd(LCD_CMD_MADCTL);
st7735s_write_data(madctl);
}
/*
* 函数功能:设置背光
* 入口参数state - 1:开 0:关
* 返回值:无
* 函数说明通过PC13控制背光如果有背光控制引脚则修改
*/
void st7735s_backlight(uint8_t state)
{
if (state) {
printf("backlight on\r\n");
} else {
printf("backlight off\r\n");
}
}