数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 347|回复: 1

[ARM] pwm失控请教

[复制链接]
发表于 2025-6-15 17:52:25 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
用esp32-s3-n16r8开发板(micropython语言)
做了一个网络时钟。

4位0.96寸tft彩屏做 时分显示
4位0.96寸tft彩屏做月日显示。

遇到一个奇怪的小问题:
当链接电脑调试时,pwm控制背光正常,
但是 脱离电脑独立运行后
pwm就失控导致背光太亮,刺眼。

请教 坛子里的朋友:

这是咋回事?
1)代码问题?
2)硬件问题?

主代码见下:
  1. # main.py - 集成月日显示的8屏网络电子表主程序(调用week_display模块)
  2. import machine
  3. from machine import Pin, PWM, SPI, RTC
  4. import time
  5. import ntptime
  6. from st7735 import ST7735
  7. from digit_font import DIGIT_FONT
  8. from week_display import WeekDisplay
  9. from neopixel import NeoPixel
  10. import gc
  11. import random

  12. # 全局PWM对象 - 初始化为0,在ScreenController中设置实际亮度
  13. screen_backlight = PWM(Pin(13), freq=1000, duty=200)

  14. class Config:
  15.     """系统配置类"""
  16.     COLORS = {
  17.         'BLACK': 0x0000,
  18.         'RED': 0x0fF8,       # 红色
  19.         'GREEN': 0xF81F,     # 绿色
  20.         'BLUE': 0xFF00,      # 蓝色
  21.         'YELLOW': 0xf0ff,    # 黄色
  22.         'MAGENTA': 0xfef0,   # 粉色(品红)
  23.         'CYAN': 0xff0f       # 青色
  24.     }
  25.     WIFI_SSID = "xxxxx"
  26.     WIFI_PASSWORD = "xxxxxxx"
  27.    
  28.     # 时分屏幕引脚(原4个)
  29.     TIME_SCREEN_CS_PINS = [7, 6, 5, 4]    # 时十位, 时个位, 分十位, 分个位
  30.     TIME_SCREEN_RST_PINS = [18, 17, 16, 15]
  31.    
  32.     # 月日屏幕引脚(新增4个)
  33.     DATE_SCREEN_CS_PINS = [1, 2, 8, 38]  # 月十位, 月个位, 日十位, 日个位
  34.     DATE_SCREEN_RST_PINS = [14, 45, 46, 47] # cs=Pin(38), rst=Pin(42)可以用
  35.    
  36.     # 星期显示配置
  37.     WEEKDAY_PIN = 9       # NeoPixel连接的GPIO引脚
  38.     WEEKDAY_LED_COUNT = 7 # NeoPixel灯数量
  39.    
  40.     SCREEN_DC_PIN = 12
  41.     SCREEN_BL_PIN = 13
  42.     UTC_OFFSET = 8
  43.     NTP_SERVERS = ['cn.pool.ntp.org', 'ntp.aliyun.com', 'time.google.com']
  44.     TIME_SYNC_INTERVAL = 3600
  45.    
  46.     # 秒指示灯配置
  47.     LED_COLORS = [
  48.         (1, 0, 0), (0, 1, 0), (0, 0, 5),
  49.         (1, 1, 0), (1, 0, 1), (0, 1, 1)
  50.     ]
  51.     SECOND_LED_PIN = 3     # 秒指示灯引脚
  52.     SECOND_LED_NUM = 2     # 秒指示灯数量

  53. class SecondIndicator:
  54.     """秒指示灯控制器"""
  55.     def __init__(self, config):
  56.         self.config = config
  57.         self.pin = config.SECOND_LED_PIN
  58.         self.num_leds = config.SECOND_LED_NUM
  59.         self.strip = NeoPixel(Pin(self.pin, Pin.OUT), self.num_leds, bpp=3, timing=1)
  60.         self.colors = config.LED_COLORS
  61.         self.current_color_idx = 0
  62.         self.blink_state = True
  63.         self.blink_counter = 0
  64.         self.timer = machine.Timer(0)
  65.         self.timer.init(period=500, mode=machine.Timer.PERIODIC, callback=self._tick)
  66.    
  67.     def _tick(self, timer):
  68.         self.blink_counter += 1
  69.         if self.blink_counter >= 2:
  70.             self.blink_counter = 0
  71.             self.current_color_idx = (self.current_color_idx + 1) % len(self.colors)
  72.         self.blink_state = not self.blink_state
  73.         if self.blink_state:
  74.             self.set_color(self.colors[self.current_color_idx])
  75.         else:
  76.             self.turn_off()
  77.    
  78.     def set_color(self, color):
  79.         for i in range(self.num_leds):
  80.             self.strip[i] = color
  81.         self.strip.write()
  82.    
  83.     def turn_off(self):
  84.         for i in range(self.num_leds):
  85.             self.strip[i] = (0, 0, 0)
  86.         self.strip.write()
  87.    
  88.     def stop(self):
  89.         if self.timer:
  90.             self.timer.deinit()
  91.         self.turn_off()

  92. class ScreenController:
  93.     """屏幕控制类 - 管理8个屏幕(4个时分+4个日月)"""
  94.     def __init__(self, config):
  95.         self.config = config
  96.         self.screens = []
  97.         self.time_color = None
  98.         self.minute_color = None
  99.         self.month_color = None
  100.         self.day_color = None
  101.         self.display_colors = [color for name, color in config.COLORS.items() if name != 'BLACK']
  102.         
  103.         # 初始化SPI
  104.         #self.backlight = Pin(config.SCREEN_BL_PIN, Pin.OUT, value=1)
  105.         self.spi = SPI(1, baudrate=20000000, sck=Pin(10), mosi=Pin(11))
  106.         # 初始化SPI(MOSI使用GPIO11,避免与PWM冲突)
  107.         global screen_backlight
  108.         self.backlight = screen_backlight
  109.         self.backlight.duty(200)  # 确保25%亮度
  110.         
  111.         
  112.         # 初始化时分屏幕(前4个)
  113.         for i in range(len(config.TIME_SCREEN_CS_PINS)):
  114.             lcd = ST7735(80, 160, self.spi, dc=Pin(self.config.SCREEN_DC_PIN),
  115.                          cs=Pin(config.TIME_SCREEN_CS_PINS[i]),
  116.                          rst=Pin(config.TIME_SCREEN_RST_PINS[i]))
  117.             self.screens.append(lcd)
  118.             lcd.fill(self.config.COLORS['BLACK'])
  119.             lcd.show()
  120.         
  121.         # 初始化月日屏幕(后4个)
  122.         for i in range(len(config.DATE_SCREEN_CS_PINS)):
  123.             lcd = ST7735(80, 160, self.spi, dc=Pin(self.config.SCREEN_DC_PIN),
  124.                          cs=Pin(config.DATE_SCREEN_CS_PINS[i]),
  125.                          rst=Pin(config.DATE_SCREEN_RST_PINS[i]))
  126.             self.screens.append(lcd)
  127.             lcd.fill(self.config.COLORS['BLACK'])
  128.             lcd.show()
  129.         
  130.         # 初始化颜色
  131.         self.update_random_colors(force=True)
  132.    
  133.     def update_random_colors(self, force=False):
  134.         """更新4组颜色(时、分、月、日)"""
  135.         # 首次初始化或强制更新
  136.         if force or any(color is None for color in [self.time_color, self.minute_color, self.month_color, self.day_color]):
  137.             # 手动实现不重复随机选择
  138.             colors = self._get_unique_colors(4)
  139.             self.time_color, self.minute_color, self.month_color, self.day_color = colors
  140.             print(f"初始化颜色 - 时:{self.time_color:04X}, 分:{self.minute_color:04X}, 月:{self.month_color:04X}, 日:{self.day_color:04X}")
  141.             return
  142.         
  143.         # 保存历史颜色
  144.         last_colors = {self.time_color, self.minute_color, self.month_color, self.day_color}
  145.         
  146.         # 优先使用新颜色(排除历史颜色)
  147.         available = [c for c in self.display_colors if c not in last_colors]
  148.         new_colors = []
  149.         
  150.         # 尝试选择4种新颜色
  151.         temp_colors = available.copy()
  152.         while len(new_colors) < 4 and temp_colors:
  153.             idx = random.randint(0, len(temp_colors) - 1)
  154.             new_colors.append(temp_colors.pop(idx))
  155.         
  156.         # 若新颜色不足,从所有颜色中补充(可能包含历史颜色)
  157.         while len(new_colors) < 4:
  158.             color = random.choice(self.display_colors)
  159.             new_colors.append(color)
  160.         
  161.         # 确保4种颜色不同(最终检查)
  162.         while len(set(new_colors)) < 4:
  163.             for i in range(4):
  164.                 if len(set(new_colors)) >= 4:
  165.                     break
  166.                 new_colors[i] = random.choice(self.display_colors)
  167.         
  168.         # 应用新颜色
  169.         self.time_color, self.minute_color, self.month_color, self.day_color = new_colors
  170.         print(f"颜色已更新 - 时:{self.time_color:04X}, 分:{self.minute_color:04X}, 月:{self.month_color:04X}, 日:{self.day_color:04X}")
  171.    
  172.     def _get_unique_colors(self, count):
  173.         """自定义不重复颜色选择函数"""
  174.         colors = self.display_colors.copy()
  175.         result = []
  176.         # 随机选择不重复颜色
  177.         while len(result) < count and colors:
  178.             idx = random.randint(0, len(colors) - 1)
  179.             result.append(colors.pop(idx))
  180.         # 若颜色不足,用剩余颜色填充(概率极低)
  181.         while len(result) < count:
  182.             result.append(random.choice(self.display_colors))
  183.         return result
  184.    
  185.     def draw_digit(self, screen_idx, digit, group):
  186.         """绘制数字,group=0:时分, group=1:月日"""
  187.         if 0 <= screen_idx < len(self.screens):
  188.             # 选择颜色(时分组或月日组)
  189.             if group == 0:  # 时分组
  190.                 color = self.time_color if screen_idx < 2 else self.minute_color
  191.             else:  # 月日组
  192.                 color = self.month_color if screen_idx < 6 else self.day_color
  193.             
  194.             # 绘制数字
  195.             self.screens[screen_idx].fill_rect(5, 20, 70, 120, self.config.COLORS['BLACK'])
  196.             for seg in DIGIT_FONT.get(str(digit), []):
  197.                 seg(self.screens[screen_idx], 5, 20, color)
  198.             self.screens[screen_idx].show()
  199.    
  200.     def clear_all(self):
  201.         for screen in self.screens:
  202.             screen.fill(self.config.COLORS['BLACK'])
  203.             screen.show()
  204.         self.backlight.value(0)

  205. class WiFiConnector:
  206.     """WiFi连接管理类"""
  207.     def __init__(self, config):
  208.         self.config = config
  209.         self.wlan = None
  210.    
  211.     def connect(self):
  212.         import network
  213.         self.wlan = network.WLAN(network.STA_IF)
  214.         self.wlan.active(True)
  215.         if self.wlan.isconnected():
  216.             return True
  217.         self.wlan.connect(self.config.WIFI_SSID, self.config.WIFI_PASSWORD)
  218.         for _ in range(20):
  219.             if self.wlan.isconnected():
  220.                 return True
  221.             time.sleep(0.5)
  222.         return False
  223.    
  224.     def disconnect(self):
  225.         if self.wlan and self.wlan.isconnected():
  226.             self.wlan.disconnect()
  227.             self.wlan.active(False)

  228. class TimeSync:
  229.     """时间同步类"""
  230.     def __init__(self, config, rtc, wifi):
  231.         self.config = config
  232.         self.rtc = rtc
  233.         self.wifi = wifi
  234.    
  235.     def sync_time(self):
  236.         if not self.wifi.connect():
  237.             return False
  238.         for server in self.config.NTP_SERVERS:
  239.             try:
  240.                 ntptime.host = server
  241.                 ntptime.settime()
  242.                 local_time = time.localtime(time.time() + self.config.UTC_OFFSET * 3600)
  243.                 self.rtc.datetime((local_time[0], local_time[1], local_time[2], local_time[6],
  244.                                   local_time[3], local_time[4], local_time[5], 0))
  245.                 print(f"时间已同步为: {local_time[3]:02d}:{local_time[4]:02d}:{local_time[5]:02d} 星期{local_time[6]+1}")
  246.                 return True
  247.             except:
  248.                 continue
  249.         self.wifi.disconnect()
  250.         return False

  251. def main():
  252.     """主程序入口"""
  253.     config = Config()
  254.     screen_ctrl = ScreenController(config)
  255.     wifi = WiFiConnector(config)
  256.     rtc = RTC()
  257.     time_sync = TimeSync(config, rtc, wifi)
  258.     second_indicator = SecondIndicator(config)
  259.    
  260.     # 初始化星期显示模块(使用配置中的引脚和LED数量)
  261.     week_display = WeekDisplay(pin=config.WEEKDAY_PIN, count=config.WEEKDAY_LED_COUNT)
  262.    
  263.     # 首次同步时间
  264.     if not time_sync.sync_time():
  265.         print("警告:首次时间同步失败,使用设备现有时间")
  266.    
  267.     # 屏幕映射关系
  268.     time_screen_mapping = {0: 0, 1: 1, 2: 2, 3: 3}  # 时分屏幕索引到数字位置
  269.     date_screen_mapping = {4: 0, 5: 1, 6: 2, 7: 3}  # 月日屏幕索引到数字位置
  270.    
  271.     last_second = -1
  272.     last_minute = -1
  273.     last_sync_time = time.time()
  274.    
  275.     try:
  276.         while True:
  277.             current_time = rtc.datetime()
  278.             year, month, day, weekday, hours, minutes, seconds, _ = current_time
  279.             
  280.             # 时分数字(倒序排列)
  281.             time_digits = [minutes % 10, minutes // 10 % 10, hours % 10, hours // 10 % 10]
  282.             
  283.             # 月日数字(倒序排列)
  284.             date_digits = [day % 10, day // 10 % 10, month % 10, month // 10 % 10]
  285.             
  286.             # 每秒更新一次显示
  287.             if seconds != last_second:
  288.                 last_second = seconds
  289.                
  290.                 # 每分钟切换颜色
  291.                 if minutes != last_minute:
  292.                     last_minute = minutes
  293.                     screen_ctrl.update_random_colors()
  294.                
  295.                 # 更新时分显示(前4个屏幕)
  296.                 for screen_idx, digit_idx in time_screen_mapping.items():
  297.                     screen_ctrl.draw_digit(screen_idx, time_digits[digit_idx], group=0)
  298.                
  299.                 # 更新月日显示(后4个屏幕)
  300.                 for screen_idx, digit_idx in date_screen_mapping.items():
  301.                     screen_ctrl.draw_digit(screen_idx, date_digits[digit_idx], group=1)
  302.                
  303.                 # 更新星期显示(0=周一,6=周日)
  304.                 week_display.show_weekday(weekday)
  305.                
  306.                 # 每小时同步一次时间
  307.                 if time.time() - last_sync_time >= config.TIME_SYNC_INTERVAL:
  308.                     if time_sync.sync_time():
  309.                         last_sync_time = time.time()
  310.             
  311.             # 垃圾回收,防止内存泄漏
  312.             gc.collect()
  313.             time.sleep(0.1)  # 降低CPU使用率
  314.         
  315.     except KeyboardInterrupt:
  316.         # 忽略中断,确保继续执行
  317.         pass
  318.    
  319.     # 清理其他资源
  320.     try:
  321.         wifi.disconnect()
  322.         print("[WiFi已断开]")
  323.         
  324.         second_indicator.stop()
  325.         print("[秒指示灯已关闭]")
  326.         
  327.         week_display.clear()
  328.         print("[星期显示已清空]")
  329.         
  330.         # 关闭屏幕
  331.         screen_ctrl.clear_all()
  332.         print("[屏幕已清空]")
  333.         
  334.     except Exception as e:
  335.         print(f"清理其他资源时出错: {e}")
  336.    
  337.     # 最终确认信息
  338.     print("\n程序已安全退出")

  339. if __name__ == "__main__":
  340.     main()
复制代码


您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-21 00:25 , Processed in 0.280800 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表