Files
STM32F103/STM32F103C8T6/Drivers/BSP/LCD/st7735s.c

622 lines
16 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驱动
* 模块功能提供128x160 RGB TFT屏幕的初始化、画点、画线、填充、显示字符串等功能
* 适用平台STM32F103C8T6 + SPI2
* 作者:王建锋
* 创建日期2026-07-13
* 修改记录:
* 2026-07-13 王建锋 创建初始版本
*/
#include "st7735s.h"
#include "lcd_data.h"
#include "spi.h"
#include <stdio.h>
#include <string.h>
static uint16_t s_lcd_width = LCD_WIDTH;
static uint16_t s_lcd_height = LCD_HEIGHT;
extern DMA_HandleTypeDef hdma_spi2_tx;
/* 8x16 ASCII字体ASCII 32-126每字符16字节 - 定义在 lcd_data.c 中 */
/*
* 函数功能软件SPI写一个字节
* 入口参数data - 要发送的数据
* 返回值:无
* 函数说明模拟SPI时序发送一个字节MSB先
*/
static void st7735s_spi_write_byte(uint8_t data)
{
uint8_t i;
for (i = 0; i < 8; i++) {
HAL_GPIO_WritePin(LCD_SCL_PORT, LCD_SCL_PIN, GPIO_PIN_RESET);
if (data & 0x80) {
HAL_GPIO_WritePin(LCD_SDA_PORT, LCD_SDA_PIN, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(LCD_SDA_PORT, LCD_SDA_PIN, GPIO_PIN_RESET);
}
__NOP();
__NOP();
HAL_GPIO_WritePin(LCD_SCL_PORT, LCD_SCL_PIN, GPIO_PIN_SET);
__NOP();
__NOP();
data <<= 1;
}
}
/*
* 函数功能:写入命令
* 入口参数cmd - 命令字节
* 返回值:无
* 函数说明拉低DC选择芯片发送命令释放芯片
*/
static 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);
}
/*
* 函数功能:写入数据
* 入口参数data - 数据字节
* 返回值:无
* 函数说明拉高DC选择芯片发送数据释放芯片
*/
static 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);
}
/*
* 函数功能写入多字节数据CS保持低
* 入口参数p_data - 数据缓冲区指针
* len - 字节数
* 返回值:无
* 函数说明用于连续写入多个数据字节省去中间CS跳变
*/
static void st7735s_write_data_multi(const uint8_t *p_data, uint16_t len)
{
uint16_t i;
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
for (i = 0; i < len; i++) {
st7735s_spi_write_byte(p_data[i]);
}
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能写入16位颜色数据
* 入口参数p_color - 16位颜色缓冲区指针
* len - 像素个数
* 返回值:无
* 函数说明MSB先发送RGB565数据
*/
static void st7735s_write_colors(uint16_t *p_color, uint16_t len)
{
uint16_t i;
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET);
for (i = 0; i < len; i++) {
st7735s_spi_write_byte((uint8_t)(p_color[i] >> 8));
st7735s_spi_write_byte((uint8_t)(p_color[i] & 0xFF));
}
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
}
/*
* 函数功能LCD初始化
* 入口参数:无
* 返回值:无
* 函数说明执行ST7735S标准初始化序列
*/
void st7735s_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
printf("LCD init start (soft SPI)...\r\n");
/* 将SCL和SDA引脚切换为GPIO输出软件SPI */
GPIO_InitStruct.Pin = LCD_SCL_PIN | LCD_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(LCD_SCL_PORT, LCD_SCL_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LCD_SDA_PORT, LCD_SDA_PIN, GPIO_PIN_SET);
/* 确保CS和RST初始为高避免LCD在初始化期间被错误选中 */
HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_RESET);
HAL_Delay(10);
printf("IO: RST=%d DC=%d CS=%d\r\n",
(int)HAL_GPIO_ReadPin(LCD_RST_PORT, LCD_RST_PIN),
(int)HAL_GPIO_ReadPin(LCD_DC_PORT, LCD_DC_PIN),
(int)HAL_GPIO_ReadPin(LCD_CS_PORT, LCD_CS_PIN));
/* 硬件复位 */
printf("HW reset...\r\n");
HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
HAL_Delay(120);
/* 软件复位 */
printf("SW reset...\r\n");
st7735s_write_cmd(LCD_CMD_SWRESET);
HAL_Delay(150);
/* 退出睡眠模式 */
printf("Sleep out...\r\n");
st7735s_write_cmd(LCD_CMD_SLPOUT);
HAL_Delay(500);
/* 帧率控制 */
printf("Frame rate...\r\n");
st7735s_write_cmd(LCD_CMD_FRMCTR1);
st7735s_write_data(0x01);
st7735s_write_data(0x2C);
st7735s_write_data(0x2D);
st7735s_write_cmd(LCD_CMD_FRMCTR2);
st7735s_write_data(0x01);
st7735s_write_data(0x2C);
st7735s_write_data(0x2D);
st7735s_write_cmd(LCD_CMD_FRMCTR3);
st7735s_write_data(0x01);
st7735s_write_data(0x2C);
st7735s_write_data(0x2D);
st7735s_write_data(0x01);
st7735s_write_data(0x2C);
st7735s_write_data(0x2D);
/* 显示反转控制 */
st7735s_write_cmd(LCD_CMD_INVCTR);
st7735s_write_data(0x07);
/* 功率控制 */
printf("Power ctrl...\r\n");
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(0x0A);
st7735s_write_data(0x00);
st7735s_write_cmd(LCD_CMD_PWCTR4);
st7735s_write_data(0x8A);
st7735s_write_data(0x2A);
st7735s_write_cmd(LCD_CMD_PWCTR5);
st7735s_write_data(0x8A);
st7735s_write_data(0xEE);
/* VCOM控制 */
st7735s_write_cmd(LCD_CMD_VMCTR1);
st7735s_write_data(0x0E);
/* 竖屏模式 */
printf("MADCTL...\r\n");
st7735s_write_cmd(LCD_CMD_MADCTL);
st7735s_write_data(0xC8);
/* 像素格式: 16位RGB565 */
printf("COLMOD...\r\n");
st7735s_write_cmd(LCD_CMD_COLMOD);
st7735s_write_data(0x05);
/* Gamma校正 */
printf("Gamma...\r\n");
st7735s_write_cmd(LCD_CMD_GMCTRP1);
st7735s_write_data(0x02);
st7735s_write_data(0x1C);
st7735s_write_data(0x07);
st7735s_write_data(0x12);
st7735s_write_data(0x37);
st7735s_write_data(0x32);
st7735s_write_data(0x29);
st7735s_write_data(0x2D);
st7735s_write_data(0x29);
st7735s_write_data(0x25);
st7735s_write_data(0x2B);
st7735s_write_data(0x39);
st7735s_write_data(0x00);
st7735s_write_data(0x01);
st7735s_write_data(0x03);
st7735s_write_data(0x10);
st7735s_write_cmd(LCD_CMD_GMCTRN1);
st7735s_write_data(0x03);
st7735s_write_data(0x1D);
st7735s_write_data(0x07);
st7735s_write_data(0x06);
st7735s_write_data(0x2E);
st7735s_write_data(0x2C);
st7735s_write_data(0x29);
st7735s_write_data(0x2D);
st7735s_write_data(0x2E);
st7735s_write_data(0x2E);
st7735s_write_data(0x37);
st7735s_write_data(0x3F);
st7735s_write_data(0x00);
st7735s_write_data(0x00);
st7735s_write_data(0x02);
st7735s_write_data(0x10);
/* 关闭反转 */
st7735s_write_cmd(0x20);
/* 进入正常显示模式(关键!) */
printf("NORON...\r\n");
st7735s_write_cmd(0x13);
HAL_Delay(10);
/* 开启显示 */
printf("DISPON...\r\n");
st7735s_write_cmd(LCD_CMD_DISPON);
HAL_Delay(100);
printf("LCD init done\r\n");
}
/*
* 函数功能:设置显示窗口
* 入口参数x1 - 起始列
* y1 - 起始行
* x2 - 结束列
* y2 - 结束行
* 返回值:无
* 函数说明:设置后续写入操作的窗口区域
*/
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((uint8_t)x1);
st7735s_write_data(0x00);
st7735s_write_data((uint8_t)x2);
st7735s_write_cmd(LCD_CMD_RASET);
st7735s_write_data(0x00);
st7735s_write_data((uint8_t)y1);
st7735s_write_data(0x00);
st7735s_write_data((uint8_t)y2);
st7735s_write_cmd(LCD_CMD_RAMWR);
}
/*
* 函数功能:填充矩形区域
* 入口参数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 pixel_count;
uint16_t i;
uint16_t buf[64];
if (x1 > x2) {
uint16_t t = x1;
x1 = x2;
x2 = t;
}
if (y1 > y2) {
uint16_t t = y1;
y1 = y2;
y2 = t;
}
pixel_count = (uint32_t)(x2 - x1 + 1) * (y2 - y1 + 1);
/* 预填充颜色缓冲区 */
for (i = 0; i < 64; i++) {
buf[i] = color;
}
st7735s_set_window(x1, y1, x2, y2);
/* 分块发送 */
while (pixel_count >= 64) {
st7735s_write_colors(buf, 64);
pixel_count -= 64;
}
if (pixel_count > 0) {
st7735s_write_colors(buf, (uint16_t)pixel_count);
}
}
/*
* 函数功能:全屏填充
* 入口参数color - 填充颜色 (RGB565)
* 返回值:无
* 函数说明:用指定颜色填充整个屏幕
*/
void st7735s_fill_screen(uint16_t color)
{
printf("fill_screen 0x%04X\r\n", color);
st7735s_fill_rect(0, 0, s_lcd_width - 1, s_lcd_height - 1, color);
}
/*
* 函数功能:画点
* 入口参数x - 列坐标
* y - 行坐标
* color - 颜色 (RGB565)
* 返回值:无
* 函数说明:在指定位置画一个点
*/
void st7735s_draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{
if (x >= s_lcd_width || y >= s_lcd_height) {
return;
}
st7735s_set_window(x, y, x, y);
st7735s_write_data((uint8_t)(color >> 8));
st7735s_write_data((uint8_t)color);
}
/*
* 函数功能:画线
* 入口参数x1 - 起始列
* y1 - 起始行
* x2 - 结束列
* y2 - 结束行
* color - 颜色 (RGB565)
* 返回值:无
* 函数说明画一条直线Bresenham算法
*/
void st7735s_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
int16_t dx;
int16_t dy;
int16_t sx;
int16_t sy;
int16_t err;
int16_t e2;
uint16_t x;
uint16_t y;
if (x1 == x2) {
/* 垂直线 */
if (y1 > y2) {
y = y1;
y1 = y2;
y2 = y;
}
st7735s_fill_rect(x1, y1, x1, y2, color);
return;
}
if (y1 == y2) {
/* 水平线 */
if (x1 > x2) {
x = x1;
x1 = x2;
x2 = x;
}
st7735s_fill_rect(x1, y1, x2, y1, color);
return;
}
dx = (int16_t)x2 - (int16_t)x1;
if (dx < 0) {
dx = -dx;
}
sx = x1 < x2 ? 1 : -1;
dy = (int16_t)y2 - (int16_t)y1;
if (dy < 0) {
dy = -dy;
}
sy = y1 < y2 ? 1 : -1;
err = (dx > dy ? dx : -dy) / 2;
x = x1;
y = y1;
while (1) {
st7735s_draw_pixel(x, y, color);
if (x == x2 && y == y2) {
break;
}
e2 = err;
if (e2 > -dx) {
err -= dy;
x += sx;
}
if (e2 < dy) {
err += dx;
y += sy;
}
}
}
/*
* 函数功能:画矩形
* 入口参数x - 左上角列
* y - 左上角行
* width - 宽度
* height - 高度
* color - 颜色 (RGB565)
* 返回值:无
* 函数说明:画一个空心矩形
*/
void st7735s_draw_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
st7735s_draw_line(x, y, x + width - 1, y, color);
st7735s_draw_line(x, y + height - 1, x + width - 1, y + height - 1, color);
st7735s_draw_line(x, y, x, y + height - 1, color);
st7735s_draw_line(x + width - 1, y, x + width - 1, y + height - 1, color);
}
/*
* 函数功能:画圆
* 入口参数x0 - 圆心列
* y0 - 圆心行
* radius - 半径
* color - 颜色 (RGB565)
* 返回值:无
* 函数说明画一个空心圆Bresenham算法
*/
void st7735s_draw_circle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t color)
{
int16_t f = 1 - radius;
int16_t ddf_x = 1;
int16_t ddf_y = -2 * radius;
int16_t x = 0;
int16_t y = radius;
st7735s_draw_pixel(x0, y0 + radius, color);
st7735s_draw_pixel(x0, y0 - radius, color);
st7735s_draw_pixel(x0 + radius, y0, color);
st7735s_draw_pixel(x0 - radius, y0, color);
while (x < y) {
if (f >= 0) {
y--;
ddf_y += 2;
f += ddf_y;
}
x++;
ddf_x += 2;
f += ddf_x;
st7735s_draw_pixel(x0 + x, y0 + y, color);
st7735s_draw_pixel(x0 - x, y0 + y, color);
st7735s_draw_pixel(x0 + x, y0 - y, color);
st7735s_draw_pixel(x0 - x, y0 - y, color);
st7735s_draw_pixel(x0 + y, y0 + x, color);
st7735s_draw_pixel(x0 - y, y0 + x, color);
st7735s_draw_pixel(x0 + y, y0 - x, color);
st7735s_draw_pixel(x0 - y, y0 - x, color);
}
}
/*
* 函数功能:显示字符
* 入口参数x - 列坐标
* y - 行坐标
* ch - 字符 (ASCII 32-126)
* color - 字符颜色 (RGB565)
* bg_color - 背景颜色 (RGB565)
* 返回值:无
* 函数说明在指定位置显示一个8x16 ASCII字符
*/
void st7735s_draw_char(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bg_color)
{
uint16_t i;
uint16_t j;
uint8_t line;
if (ch < 32 || ch > 126) {
ch = ' ';
}
for (i = 0; i < 16; i++) {
line = LCD_F8x16[ch - 32][i];
for (j = 0; j < 8; j++) {
if (line & 0x80) {
st7735s_draw_pixel(x + j, y + i, color);
} else {
st7735s_draw_pixel(x + j, y + i, bg_color);
}
line <<= 1;
}
}
}
/*
* 函数功能:显示字符串
* 入口参数x - 列坐标
* y - 行坐标
* str - 字符串指针
* color - 字符颜色 (RGB565)
* bg_color - 背景颜色 (RGB565)
* 返回值:无
* 函数说明:在指定位置显示字符串
*/
void st7735s_draw_string(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bg_color)
{
while (*str) {
if (x + 8 > s_lcd_width) {
x = 0;
y += 16;
}
if (y + 16 > s_lcd_height) {
break;
}
st7735s_draw_char(x, y, *str, color, bg_color);
x += FONT_WIDTH_8;
str++;
}
}
/*
* 函数功能:设置屏幕方向
* 入口参数rotation - 方向 (0-3)
* 返回值:无
* 函数说明0:竖屏 1:横屏 2:竖屏反转 3:横屏反转
*/
void st7735s_set_rotation(uint8_t rotation)
{
st7735s_write_cmd(LCD_CMD_MADCTL);
switch (rotation) {
case 0:
st7735s_write_data(0xC8);
s_lcd_width = 128;
s_lcd_height = 160;
break;
case 1:
st7735s_write_data(0x78);
s_lcd_width = 160;
s_lcd_height = 128;
break;
case 2:
st7735s_write_data(0x08);
s_lcd_width = 128;
s_lcd_height = 160;
break;
case 3:
st7735s_write_data(0xA8);
s_lcd_width = 160;
s_lcd_height = 128;
break;
default:
break;
}
}
/*
* 函数功能:设置背光
* 入口参数state - 1:开 0:关
* 返回值:无
* 函数说明控制LCD背光如有硬件背光控制
*/
void st7735s_backlight(uint8_t state)
{
(void)state;
/* 当前硬件未连接背光控制引脚,预留接口 */
}