|
爱科技、爱创意、爱折腾、爱极致,我们都是技术控
您需要 登录 才可以下载或查看,没有账号?立即注册
x
用esp32-s3-n16r8开发板(micropython语言)
做了一个网络时钟。
4位0.96寸tft彩屏做 时分显示
4位0.96寸tft彩屏做月日显示。
遇到一个奇怪的小问题:
当链接电脑调试时,pwm控制背光正常,
但是 脱离电脑独立运行后
pwm就失控导致背光太亮,刺眼。
请教 坛子里的朋友:
这是咋回事?
1)代码问题?
2)硬件问题?
主代码见下:
- # main.py - 集成月日显示的8屏网络电子表主程序(调用week_display模块)
- import machine
- from machine import Pin, PWM, SPI, RTC
- import time
- import ntptime
- from st7735 import ST7735
- from digit_font import DIGIT_FONT
- from week_display import WeekDisplay
- from neopixel import NeoPixel
- import gc
- import random
- # 全局PWM对象 - 初始化为0,在ScreenController中设置实际亮度
- screen_backlight = PWM(Pin(13), freq=1000, duty=200)
- class Config:
- """系统配置类"""
- COLORS = {
- 'BLACK': 0x0000,
- 'RED': 0x0fF8, # 红色
- 'GREEN': 0xF81F, # 绿色
- 'BLUE': 0xFF00, # 蓝色
- 'YELLOW': 0xf0ff, # 黄色
- 'MAGENTA': 0xfef0, # 粉色(品红)
- 'CYAN': 0xff0f # 青色
- }
- WIFI_SSID = "xxxxx"
- WIFI_PASSWORD = "xxxxxxx"
-
- # 时分屏幕引脚(原4个)
- TIME_SCREEN_CS_PINS = [7, 6, 5, 4] # 时十位, 时个位, 分十位, 分个位
- TIME_SCREEN_RST_PINS = [18, 17, 16, 15]
-
- # 月日屏幕引脚(新增4个)
- DATE_SCREEN_CS_PINS = [1, 2, 8, 38] # 月十位, 月个位, 日十位, 日个位
- DATE_SCREEN_RST_PINS = [14, 45, 46, 47] # cs=Pin(38), rst=Pin(42)可以用
-
- # 星期显示配置
- WEEKDAY_PIN = 9 # NeoPixel连接的GPIO引脚
- WEEKDAY_LED_COUNT = 7 # NeoPixel灯数量
-
- SCREEN_DC_PIN = 12
- SCREEN_BL_PIN = 13
- UTC_OFFSET = 8
- NTP_SERVERS = ['cn.pool.ntp.org', 'ntp.aliyun.com', 'time.google.com']
- TIME_SYNC_INTERVAL = 3600
-
- # 秒指示灯配置
- LED_COLORS = [
- (1, 0, 0), (0, 1, 0), (0, 0, 5),
- (1, 1, 0), (1, 0, 1), (0, 1, 1)
- ]
- SECOND_LED_PIN = 3 # 秒指示灯引脚
- SECOND_LED_NUM = 2 # 秒指示灯数量
- class SecondIndicator:
- """秒指示灯控制器"""
- def __init__(self, config):
- self.config = config
- self.pin = config.SECOND_LED_PIN
- self.num_leds = config.SECOND_LED_NUM
- self.strip = NeoPixel(Pin(self.pin, Pin.OUT), self.num_leds, bpp=3, timing=1)
- self.colors = config.LED_COLORS
- self.current_color_idx = 0
- self.blink_state = True
- self.blink_counter = 0
- self.timer = machine.Timer(0)
- self.timer.init(period=500, mode=machine.Timer.PERIODIC, callback=self._tick)
-
- def _tick(self, timer):
- self.blink_counter += 1
- if self.blink_counter >= 2:
- self.blink_counter = 0
- self.current_color_idx = (self.current_color_idx + 1) % len(self.colors)
- self.blink_state = not self.blink_state
- if self.blink_state:
- self.set_color(self.colors[self.current_color_idx])
- else:
- self.turn_off()
-
- def set_color(self, color):
- for i in range(self.num_leds):
- self.strip[i] = color
- self.strip.write()
-
- def turn_off(self):
- for i in range(self.num_leds):
- self.strip[i] = (0, 0, 0)
- self.strip.write()
-
- def stop(self):
- if self.timer:
- self.timer.deinit()
- self.turn_off()
- class ScreenController:
- """屏幕控制类 - 管理8个屏幕(4个时分+4个日月)"""
- def __init__(self, config):
- self.config = config
- self.screens = []
- self.time_color = None
- self.minute_color = None
- self.month_color = None
- self.day_color = None
- self.display_colors = [color for name, color in config.COLORS.items() if name != 'BLACK']
-
- # 初始化SPI
- #self.backlight = Pin(config.SCREEN_BL_PIN, Pin.OUT, value=1)
- self.spi = SPI(1, baudrate=20000000, sck=Pin(10), mosi=Pin(11))
- # 初始化SPI(MOSI使用GPIO11,避免与PWM冲突)
- global screen_backlight
- self.backlight = screen_backlight
- self.backlight.duty(200) # 确保25%亮度
-
-
- # 初始化时分屏幕(前4个)
- for i in range(len(config.TIME_SCREEN_CS_PINS)):
- lcd = ST7735(80, 160, self.spi, dc=Pin(self.config.SCREEN_DC_PIN),
- cs=Pin(config.TIME_SCREEN_CS_PINS[i]),
- rst=Pin(config.TIME_SCREEN_RST_PINS[i]))
- self.screens.append(lcd)
- lcd.fill(self.config.COLORS['BLACK'])
- lcd.show()
-
- # 初始化月日屏幕(后4个)
- for i in range(len(config.DATE_SCREEN_CS_PINS)):
- lcd = ST7735(80, 160, self.spi, dc=Pin(self.config.SCREEN_DC_PIN),
- cs=Pin(config.DATE_SCREEN_CS_PINS[i]),
- rst=Pin(config.DATE_SCREEN_RST_PINS[i]))
- self.screens.append(lcd)
- lcd.fill(self.config.COLORS['BLACK'])
- lcd.show()
-
- # 初始化颜色
- self.update_random_colors(force=True)
-
- def update_random_colors(self, force=False):
- """更新4组颜色(时、分、月、日)"""
- # 首次初始化或强制更新
- if force or any(color is None for color in [self.time_color, self.minute_color, self.month_color, self.day_color]):
- # 手动实现不重复随机选择
- colors = self._get_unique_colors(4)
- self.time_color, self.minute_color, self.month_color, self.day_color = colors
- print(f"初始化颜色 - 时:{self.time_color:04X}, 分:{self.minute_color:04X}, 月:{self.month_color:04X}, 日:{self.day_color:04X}")
- return
-
- # 保存历史颜色
- last_colors = {self.time_color, self.minute_color, self.month_color, self.day_color}
-
- # 优先使用新颜色(排除历史颜色)
- available = [c for c in self.display_colors if c not in last_colors]
- new_colors = []
-
- # 尝试选择4种新颜色
- temp_colors = available.copy()
- while len(new_colors) < 4 and temp_colors:
- idx = random.randint(0, len(temp_colors) - 1)
- new_colors.append(temp_colors.pop(idx))
-
- # 若新颜色不足,从所有颜色中补充(可能包含历史颜色)
- while len(new_colors) < 4:
- color = random.choice(self.display_colors)
- new_colors.append(color)
-
- # 确保4种颜色不同(最终检查)
- while len(set(new_colors)) < 4:
- for i in range(4):
- if len(set(new_colors)) >= 4:
- break
- new_colors[i] = random.choice(self.display_colors)
-
- # 应用新颜色
- self.time_color, self.minute_color, self.month_color, self.day_color = new_colors
- print(f"颜色已更新 - 时:{self.time_color:04X}, 分:{self.minute_color:04X}, 月:{self.month_color:04X}, 日:{self.day_color:04X}")
-
- def _get_unique_colors(self, count):
- """自定义不重复颜色选择函数"""
- colors = self.display_colors.copy()
- result = []
- # 随机选择不重复颜色
- while len(result) < count and colors:
- idx = random.randint(0, len(colors) - 1)
- result.append(colors.pop(idx))
- # 若颜色不足,用剩余颜色填充(概率极低)
- while len(result) < count:
- result.append(random.choice(self.display_colors))
- return result
-
- def draw_digit(self, screen_idx, digit, group):
- """绘制数字,group=0:时分, group=1:月日"""
- if 0 <= screen_idx < len(self.screens):
- # 选择颜色(时分组或月日组)
- if group == 0: # 时分组
- color = self.time_color if screen_idx < 2 else self.minute_color
- else: # 月日组
- color = self.month_color if screen_idx < 6 else self.day_color
-
- # 绘制数字
- self.screens[screen_idx].fill_rect(5, 20, 70, 120, self.config.COLORS['BLACK'])
- for seg in DIGIT_FONT.get(str(digit), []):
- seg(self.screens[screen_idx], 5, 20, color)
- self.screens[screen_idx].show()
-
- def clear_all(self):
- for screen in self.screens:
- screen.fill(self.config.COLORS['BLACK'])
- screen.show()
- self.backlight.value(0)
- class WiFiConnector:
- """WiFi连接管理类"""
- def __init__(self, config):
- self.config = config
- self.wlan = None
-
- def connect(self):
- import network
- self.wlan = network.WLAN(network.STA_IF)
- self.wlan.active(True)
- if self.wlan.isconnected():
- return True
- self.wlan.connect(self.config.WIFI_SSID, self.config.WIFI_PASSWORD)
- for _ in range(20):
- if self.wlan.isconnected():
- return True
- time.sleep(0.5)
- return False
-
- def disconnect(self):
- if self.wlan and self.wlan.isconnected():
- self.wlan.disconnect()
- self.wlan.active(False)
- class TimeSync:
- """时间同步类"""
- def __init__(self, config, rtc, wifi):
- self.config = config
- self.rtc = rtc
- self.wifi = wifi
-
- def sync_time(self):
- if not self.wifi.connect():
- return False
- for server in self.config.NTP_SERVERS:
- try:
- ntptime.host = server
- ntptime.settime()
- local_time = time.localtime(time.time() + self.config.UTC_OFFSET * 3600)
- self.rtc.datetime((local_time[0], local_time[1], local_time[2], local_time[6],
- local_time[3], local_time[4], local_time[5], 0))
- print(f"时间已同步为: {local_time[3]:02d}:{local_time[4]:02d}:{local_time[5]:02d} 星期{local_time[6]+1}")
- return True
- except:
- continue
- self.wifi.disconnect()
- return False
- def main():
- """主程序入口"""
- config = Config()
- screen_ctrl = ScreenController(config)
- wifi = WiFiConnector(config)
- rtc = RTC()
- time_sync = TimeSync(config, rtc, wifi)
- second_indicator = SecondIndicator(config)
-
- # 初始化星期显示模块(使用配置中的引脚和LED数量)
- week_display = WeekDisplay(pin=config.WEEKDAY_PIN, count=config.WEEKDAY_LED_COUNT)
-
- # 首次同步时间
- if not time_sync.sync_time():
- print("警告:首次时间同步失败,使用设备现有时间")
-
- # 屏幕映射关系
- time_screen_mapping = {0: 0, 1: 1, 2: 2, 3: 3} # 时分屏幕索引到数字位置
- date_screen_mapping = {4: 0, 5: 1, 6: 2, 7: 3} # 月日屏幕索引到数字位置
-
- last_second = -1
- last_minute = -1
- last_sync_time = time.time()
-
- try:
- while True:
- current_time = rtc.datetime()
- year, month, day, weekday, hours, minutes, seconds, _ = current_time
-
- # 时分数字(倒序排列)
- time_digits = [minutes % 10, minutes // 10 % 10, hours % 10, hours // 10 % 10]
-
- # 月日数字(倒序排列)
- date_digits = [day % 10, day // 10 % 10, month % 10, month // 10 % 10]
-
- # 每秒更新一次显示
- if seconds != last_second:
- last_second = seconds
-
- # 每分钟切换颜色
- if minutes != last_minute:
- last_minute = minutes
- screen_ctrl.update_random_colors()
-
- # 更新时分显示(前4个屏幕)
- for screen_idx, digit_idx in time_screen_mapping.items():
- screen_ctrl.draw_digit(screen_idx, time_digits[digit_idx], group=0)
-
- # 更新月日显示(后4个屏幕)
- for screen_idx, digit_idx in date_screen_mapping.items():
- screen_ctrl.draw_digit(screen_idx, date_digits[digit_idx], group=1)
-
- # 更新星期显示(0=周一,6=周日)
- week_display.show_weekday(weekday)
-
- # 每小时同步一次时间
- if time.time() - last_sync_time >= config.TIME_SYNC_INTERVAL:
- if time_sync.sync_time():
- last_sync_time = time.time()
-
- # 垃圾回收,防止内存泄漏
- gc.collect()
- time.sleep(0.1) # 降低CPU使用率
-
- except KeyboardInterrupt:
- # 忽略中断,确保继续执行
- pass
-
- # 清理其他资源
- try:
- wifi.disconnect()
- print("[WiFi已断开]")
-
- second_indicator.stop()
- print("[秒指示灯已关闭]")
-
- week_display.clear()
- print("[星期显示已清空]")
-
- # 关闭屏幕
- screen_ctrl.clear_all()
- print("[屏幕已清空]")
-
- except Exception as e:
- print(f"清理其他资源时出错: {e}")
-
- # 最终确认信息
- print("\n程序已安全退出")
- if __name__ == "__main__":
- main()
复制代码
|
|