390 lines
10 KiB
C
390 lines
10 KiB
C
/*
|
||
* 模块名称: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");
|
||
}
|
||
}
|