M5Stack Atom Lite: Was taugt die interne Infrarot-LED?
Im vorhergehenden Artikel hatte ich ja den M5Stack Atom Lite vorgestellt. Dort habe ich erklärt, dass er auf dem ESP32-PICO-D4 basiert und das Pinout beschrieben. Außerdem bin ich auf den Knopf, den I2C-Port, den SPI-Port, und die interne RGB-LED eingegangen.Ich hatte erklärt, wie man den Atom Lite einrichtet und in der Arduino IDE programmiert und habe ein kleines Beispielprogramm zum austesten geschrieben.
Aber der M5Stack Atom Lite hat noch eine Kleinigkeit eingebaut. Eine bereits verbaute IR-LED (auf dem Foto rechts gelb eingekreist rechts unten) ist auch noch vorhanden.
Damit die IR-LED nicht durch das Gehäuse verdeckt wird, gibt es ein winziges Loch auf der Rückseite des Atom Lite gegenüber des USB-C-Ports.
Allerdings finden sich so gut wie keine Informationen dazu auf der M5Stack Webseite oder sonstwo im Internet.
Lediglich auf der Rückseite des Atom Lite steht oben rechts "IR G12". Ja, das ist ein "G" und keine "6". Daraus erfahren wir, dass die Infrarot-LED den GPIO-Pin G12 benutzt. Das ist alles, was wir an Infos haben.
Wir wissen nicht, ob das eine Sende, oder eine Empfangs-Diode ist, oder beides zusammen in einem Gehäuse.
Auf der Suche nach weiteren Infos habe ich nur den Beispielcode für das IR-Modul, welche es extra von M5Stack zu kaufen gibt und dass Sende als auch eine Empfangs-Diode beinhaltet, gefunden.
Aber sehr nützlich ist dieses Beispiel nicht, bringt es doch nur die IR-LED für einen bestimmten Zeitraum zum leuchten, wie auf dem Foto rechts unter Zuhilfenahme einer Kamera zu erkennen ist. Dazu muss man den GPIO-Port natülrich im Sourcecode auf G12 ändern.
Nunja, jetzt wissen wir zumindest, dass die IR-LED IR-Licht aussenden kann und dass die winzige LED da auf dem Atom Lite Board eine Sende-Diode sein muss. Könnte sie auch noch empfangen, dann hätte sie bestimmt noch einen weiteren GPIO-Port. Sie hat aber nur einen.
Die Idee, über die IR-LED die Zifferntaste einer Fernbedienung zu empfangen und so als Tastatur zur Eingabe von Codes zu benutzen, kann ich damit beerdigen.
Mit der internen IR-LED des Atom Lite senden
Aber IR senden kann der Atom Lite. Vielleicht taugt er damit als Fernbedienungsersatz? Mein Smartphone Redmi 9 hat zwar ein tadellos funktionierendes, komfortables IR-Sende-Interface, aber hier geht es ja ums Austesten, was der Atom Lite kann.Als erstes brauche ich natürlich ein paar Infrarot-Codes, um diese auszusenden. Und dann brauche ich noch eine Empfangsschaltung, um zu schauen, ob das auch richtig ankommt. Eigentlich brauche ich sogar die Empfangsschaltung zuerst, um von irgendeiner Fernbedienung IR-Codes zu empfangen und dann zu dekodieren, damit ich weiß, welche Code ich überhaupt mit dem Atom Lite senden soll.
Empfangsschaltung mit dem Arduino
Dazu hilft mir die Schaltung Universelle programmierbare Infrarot Fernbedienung für den Arduino, die ich mal gebastelt und programmiert habe. Dort gebrauche ich einen IR-Empfänger (Modul KY-022) und eine IR-Sende-LED (Modul KY-005).
Allerdings habe ich die Schaltung nur mit der Empfangs-LED und dem Multi Function Shield neu aufgebaut. Senden muss ich auf dem Arduino ja nicht.
Dazu wird das Multi Function Shield auf den Arduino Uno gesteckt und auf den 4x3 Male Header einen Doppel-4x3-Female-Header rechts unten und darauf dann das Modul a style="color:green" title="Affiliate Link" rel="nofollow" target="_blank" href="http://qul.de/ky-022">KY-022 mit IR-Empfänger.
Außerdem braucht es natürlich noch einen Source-Code. Dazu habe ich den alten hergenommen und noch ein wenig angepasst, so dass der letzte korrekt empfangene IR-Code auf der 7-Segment-Anzeige des MFS angezeigt wird.
Wer keinen Arduino Uno zur Hand hat, sondern einen Raspberry Pi, der findet in meinen Artikel Den Raspberry Pi mit der Infrarot-Fernbedienung fernsteuern eine Anleitung, wie man mit dem Raspi IR-Codes empfängt.
Hier also der Source-Code für den Arduino:
////////////////////////////////////////////////////////
// (C) 2022 by Oliver Kuhlemann //
// Bei Verwendung freue ich mich über Namensnennung, //
// Quellenangabe und Verlinkung //
// Quelle: http://cool-web.de/arduino/ //
////////////////////////////////////////////////////////
#include <TimerOne.h>
#include <MultiFuncShield.h>
#include <IRremote.h> // für Empf./Send. IR
#define PinEmpf 5 // wo ist Data des IR-Empfängers angeschlossen?
#define DurPause 10 // Pause in ms zwischen den Messungen
unsigned long TasterMsecs = 0; // wie lange wurde ein Taster gedrückt?
IRrecv irEmpf(PinEmpf); // IR-Empf. instanziieren
decode_results decoding; // Speicher für Decoding bereitstellen
/* wichtiger Code aus IRremote.h
class decode_results
{
public:
decode_type_t decode_type; // UNKNOWN, NEC, SONY, RC5, ...
unsigned int address; // Used by Panasonic & Sharp [16-bits]
unsigned long value; // Decoded value [max 32-bits]
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in 50uS ticks
int rawlen; // Number of records in rawbuf
int overflow; // true iff IR raw code too long
};
typedef
enum {
UNKNOWN = -1,
UNUSED = 0,
RC5, RC6, NEC, SONY, PANASONIC, JVC, SAMSUNG, WHYNTER, AIWA_RC_T501,
LG, SANYO, MITSUBISHI, DISH, SHARP, DENON, PRONTO, LEGO_PF, }
decode_type_t;
*/
void setup() {
Timer1.initialize();
MFS.initialize(&Timer1); // initialize multi-function shield library
MFS.beep(1, 5, 2); // bereit
irEmpf.enableIRIn(); // IR-Empfang starten
// irEmpf.blink13(1); // lässt LED1 bei Empfang blinken
Serial.begin (115200);
MFS.writeLeds(LED_ALL, OFF);
MFS.write("");
}
void showIRCode (decode_results* decoding) {
char tmp [10];
Serial.print("Protocol: "); Serial.println(decoding->decode_type, HEX);
Serial.print("Address: "); Serial.println(decoding->address, HEX);
Serial.print("Code: "); Serial.println(decoding->value, HEX);
Serial.print("Bits: "); Serial.println(decoding->bits, DEC);
Serial.print("Raw-Len: "); Serial.println(decoding->rawlen, DEC);
Serial.print("Raw-Ovfl: "); Serial.println(decoding->overflow, DEC);
Serial.print("Raw: ");
for (int i = 0; i < decoding->rawlen; i++) {
Serial.print (decoding->rawbuf[i], HEX);
Serial.print (" ");
}
Serial.println("\n");
if (decoding->decode_type == 0xFFFFFFFF ||
decoding->value == 0xFF ||
decoding->value == 0xFFFFFFFF) { //Protokoll ungültig
MFS.beep(1);
MFS.writeLeds(LED_ALL, OFF);
} else {
MFS.beep(10);
sprintf(tmp, "%4x", decoding->value);
MFS.writeLeds(LED_ALL, ON);
MFS.write(tmp);
}
}
void loop() {
Serial.println("PROGRAMM GESTARTET");
while (1) {
if (irEmpf.decode(&decoding)) {
Serial.println("IR SIGNAL EMPFANGEN");
showIRCode(&decoding);
irEmpf.resume();
}
delay(10);
}
}
IR SIGNAL EMPFANGEN
Protocol: 3
Address : 0
Code: FF6897
Bits: 32
Raw-Len: 68
Raw-Ovf1: 0
Raw: DD37 BA 5A B C B C B C B C B C B C B C B C A 22 B 22 B 22 B 21 B 22 B 22 B ...
Wir haben also den Code "FF6897" des Protocols 3 empfangen. Oben im Source-Code können wir nachschauen, das Protovol 3 für NEC steht. NEC ist ein großer japanischer Elektronik- und Consumergeräte-Hersteller, der natürlich auch Fernseher und ähnliches produziert hat und dafür seine eigenen Fernbedienung-Codes vor langer Zeit definiert hat.
Das NEC-Protokoll ist aber sehr üblich und auch andere haben das einfach so übernommen. Warum das Rad auch zweimal erfinden?
Die Codes des NEC-NEC-Protokolls fangen eigentlich alle mit "FF" an. Es sind also nur die letzten 4 hexadezimale Ziffern wichtig. Für die "1" auf der Fernbedienung ist das 6897 und die wird auch im 7-Segment-Display des MFS angezeigt.
Wunderbar. Jetzt müssen wir nur den Atom Lite dazu überreden, diesen Infrarot-Code auszusenden und dann könnten wir ihn als Ersatz für unsere Fernbedienung benutzen.
Infrarot-Codes senden mit dem Atom Lite
Es gibt eine Bibliothek für den ESP8266, die auch mit dem ESP32 zusammenarbeitet, der ja in unserem Atom Lite steckt, die uns das Senden von IR-Codes sehr vereinfacht. Dies ist die IRremoteESP8266-Library, zu finden im Bibliotheksverwalter der Arduino IDE oderhier unter GitHub. Die macht uns das Senden von den Codes sehr einfach, denn dort gibt es die Funktion sendNEC(), die einen IR-Code nach dem NEC-Protokoll aussendet. Genau das, was wir brauchen.
Also habe ich ein kleines Progrämmchen für den Atom Lite geschrieben bzw. mein bisheriges Test-Programm erweitert:
////////////////////////////////////////////////////////
// (C) 2022 by Oliver Kuhlemann //
// Bei Verwendung freue ich mich über Namensnennung, //
// Quellenangabe und Verlinkung //
// Quelle: https://cool-web.de/esp8266-esp32/ //
////////////////////////////////////////////////////////
// API-Dokumentationen:
// https://docs.m5stack.com/en/api/atom/system
// https://docs.m5stack.com/en/api/atom/led_display
#include "M5Atom.h"
// Für IR-Sende-LED
#include <IRremoteESP8266.h>
#include <IRsend.h>
const uint16_t IR_sendPin = 12; // (Atom Lite IR LED is on pin 12.)
void setup()
{
M5.begin(true, false, true); // void begin(bool LCDEnable=true, bool SDEnable=true, bool SerialEnable=true,bool I2CEnable=false);
IRsend irsend(IR_sendPin); // Pin für IRSend setzen
irsend.begin();
delay(100);
M5.dis.drawpix(0, 0x000000); // Der Atom Lite hat nur eine LED (Nr. 0); es folgen die Farbwerte in Hex für RGB (rot, grün, blau)
Serial.println("Teste IR-Sende-LED (hinten links am Gehäuse)\nKnopf für weiter...");
while (!M5.Btn.wasPressed()){
M5.dis.drawpix(0, 0xFF00FF);
irsend.sendNEC(0xFF6897UL); // 1 auf der kleinen IR-Fernbedienung
delay (50);
M5.dis.drawpix(0, 0x000000);
M5.update();
delay(1000);
M5.dis.drawpix(0, 0xFF0000);
irsend.sendNEC(0x804E58A7UL); // On/Off auf der Fernseher-Fernbedienung
delay (50);
M5.dis.drawpix(0, 0x000000);
M5.update();
delay(1000);
}
}
uint32_t color;
void loop()
{
M5.update(); // Auslesen des Knopf-Status
if (M5.Btn.wasPressed()){ // wenn Knopf gedrückt wurde
color=random(pow(2,24)); // Zufallsfarbwert holen
M5.dis.drawpix(0, color); // und die LED in dieser Farbe leuchten lassen
while (M5.Btn.wasPressed()){ // warten, bis Knopf wieder losgelassen
M5.update();
delay(10);
}
}
delay(10);
}
Den Code hochgeladen sollte der Atom Lite im Sekundentakt abwechselnd den Code für die Taste "1" der Mini-Fernbedienung und den für meinen Fernseher (Ein-Aus-Taste) aussenden.
Die Mini-Fernbedienung hatte beim Arduino-Test gut funktioniert. Es saß zwar nicht jeder einzelne Tastendruck, aber auch dem richtigen Winkel kam es doch schnell zu einer richtigen Erkennung.
Den Code für meinen Fernseher (auch NEC-Protokoll) habe ich gewählt, weil die IR-Empfänger in Consumer-Geräten meist empfindlicher sind und toleranter auf IR-Empfangscodes reagieren. Die haben ganz spezielle Chips dafür on board.
Meine Test mit dem Atom Lite waren leider nicht von Erfolg gekrönt. Der Arduino erkannte zwar, dass Infrarot-Codes reinkommen, konnte aber nicht einmal den richtigen erkennen, egal in welchem Winkel und in welchem Abstand ich ihn vor der Sender hielt. Ich konnte lediglich ausmachen, dass bei einem Abstand von bis zu circa 20 Zentimetern die emfangenen Codes zwar ungültig, aber wenigstens gleichbleibend waren. Wurde er Atom weiter weg gehalten, verloren sich die Codes in Zufallszahlen, es kam immer etwas anderes an.
Das Protokoll wird also nicht erkannt und man damit nicht sichergehen, dass der Code richtig ist, selbst wenn man die Empfängerseite selbst programmieren kann und sich auf den "falschen" Code einlässt. Und mit der Fernsteuerung von anderen Geräte wird es dann wohl auch hapern.
Was ich natürlich mit dem IR-Code für an/aus für meinen Fernsehen ausprobiert habe. Aber auch hier: ich kann den Atom Lite so nah oder fern und in jedem möglichen Winkel in Richtung Fernseher halten: es tut sich nichts.
Wahrscheinlich schafft die IR-LED es nicht, den Code richtig aufzumodellieren. Vielleicht ist sie zu langsam? Leuchtet sie nach?
An der Library wird es nicht liegen. Die basiert auf der Library für den Arduino, mit der ich auch meine Universelle programmierbare Infrarot Fernbedienung einsetzt habe. Und die tut es ja einwandfrei, getestet eben an meinem Fernseher.
Video
Vom Test mit einer Standard IR-Fernbedienung und dem Atom Lite als Sender und der Arduino-Schaltung als Empfänger habe ich ein Video gemacht:Fazit
Die IR-LED des Atom Lite kann zwar leuchten, ist aber nicht zum Senden von IR-Codes als Fernbedienungsersatz geeignet.Vielleicht kann man mir ihr noch etwas langsames machen wie Morsen über Infrarot, aber so einen richtigen alltäglichen Anwendungsfall sehe ich hier nicht.
Okay, die IR-LED kann man als Dreingabe sehen. Eine normale 5mm IR-LED mit Vorwiderstand kostet nur ein paar Cents. Es ist nicht das Problem, dass man dem Manko nicht günstig abhelfen könnte, nur macht eine externe IR-LED natürlich das schöne geschlossene Gehäuse-Design zunichte. Außerdem ist der Pin G12 damit verschenkt. Schade, ich sehe das als verpasste und verpatzte Gelegenheit.
Vielleicht ist das auch der Grund, dass es keine gescheite Dokumentation zur IR-LED gibt geschweige denn einen Beispielcode und eine Library von M5Stack: weil sie einfach nicht richtig funktioniert.
Wegen der IR-LED sollte man sich deshalb keinen Atom Lite kaufen. Am besten vergisst man die IR-LED einfach und tut so, als sei sie nicht da. Fast so wie der Hersteller.