news 2026/9/23 6:46:59

使用 Johnny-Five 的 Led.Digits 打造七段数码管数字时钟

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Johnny-Five 的 Led.Digits 打造七段数码管数字时钟

使用 Johnny-Five 的 Led.Digits 打造七段数码管数字时钟

【免费下载链接】johnny-fiveJavaScript Robotics and IoT programming framework, developed at Bocoup.项目地址: https://gitcode.com/gh_mirrors/jo/johnny-five

导读

本文围绕 Johnny-Five(JavaScript Robotics and IoT 编程框架)官方示例文档 docs/led-digits-clock.md 展开,讲解如何利用Led.Digits驱动七段数码管(7 Segment Digits)在 Arduino、Intel Galileo Gen 2 等平台上实现一个每秒刷新的数字时钟。读完本文,你将掌握Led.Digits的初始化方式、print()digit()的底层工作机制、时间字符串的格式化技巧,以及如何将同一段代码移植到不同控制器平台。

示例概述:一块会走的数字钟

原文档给出了一个非常直观的示例:使用七段数码管和 Intel Galileo Gen 2 打造一台时钟,并且明确指出该示例可以轻松移植到任何 Johnny-Five 支持的平台(例如 Arduino Uno)。核心思路如下:

  • 通过Led.Digits封装数码管硬件,指定datacsclock三个引脚;
  • board.on("ready")之后,用setInterval每秒调用一次digits.print(time())
  • time()函数借助 moment.js 生成形如02.25.54 P的格式化字符串,并做一次正则替换,得到适合单字母上下午(meridiem)的显示内容。

在仓库中,该示例存在三个版本,可直接对照阅读:

  • eg/led-digits-clock.js:默认 Arduino 平台版本;
  • eg/led-digits-clock-arduino.js:与默认版本等价;
  • eg/led-digits-clock-galileo.js:使用galileo-io作为 IO 层的 Galileo 版本。

运行 Galileo 版本的方式(与文档一致):

node eg/led-digits-clock-galileo.js

运行普通 Arduino 版本则执行:

node eg/led-digits-clock.js

接线图与硬件准备

原文档提供了两种接线的 Fritzing 图,均以仓库根目录为起点:

  • Galileo 接线图:docs/breadboard/led-digits-clock-galileo.png,对应 Fritzing 源文件 docs/breadboard/led-digits-clock-galileo.fzz;
  • Arduino 接线图:docs/breadboard/led-digits-clock-arduino.png,对应 Fritzing 源文件 docs/breadboard/led-digits-clock-arduino.fzz。

接线要点(对应源码中的引脚配置):数码管/驱动板的datacsclock三根信号线分别接到控制器的 2、3、4 号数字引脚(本例配置),公共端与电源按驱动板手册连接。仓库中还有基于 HT16K33 等 I2C 控制器的变体接线图,如 docs/breadboard/led-digits-clock-HT16K33.png 和 docs/breadboard/led-digits-clock-dual.png,可作为后续移植参考。

完整代码与逐段讲解

const moment = require("moment"); const { Board, Led } = require("johnny-five"); const Galileo = require("galileo-io"); const board = new Board({ io: new Galileo() }); board.on("ready", () => { var digits = new Led.Digits({ pins: { data: 2, cs: 3, clock: 4, } }); setInterval(() => digits.print(time()), 1000); }); function time() { /* The desired display looks something like these examples: 02.25.54 P 12.30.00 A moment doesn't have an option for a single letter meridiem (nor should it, that would be silly), so we need to manipulate the string a bit to so that it the string matches our desired display. */ return moment().format("hh.mm.ssA") .replace(/([AP])M/, " $1"); }

1. 依赖与平台抽象

const moment = require("moment"); const { Board, Led } = require("johnny-five"); const Galileo = require("galileo-io");
  • moment:时间格式化库,负责生成hh.mm.ssA形式的时间字符串;
  • johnny-five:提供Board(板卡抽象)与Led(LED 家族,含Led.Digits);
  • galileo-io:Galileo 平台的 IO 适配层。若使用 Arduino,则省略这一行,直接new Board()即可(见 eg/led-digits-clock-arduino.js)。

