電子發(fā)燒友App

硬聲App

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>矩陣顯示器上的新聞閱讀器開源項(xiàng)目

矩陣顯示器上的新聞閱讀器開源項(xiàng)目

2023-02-08 | zip | 0.07 MB | 次下載 | 免費(fèi)

資料介紹

描述

在這個(gè)項(xiàng)目中,時(shí)間、日期和最新的頭條新聞將在 LED 矩陣上顯示為自動(dòng)收?qǐng)?bào)機(jī)。日期和時(shí)間將從時(shí)間服務(wù)器更新。標(biāo)題來自所謂的 RSS 提要。這是由各種網(wǎng)絡(luò)服務(wù)器提供的服務(wù),例如 tagesschau.de。此服務(wù)使用 http 或 https 作為傳輸協(xié)議,但數(shù)據(jù)不是像往常一樣以 HTML 格式提供,而是以 XML 格式提供,即沒有布局信息。

電路

LED 矩陣僅連接到 ESP32 的 SPI 總線。ESP32 MOSI (GPIO23) 的數(shù)據(jù)輸出連接到矩陣的 DIN。ESP32 CLK (GPIO19) 的時(shí)鐘輸出連接到矩陣的時(shí)鐘輸入。ESP32的GPIO16用作片選,連接到矩陣的CS連接器矩陣由 5V 供電,這對(duì) ESP32 沒有問題,因?yàn)檫@里使用的所有連接器都用作輸出,因此無法從矩陣獲得更高的電壓。

?
poYBAGPi-SSASVXTAAAzp1r1Jd8077.png
?

程序

除了 ESP32 包之外,您還需要四個(gè)庫(kù)。我們使用 TinyXML 庫(kù)從接收到的 XML 數(shù)據(jù)中提取所需的信息。圖書館只有三個(gè)功能。

void init (uint8_t* buffer, uint16_t maxbuflen, XMLcallback XMLcb); 該函數(shù)在設(shè)置函數(shù)中被調(diào)用。參數(shù)buffer指向一個(gè)存放臨時(shí)數(shù)據(jù)的字節(jié)數(shù)組,參數(shù)maxbuflen指定了緩沖區(qū)的大小。參數(shù) XMLcallback 指向一個(gè)回調(diào)函數(shù)

void XML_callback(uint8_t statusflags, char* tagName, uint16_t tagNameLen, char* data, uint16_t dataLen)

只要 XML 元素已被完全處理,就會(huì)調(diào)用它。statusflags 參數(shù)指定提供哪些數(shù)據(jù)。由于我們對(duì) XML 標(biāo)記的內(nèi)容感興趣,因此我們將只使用狀態(tài) STATUS_TAG_TEXT。tagName 參數(shù)指向包含項(xiàng)目完整 XML 路徑的字符數(shù)組。對(duì)于新聞源項(xiàng)目的標(biāo)題,這是路徑“/rss/channel/item/title”。tagNameLen 參數(shù)返回路徑的長(zhǎng)度。參數(shù)數(shù)據(jù)還指向包含數(shù)據(jù)的字符數(shù)組。最后一個(gè)參數(shù) dataLen 返回?cái)?shù)據(jù)數(shù)組的大小。

無效重置();此函數(shù)重置所有內(nèi)部指針。它應(yīng)該總是在讀入新的 XML 數(shù)據(jù)之前被調(diào)用。

void processChar(uint8_t ch); 此函數(shù)將要處理的 XML 數(shù)據(jù)的一個(gè)字符發(fā)送到 XML 解析器。必須為接收到的每個(gè)字符順序調(diào)用此函數(shù)。如果傳輸?shù)淖址麑?dǎo)致 XML 塊的完成,則使用相應(yīng)的數(shù)據(jù)調(diào)用回調(diào)函數(shù)。LG_Matrix_Print 庫(kù)用于在 LED 矩陣上顯示字符串。草圖中使用了以下函數(shù):void setEnabled(bool enabled); ?啟用或禁用對(duì) LED 矩陣的訪問。

void setIntensity(uint8_t level); 此功能更改顯示屏的亮度。允許使用 0 到 15 之間的值。通常1就足夠了

無效顯示();顯示存儲(chǔ)器的內(nèi)容被傳輸?shù)骄仃嚥⒁虼丝梢姟?/font>

void clear()清除顯示內(nèi)存。

int printText(int start, String text, boolean isUTF8 = true); 此函數(shù)使用內(nèi)部字符集將文本參數(shù)中指定的字符串(從第 n 個(gè)字符開始)轉(zhuǎn)換為顯存中相應(yīng)的位模式。輸出開始的字符在 start 參數(shù)中指定。可選參數(shù) isUTF8 打開或關(guān)閉內(nèi)部代碼轉(zhuǎn)換器

void ticker(字符串消息,uint16_t 等待);這個(gè)函數(shù)可以很容易地實(shí)現(xiàn)一個(gè)自動(dòng)收?qǐng)?bào)機(jī)。參數(shù) message 指向包含要顯示的文本的字符串。第二個(gè)參數(shù) wait 指定在文本前進(jìn)一個(gè)像素之前等待的時(shí)間(以毫秒為單位)。圖書館負(fù)責(zé)其他一切。

布爾更新代碼();必須在循環(huán)函數(shù)中調(diào)用此函數(shù)以更新代碼。

該庫(kù)包含其他功能,但在此草圖中未使用它們。WebConfig 庫(kù)用于通過瀏覽器配置 WLAN 訪問數(shù)據(jù)以及其他設(shè)置。配置存儲(chǔ)在閃存文件系統(tǒng) SPIFFS 中,即使在微控制器關(guān)閉后也會(huì)保留。詳細(xì)說明可以在:? https? ://github.com/GerLech/WebConfig/blob/master/README.md或在我的書Smarthome 中找到。

