接线:

  1. 显示屏接线:

    • 确认 SPI 引脚连接:SCK=18, MOSI=23, MISO=19
    • 确认控制引脚:RESET=15, DC=2, CS=5, BACKLIGHT=21
    • 检查显示屏供电是否正常(3.3V)
  2. DS18B20 接线:

    • 确认 DATA 引脚连接到 GPIO4 并接 4.7kΩ 上拉电阻
    • 确认 VCC 和 GND 连接正确
    • 尝试更换传感器或上拉电阻

下面是相关代码:

from machine import Pin, SoftSPI, RTC
import st7789
import vga1_16x32_1 as font
import time

# 屏幕参数配置
SCREEN_WIDTH = 240
SCREEN_HEIGHT = 240
ROTATION = 0  # 旋转方向:0=默认,1=90度,2=180度,3=270度

# 温度传感器配置(软件模拟单总线)
DS18B20_PIN = 4  # DS18B20数据引脚连接到ESP32的GPIO4

class DS18B20:
    """纯软件实现DS18B20温度传感器驱动"""
    def __init__(self, pin):
        self.pin = Pin(pin, Pin.OUT)
    
    def _write_bit(self, bit):
        """写一位数据到DS18B20"""
        self.pin(0)
        # 拉低总线至少1us
        time.sleep_us(1)
        self.pin(bit)
        # 保持位状态60-120us
        time.sleep_us(60)
        self.pin(1)
        time.sleep_us(1)
    
    def _read_bit(self):
        """从DS18B20读一位数据"""
        self.pin(0)
        time.sleep_us(1)
        self.pin(1)
        time.sleep_us(1)
        # 读取总线状态
        bit = self.pin()
        time.sleep_us(60)
        return bit
    
    def _write_byte(self, byte):
        """写一个字节到DS18B20"""
        for i in range(8):
            self._write_bit(byte & 0x01)
            byte >>= 1
    
    def _read_byte(self):
        """从DS18B20读一个字节"""
        byte = 0
        for i in range(8):
            byte >>= 1
            if self._read_bit():
                byte |= 0x80
        return byte
    
    def reset(self):
        """重置DS18B20"""
        self.pin(0)
        # 拉低总线至少480us
        time.sleep_us(500)
        self.pin(1)
        time.sleep_us(60)
        # 等待DS18B20响应
        response = self.pin()
        time.sleep_us(440)
        return not response  # 返回True表示设备响应
    
    def read_temp(self):
        """读取温度值"""
        if not self.reset():
            print("DS18B20未响应")
            return None
        
        self._write_byte(0xCC)  # 跳过ROM命令
        self._write_byte(0x44)  # 启动温度转换
        time.sleep_ms(750)  # 等待转换完成
        
        if not self.reset():
            return None
        
        self._write_byte(0xCC)  # 跳过ROM命令
        self._write_byte(0xBE)  # 读取暂存寄存器
        
        # 读取温度数据(低字节在前,高字节在后)
        low = self._read_byte()
        high = self._read_byte()
        
        # 组合温度值(16位有符号数)
        temp = (high << 8) | low
        # 转换为浮点数(0.5℃精度)
        return round((temp * 0.0625), 1)

# 颜色定义(RGB565格式)
def color565(r, g, b):
    """将RGB888颜色转换为RGB565格式"""
    return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3

# 预定义常用颜色
BLACK = color565(0, 0, 0)
WHITE = color565(255, 255, 255)
RED = color565(255, 0, 0)
GREEN = color565(0, 255, 0)
BLUE = color565(0, 0, 255)
YELLOW = color565(255, 255, 0)
CYAN = color565(0, 255, 255)
MAGENTA = color565(255, 0, 255)
ORANGE = color565(255, 165, 0)  # 新增橙色用于温度显示

