一、系统架构设计
┌─────────────────────────────────────────────────────────────┐
│ STM32 + SHT20 + TFT 系统 │
├─────────────────────────────────────────────────────────────┤
│ SHT20传感器 │ STM32F103 │ TFT显示屏 │ 用户界面 │
│ │ │ │ │
│ • 温度测量 │ • I2C通信 │ • 320x240 │ • 数值显示 │
│ • 湿度测量 │ • 数据处理 │ • 16位色深 │ • 曲线图表 │
│ • 精度±0.3℃ │ • 算法滤波 │ • SPI接口 │ • 状态指示 │
│ • 精度±2%RH │ • 定时采集 │ • 触摸控制 │ • 数据记录 │
└─────────────────────────────────────────────────────────────┘
二、硬件连接设计
2.1 硬件连接图
STM32F103C8T6 SHT20传感器 2.4寸 TFT LCD
─────────────────────────────────────────────────────────────
PB6 (I2C1_SCL) ──────> SCL (第4脚) VCC ──────────> 3.3V
PB7 (I2C1_SDA) ──────> SDA (第3脚) GND ──────────> GND
3.3V ───────────────> VDD (第1脚) CS ──────────> PB12
GND ────────────────> GND (第2脚) RST ──────────> PB13
SCK ──────────> PB14
MISO ─────────> PB15 (可选)
MOSI ─────────> PB15
DC ──────────> PB11
BL ──────────> PB10 (背光)
2.2 电源设计
电源方案:
• SHT20: 3.3V ±0.1V,电流约1.5mA
• TFT: 3.3V,背光电流约80mA
• 总电流: < 100mA,可用USB供电
• 建议在VDD和GND间加100nF去耦电容
三、完整源码实现
3.1 SHT20 驱动头文件 (sht20.h)
c
#ifndef __SHT20_H
#define __SHT20_H
#include "stm32f10x.h"
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
// SHT20 I2C地址
#define SHT20_ADDR_WRITE 0x80 // 10000000
#define SHT20_ADDR_READ 0x81 // 10000001
// SHT20 命令定义
#define SHT20_CMD_TRIGGER_TEMP_HOLD 0xE3 // 温度测量,保持主机
#define SHT20_CMD_TRIGGER_HUMI_HOLD 0xE5 // 湿度测量,保持主机
#define SHT20_CMD_TRIGGER_TEMP_NOHOLD 0xF3 // 温度测量,不保持主机
#define SHT20_CMD_TRIGGER_HUMI_NOHOLD 0xF5 // 湿度测量,不保持主机
#define SHT20_CMD_WRITE_USER_REG 0xE6 // 写用户寄存器
#define SHT20_CMD_READ_USER_REG 0xE7 // 读用户寄存器
#define SHT20_CMD_SOFT_RESET 0xFE // 软件复位
// 用户寄存器位定义
#define SHT20_USER_REG_RESOLUTION_12_14 0x00 // 温度12位,湿度14位
#define SHT20_USER_REG_RESOLUTION_8_12 0x01 // 温度8位,湿度12位
#define SHT20_USER_REG_RESOLUTION_10_13 0x80 // 温度10位,湿度13位
#define SHT20_USER_REG_RESOLUTION_11_11 0x81 // 温度11位,湿度11位
#define SHT20_USER_REG_BATTERY_STATUS 0x40 // 电池状态位
#define SHT20_USER_REG_HEATER_ON 0x04 // 加热器开启
#define SHT20_USER_REG_HEATER_OFF 0x00 // 加热器关闭
// 测量分辨率
typedef enum {
RESOLUTION_12_14 = 0, // 温度12位(0.04°C),湿度14位(0.01%RH)
RESOLUTION_8_12, // 温度8位(0.5°C),湿度12位(0.04%RH)
RESOLUTION_10_13, // 温度10位(0.1°C),湿度13位(0.02%RH)
RESOLUTION_11_11 // 温度11位(0.2°C),湿度11位(0.1%RH)
} Resolution_t;
// 温湿度数据结构体
typedef struct {
float temperature; // 温度值 (°C)
float humidity; // 湿度值 (%RH)
uint8_t battery_low; // 电池低电压标志
uint32_t timestamp; // 时间戳
bool valid; // 数据有效性
} SHT20_Data_t;
// 校准参数结构体
typedef struct {
float temp_offset; // 温度偏移校准
float humi_offset; // 湿度偏移校准
float temp_scale; // 温度比例校准
float humi_scale; // 湿度比例校准
} SHT20_Calibration_t;
// 函数声明
bool SHT20_Init(void);
bool SHT20_SoftReset(void);
bool SHT20_ReadUserReg(uint8_t *reg_value);
bool SHT20_WriteUserReg(uint8_t reg_value);
bool SHT20_SetResolution(Resolution_t resolution);
bool SHT20_ReadTemperature(float *temperature);
bool SHT20_ReadHumidity(float *humidity);
bool SHT20_ReadTempAndHumi(SHT20_Data_t *data);
void SHT20_SetCalibration(SHT20_Calibration_t *cal);
float SHT20_GetCompensatedTemp(float raw_temp);
float SHT20_GetCompensatedHumi(float raw_humi);
#endif /* __SHT20_H */
3.2 SHT20 驱动核心 (sht20.c)
c
#include "sht20.h"
#include "i2c.h"
#include "delay.h"
static SHT20_Calibration_t sht20_cal = {0};
// I2C底层函数
static bool I2C_WriteByte(uint8_t addr, uint8_t data) {
return I2C_WriteByte_ToSlave(addr, data);
}
static bool I2C_ReadByte(uint8_t addr, uint8_t *data) {
return I2C_ReadByte_FromSlave(addr, data);
}
static bool I2C_ReadBytes(uint8_t addr, uint8_t *data, uint8_t len) {
return I2C_ReadBytes_FromSlave(addr, data, len);
}
// 初始化SHT20
bool SHT20_Init(void) {
uint8_t user_reg;
// 软件复位
if (!SHT20_SoftReset()) {
return false;
}
Delay_ms(50); // 等待复位完成
// 读取用户寄存器
if (!SHT20_ReadUserReg(&user_reg)) {
return false;
}
// 设置分辨率为12位温度,14位湿度
if (!SHT20_SetResolution(RESOLUTION_12_14)) {
return false;
}
// 关闭加热器
user_reg &= ~SHT20_USER_REG_HEATER_ON;
if (!SHT20_WriteUserReg(user_reg)) {
return false;
}
return true;
}
// 软件复位
bool SHT20_SoftReset(void) {
return I2C_WriteByte(SHT20_ADDR_WRITE, SHT20_CMD_SOFT_RESET);
}
// 读取用户寄存器
bool SHT20_ReadUserReg(uint8_t *reg_value) {
if (!I2C_WriteByte(SHT20_ADDR_WRITE, SHT20_CMD_READ_USER_REG)) {
return false;
}
return I2C_ReadByte(SHT20_ADDR_READ, reg_value);
}
// 写用户寄存器
bool SHT20_WriteUserReg(uint8_t reg_value) {
uint8_t data[2] = {SHT20_CMD_WRITE_USER_REG, reg_value};
return I2C_WriteByte(SHT20_ADDR_WRITE, data[0]) &&
I2C_WriteByte(SHT20_ADDR_WRITE, data[1]);
}
// 设置测量分辨率
bool SHT20_SetResolution(Resolution_t resolution) {
uint8_t user_reg;
if (!SHT20_ReadUserReg(&user_reg)) {
return false;
}
// 清除分辨率位
user_reg &= ~0x81;
// 设置新的分辨率
switch(resolution) {
case RESOLUTION_12_14:
user_reg |= SHT20_USER_REG_RESOLUTION_12_14;
break;
case RESOLUTION_8_12:
user_reg |= SHT20_USER_REG_RESOLUTION_8_12;
break;
case RESOLUTION_10_13:
user_reg |= SHT20_USER_REG_RESOLUTION_10_13;
break;
case RESOLUTION_11_11:
user_reg |= SHT20_USER_REG_RESOLUTION_11_11;
break;
}
return SHT20_WriteUserReg(user_reg);
}
// 读取温度
bool SHT20_ReadTemperature(float *temperature) {
uint8_t data[3];
// 发送温度测量命令
if (!I2C_WriteByte(SHT20_ADDR_WRITE, SHT20_CMD_TRIGGER_TEMP_NOHOLD)) {
return false;
}
// 等待测量完成(最大85ms)
Delay_ms(100);
// 读取温度数据
if (!I2C_ReadBytes(SHT20_ADDR_READ, data, 3)) {
return false;
}
// 检查CRC(可选)
// if (!CheckCRC(data, 2, data[2])) return false;
// 转换温度值
uint16_t temp_raw = ((uint16_t)data[0] << 8) | data[1];
temp_raw &= ~0x0003; // 清除状态位
*temperature = -46.85 + 175.72 * (float)temp_raw / 65536.0;
return true;
}
// 读取湿度
bool SHT20_ReadHumidity(float *humidity) {
uint8_t data[3];
// 发送湿度测量命令
if (!I2C_WriteByte(SHT20_ADDR_WRITE, SHT20_CMD_TRIGGER_HUMI_NOHOLD)) {
return false;
}
// 等待测量完成(最大29ms)
Delay_ms(50);
// 读取湿度数据
if (!I2C_ReadBytes(SHT20_ADDR_READ, data, 3)) {
return false;
}
// 转换湿度值
uint16_t humi_raw = ((uint16_t)data[0] << 8) | data[1];
humi_raw &= ~0x0003; // 清除状态位
*humidity = -6.0 + 125.0 * (float)humi_raw / 65536.0;
// 限制湿度范围
if (*humidity < 0.0) *humidity = 0.0;
if (*humidity > 100.0) *humidity = 100.0;
return true;
}
// 同时读取温度和湿度
bool SHT20_ReadTempAndHumi(SHT20_Data_t *data) {
if (data == NULL) return false;
// 读取温度
if (!SHT20_ReadTemperature(&data->temperature)) {
data->valid = false;
return false;
}
// 读取湿度
if (!SHT20_ReadHumidity(&data->humidity)) {
data->valid = false;
return false;
}
// 应用校准参数
data->temperature = SHT20_GetCompensatedTemp(data->temperature);
data->humidity = SHT20_GetCompensatedHumi(data->humidity);
// 读取电池状态
uint8_t user_reg;
if (SHT20_ReadUserReg(&user_reg)) {
data->battery_low = (user_reg & SHT20_USER_REG_BATTERY_STATUS) ? 1 : 0;
}
data->timestamp = Get_SystemTime();
data->valid = true;
return true;
}
// 设置校准参数
void SHT20_SetCalibration(SHT20_Calibration_t *cal) {
if (cal != NULL) {
sht20_cal = *cal;
}
}
// 温度补偿
float SHT20_GetCompensatedTemp(float raw_temp) {
return (raw_temp + sht20_cal.temp_offset) * sht20_cal.temp_scale;
}
// 湿度补偿
float SHT20_GetCompensatedHumi(float raw_humi) {
return (raw_humi + sht20_cal.humi_offset) * sht20_cal.humi_scale;
}
3.3 TFT 显示屏驱动 (tft_lcd.c)
c
#include "tft_lcd.h"
#include "spi.h"
#include "delay.h"
// TFT引脚定义
#define TFT_CS_PIN GPIO_Pin_12
#define TFT_RST_PIN GPIO_Pin_13
#define TFT_DC_PIN GPIO_Pin_11
#define TFT_BL_PIN GPIO_Pin_10
#define TFT_PORT GPIOB
// 颜色定义
uint16_t Color_Table[16] = {
BLACK, NAVY, DARKGREEN, DARKCYAN, MAROON, PURPLE, OLIVE, LIGHTGREY,
DARKGREY,YELLOW, GREEN, CYAN, RED, MAGENTA, BLUE, WHITE
};
// TFT命令
#define TFT_CMD_SWRESET 0x01
#define TFT_CMD_SLPOUT 0x11
#define TFT_CMD_DISPOFF 0x28
#define TFT_CMD_DISPON 0x29
#define TFT_CMD_CASET 0x2A
#define TFT_CMD_PASET 0x2B
#define TFT_CMD_RAMWR 0x2C
#define TFT_CMD_MADCTL 0x36
#define TFT_CMD_PIXFMT 0x3A
// GPIO控制
static inline void TFT_CS_LOW(void) { GPIO_ResetBits(TFT_PORT, TFT_CS_PIN); }
static inline void TFT_CS_HIGH(void) { GPIO_SetBits(TFT_PORT, TFT_CS_PIN); }
static inline void TFT_DC_LOW(void) { GPIO_ResetBits(TFT_PORT, TFT_DC_PIN); }
static inline void TFT_DC_HIGH(void) { GPIO_SetBits(TFT_PORT, TFT_DC_PIN); }
static inline void TFT_RST_LOW(void) { GPIO_ResetBits(TFT_PORT, TFT_RST_PIN); }
static inline void TFT_RST_HIGH(void) { GPIO_SetBits(TFT_PORT, TFT_RST_PIN); }
static inline void TFT_BL_ON(void) { GPIO_SetBits(TFT_PORT, TFT_BL_PIN); }
static inline void TFT_BL_OFF(void) { GPIO_ResetBits(TFT_PORT, TFT_BL_PIN); }
// 写命令
static void TFT_WriteCmd(uint8_t cmd) {
TFT_DC_LOW();
TFT_CS_LOW();
SPI_WriteByte(cmd);
TFT_CS_HIGH();
}
// 写数据
static void TFT_WriteData(uint8_t data) {
TFT_DC_HIGH();
TFT_CS_LOW();
SPI_WriteByte(data);
TFT_CS_HIGH();
}
static void TFT_WriteData16(uint16_t data) {
TFT_DC_HIGH();
TFT_CS_LOW();
SPI_WriteByte(data >> 8);
SPI_WriteByte(data & 0xFF);
TFT_CS_HIGH();
}
// 设置窗口
static void TFT_SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
TFT_WriteCmd(TFT_CMD_CASET);
TFT_WriteData16(x0);
TFT_WriteData16(x1);
TFT_WriteCmd(TFT_CMD_PASET);
TFT_WriteData16(y0);
TFT_WriteData16(y1);
TFT_WriteCmd(TFT_CMD_RAMWR);
}
// 画点
void TFT_DrawPoint(uint16_t x, uint16_t y, uint16_t color) {
TFT_SetWindow(x, y, x, y);
TFT_WriteData16(color);
}
// 填充矩形
void TFT_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
uint32_t i;
TFT_SetWindow(x, y, x + w - 1, y + h - 1);
TFT_DC_HIGH();
TFT_CS_LOW();
for (i = 0; i < (uint32_t)w * h; i++) {
SPI_WriteByte(color >> 8);
SPI_WriteByte(color & 0xFF);
}
TFT_CS_HIGH();
}
// 初始化TFT
void TFT_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIO
GPIO_InitStructure.GPIO_Pin = TFT_CS_PIN | TFT_RST_PIN | TFT_DC_PIN | TFT_BL_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(TFT_PORT, &GPIO_InitStructure);
// 初始化SPI
SPI_Init();
// 复位TFT
TFT_RST_LOW();
Delay_ms(100);
TFT_RST_HIGH();
Delay_ms(120);
// 初始化序列
TFT_WriteCmd(TFT_CMD_SWRESET);
Delay_ms(120);
TFT_WriteCmd(TFT_CMD_SLPOUT);
Delay_ms(120);
TFT_WriteCmd(TFT_CMD_PIXFMT);
TFT_WriteData(0x55); // 16位色
TFT_WriteCmd(TFT_CMD_MADCTL);
TFT_WriteData(0x08); // 竖屏
TFT_WriteCmd(TFT_CMD_DISPON);
Delay_ms(120);
// 开启背光
TFT_BL_ON();
// 清屏
TFT_FillRect(0, 0, TFT_WIDTH, TFT_HEIGHT, BLACK);
}
// 显示字符
void TFT_ShowChar(uint16_t x, uint16_t y, uint8_t chr, uint16_t color, uint16_t bg_color) {
uint8_t temp, t1;
uint16_t y0 = y;
chr = chr - ' '; // 得到偏移后的值
for (t1 = 0; t1 < 12; t1++) {
temp = asc2_1206[chr][t1];
for (uint8_t t = 0; t < 6; t++) {
if (temp & 0x01) {
TFT_DrawPoint(x + t, y, color);
} else {
TFT_DrawPoint(x + t, y, bg_color);
}
temp >>= 1;
}
y++;
if ((y - y0) == 12) {
y = y0;
x += 6;
}
}
}
// 显示字符串
void TFT_ShowString(uint16_t x, uint16_t y, char *str, uint16_t color, uint16_t bg_color) {
while (*str) {
TFT_ShowChar(x, y, *str, color, bg_color);
x += 6;
str++;
}
}
// 显示数字
void TFT_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint16_t color, uint16_t bg_color) {
uint8_t t, temp;
uint8_t enshow = 0;
for (t = 0; t < len; t++) {
temp = (num / (uint32_t)pow(10, len - t - 1)) % 10;
if (enshow == 0 && t < (len - 1)) {
if (temp == 0) {
TFT_ShowChar(x + t * 6, y, ' ', color, bg_color);
continue;
} else {
enshow = 1;
}
}
TFT_ShowChar(x + t * 6, y, temp + '0', color, bg_color);
}
}
// 显示浮点数
void TFT_ShowFloat(uint16_t x, uint16_t y, float num, uint8_t precision, uint16_t color, uint16_t bg_color) {
char buffer[20];
sprintf(buffer, "%.*f", precision, num);
TFT_ShowString(x, y, buffer, color, bg_color);
}
// 画圆
void TFT_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color) {
int16_t a, b;
int16_t di;
a = 0;
b = r;
di = 3 - (r << 1);
while (a <= b) {
TFT_DrawPoint(x0 + a, y0 - b, color);
TFT_DrawPoint(x0 + b, y0 - a, color);
TFT_DrawPoint(x0 + b, y0 + a, color);
TFT_DrawPoint(x0 + a, y0 + b, color);
TFT_DrawPoint(x0 - a, y0 + b, color);
TFT_DrawPoint(x0 - b, y0 + a, color);
TFT_DrawPoint(x0 - b, y0 - a, color);
TFT_DrawPoint(x0 - a, y0 - b, color);
if (di < 0) {
di += (a << 2) + 6;
} else {
di += ((a - b) << 2) + 10;
b--;
}
a++;
}
}
3.4 主程序 (main.c)
c
#include "stm32f10x.h"
#include "sht20.h"
#include "tft_lcd.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
// 系统参数
#define UPDATE_INTERVAL 2000 // 更新间隔 (ms)
#define TEMP_HISTORY_LEN 60 // 温度历史长度
// 全局变量
SHT20_Data_t env_data;
float temp_history[TEMP_HISTORY_LEN];
uint8_t history_index = 0;
// UI界面元素
typedef struct {
uint16_t x, y, w, h;
uint16_t bg_color;
uint16_t border_color;
char title[32];
} UI_Box_t;
UI_Box_t temp_box = {10, 30, 140, 80, DARKBLUE, WHITE, "Temperature"};
UI_Box_t humi_box = {170, 30, 140, 80, DARKGREEN, WHITE, "Humidity"};
UI_Box_t status_box = {10, 130, 300, 60, BLACK, WHITE, "System Status"};
// 初始化系统
void System_Init(void) {
SystemClock_Init();
Delay_Init();
USART_Init(115200);
LED_Init();
printf("STM32 + SHT20 Temperature & Humidity Monitor\r\n");
printf("Initializing...\r\n");
// 初始化TFT
TFT_Init();
printf("TFT LCD Initialized\r\n");
// 初始化SHT20
if (SHT20_Init()) {
printf("SHT20 Sensor Initialized\r\n");
LED_On(LED0);
} else {
printf("SHT20 Sensor Init Failed!\r\n");
TFT_ShowString(10, 200, "SHT20 Error!", RED, BLACK);
while(1);
}
// 设置校准参数(根据实际环境调整)
SHT20_Calibration_t cal = {
.temp_offset = -0.5f, // 温度偏移-0.5°C
.humi_offset = 2.0f, // 湿度偏移+2%RH
.temp_scale = 1.0f, // 温度比例系数
.humi_scale = 1.0f // 湿度比例系数
};
SHT20_SetCalibration(&cal);
// 初始化历史数据
for (uint8_t i = 0; i < TEMP_HISTORY_LEN; i++) {
temp_history[i] = 25.0f; // 初始化为室温
}
printf("System Ready!\r\n");
}
// 绘制UI界面
void Draw_UI(void) {
// 清屏
TFT_FillRect(0, 0, TFT_WIDTH, TFT_HEIGHT, BLACK);
// 标题
TFT_ShowString(80, 5, "ENVIRONMENT MONITOR", WHITE, BLACK);
TFT_DrawLine(0, 25, TFT_WIDTH, 25, WHITE);
// 温度显示框
TFT_FillRect(temp_box.x, temp_box.y, temp_box.w, temp_box.h, temp_box.bg_color);
TFT_DrawRect(temp_box.x, temp_box.y, temp_box.w, temp_box.h, temp_box.border_color);
TFT_ShowString(temp_box.x + 10, temp_box.y + 5, temp_box.title, WHITE, temp_box.bg_color);
// 湿度显示框
TFT_FillRect(humi_box.x, humi_box.y, humi_box.w, humi_box.h, humi_box.bg_color);
TFT_DrawRect(humi_box.x, humi_box.y, humi_box.w, humi_box.h, humi_box.border_color);
TFT_ShowString(humi_box.x + 10, humi_box.y + 5, humi_box.title, WHITE, humi_box.bg_color);
// 状态显示框
TFT_FillRect(status_box.x, status_box.y, status_box.w, status_box.h, status_box.bg_color);
TFT_DrawRect(status_box.x, status_box.y, status_box.w, status_box.h, status_box.border_color);
TFT_ShowString(status_box.x + 10, status_box.y + 5, status_box.title, WHITE, status_box.bg_color);
}
// 更新数据显示
void Update_Display(void) {
char buffer[32];
// 更新温度显示
TFT_FillRect(temp_box.x + 10, temp_box.y + 25, 120, 30, temp_box.bg_color);
sprintf(buffer, "%.1f C", env_data.temperature);
TFT_ShowString(temp_box.x + 10, temp_box.y + 25, buffer, WHITE, temp_box.bg_color);
// 温度图标
TFT_DrawCircle(temp_box.x + 120, temp_box.y + 40, 8, RED);
TFT_FillCircle(temp_box.x + 120, temp_box.y + 40, 6, RED);
// 更新湿度显示
TFT_FillRect(humi_box.x + 10, humi_box.y + 25, 120, 30, humi_box.bg_color);
sprintf(buffer, "%.1f %%", env_data.humidity);
TFT_ShowString(humi_box.x + 10, humi_box.y + 25, buffer, WHITE, humi_box.bg_color);
// 湿度图标(水滴形状)
TFT_DrawCircle(humi_box.x + 120, humi_box.y + 40, 8, BLUE);
TFT_FillCircle(humi_box.x + 120, humi_box.y + 40, 6, BLUE);
// 更新状态信息
TFT_FillRect(status_box.x + 10, status_box.y + 25, 280, 25, status_box.bg_color);
sprintf(buffer, "Battery: %s | Time: %lu s",
env_data.battery_low ? "LOW" : "OK",
env_data.timestamp / 1000);
TFT_ShowString(status_box.x + 10, status_box.y + 25, buffer, GREEN, status_box.bg_color);
// 绘制温度历史曲线
Draw_TemperatureGraph();
}
// 绘制温度历史曲线
void Draw_TemperatureGraph(void) {
uint16_t graph_x = 10;
uint16_t graph_y = 210;
uint16_t graph_w = 300;
uint16_t graph_h = 50;
// 绘制坐标轴
TFT_DrawRect(graph_x, graph_y, graph_w, graph_h, WHITE);
TFT_ShowString(graph_x, graph_y - 15, "Temperature History (60s)", WHITE, BLACK);
// 绘制网格
for (uint8_t i = 1; i < 6; i++) {
uint16_t x = graph_x + (graph_w * i / 6);
TFT_DrawLine(x, graph_y, x, graph_y + graph_h, DARKGREY);
}
// 绘制温度曲线
uint16_t prev_x = graph_x;
uint16_t prev_y = graph_y + graph_h - (uint16_t)((temp_history[0] - 20) * graph_h / 30);
for (uint8_t i = 1; i < TEMP_HISTORY_LEN; i++) {
uint16_t curr_x = graph_x + (graph_w * i / (TEMP_HISTORY_LEN - 1));
uint16_t curr_y = graph_y + graph_h - (uint16_t)((temp_history[i] - 20) * graph_h / 30);
TFT_DrawLine(prev_x, prev_y, curr_x, curr_y, RED);
prev_x = curr_x;
prev_y = curr_y;
}
}
// 更新温度历史
void Update_TemperatureHistory(float temperature) {
temp_history[history_index] = temperature;
history_index = (history_index + 1) % TEMP_HISTORY_LEN;
}
// 主循环
int main(void) {
uint32_t last_update = 0;
uint8_t update_count = 0;
// 系统初始化
System_Init();
// 绘制UI
Draw_UI();
printf("Entering Main Loop...\r\n");
while(1) {
uint32_t current_time = Get_SystemTime();
// 定时更新数据
if (current_time - last_update >= UPDATE_INTERVAL) {
// 读取温湿度
if (SHT20_ReadTempAndHumi(&env_data)) {
printf("Temp: %.2f°C, Humi: %.2f%%RH, Battery: %s\r\n",
env_data.temperature, env_data.humidity,
env_data.battery_low ? "LOW" : "OK");
// 更新显示
Update_Display();
// 更新历史数据
Update_TemperatureHistory(env_data.temperature);
// LED闪烁指示
if (++update_count % 2) {
LED_On(LED1);
} else {
LED_Off(LED1);
}
} else {
printf("Failed to read SHT20 data!\r\n");
TFT_ShowString(10, 250, "Sensor Read Error!", RED, BLACK);
}
last_update = current_time;
}
// 其他任务处理
// ...
Delay_ms(10);
}
}
四、ASCII字体库 (font.h)
c
#ifndef __FONT_H
#define __FONT_H
// 6x12 ASCII字体
const unsigned char asc2_1206[95][12] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 空格
{0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // !
{0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00}, // "
// ... 其他字符省略
};
#endif /* __FONT_H */
参考代码 STM32+SHT20测试温度输出和湿度测试TFT显示 www.youwenfan.com/contentcsu/60560.html
五、编译与部署
5.1 工程配置
Project Structure:
├── User/
│ ├── main.c
│ ├── sht20.c/h
│ ├── tft_lcd.c/h
│ └── font.h
├── Hardware/
│ ├── i2c.c/h
│ ├── spi.c/h
│ ├── usart.c/h
│ └── delay.c/h
├── System/
│ └── sys.c/h
└── Libraries/
└── STM32F10x_StdPeriph_Driver/
5.2 测试步骤
- 硬件检查: 确认所有连接正确,电源电压3.3V稳定
- I2C测试: 使用逻辑分析仪检查I2C通信是否正常
- SHT20测试: 读取传感器ID,验证通信
- TFT测试: 显示基本图形和文字
- 系统集成: 运行完整程序,验证温湿度显示
5.3 常见问题解决
| 问题 | 原因 | 解决方案 |
|---|---|---|
| SHT20无响应 | I2C地址错误 | 确认地址为0x80/0x81 |
| 温度读数异常 | 校准参数不当 | 调整temp_offset和temp_scale |
| TFT显示花屏 | SPI时序问题 | 降低SPI时钟频率 |
| 湿度漂移 | 传感器老化 | 定期校准或更换传感器 |
| 数据跳变 | 电源干扰 | 增加去耦电容,改善布线 |