数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 431|回复: 15

[Arduino] AKClock:ESP32C3直驱数码管的NTP对时电子钟

[复制链接]
发表于 3 天前 | 显示全部楼层 |阅读模式
老当益壮的麦兜也混迹一下开源社区。
从老王家买过蓝牙播放器的主板,上面有一个看上去还不错的led时钟屏,总想着怎么把它点起来。可惜不知道屏是如何接线的。
借助坛子里大家的智慧,感谢zj97czb坛友、得知这叫做  “四位七脚led数码管”。参见:《求助 一个时钟屏有37个段码却只有7个引脚是怎么做到的》 https://www.mydigit.cn/thread-526378-1-1.html
595953427@qq坛友、撒飒飒坛友 都提示了控制亮度,得用pwm波控制占空比。

又找到了坛子里6年前的老帖子,感谢 hecat、bg4rff 坛友提供了驱动程序的设计思路。参见:《五脚三位数码管的编码应该怎么编写》 https://www.mydigit.cn/thread-14059-1-2.html

有了以上框架和设计思路,就可以动手写软件了。基于软件是需要控制GPIO切换正负极,分别驱动LED的阳极A和阴极K来完成动态显示,所以给这个软件起了个名字叫做 AKClock
V0.0.1的初始版本,放到码云开源平台了。 https://gitee.com/maidoo/AKClock/tree/v0.0.1





大家要用首个初始版本V0.0.1的话,需要:
  • 修改主程序里的 SSID和WIFI密码。 下个版本把WifiManager模块加上就可以手机配置WIFI密码了。
  • 数码管内部接线如有不同,修改 ledmap.h 头文件即可重新适配。
  • 使用了ESP32中的LEDC设备输出PWM控制LED亮度(0~255),代码里设置初始值55。启动后,可以通过开发版的USB CDC串口设置亮度值(直接发送三个ASCII字符255,不要带回车)。

初始版本还很粗糙,后续功能展望:
  • 增加闹钟,直接模拟红外遥控器打开机顶盒、打开电视机,调到13频道看新闻联播
  • 开启蓝牙配置功能
  • 闹钟可以播放8bit音乐


代码创建了一个7x7的数组作为显示缓存,清楚表述了每个引脚作为正极时,其它6个引脚哪些该拉低(亮)或者高阻(灭)。
一个刷新显示的任务周期执行下面这个 refresh_led_one_frame()函数来实现动态显示
  1. /*
  2. * [url=home.php?mod=space&uid=650075]@brief[/url] 刷新一帧LED显示数据,执行时间16毫秒。
  3. * 该函数通过逐引脚扫描的方式,依次激活每个数码管控制引脚,
  4. * 根据显示缓存数据决定对应LED的亮灭,实现数码管的动态显示。
  5. * 最后会补充一个消隐时间,避免余晖影响显示效果。
  6. */
  7. void refresh_led_one_frame(void)
  8. {
  9.     uint8_t a, k;

  10.     // 7个正极引脚逐个扫描,依次激活每个数码管控制引脚
  11.     for(a = 0 ; a < IO_NUM7 ; a++) {

  12.         // 先将所有引脚设置为高阻态,即输入状态,避免引脚间的干扰
  13.         led_gpio_clear();

  14.         // 再将当前引脚设置为高电平,即选中当前引脚,作为正极输出(推挽模式,作为正极公共极)
  15.        pinMode     (led_pin_gpio[a], OUTPUT);
  16.        digitalWrite(led_pin_gpio[a], HIGH);

  17.         // 配置LEDC通道,控制PWM占空比来控制LED亮度
  18.         pinMatrixOutAttach(led_pin_gpio[a], LEDC_CHANNEL0_FUNC, false, false);

  19.         // 每个正极对应的6个负极引脚逐个扫描,处理每个点位
  20.         for (k = 0; k < IO_NUM7; k++)  {

  21.                 if (display_cache[a][k] == 1)  {
  22.                     // 若当前显示点位需要点亮,则需要拉低对应的负极引脚(OD或者推挽模式都可以)。
  23.                     digitalWrite  (led_pin_gpio[k], LOW);
  24.                 }
  25.                 else if (display_cache[a][k] == 0) {
  26.                     // 若当前显示点位需要熄灭,将对应负极设置为高阻态,即OD输出模式下拉高
  27.                     // 前面 led_gpio_clear() 已经设置为默认的HIGH状态,这里可以减少重复操作
  28.                     // digitalWrite  (led_pin_gpio[k], HIGH);
  29.                 } else {
  30.                     // 其他的=3的值,是数组中a==k情况,无意义,无需任何操作
  31.                     // pinMode(led_pin_gpio[k], OUTPUT_OPEN_DRAIN);
  32.                 }
  33.         }

  34.         // 每个公共正极引脚扫描显示暂留2毫秒,一轮16毫秒(7个引脚 * 2毫秒 + 2ms),显示整体刷新速率约62赫兹。
  35.         vTaskDelay(pdMS_TO_TICKS(2));

  36.         // 拆除公共正极的PWM调制波
  37.         ledcDetachPin(led_pin_gpio[a]);

  38.         // 扮演完毕的公共极,从推挽输出模式切换为OD开漏输出模式,默认状态为高阻态
  39.         pinMode(led_pin_gpio[a], OUTPUT_OPEN_DRAIN);
  40.         digitalWrite(led_pin_gpio[a], HIGH);
  41.     }

  42.     // 补充一个周期的消隐时间,熄灭所有段位,避免余晖影响显示效果
  43.     led_gpio_clear();
  44.     vTaskDelay(pdMS_TO_TICKS(2));
  45. }
