资料介绍
描述
在这个项目中,时间、日期和最新的头条新闻将在 LED 矩阵上显示为自动收报机。日期和时间将从时间服务器更新。标题来自所谓的 RSS 提要。这是由各种网络服务器提供的服务,例如 tagesschau.de。此服务使用 http 或 https 作为传输协议,但数据不是像往常一样以 HTML 格式提供,而是以 XML 格式提供,即没有布局信息。
电路
LED 矩阵仅连接到 ESP32 的 SPI 总线。ESP32 MOSI (GPIO23) 的数据输出连接到矩阵的 DIN。ESP32 CLK (GPIO19) 的时钟输出连接到矩阵的时钟输入。ESP32的GPIO16用作片选,连接到矩阵的CS连接器。矩阵由 5V 供电,这对 ESP32 没有问题,因为这里使用的所有连接器都用作输出,因此无法从矩阵获得更高的电压。
程序
除了 ESP32 包之外,您还需要四个库。我们使用 TinyXML 库从接收到的 XML 数据中提取所需的信息。图书馆只有三个功能。
void init (uint8_t* buffer, uint16_t maxbuflen, XMLcallback XMLcb); 该函数在设置函数中被调用。参数buffer指向一个存放临时数据的字节数组,参数maxbuflen指定了缓冲区的大小。参数 XMLcallback 指向一个回调函数
void XML_callback(uint8_t statusflags, char* tagName, uint16_t tagNameLen, char* data, uint16_t dataLen)
只要 XML 元素已被完全处理,就会调用它。statusflags 参数指定提供哪些数据。由于我们对 XML 标记的内容感兴趣,因此我们将只使用状态 STATUS_TAG_TEXT。tagName 参数指向包含项目完整 XML 路径的字符数组。对于新闻源项目的标题,这是路径“/rss/channel/item/title”。tagNameLen 参数返回路径的长度。参数数据还指向包含数据的字符数组。最后一个参数 dataLen 返回数据数组的大小。
无效重置();此函数重置所有内部指针。它应该总是在读入新的 XML 数据之前被调用。
void processChar(uint8_t ch); 此函数将要处理的 XML 数据的一个字符发送到 XML 解析器。必须为接收到的每个字符顺序调用此函数。如果传输的字符导致 XML 块的完成,则使用相应的数据调用回调函数。LG_Matrix_Print 库用于在 LED 矩阵上显示字符串。草图中使用了以下函数:void setEnabled(bool enabled); 启用或禁用对 LED 矩阵的访问。
void setIntensity(uint8_t level); 此功能更改显示屏的亮度。允许使用 0 到 15 之间的值。通常1就足够了
无效显示();显示存储器的内容被传输到矩阵并因此可见。
void clear()清除显示内存。
int printText(int start, String text, boolean isUTF8 = true); 此函数使用内部字符集将文本参数中指定的字符串(从第 n 个字符开始)转换为显存中相应的位模式。输出开始的字符在 start 参数中指定。可选参数 isUTF8 打开或关闭内部代码转换器。
void ticker(字符串消息,uint16_t 等待);这个函数可以很容易地实现一个自动收报机。参数 message 指向包含要显示的文本的字符串。第二个参数 wait 指定在文本前进一个像素之前等待的时间(以毫秒为单位)。图书馆负责其他一切。
布尔更新代码();必须在循环函数中调用此函数以更新代码。
该库包含其他功能,但在此草图中未使用它们。WebConfig 库用于通过浏览器配置 WLAN 访问数据以及其他设置。配置存储在闪存文件系统 SPIFFS 中,即使在微控制器关闭后也会保留。详细说明可以在: https ://github.com/GerLech/WebConfig/blob/master/README.md或在我的书Smarthome 中找到。
WebConfig 库需要 Arduino_JSON 库,因此也必须安装它,但未包含在草图中。
草图
#include //Bibliothek für die Matrixanzeige
#include
//Web Client für den Empfang des RSS-Feeds
#include //Filesystem zum Speichern der Konfiguration
#include //Webserver für die Konfiguration
#include //Multicast DNS für Namensauflösung
#include
//Bibliothek zur Konfiguration über eine Webseite
#include //XML-Interpreter zum Lesen des RSS-Feed
#define LEDMATRIX_CS_PIN 16 //CS Pin der LED Matrix
// Anzahl der 8x8 LED Segmente
#define LEDMATRIX_SEGMENTS 4
// Timeout zum Lesen des RSS-Feed in Sekunden
#define READ_TIMEOUT 10
//Prameter für das Konfigurations-Formular
String params = "["
"{"
"'name':'ssid',"
"'label':'Name des WLAN',""'type':"+String(INPUTTEXT)+","
"'default':''"
"},"
"{"
"'name':'pwd',"
"'label':'WLAN Passwort',"
"'type':"+String(INPUTPASSWORD)+","
"'default':''"
"},"
"{"
"'name':'rssUrl',"
"'label':'RSS Feed URL',"
"'type':"+String(INPUTTEXT)+","
"'default':''"
"},"
"{"
"'name':'ntp',"
"'label':'NTP Server',"
"'type':"+String(INPUTTEXT)+","
"'default':'de.pool.ntp.org'"
"},"
"{"
"'name':'maxNews',"
"'label':'Schlagzeilen',"
"'type':"+String(INPUTNUMBER)+","
"'min':1,'max':10,"
"'default':'1'"
"},"
"{"
"'name':'intens',"
"'label':'Helligkeit',"
"'type':"+String(INPUTNUMBER)+","
"'min':1,'max':15,"
"'default':'1'"
"},"
"{"
"'name':'disptime',"
"'label':'Anzeigedauer (s)',"
"'type':"+String(INPUTNUMBER)+","
"'min':1,'max':30,"
"'default':'5'"
"}"
"]";
//Web Server Instanz
WebServer server;
//Web Konfigurations Instanz
WebConfig conf;
//LED Matrix Instanz
LG_Matrix_Print lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);
//XML Interpreter Instanz
TinyXML xml;
//Globale Variablen
uint32_t last = 0; //Zeit der letzten Aktion in ms
uint8_t buffer[2000]; //Buffer für XML-Interpreter
String news[10]; //Speicher für Nachrichten (Max. 10)
uint8_t newsCnt = 0; //Anzahl der aktuellen Nachrichten im Speicher
uint8_t curNews = 0; //Index der gerade angezeigten Nachricht
uint8_t dispMode = 0; //Art der Anzeige 0=Zeit, 1=Datum, 2=News;
//Diese Funktion wird vom XML-Interpreter aufgerufen,
//wenn ein XML-Tag gelesen wurde
//tagName enthält den vollständigen XML-Pfad des Tags,
//data den Inhalt des Tags
void XML_callback(uint8_t statusflags, char* tagName, uint16_t tagNameLen, char* data, uint16_t dataLen) {
if (statusflags & STATUS_TAG_TEXT) {
//Serial.println(tagName);
//wenn wir einen Titel-Tag finden,
//und die maximale Anzahl der Meldungen noch
//nicht erreicht ist, wird die Meldung gespeichert
//und der Zähler erhöht
if (strcasecmp(tagName,"/rss/channel/item/title")==0) {
data[dataLen] = '\0';
if (newsCnt < conf.getInt("maxNews")) {
//Die maximale Anzahl der Nachrichten wird
//aus der Konfiguration gelesen
news[newsCnt] = data;
newsCnt++;
}
}
}
}
//WLAN Verbindung initialisieren
boolean initWiFi() {
boolean connected = false;
WiFi.mode(WIFI_STA);
Serial.print("Verbindung zu ");
Serial.print(conf.values[0]);
Serial.println(" herstellen");
if (conf.values[0] != "") {
//wenn eine SSID bekannt ist,
//wird versucht eine Verbindung herzustellen
WiFi.begin(conf.values[0].c_str(),conf.values[1].c_str());
uint8_t cnt = 0;
while ((WiFi.status() != WL_CONNECTED) && (cnt<20)){
delay(500);
Serial.print(".");
cnt++;
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("IP-Adresse = ");
Serial.println(WiFi.localIP());
connected = true;
}
}
//konnte keine Verbindung hergestellt werden,
//wird ein Accesspoint gestartet
//der Accesspoint hat kein Passwort. Über die IP-Adresse
//192.168.4.1 kann die Konfiguration durchgeführt werden
if (!connected) {
WiFi.mode(WIFI_AP);
WiFi.softAP(conf.getApName(),"",1);
}
return connected;
}
//Diese Funktion wird aufgerufen,
//wenn der Webserver eine Anfrage erhält
void handleRoot() {
//Die Anfrage wird an die Konfigurationsinstanz weitergegeben
conf.handleFormRequest(&server);
}
//Neue Nachrichten vom RSS-Feed lesen
void getNews() {
String error = "";
if(WiFi.status()== WL_CONNECTED){
//HTTP Client
HTTPClient http;
Serial.print("[HTTP] begin...\n");
//url aus der Konfiguration
http.begin(conf.getValue("rssUrl"));
Serial.print("[HTTP] GET...\n");
// Anfrage abschicken
int httpCode = http.GET();
// httpCode ist im Fall eines Fehlers negativ
if(httpCode > 0) {
// HTTP Antwort vom Server erhalten
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
xml.reset();
for (uint16_t i=0; i.length(); i++) xml.processChar(payload[i]);
}
else{
error = "Server antwortet mit "+String(httpCode);
}
} else {
error = "Server antwortet mit "+http.errorToString(httpCode);
}
http.end();
if (newsCnt > 0) {
//Falls Nachrichten empfangen wurden,
//wird die erste Nachricht angezeigt
curNews = 0;
lmd.ticker(news[0],100);
}
} else {
initWiFi();
error = "Keine Internetverbindung!";
}
if (error != "") {
news[0] = error;
newsCnt = 1;
curNews = 0;
lmd.ticker(news[0],100);
}
}
//Die aktuelle Uhrzeit wird angezeigt wenn start wahr ist
void showTime(boolean start){
if (start) {
Serial.println("Time Start");
last = millis();
char sttime[10];
struct tm timeinfo;
dispMode=0;
if(getLocalTime(&timeinfo)){
strftime(sttime, sizeof(sttime), "%H:%M ", &timeinfo);
lmd.printText(0,String(sttime));
lmd.display();
} else {
//liefert die RTC keine Werte so wird ??:?? angezeigt
lmd.printText(0,"??:?? ");
lmd.display();
}
} else {
//Wenn das Ende der Anzeigedauer erreicht wurde,
//wird auf Datum umgeschaltet
if ((millis()-last) > (conf.getInt("disptime")*1000)) {
showDate(true);
}
}
}
//Das aktuelle Datum wird angezeigt wenn start wahr ist
void showDate(boolean start) {
if (start) {
Serial.println("Date Start");
last = millis();
char sttime[10];
struct tm timeinfo;
dispMode = 1;
if(getLocalTime(&timeinfo)){
strftime(sttime, sizeof(sttime), "%d.%b ", &timeinfo);
lmd.printText(0,String(sttime));
lmd.display();
} else {
//liefert die RTC keine Werte so wird ??.??? angezeigt
lmd.printText(0,"??.???");
lmd.display();
}
} else {
//Wenn das Ende der Anzeigedauer erreicht wurde,
//wird auf News umgeschaltet
if ((millis()-last) > (conf.getInt("disptime")*1000)) {
showNews(true);
}
}
}
//Eine Nachricht wird angezeigt wenn start wahr ist
//werden Nachrichten vom Server geholt und
//die erste Nachricht angezeigt sonst die nächste
void showNews(boolean start) {
if (start) {
Serial.println("News Start");
if (curNews == 0) {
getNews();
} else {
lmd.ticker(news[curNews],100);
}
dispMode = 2;
} else {
//der Ticker wird aktualisiert. Wenn das Ende der Nachricht erreicht
//wurde wird auf die nächste Nachricht weitergeschaltet.
//Die Anzeige wird auf Zeitanzeige umgeschaltet
if (!lmd.updateTicker()) {
curNews++;
if (curNews >= newsCnt) curNews = 0;
showTime(true);
}
}
}
//Wird einmal beim Start des Programms ausgeführt
void setup() {
//Filesystem initialisieren und
//falls noch nicht geschehen, formatieren
SPIFFS.begin(true);
//Serielle Schnittstelle starten
Serial.begin(115200);
//XML-Interpreter initialisieren
xml.init((uint8_t *)buffer, sizeof(buffer), &XML_callback);
//Formular zur Webkonfiguration vorbereiten
conf.setDescription(params);
//Konfiguration falls vorhanden aus dem Filesystem lesen
conf.readConfig();
// Anzeige initialisieren
lmd.setEnabled(true);
lmd.setIntensity(conf.getInt("intens")); // 0 = low, 10 = high
lmd.clear();
lmd.display();
//WLAN Verbindung herstellen
initWiFi();
//Multicast DNS starten
char dns[30];
sprintf(dns,"%s.local",conf.getApName());
if (MDNS.begin(dns)) {
Serial.println("MDNS responder gestartet");
}
//Webserver starten
server.on("/",handleRoot);
server.begin(80);
delay(1000);
//Wenn eine Internetvebindung besteht, die Echtzeituhr des ESP32
//mit Daten vom Zeitserver starten
if (WiFi.status()== WL_CONNECTED) configTzTime("CET-1CEST,M3.5.0/03,M10.5.0/03", conf.getValue("ntp"));
showTime(true);
}
void loop() {
if (millis() < last) last=millis();
//falls ein Überlauf auftrat nach etwa 50 Tagen
//Anfragen des Webserver behandeln
server.handleClient();
//Anzeige aktualisieren
switch (dispMode) {
case 0: showTime(false); break;
case 1: showDate(false); break;
case 2: showNews(false); break;
}
}
启动后,程序还不能与WLAN建立连接。因此,接入点被启动。它的 SSID 是 ESP32 的 MAC 地址。在智能手机的 WLAN 设置中,您应该会看到 SSID。您现在可以选择此网络并连接到它。网络不需要密码。智能手机可能会报告无法连接互联网,以及您是否要保留所选网络。在这种情况下,点击 Keep。< pan>
现在您可以启动浏览器并调用 URL 192.168.4.1。矩阵时钟的配置页面应该会出现。
接入点的名称是 MAC 地址,可以根据需要进行更改。随后是 WLAN 的访问数据。例如,对于 RSS 提要的 URL,您可NTP 服务器可以保持原样。但是您也可以设置例如带有 fritz.box 的 Fritzbox。接下来,您必须设置标题的最大数量、显示屏的亮度和以秒为单位的时间,时间和日期应显示多长时间。最后点击保存并重新启动。矩阵时钟将重新启动,现在应该连接到 WLAN。在串行监视器的输出中,您可以跟随登录。然后可以通过路由器分配给矩阵时钟的 IP 地址访问配置页面。
安装在外壳中
那些拥有 3D 打印机的人可以打印出合适的房屋。一共需要四个部分。一个底部部件 Uhr_unterten.stl,一个盖子 Uhr_deckel.stl 和两个显示器支架 Uhr_halter.stl。现在到大会。首先,面包板配有两个母连接器和一个带角度的公连接器。< pan>
下面的接线是在后面板上进行的。
现在您可以将控制器插入母连接器,并通过 5 针电缆将矩阵与控制器连接起来。在这里你必须注意引脚的正确顺序。插入后,是时候再次检查所有内容并在开始安装之前进行试运行了。
下一步是在外壳中安装矩阵和面包板。为了连接矩阵,必须首先将两个支架连接到矩阵。
现在您可以将矩阵固定在盖子上,将面包板固定在底座上。< pan>
就是这样了。带有新闻提要的矩阵时钟已准备就绪
玩得开心。
- Haiku eInk阅读器开源分享
- 模拟阅读器开源分享
- 基于鸿蒙系统的ZBar条形码阅读器教程 11次下载
- 电子阅读器的电路原理图免费下载 49次下载
- Python简历样本—模拟仪表阅读器下载 1次下载
- 基于图论的阅读器防碰撞算法 1次下载
- PDF阅读器AcroRd32软件 22次下载
- 身份证阅读器SDK使用手册 23次下载
- Flash单片机原理(请用超星阅读器阅读) 5次下载
- 超星阅读器免费下载 19次下载
- 基于S1D13521的电子纸阅读器的设计 129次下载
- PDF阅读器绿色版 0次下载
- 基于S6700的阅读器的设计与实现
- txt文档阅读器
- djvu阅读器下载
- 手搓了一个ESP32墨水屏阅读器,蛮简单的 331次阅读
- 基于XIAO的翻页显示器设计 504次阅读
- 工业显示器和普通显示器的区别 4945次阅读
- 基于钻井深度显示器和带有Arduino支持的7段显示器设计 2480次阅读
- ZigBee模块在RFID射频识别阅读器中有着怎样的作用 2689次阅读
- 数字显示器的工作原理_数字显示器电路图 3w次阅读
- 显示器上的众多接口你都了解吗 6702次阅读
- 采用LabVIEW图形化编程语言设计的基于软件无线电的RFID阅读器 2226次阅读
- 电脑硬件基础篇显示器(显示器工作原理及作用_特性参数及型号和位置) 3.1w次阅读
- 液晶显示器的优缺点_液晶显示器原理介绍 1.5w次阅读
- 平视显示器是什么_平视显示器原理_平视显示器类型 4031次阅读
- 显示器色温怎么调节 2.1w次阅读
- 采用新型集成元件来简化RFID阅读器设计 1083次阅读
- 基于ISO18000-6C协议的UHF RFID阅读器接收电路设计 3772次阅读
- AMOLED显示器电源所需IC简述 5750次阅读
下载排行
本周
- 1山景DSP芯片AP8248A2数据手册
- 1.06 MB | 532次下载 | 免费
- 2RK3399完整板原理图(支持平板,盒子VR)
- 3.28 MB | 339次下载 | 免费
- 3TC358743XBG评估板参考手册
- 1.36 MB | 330次下载 | 免费
- 4DFM软件使用教程
- 0.84 MB | 295次下载 | 免费
- 5元宇宙深度解析—未来的未来-风口还是泡沫
- 6.40 MB | 227次下载 | 免费
- 6迪文DGUS开发指南
- 31.67 MB | 194次下载 | 免费
- 7元宇宙底层硬件系列报告
- 13.42 MB | 182次下载 | 免费
- 8FP5207XR-G1中文应用手册
- 1.09 MB | 178次下载 | 免费
本月
- 1OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 2555集成电路应用800例(新编版)
- 0.00 MB | 33566次下载 | 免费
- 3接口电路图大全
- 未知 | 30323次下载 | 免费
- 4开关电源设计实例指南
- 未知 | 21549次下载 | 免费
- 5电气工程师手册免费下载(新编第二版pdf电子书)
- 0.00 MB | 15349次下载 | 免费
- 6数字电路基础pdf(下载)
- 未知 | 13750次下载 | 免费
- 7电子制作实例集锦 下载
- 未知 | 8113次下载 | 免费
- 8《LED驱动电路设计》 温德尔著
- 0.00 MB | 6656次下载 | 免费
总榜
- 1matlab软件下载入口
- 未知 | 935054次下载 | 免费
- 2protel99se软件下载(可英文版转中文版)
- 78.1 MB | 537798次下载 | 免费
- 3MATLAB 7.1 下载 (含软件介绍)
- 未知 | 420027次下载 | 免费
- 4OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 5Altium DXP2002下载入口
- 未知 | 233046次下载 | 免费
- 6电路仿真软件multisim 10.0免费下载
- 340992 | 191187次下载 | 免费
- 7十天学会AVR单片机与C语言视频教程 下载
- 158M | 183279次下载 | 免费
- 8proe5.0野火版下载(中文版免费下载)
- 未知 | 138040次下载 | 免费
评论
查看更多