class DisplayController:
    """ST7789显示屏控制器"""
    
    def __init__(self):
        """初始化显示屏控制器"""
        self.tft = None
        self.backlight = None
        self.rtc = RTC()  # 初始化RTC
        self.last_time = (0, 0, 0, 0, 0, 0)  # 记录上次显示的 时,分,秒,年,月,日
        self.last_temp = -99.9  # 记录上次显示的温度
        self.ds18b20 = DS18B20(DS18B20_PIN)  # 初始化DS18B20
    
    def initialize(self):
        """初始化SPI总线和显示屏"""
        try:
            # 初始化SPI总线
            spi = SoftSPI(
                baudrate=40000000,
                polarity=1,
                phase=0,
                sck=Pin(18),
                mosi=Pin(23),
                miso=Pin(19)
            )
            
            # 初始化控制引脚
            reset = Pin(15, Pin.OUT)
            dc = Pin(2, Pin.OUT)
            cs = Pin(5, Pin.OUT)
            self.backlight = Pin(21, Pin.OUT)
            
            # 初始化ST7789显示屏
            self.tft = st7789.ST7789(
                spi,
                SCREEN_WIDTH,
                SCREEN_HEIGHT,
                reset=reset,
                dc=dc,
                cs=cs,
                backlight=self.backlight,
                rotation=ROTATION
            )
            
            # 开启背光
            self.backlight.on()
            
            # 设置RTC时间(可选,若需要准确时间可通过NTP同步)
            # self.rtc.datetime((2025, 6, 29, 0, 12, 30, 0, 0))  # 年-月-日-周,时-分-秒-毫秒
            
            return True
            
        except Exception as e:
            print(f"显示屏初始化失败: {str(e)}")
            return False
    
    def test_pattern(self):
        """显示测试图案"""
        if not self.tft:
            print("显示屏未初始化")
            return
        
        try:
            # 填充背景
            self.tft.fill(BLACK)
            
            # 绘制边框
            self.tft.rect(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, WHITE)
            
            # 绘制对角线
            self.tft.line(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, RED)
            self.tft.line(0, SCREEN_HEIGHT-1, SCREEN_WIDTH-1, 0, GREEN)
            
            # 绘制彩色矩形
            self.tft.fill_rect(10, 10, 40, 40, BLUE)
            self.tft.rect(10, 10, 40, 40, WHITE)
            
            # 使用矩形替代圆形
            self.tft.rect(SCREEN_WIDTH//2-30, SCREEN_HEIGHT//2-30, 60, 60, YELLOW)
            
            # 显示文字
            self.tft.text(font, "ST7789 Clock & Temp", 10, 100, WHITE)
            self.tft.text(font, f"{SCREEN_WIDTH}x{SCREEN_HEIGHT}", 10, 140, CYAN)
            
        except Exception as e:
            print(f"显示测试图案失败: {str(e)}")
    
    def read_temperature(self):
        """读取DS18B20温度值"""
        return self.ds18b20.read_temp()
    
    def show_time_and_temp(self, update_all=False):
        """显示时间和温度(智能更新变化部分)"""
        if not self.tft:
            print("显示屏未初始化")
            return
        
        try:
            # 获取当前时间
            year, month, day, weekday, hour, minute, second, _ = self.rtc.datetime()
            current_time = (hour, minute, second, year, month, day)
            
            # 读取温度
            temp = self.read_temperature()
            if temp is not None and abs(temp - self.last_temp) > 0.1 or update_all:
                need_update_temp = True
                self.last_temp = temp
            else:
                need_update_temp = False
            
            # 首次显示或强制更新时全屏绘制
            if self.last_time == (0, 0, 0, 0, 0, 0) or update_all:
                self._draw_full_screen(year, month, day, hour, minute, second, temp)
                self.last_time = current_time
                return
            
            # 判断哪些部分需要更新
            need_update_second = (current_time[2] != self.last_time[2])
            need_update_minute = (current_time[1] != self.last_time[1])
            need_update_hour = (current_time[0] != self.last_time[0])
            need_update_date = (current_time[3:6] != self.last_time[3:6])
            
            # 仅更新变化的部分
            if need_update_date:
                self._draw_date(year, month, day)
            if need_update_hour or need_update_minute or need_update_second:
                self._draw_time(hour, minute, second)
            if need_update_temp:
                self._draw_temperature(temp)
            
            # 更新最后一次记录的时间
            self.last_time = current_time
            
        except Exception as e:
            print(f"显示时间和温度失败: {str(e)}")
    
    def _draw_full_screen(self, year, month, day, hour, minute, second, temp):
        """绘制完整屏幕内容(首次或强制更新时使用)"""
        # 清屏
        self.tft.fill(BLACK)
        
        # 绘制日期(年月日)
        date_str = f"{year:04d}-{month:02d}-{day:02d}"
        date_width = len(date_str) * font.WIDTH
        date_x = (SCREEN_WIDTH - date_width) // 2
        date_y = (SCREEN_HEIGHT // 3) - font.HEIGHT
        self.tft.text(font, date_str, date_x, date_y, WHITE)
        
        # 绘制时间(时分秒)
        time_str = f"{hour:02d}:{minute:02d}:{second:02d}"
        time_width = len(time_str) * font.WIDTH
        time_x = (SCREEN_WIDTH - time_width) // 2
        time_y = (SCREEN_HEIGHT // 3) * 2 - font.HEIGHT
        self.tft.text(font, time_str, time_x, time_y, WHITE)
        
        # 绘制温度
        temp_str = f"Temp: {temp}°C" if temp is not None else "Temp: --.-°C"
        temp_width = len(temp_str) * font.WIDTH
        temp_x = (SCREEN_WIDTH - temp_width) // 2
        temp_y = (SCREEN_HEIGHT // 3) * 2 + 10
        self.tft.text(font, temp_str, temp_x, temp_y, ORANGE)
    
    def _draw_date(self, year, month, day):
        """仅更新日期部分"""
        date_str = f"{year:04d}-{month:02d}-{day:02d}"
        date_width = len(date_str) * font.WIDTH
        date_x = (SCREEN_WIDTH - date_width) // 2
        date_y = (SCREEN_HEIGHT // 3) - font.HEIGHT
        
        # 先绘制黑色背景覆盖旧日期
        self.tft.fill_rect(date_x, date_y, date_width, font.HEIGHT, BLACK)
        # 再绘制新日期
        self.tft.text(font, date_str, date_x, date_y, WHITE)
    
    def _draw_time(self, hour, minute, second):
        """仅更新时间部分(时分秒)"""
        time_str = f"{hour:02d}:{minute:02d}:{second:02d}"
        time_width = len(time_str) * font.WIDTH
        time_x = (SCREEN_WIDTH - time_width) // 2
        time_y = (SCREEN_HEIGHT // 3) * 2 - font.HEIGHT
        
        # 先绘制黑色背景覆盖旧时间
        self.tft.fill_rect(time_x, time_y, time_width, font.HEIGHT, BLACK)
        # 再绘制新时间
        self.tft.text(font, time_str, time_x, time_y, WHITE)
    
    def _draw_temperature(self, temp):
        """仅更新温度部分"""
        temp_str = f"Temp: {temp}°C"
        temp_width = len(temp_str) * font.WIDTH
        temp_x = (SCREEN_WIDTH - temp_width) // 2
        temp_y = (SCREEN_HEIGHT // 3) * 2 + 10
        
        # 先绘制黑色背景覆盖旧温度
        self.tft.fill_rect(temp_x, temp_y, temp_width, font.HEIGHT, BLACK)
        # 再绘制新温度(橙色)
        self.tft.text(font, temp_str, temp_x, temp_y, ORANGE)
    
    def clear(self):
        """清屏"""
        if self.tft:
            self.tft.fill(BLACK)
    
    def turn_off(self):
        """关闭显示屏和背光"""
        if self.tft:
            self.clear()
        
        if self.backlight:
            self.backlight.off()

def main():
    """主程序"""
    display = DisplayController()
    
    # 初始化显示屏
    if not display.initialize():
        print("显示屏初始化失败,程序退出")
        return
    
    try:
        # 显示测试图案
        display.test_pattern()
        time.sleep(2)
        
        # 清屏并显示时间和温度
        display.clear()
        display.show_time_and_temp(update_all=True)  # 首次全屏绘制
        
        print("时间和温度显示启动,按Ctrl+C退出")
        last_second = -1
        
        while True:
            # 获取当前秒数
            _, _, _, _, _, _, second, _ = display.rtc.datetime()
            
            # 每秒更新一次显示
            if second != last_second:
                display.show_time_and_temp()
                last_second = second
            
            time.sleep(0.1)  # 小延迟减少CPU占用
            
    except KeyboardInterrupt:
        # 清屏并关闭背光
        display.turn_off()
        print("程序已停止")
    except Exception as e:
        # 发生其他异常时关闭显示屏
        print(f"发生错误: {str(e)}")
        display.turn_off()

if __name__ == "__main__":
    main()  
其中有需要st7789.py和vga1_16x32.py,付费,请知晓

更多推荐