复制代码


本帖子中包含更多资源

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

x

打赏

参与人数 1家元 +60 收起 理由
家睦 + 60

查看全部打赏

发表于 3 天前 | 显示全部楼层
谢谢分享支持一下
回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
ESP32C3,便宜、性能强大,是高性价比的物联网模块
回复 支持 1 反对 0

使用道具 举报

发表于 3 天前 | 显示全部楼层
谢谢分享支持一下
回复 支持 反对

使用道具 举报

发表于 前天 10:03 | 显示全部楼层
牛B+Plus,牛B+Plus,牛B+Plus
回复 支持 反对

使用道具 举报

发表于 前天 11:35 | 显示全部楼层
谢谢分享~进来学习一下
回复 支持 反对

使用道具 举报

发表于 前天 12:02 | 显示全部楼层
谢谢分享,有空也试试。
回复 支持 反对

使用道具 举报

发表于 前天 20:47 | 显示全部楼层
看着好复杂啊
回复 支持 反对

使用道具 举报

发表于 前天 21:12 来自手机浏览器 | 显示全部楼层
如果驱动芯片没有恒流功能,非必要不要使用这种数码管。
回复 支持 反对

使用道具 举报

 楼主| 发表于 前天 21:46 | 显示全部楼层
mmxx2015 发表于 2025-7-16 21:12
如果驱动芯片没有恒流功能,非必要不要使用这种数码管。

你是有经验的,能请教展开讲讲吗?
ESP32C3手册上提到,可以配置IO口的最大驱动电流,但是也算不上是你口中的横流功能吧?这种情况下,如何软件上优化亮度的均匀度?感谢!
回复 支持 反对

使用道具 举报

发表于 昨天 00:34 | 显示全部楼层
本帖最后由 mmxx2015 于 2025-7-17 00:40 编辑
maidoo 发表于 2025-7-16 21:46
你是有经验的,能请教展开讲讲吗?
ESP32C3手册上提到,可以配置IO口的最大驱动电流,但是也算不上是你口 ...

显示周期相同的情况下,LED亮度和电流、显示时间有关,我一般把它们等价线性处理,即它们的乘积=亮度值,比如,假设显示周期相同,LED电流=10mA && 显示时间=1mS和LED电流=5mA && 显示时间=2mS显示亮度相当。

因为I/O存在电阻,输出/输入电流越大,压降越大,这导致同一时间点亮不同LED数时每个LED的电流不一样,点亮的LED少,单个LED电流大,点亮的LED多,单个LED电流小。先测得点亮单个LED~最多个LED n的单个LED电流I1~In,假设点亮最多个LED时显示时间=Tn,则点亮(n-1)个LED的显示时间为(In/I(n-1))*Tn。要实现这个控制,需要2个定时器,一个控制显示周期,一个控制显示时间,以上述假设为例,假设Tn=1mS,T(n-1)=0.9mS,点亮n个LED时定时器1控制显示切换时间=1mS,另一个定时器2不工作,点亮(n-1)个LED时定时器1控制显示切换时间=1mS,另一个定时器2定时(1mS-0.9mS)=0.1mS后关闭显示(暂不换)。

显示LED数从多到少控制时序示意图



本帖子中包含更多资源

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

x
回复 支持 反对

使用道具 举报

发表于 昨天 10:55 | 显示全部楼层
mmxx2015 发表于 2025-7-17 00:34
显示周期相同的情况下,LED亮度和电流、显示时间有关,我一般把它们等价线性处理,即它们的乘积=亮度值, ...

看不懂,感觉很牛!
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 14:05 来自手机浏览器 | 显示全部楼层
mmxx2015 发表于 2025-7-17 00:34
显示周期相同的情况下,LED亮度和电流、显示时间有关,我一般把它们等价线性处理,即它们的乘积=亮度值, ...

谢谢mmxx2015的指点,我明白了,软件修正方法就是要控制电流和时间的乘积相等来达到亮度均匀。七脚的数码管,那就需要实际测量最大电流i1到最小电流I6。这6个数值因数码管型号和颜色不同而不同。而且还需要工装程序配合操作。有点麻烦。
在实际应用当中有没有再简便一点的方法?比如把这6个电流值经曲线拟合后,是否能简化出一个经验公式?就是说把I(n)相关的函数简化为只跟下标n相关?这样我可以不测电流或者仅测一个i1电流值?
借用一下您智慧,在平常工作中有这样的经验公式吗?谢谢
回复 支持 反对

使用道具 举报

发表于 昨天 17:45 来自手机浏览器 | 显示全部楼层
maidoo 发表于 2025-7-17 14:05
谢谢mmxx2015的指点,我明白了,软件修正方法就是要控制电流和时间的乘积相等来达到亮度均匀。七脚的数码 ...

这个没有经验值,因为每一种单片机I/O的输出/输入电流能力不同,比如传统8051单片机输出电流都不足以点亮一个LED,但很多改进的8051单片机I/O有100mA以上输出能力,一般单片机输入电流能力比较强,可能与推挽拉低使用NMOS管比拉高使用线PMOS管好做且n导通内阻更低有关。数码管差异的影响小一些,如果相同的单片机测一次值后下次可以直接参考,换其它驱动能力相近的单片机也可以直接参考。
回复 支持 反对

使用道具 举报

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

本版积分规则

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

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-18 23:15 , Processed in 0.140400 second(s), 8 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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