这种"Board + io 注入"的结构正是 Johnny-Five 的平台可移植性来源:代码逻辑不变,只换 IO 层就能换硬件平台。

2. 初始化数码管

const digits = new Led.Digits({ pins: { data: 2, cs: 3, clock: 4, } });

Led.Digits是 lib/led/digits.js 中定义的一个极简类,它继承自LedControl并强制options.isMatrix = false

class Digits extends LedControl { constructor(options) { options.isMatrix = false; super(options); } static get CHARS() { return LedControl.DIGIT_CHARS; } }

LedControl(见 lib/led/ledcontrol.js)支持两种控制器:

  • 默认控制器(MAX7219/MAX7221 类 SPI 驱动):通过pins指定dataclockcs(chip select,也接受别名latch)三个数字引脚。源码中初始化时会把这几个引脚全部设为OUTPUT模式(见 lib/led/ledcontrol.js),并按 MAX7219 的寄存器顺序发送BRIGHTNESSSCANLIMITSHUTDOWNDISPLAYTEST等配置指令;
  • HT16K33 控制器(I2C 驱动):通过address/addressesdims配置,适用于带 I2C 接口的数码管背板。

pins既可以是对象{ data, clock, cs },也可以是数组[data, clock, cs]。其它可用选项还包括devices(级联的驱动芯片数量)、digits(每块芯片的位数,默认 8)、colon(设备是否内置冒号)等。

3. 每秒刷新一次

setInterval(() => digits.print(time()), 1000);

每 1000ms 生成一次当前时间字符串并调用digits.print()print()LedControl的核心显示方法(见 lib/led/ledcontrol.js),它会用正则/([0-9A-Za-z][.]|[0-9A-Za-z:]|[\s])/g把字符串拆成"字符单元"(支持带小数点字符、冒号、空白),然后逐个调用digit()写入对应位置。若设备配置了colon: trueprint()还会在超过两个字符且第 3 个字符不是:或空格时自动插入空格占位,让内置冒号的数码管更自然地居中显示。

digit()(见 lib/led/ledcontrol.js)则负责把单个字符映射成段码:优先查LedControl.DIGIT_CHARS字模表,查不到时回退为Math.abs(Number(character));若字符后带.,则与小数点段码0x80做按位或。

4. 时间格式化与字符串处理

return moment().format("hh.mm.ssA") .replace(/([AP])M/, " $1");
  • moment().format("hh.mm.ssA"):输出 12 小时制时间,如02.25.54PM。其中hh是 12 小时制(01-12),mm是分钟,ss是秒,A是 AM/PM 大写字母;
  • .replace(/([AP])M/, " $1"):把AM/PM压缩成单个字母A/P,并在前面补一个空格,使最终显示为02.25.54 P/12.30.00 A,与七段数码管的显示习惯一致。

小数点在这里起到分隔时、分、秒的作用(., 段码为0x80),这正是print()正则允许"数字 + 小数点"单元的原因。

显示字模与字符支持

Led.Digits.CHARS暴露了完整的数字字模表(见 lib/led/led-chars.js),它是LedControl.DIGIT_CHARS的静态别名,支持:

  • 数字:09(例如"8": 0x7F,全段点亮);
  • 标点与分隔符:空格0x00、小数点.0x80、冒号:0xFF、感叹号!0xB0
  • 大小写字母:AZaz(七段近似显示)。

如果你要显示自定义字符,可以基于这张表扩展,并把对应的 8 位段码直接传给digit(addr, position, chr),或直接传数字段码。

移植到其它平台与控制器

原文档强调"这个示例可以轻松移植到任何其它受支持平台",移植路径有两种:

  1. 更换 IO 层(同一块数码管):Galileo 用new Board({ io: new Galileo() }),Arduino 用new Board(),Raspberry Pi 可换成raspi-io,Tessel 可换成tessel-io等,业务代码不变;
  2. 更换驱动控制器(同一套代码):若数码管背板是 HT16K33(I2C),将pins换成address(如0x70)与dims,其余print()/digit()调用方式一致;该控制器的初始化、blinkbrightnessclear等实现在 lib/led/ledcontrol.js 的Controllers.HT16K33中,可据此了解 I2C 版本的行为差异。