WebConfig 庫(kù)需要 Arduino_JSON 庫(kù),因此也必須安裝它,但未包含在草圖中。

草圖

#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;
}
}

下載草圖

啟動(dòng)后,程序還不能與WLAN建立連接。因此,接入點(diǎn)被啟動(dòng)。它的 SSID 是 ESP32 的 MAC 地址。智能手機(jī)的 WLAN 設(shè)置中,您應(yīng)該會(huì)看到 SSID。您現(xiàn)在可以選擇此網(wǎng)絡(luò)并連接到它。網(wǎng)絡(luò)不需要密碼。智能手機(jī)可能會(huì)報(bào)告無法連接互聯(lián)網(wǎng),以及您是否要保留所選網(wǎng)絡(luò)。在這種情況下,點(diǎn)擊 Keep。< pan>

?
poYBAGPi-SiATwYqAABQsccSrMw494.png
?

現(xiàn)在您可以啟動(dòng)瀏覽器并調(diào)用 URL 192.168.4.1。矩陣時(shí)鐘的配置頁(yè)面應(yīng)該會(huì)出現(xiàn)。

?
pYYBAGPi-TSAKmMxAAA1kwrMeOU145.jpg
?

接入點(diǎn)的名稱是 MAC 地址,可以根據(jù)需要進(jìn)行更改。隨后是 WLAN 的訪問數(shù)據(jù)。例如,對(duì)于 RSS 提要的 URL,您可NTP 服務(wù)器可以保持原樣。但是您也可以設(shè)置例如帶有 fritz.box 的 Fritzbox。接下來,您必須設(shè)置標(biāo)題的最大數(shù)量、顯示屏的亮度和以秒為單位的時(shí)間,時(shí)間和日期應(yīng)顯示多長(zhǎng)時(shí)間。最后點(diǎn)擊保存并重新啟動(dòng)。矩陣時(shí)鐘將重新啟動(dòng),現(xiàn)在應(yīng)該連接到 WLAN。在串行監(jiān)視器的輸出中,您可以跟隨登錄。然后可以通過路由器分配給矩陣時(shí)鐘的 IP 地址訪問配置頁(yè)面。

安裝在外殼中

那些擁有 3D 打印機(jī)的人可以打印出合適的房屋。一共需要四個(gè)部分。一個(gè)底部部件 Uhr_unterten.stl,一個(gè)蓋子 Uhr_deckel.stl 和兩個(gè)顯示器支架 Uhr_halter.stl。現(xiàn)在到大會(huì)。首先,面包板配有兩個(gè)母連接器和一個(gè)帶角度的公連接器。< pan>

?
?
poYBAGPi-TaAO19OAACyb_c0mAg492.jpg
?

下面的接線是在后面板上進(jìn)行的。

?
pYYBAGPi-TmAYoSfAACretqVF_M729.png
?

現(xiàn)在您可以將控制器插入母連接器,并通過 5 針電纜將矩陣與控制器連接起來。在這里你必須注意引腳的正確順序。插入后,是時(shí)候再次檢查所有內(nèi)容并在開始安裝之前進(jìn)行試運(yùn)行了。

?
pYYBAGPi-UaALRoPAAB_B01OKP0957.jpg
?

下一步是在外殼中安裝矩陣和面包板。為了連接矩陣,必須首先將兩個(gè)支架連接到矩陣。

?
pYYBAGPi-UqAd7VGAABAfsdHv84018.jpg
?

現(xiàn)在您可以將矩陣固定在蓋子上,將面包板固定在底座上。< pan>

?
pYYBAGPi-U2AAbTzAABbWSsrhWc818.jpg
?

就是這樣了。帶有新聞提要的矩陣時(shí)鐘已準(zhǔn)備就緒

?
pYYBAGPi-VWAHssTAABOSoBfAKI227.jpg
?

玩得開心。

?


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評(píng)論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
  2. 1.06 MB  |  532次下載  |  免費(fèi)
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費(fèi)
  5. 3TC358743XBG評(píng)估板參考手冊(cè)
  6. 1.36 MB  |  330次下載  |  免費(fèi)
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費(fèi)
  9. 5元宇宙深度解析—未來的未來-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費(fèi)
  11. 6迪文DGUS開發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費(fèi)
  13. 7元宇宙底層硬件系列報(bào)告
  14. 13.42 MB  |  182次下載  |  免費(fèi)
  15. 8FP5207XR-G1中文應(yīng)用手冊(cè)
  16. 1.09 MB  |  178次下載  |  免費(fèi)

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費(fèi)
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費(fèi)
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費(fèi)
  7. 4開關(guān)電源設(shè)計(jì)實(shí)例指南
  8. 未知  |  21549次下載  |  免費(fèi)
  9. 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費(fèi)
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費(fèi)
  13. 7電子制作實(shí)例集錦 下載
  14. 未知  |  8113次下載  |  免費(fèi)
  15. 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費(fèi)

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費(fèi)
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費(fèi)
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費(fèi)
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費(fèi)
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費(fèi)
  11. 6電路仿真軟件multisim 10.0免費(fèi)下載
  12. 340992  |  191187次下載  |  免費(fèi)
  13. 7十天學(xué)會(huì)AVR單片機(jī)與C語(yǔ)言視頻教程 下載
  14. 158M  |  183279次下載  |  免費(fèi)
  15. 8proe5.0野火版下載(中文版免費(fèi)下載)
  16. 未知  |  138040次下載  |  免費(fèi)