/* * 模块名称: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 /* * 部分屏幕厂家虽然标称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"); } }