常见问题与注意事项

  • 必须等board.on("ready")再操作:所有 IO 初始化都在 ready 事件之后进行,否则引脚与控制器尚未就绪;
  • 字符数量不要超过位数:默认digits: 8,本示例显示 8 个字符(hh.mm.ss P恰好 8 个单元);超出位数的字符会被忽略;
  • time()始终返回固定长度字符串moment().format("hh.mm.ssA")hh/mm/ss均会补零,保证 12 小时制下字符串长度稳定,避免因数字位数变化导致显示错位;
  • SPI 引脚需要支持数字输出dataclockcs必须使用数字引脚,且注意电平与驱动板兼容。

深入阅读

  • 数码管实现类:lib/led/digits.js
  • 底层控制器(MAX7219/HT16K33 双控制器实现):lib/led/ledcontrol.js
  • 字模表(含数字、冒号、小数点与字母):lib/led/led-chars.js
  • 示例源码:eg/led-digits-clock.js、eg/led-digits-clock-galileo.js
  • 相关教程文档:docs/led-digits-clock-dual.md(双模块时钟)、docs/led-digits-clock-HT16K33.md(HT16K33 版)

结合本文的源码剖析,你可以在任意 Johnny-Five 支持的平台上快速复现这台数码管时钟,并将Led.Digitsprint()能力扩展到倒计时器、秒表、计数器等更多场景。

【免费下载链接】johnny-fiveJavaScript Robotics and IoT programming framework, developed at Bocoup.项目地址: https://gitcode.com/gh_mirrors/jo/johnny-five

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 6:46:56

Z3 TypeScript API 正则表达式(Regular Expression)支持完全指南

Z3 TypeScript API 正则表达式(Regular Expression)支持完全指南 【免费下载链接】z3 The Z3 Theorem Prover 项目地址: https://gitcode.com/gh_mirrors/z3/z3 本文以 Z3 官方 TypeScript 绑定(npm 包 z3-solver)新增的正…

作者头像 李华
网站建设 2026/9/23 6:46:55

苹果x拍照技巧源码解析 新手避坑指南

苹果x拍照技巧源码解析 新手避坑指南 配置环境就卡半天,是不是你的常态?很多刚入行的同学拿到 iPhone X 想搞点自动化测试或者图像采集,结果被环境配置折磨得怀疑人生。别急,今天咱们不整虚的,直接通过 源码解析 的思路,拆解苹果x拍照技巧背后的底层逻辑。你不需要成为系统工程师,只要懂点…

作者头像 李华
网站建设 2026/9/23 6:46:43

3步手写实现网站建设文章系统告别只会语法

3步手写实现网站建设文章系统告别只会语法 刚毕业那会儿,我盯着IDE里满屏的绿色代码,心里直打鼓。语法都背熟了,正则表达式能默写,设计模式能讲出个一二三,但真要让我从零搭一个能上线的网站,手就开始抖。这种 学会语法却不知怎么搭项目…

作者头像 李华
网站建设 2026/9/23 6:46:39

90科技面试避坑指南,一文搞懂证书变更注销流程

90科技面试避坑指南,一文搞懂证书变更注销流程 配置环境就卡半天?别慌,这不是你的问题,是流程没理顺。很多转岗过来的朋友,一到“90科技”这种特定业务场景的面试,脑子里就一团浆糊。面试官问起证书变更、注销流程,你张口就来“找管理员”,瞬间露怯。今天这篇文章,不整虚的,咱们把【90科技】高频面试题拆碎…

作者头像 李华
网站建设 2026/9/23 6:46:23

5分钟搞懂工商个人网上银行登录源码 从入门到精通

5分钟搞懂工商个人网上银行登录源码 从入门到精通 盯着满屏红色的 StackTrace 报错,是不是脑子瞬间炸了?别慌,咱们今天不背八股文,直接拆解【工商个人网上银行登录】背后的技术逻辑,带你从入门到精通。很多开发者觉得银行系统黑盒,其实核心就那点事:会话保持、令牌验证、前端交互。…

作者头像 李华