Inhaltsverzeichnis:

AVRSH: eine Befehlsinterpreter-Shell für Arduino / AVR. - Gunook
AVRSH: eine Befehlsinterpreter-Shell für Arduino / AVR. - Gunook

Video: AVRSH: eine Befehlsinterpreter-Shell für Arduino / AVR. - Gunook

Video: AVRSH: eine Befehlsinterpreter-Shell für Arduino / AVR. - Gunook
Video: AVR Mastermind 2024, Juli
Anonim
AVRSH: eine Befehlsinterpreter-Shell für Arduino/AVR
AVRSH: eine Befehlsinterpreter-Shell für Arduino/AVR

Wollten Sie schon immer bei Ihrem AVR-Mikrocontroller "eingeloggt" sein? Haben Sie jemals gedacht, dass es cool wäre, ein Register zu "catchen", um seinen Inhalt zu sehen? Wollten Sie schon immer eine Möglichkeit, einzelne periphere Subsysteme Ihres AVR oder Arduino in *Echtzeit* ein- und auszuschalten? Ich auch, also habe ich die AVR-Shell geschrieben, eine UNIX-ähnliche Shell. Es ist UNIX-ähnlich, weil es an das Shell-Konto erinnert, das Sie gekauft haben, um Ihre IRC-Nick-Kollisions-Bots auszuführen, und es hat auch ein oder zwei Befehle gemeinsam. Es hat auch ein Dateisystem, das UNIX-extfs ähnelt und ein externes EEPROM verwendet, aber das ist ein Projekt für sich geworden, also werde ich dieses Modul separat unter einem anderen instructable freigeben, wenn es produktionsbereit ist. Hier ist eine Liste der Dinge, die Sie derzeit mit der AVR Shell tun können:

  • Lesen Sie alle Ihre Datenrichtungsregister (DDRn), Ports und Pins in Echtzeit
  • Schreiben Sie auf alle Ihre DDRns, Ports und Pins, um Motoren, LEDs oder Sensoren in Echtzeit einzuschalten
  • Listen Sie alle bekannten Register auf dem System auf
  • Erstellen und speichern Sie Werte in benutzerdefinierten Variablen, die durch EEPROM gesichert werden.
  • Erstellen Sie ein Root-Passwort und authentifizieren Sie sich damit (wird für den Telnet-Zugriff verwendet)
  • Auslesen der konfigurierten CPU-Taktgeschwindigkeit
  • Ändern Sie Ihre CPU-Taktrate, indem Sie einen Prescaler einstellen
  • Starten und stoppen Sie 16-Bit-Timer für das Timing verschiedener Dinge
  • Ein- und/oder Ausschalten peripherer Subsysteme: Analog-Digital-Wandler (ADC), Serial Peripheral Interface (SPI), Zweidraht-Schnittstelle (TWI/I2C), UART/USART. Nützlich, wenn Sie den Stromverbrauch des Mikrocontrollers reduzieren oder bestimmte Funktionen aktivieren möchten.
  • Geschrieben in C++ mit wiederverwendbaren Objekten.

Dieses anweisbare wird durch die Installation, Verwendung und Anpassung von avrsh gehen.

Schritt 1: Was Sie brauchen

Was du brauchen wirst
Was du brauchen wirst

Dieses anweisbare erfordert nicht viel, außer dass Sie:

  • Habe einen Arduino oder ATmega328P. Andere AVRs könnten funktionieren, aber Sie müssen möglicherweise den Code ändern, um alle Register aufzulisten, die für Ihre MCU einzigartig sind. Die Namen müssen nur mit dem übereinstimmen, was in der für Ihre MCU eindeutigen Header-Datei aufgeführt ist. Viele der Registernamen sind bei den AVRs gleich, sodass Ihre Laufleistung bei der Portierung variieren kann.
  • Haben Sie eine Möglichkeit, eine Verbindung zum seriellen USART Ihres Arduino / AVR herzustellen. Am umfangreichsten wurde das System mit dem AVR Terminal getestet, einer Windows-App, die eine serielle Verbindung über Ihren USB- oder COM-Port herstellt. Funktioniert mit Arduinos über die USB-Verbindung und jedem AVR mit dem USB-BUB von Moderndevice.com. Andere Terminaloptionen sind: Putty, Minicom (Linux und FreeBSD), Bildschirm (Linux/FreeBSD), Hyperterminal, Teraterm. Ich habe festgestellt, dass Putty und Teraterm beim Verbinden etwas Müll senden, sodass Ihr erster Befehl möglicherweise verstümmelt ist.
  • Lassen Sie die AVR Shell-Firmware installieren und ausführen, die Sie von diesen Seiten herunterladen können, oder holen Sie sich immer die neueste Version von BattleDroids.net.

Um das AVR Terminal zu installieren, entpacken Sie es einfach und führen es aus. Um die AVR Shell-Firmware zu installieren, laden Sie diese herunter und laden Sie entweder direkt die Hex-Datei hoch und schließen Sie Ihr serielles Terminal mit 9600 Baud an, oder kompilieren Sie sie selbst mit "make" und dann "make program", um die Hex-Datei hochzuladen. Beachten Sie, dass Sie möglicherweise die AVRDUDE-Einstellungen ändern müssen, um Ihren COM-Port widerzuspiegeln. Hinweis: Das PROGMEM-Attribut ist in der aktuellen AVR GCC-Implementierung für C++ defekt und dies ist ein bekannter Fehler. Wenn Sie es kompilieren, erwarten Sie viele Warnmeldungen mit der Aufschrift "Warnung: Nur initialisierte Variablen können im Programmspeicherbereich platziert werden". Abgesehen davon, dass diese Warnung ärgerlich ist, ist sie harmlos. Da C++ auf der Embedded-Plattform nicht ganz oben auf der Prioritätenliste des AVR GCC steht, ist nicht bekannt, wann dies behoben wird. Wenn Sie sich den Code ansehen, werden Sie sehen, wo ich Abhilfe geschaffen habe, um diese Warnung zu reduzieren, indem ich meine eigenen Attributanweisungen implementiert habe. Ziemlich einfach. Laden und installieren Sie alles, was Sie benötigen, um dann die Seite umzublättern und los geht's.

Schritt 2: Register lesen und schreiben

Lesen und Schreiben von Registern
Lesen und Schreiben von Registern

Die AVR-Shell wurde hauptsächlich geschrieben, um auf einige Sensoren zuzugreifen, die ich an meinen AVR angeschlossen hatte. Es begann mit einer einfachen LED, ging dann über Lichtsensoren, Temperatursensoren und schließlich zu zwei Ultraschallwandlern. avrsh kann die digitalen Komponenten dieser Sensoren einstellen, indem sie in die Register schreiben, die sie steuern. AVR-Register im laufenden Betrieb manipulieren Um eine Liste aller bekannten Register auf Ihrem Arduino zu erhalten, geben Sie Folgendes ein:

Register drucken und Sie erhalten einen Ausdruck, der so aussieht

Ich kenne folgende Register:

TIFR0 PORTC TIFR1 PORTD TIFR2 DDRD PCIFR DDRB EIFR DDRC EIMSK PINB EECR PINC EEDR PIND SREG EEARL GPIOR0 EEARH GPIOR1 GTCCR GPIOR2 TCCR0A TCCR0B TCNT0 OCR0A OCR0B SPCR SPDR ACSR SMCR MCUSR MCUCR SPMCSR WDTCSR CLKPR PRR OSCCAL PCICR EICRA PCMSK0 PCMSK1 TIMSK0 TIMSK1 TIMSK2 ADCL ADCH ADCSRA ADCSRB ADMUX DIDR0 DIDR1 TCCR1A TCCR1B TCCR1C TCNT1L TCNT1H ICR1L ICR1H OCR1AL OCR1AH OCR1BL OCR1BH TCCR2A TCCR2B TCNT2 OCR2A OCR2B ASSR TWBR TWSR TWAR TWAMRUC0DR TW0CRUBR Um zu sehen, wie die einzelnen Bits in einem beliebigen Register gesetzt sind, verwenden Sie den Befehl cat oder echo

Katze %GPIOR0 Hier bitte ich den Befehlsinterpreter, den Inhalt des Allzweck-E/A-Registers #0 anzuzeigen oder zu wiederholen. Beachten Sie das Prozentzeichen (%) vor dem Registernamen. Sie benötigen dies, um der Shell anzuzeigen, dass dies ein reserviertes Schlüsselwort ist, das ein Register identifiziert. Die typische Ausgabe eines Echo-Befehls sieht so aus

GPIOR0(0x0) auf [00000000] gesetzt Der Ausgang zeigt den Namen des Registers, den im Register gefundenen hexadezimalen Wert und die binäre Darstellung des Registers (jedes Bit als 1 oder 0) an. Um ein bestimmtes Bit in einem beliebigen Register zu setzen, verwenden Sie den "Index von"-Operator . Nehmen wir zum Beispiel an, ich möchte, dass das 3. Bit 1 ist

%GPIOR0[3] = 1 und die Shell gibt Ihnen eine Antwort, die ihre Aktion und das Ergebnis angibt

GPIOR0(0x0) auf [00000000] (0x8) eingestellt auf [00001000] Vergessen Sie nicht das Prozentzeichen, um der Shell mitzuteilen, dass Sie mit einem Register arbeiten. Beachten Sie auch, dass das Setzen des 3. Bits 4 Bits sind, da unsere AVRs einen nullbasierten Index verwenden. Mit anderen Worten, wenn Sie bis zum 3. Bit zählen, zählen Sie 0, 1, 2, 3, das ist der 4. Platz, aber das 3. Bit. Auf die gleiche Weise können Sie ein Bit löschen, indem Sie ein Bit auf Null setzen. Durch das Setzen solcher Bits können Sie die Funktionsweise Ihres AVR im Handumdrehen ändern. Zum Beispiel durch Ändern des CTC-Timer-Übereinstimmungswerts, der in OCR1A gefunden wird. Es ermöglicht Ihnen auch einen Blick in bestimmte Einstellungen, die Sie programmgesteuert in Ihrem Code überprüfen müssten, wie z. B. den UBBR-Wert für Ihre Baudrate. Arbeiten mit DDRn, PORTn und PINn Die I/O-Pins sind ebenfalls Registern zugeordnet und können genauso eingestellt werden, jedoch wurde eine spezielle Syntax für diese Art von Registern geschaffen. Im Code gibt es einen normalen Prozess, um beispielsweise eine LED oder ein anderes Gerät einzuschalten, das ein digitales High oder Low erfordert. Es erfordert das Setzen des Datenrichtungsregisters, um anzuzeigen, dass der Pin für die Ausgabe vorgesehen ist, und dann das Schreiben einer 1 oder 0 in das bestimmte Bit im richtigen Port. Angenommen, wir haben eine LED an den digitalen Pin 13 (PB5) angeschlossen und möchten sie einschalten, dann gehen Sie wie folgt vor, während Ihr AVR läuft

set pin pb5 outputwrite pin pb5 hoch Die Ausgabe würde, abgesehen davon, dass Sie Ihre LED aufleuchten sehen, so aussehen:

root@ATmega328p> setze pin pb5 outputSet pb5 for outputroot@ATmega328p> schreibe pin pb5 highSchreibte logisch hoch auf pin pb5 "root@ATmega328p>" ist die Eingabeaufforderung der Shell, die anzeigt, dass sie bereit ist, Befehle von Ihnen zu akzeptieren. Um die LED auszuschalten, schreiben Sie einfach ein Low an den Pin. Wenn Sie den digitalen Eingang von einem Pin lesen möchten, verwenden Sie den Lesebefehl. Mit unserem obigen Beispiel

root@ATmega328p> Pin pb5Pin lesen: pb5 ist HIGH Alternativ können Sie einfach das Pin-Register wiederholen, das diesen Pin-Port steuert. Wenn wir beispielsweise Dip-Schalter an die digitalen Pins 7 und 8 (PD7 und PD8) angeschlossen haben, können Sie den Befehl senden

echo %PIND und die Shell würde dann den Inhalt dieses Registers anzeigen und Ihnen alle Eingangs-/Ausgangszustände der angeschlossenen Geräte anzeigen und zeigen, ob der Schalter ein- oder ausgeschaltet war.

Schritt 3: Lesen und Schreiben von Sicherungen

Lese- und Schreibsicherungen
Lese- und Schreibsicherungen

Sicherungen sind besondere Arten von Registern. Sie steuern alles, von der Taktrate Ihres Mikrocontrollers über die verfügbaren Programmiermethoden bis hin zum schreibgeschützten EEPROM. Manchmal müssen Sie diese Einstellungen ändern, insbesondere wenn Sie ein eigenständiges AVR-System erstellen. Ich bin mir nicht sicher, ob Sie Ihre Sicherungseinstellungen auf Arduino ändern sollten. Seien Sie vorsichtig mit Ihren Sicherungen; Sie können sich aussperren, wenn Sie sie falsch einstellen. In einer früheren Anleitung habe ich gezeigt, wie Sie Ihre Sicherungen mit Ihrem Programmierer und Avrdude lesen und einstellen können. Hier zeige ich Ihnen, wie Sie Ihre Sicherungen zur Laufzeit zurücklesen, um zu sehen, wie Ihre MCU sie tatsächlich eingestellt hat. Beachten Sie, dass dies nicht die Kompilierzeiteinstellung ist, die Sie aus den Definitionen erhalten, sondern die tatsächlichen Sicherungen, wie sie die MCU zur Laufzeit liest. Aus Tabelle 27-9 im ATmega328P-Datenblatt (Datenbuch, ähnlicher) sind die Bits des Fuse Low Byte wie folgt:

CKDIV8 CKOUT SUT1 SUT0 CKSEL3 CKSEL2 CKSEL1 CKSEL0Interessant ist, dass bei Sicherungen 0 programmiert und 1 bedeutet, dass dieses bestimmte Bit unprogrammiert ist. Etwas kontraintuitiv, aber wenn Sie es wissen, wissen Sie es.

  • CKDIV8 stellt Ihren CPU-Takt so ein, dass er durch 8 geteilt wird. Der ATmega328P ist werkseitig so programmiert, dass er seinen internen Oszillator bei 8MHz verwendet, wobei CKDIV8 programmiert (dh auf 0) eingestellt ist, was Ihnen eine endgültige F_CPU- oder CPU-Frequenz von 1MHz gibt. Bei Arduinos wird dies geändert, da sie für die Verwendung eines externen Oszillators bei 16 MHz konfiguriert sind.
  • CKOUT gibt, wenn es programmiert ist, Ihren CPU-Takt auf PB0 aus, der digitaler Pin 8 auf Arduinos ist.
  • SUT[1..0] gibt die Startzeit für Ihren AVR an.
  • CKSEL[3..0] stellt die Taktquelle ein, z. B. den internen RC-Oszillator, den externen Oszillator usw.

Wenn Sie Ihre Sicherungen lesen, wird sie hexadezimal an Sie zurückgegeben. Dies ist das Format, das Sie benötigen, wenn Sie die Fuses über avrdude schreiben möchten. Auf meinem Arduino erhalte ich Folgendes, wenn ich das untere Sicherungsbyte lese:

root@ATmega328p> read lfuseLower Fuse: 0xffAlle Bits sind also auf 1 gesetzt. Ich habe das gleiche Verfahren bei einem Arduino-Klon durchgeführt und den gleichen Wert erhalten. Bei der Überprüfung eines meiner Standalone-AVR-Systeme erhielt ich 0xDA, den Wert, den ich vor einiger Zeit bei der Konfiguration des Chips eingestellt hatte. Das gleiche Verfahren wird für die Überprüfung der Sicherungen High Fuse Byte, Extended Fuse Byte und Lock verwendet. Die Kalibrierungs- und Signatur-Fuse-Bytes wurden im Code mit einer #if 0-Präprozessordirektive deaktiviert, die Sie ändern können, wenn Sie sich unsicher fühlen.

Schritt 4: Andere Befehle

Andere Befehle
Andere Befehle

Es gibt mehrere andere Befehle, die der Standardbefehlsinterpreter versteht und die Sie möglicherweise nützlich finden. Sie können alle implementierten und zukünftigen Befehle anzeigen, indem Sie Hilfe oder ein Menü an der Eingabeaufforderung eingeben. Ich werde sie hier schnell behandeln, da sie größtenteils selbsterklärend sind. CPU-Taktfrequenzeinstellungen Sie können mit dem Befehl fcpu herausfinden, was Ihre Firmware als CPU-Takteinstellungen verwendet hat:

root@ATmega328p> fcpuCPU Freq: 16000000Das sind 16 Millionen oder 16 Millionen Herz, besser bekannt als 16 MHz. Sie können dies, aus welchen Gründen auch immer, im Handumdrehen mit dem Clock-Befehl ändern. Dieser Befehl benötigt ein Argument: den Prescaler, der beim Teilen der Taktfrequenz verwendet wird. Der Clock-Befehl versteht diese Prescaler-Werte:

  • ckdiv2
  • ckdiv4
  • ckdiv8
  • ckdiv16
  • ckdiv32
  • ckdiv64
  • ckdiv128
  • ckdiv256

Mit dem Befehl:

Uhr ckdiv2 Wenn Ihre CPU-Geschwindigkeit 16 MHz beträgt, wird Ihre Taktfrequenz auf 8 MHz geändert. Die Verwendung eines Prescalers von ckdiv64 mit einer anfänglichen Taktrate von 16 MHz führt zu einer endgültigen Taktrate von 250 KHz. Warum in aller Welt möchten Sie Ihre MCU langsamer machen? Nun, zum einen verbraucht eine niedrigere Taktfrequenz weniger Strom, und wenn Ihre MCU in einem Projektgehäuse mit einer Batterie betrieben wird, benötigen Sie sie möglicherweise nicht, um mit Höchstgeschwindigkeit zu laufen, und können daher die Geschwindigkeit verringern und den Stromverbrauch reduzieren, erhöht die Akkulaufzeit. Wenn Sie die Uhr auch für Timing-Probleme mit einer anderen MCU verwenden, z niedrigere Fehlerquoten. Ein- und Ausschalten von Peripherie-Subsystemen Analog zur oben erwähnten Reduzierung des Stromverbrauchs möchten Sie möglicherweise den Stromverbrauch weiter reduzieren, indem Sie einige der On-Board-Peripheriegeräte, die Sie nicht verwenden, ausschalten. Der Befehlsinterpreter und die Shell können derzeit die folgenden Peripheriegeräte ein- und ausschalten:

  • Analog-Digital-Wandler (ADC). Dieses Peripheriegerät wird verwendet, wenn Sie einen analogen Sensor haben, der Daten liefert (wie Temperatur, Licht, Beschleunigung usw.) und diese in einen digitalen Wert umwandeln müssen.
  • Serielle Peripherieschnittstelle (SPI). Der SPI-Bus wird verwendet, um mit anderen SPI-fähigen Geräten wie externen Speichern, LED-Treibern, externen ADCs usw. zu kommunizieren. Teile des SPI werden für die ISP-Programmierung verwendet, oder zumindest die Pins, also seien Sie beim Herunterfahren vorsichtig wenn Sie über ISP programmieren.
  • Zweidraht-Schnittstelle. Einige externe Geräte verwenden den I2C-Bus zur Kommunikation, obwohl diese schnell durch SPI-fähige Geräte ersetzt werden, da SPI einen größeren Durchsatz hat.
  • USART. Dies ist Ihre serielle Schnittstelle. Sie möchten dies wahrscheinlich nicht ausschalten, wenn Sie über die serielle Verbindung mit dem AVR verbunden sind! Ich habe dies jedoch hier als Skelett für die Portierung auf Geräte hinzugefügt, die mehrere USARTs wie den ATmega162 oder ATmega644P haben.
  • alle. Dieses Argument zum powerup- oder powerdown-Befehl schaltet alle genannten Peripheriegeräte ein oder schaltet sie alle mit einem Befehl aus. Verwenden Sie diesen Befehl erneut mit Bedacht.

root@ATmega328p> powerdown twiPowerdown von twi komplett.root@ATmega328p> powerup twiPowerup von twi komplett.

Starten und Stoppen von Timern Die Shell verfügt über einen eingebauten 16-Bit-Timer, der verwendet werden kann. Sie starten den Timer mit dem Timer-Befehl:

Timer-Startund stoppen Sie den Timer mit dem Argument stop

Timer-StoppDieser Timer wird nicht mit dem internen USART-Timer kollidieren. Sehen Sie sich den Code für die Implementierungsdetails des USART-Timers an, wenn Sie an dieser Art von blutigen Details interessiert sind

root@ATmega328p> Timer startStarted timer.root@ATmega328p> Timer stopVerstrichene Zeit: ~ 157 Sekunden Authentifizierung Die Shell kann ein 8-stelliges Passwort im EEPROM speichern. Dieser Passwortmechanismus wurde entwickelt, um die Telnet-Anmeldefunktionen zu unterstützen, könnte jedoch erweitert werden, um andere Dinge zu schützen. Sie können beispielsweise bestimmte Befehle, wie das Ändern von Registerwerten, über den Authentifizierungsmechanismus anfordern. Legen Sie das Passwort mit dem Passwort-Befehl fest

root@ATmega328p> passwd blahWrote das Root-Passwort ins EEPROMAutorisieren Sie mit dem auth-Befehl (oder fordern Sie die Autorisierung programmgesteuert über den Code an). Beachten Sie, dass Sie sich beim Versuch, das Root-Passwort zu ändern und bereits ein Root-Passwort eingerichtet ist, mit dem alten Passwort autorisieren müssen, bevor Sie es in ein neues Passwort ändern dürfen

root@ATmega328p> passwd blinkySie müssen sich zuerst autorisieren.root@ATmega328p> auth blahAuthorized.root@ATmega328p> passwd blinkyWrote NEW root password to EEPROMNatürlich müssen Sie die Datei avrsh.eep laden, wenn Sie die Firmware löschen, um Ihre alten Werte und Variablen wiederherzustellen. Das Makefile erstellt die EEPROM-Datei für Sie. Variablen Die Shell versteht den Begriff benutzerdefinierter Variablen. Der Code begrenzt dies auf 20, aber Sie können dies ändern, wenn Sie möchten, indem Sie die Definition von MAX_VARIABLES in script.h ändern. Sie können jeden 16-Bit-Wert (d. h. jede Zahl bis 65, 536) in einer Variablen speichern, die später wieder aufgerufen werden soll. Die Syntax ähnelt der von Registern, außer dass ein Dollarzeichen ($) verwendet wird, um Variablen für die Shell zu kennzeichnen. Listen Sie alle Ihre Variablen mit dem Befehl Variablen drucken auf

Variablen druckenBenutzerdefinierte Variablen:Indexname -> Wert(01): $FREE$ -> 0(02): $FREE$ -> 0(03): $FREE$ -> 0(04): $FREE$ -> 0(05): $FREE$ -> 0(06): $FREE$ -> 0(07): $FREE$ -> 0(08): $FREE$ -> 0(09): $FREE$ -> 0(10): $FREE$ -> 0(11): $FREE$ -> 0(12): $FREE$ -> 0(13): $FREE$ -> 0(14): $FREE$ -> 0(15): $FREE$ -> 0(16): $FREE$ -> 0(17): $FREE$ -> 0(18): $FREE$ -> 0(19): $FREE$ -> 0(20): $FREE$ -> 0Vollständig. Legen Sie eine Variable fest

$newvar = 25$timeout = 23245Holen Sie sich den Wert einer gegebenen Variablen

root@ATmega328p> echo $newvar$ newvar 25Sie können alle Variablen sehen, die Sie derzeit mit dem Druckbefehl instanziiert haben, die Sie bereits kennen

Benutzerdefinierte Variablen:Indexname -> Wert(01): newvar -> 25(02): Timeout -> 23245(03): $FREE$ -> 0(04): $FREE$ -> 0(05): $FREE$ -> 0(06): $FREE$ -> 0(07): $FREE$ -> 0(08): $FREE$ -> 0(09): $FREE$ -> 0(10): $FREE$ -> 0(11): $FREE$ -> 0(12): $FREE$ -> 0(13): $FREE$ -> 0(14): $FREE$ -> 0(15): $FREE$ -> 0(16): $FREE$ -> 0(17): $FREE$ -> 0(18): $FREE$ -> 0(19): $FREE$ -> 0(20): $FREE$ -> 0Vollständig. Der Name $FREE$ zeigt lediglich an, dass dieser Variablenplatz frei ist und noch kein Variablenname zugewiesen wurde.

Schritt 5: Anpassen der Shell

Anpassen der Shell
Anpassen der Shell

Es steht Ihnen frei, den Code zu hacken und ihn an Ihre eigenen Bedürfnisse anzupassen, wenn Sie möchten. Wenn ich gewusst hätte, dass ich diesen Code veröffentlichen würde, hätte ich eine separate Befehlsinterpreterklasse und Befehlsstruktur erstellt und einfach diesen Aufruf eines Funktionszeigers durchlaufen. Es würde die Codemenge reduzieren, aber so wie es aussieht, parst die Shell die Befehlszeile und ruft die entsprechende Shell-Methode auf. Um Ihre eigenen benutzerdefinierten Befehle hinzuzufügen, gehen Sie wie folgt vor: 1. Fügen Sie Ihren Befehl zur Parse-Liste hinzu Der Befehlsparser wird Analysieren Sie die Befehlszeile und geben Sie den Befehl und alle Argumente separat an. Die Argumente werden als Zeiger auf Zeiger oder als Array von Zeigern übergeben, wie auch immer Sie mit ihnen arbeiten möchten. Diese befindet sich in der Datei shell.cpp. Öffnen Sie shell.cpp und suchen Sie die ExecCmd-Methode der AVRShell-Klasse. Sie können den Befehl zum Programmspeicher hinzufügen. Fügen Sie in diesem Fall den Befehl in progmem.h und progmem.cpp hinzu. Sie können den Befehl direkt mit dem PSTR()-Makro zum Programmspeicher hinzufügen, erzeugen aber eine weitere Warnung des oben erwähnten Typs. Auch dies ist ein bekannter Fehler, der mit C++ arbeitet, aber Sie können dies umgehen, indem Sie den Befehl direkt in die progmem.*-Dateien einfügen, wie ich es getan habe. Wenn es Ihnen nichts ausmacht, Ihre SRAM-Nutzung zu erhöhen, können Sie den Befehl hinzufügen, wie ich ihn mit dem Befehl "clock" veranschaulicht habe. Angenommen, Sie möchten einen neuen Befehl namens "newcmd" hinzufügen. Gehen Sie zu AVRShell::ExecCmd und suchen Sie eine geeignete Stelle, um den folgenden Code einzufügen:

else if (!strcmp(c, "newcmd")) cmdNewCmd(args);Dadurch wird Ihr Befehl hinzugefügt und die cmdNewCmd-Methode aufgerufen, die Sie im nächsten Schritt schreiben werden. 2. Schreiben Sie Ihren benutzerdefinierten Befehlscode Fügen Sie in derselben Datei Ihren benutzerdefinierten Befehlscode hinzu. Dies ist die Methodendefinition. Sie werden die Deklaration dennoch zu shell.h hinzufügen wollen. Hängen Sie es einfach an die anderen Befehle an. Im vorherigen Beispiel könnte der Code etwa so aussehen

voidAVRShell::cmdNewCmd(char ** args){ sprintf_P(buff, PSTR("Ihr Befehl ist %s\r\n", args[0]); WriteRAM(buff);}Hier gibt es mehrere Dinge. Erstens ist "buff" ein 40-stelliger Array-Puffer, der im Code für Ihre Verwendung bereitgestellt wird. Wir verwenden die Programmspeicherversion von sprintf, da wir ihr einen PSTR übergeben. Sie können die reguläre Version verwenden, wenn Sie möchten, aber stellen Sie sicher, dass Sie das Format nicht in einem PSTR übergeben. Außerdem befinden sich die Argumente im Array args. Wenn Sie "newcmd arg1 arg2" eingegeben haben, können Sie diese Argumente mit den Indizes args[0] und args[1] abrufen. Sie können maximal MAX_ARGS Argumente übergeben, wie im Code definiert. Sie können diesen Wert beim Neukompilieren gerne ändern, wenn viele weitere Argumente gleichzeitig übergeben werden müssen. WriteLine und WriteRAM sind globale Funktionen, die die gleichnamigen Methoden des UART zurückgeben. Das zweite Argument dieser Funktion ist implizit. Wenn Sie nichts übergeben, wird anschließend eine Eingabeaufforderung geschrieben. Wenn Sie als 2. Argument eine 0 übergeben, wird keine Eingabeaufforderung geschrieben. Dies ist nützlich, wenn Sie mehrere separate Zeichenfolgen in die Ausgabe schreiben möchten, bevor die Eingabeaufforderung an den Benutzer zurückgegeben wird. 3. Befehlscode von der Shell ausführen lassen Sie haben den Shell-Executor bereits angewiesen, die Methode cmdNewCmd auszuführen, wenn Sie den neuen Befehl einrichten, aber fügen Sie sie der Datei shell.h hinzu, damit sie vom Shell-Objekt verstanden wird. Fügen Sie es einfach unter dem letzten Befehl oder vor dem ersten Befehl oder irgendwo dort hinzu. Und das war's. Kompilieren Sie die Firmware neu und laden Sie sie auf Ihren Arduino hoch, und Ihr neuer Befehl ist an der Eingabeaufforderung in der Shell verfügbar.

Schritt 6: Zusammenfassung

Sie sollten wissen, wie Sie Ihren AVR/Arduino installieren und mit ihm verbinden und eine Live-Eingabeaufforderung auf Ihrem laufenden Mikrocontroller erhalten. Sie kennen mehrere Befehle, die Laufzeitdaten von der MCU abrufen oder Werte im laufenden Betrieb in die MCU setzen. Ihnen wurde auch gezeigt, wie Sie Ihren eigenen benutzerdefinierten Code hinzufügen, um Ihre eigenen einzigartigen Befehle zur Shell zu erstellen, um sie weiter an Ihre eigenen Bedürfnisse anzupassen. Sie können den Befehlsinterpreter sogar ausnehmen, damit er nur Ihre benutzerdefinierten Befehle enthält, wenn dies Ihren Anforderungen entspricht. Ich hoffe, Sie haben dieses anweisbare genossen und dass die AVR Shell für Sie nützlich sein kann, entweder als Echtzeit-Befehlsinterpreter oder als Lernprozess bei der Umsetzung Ihrer eigenen. Wie immer freue ich mich über Kommentare oder Vorschläge, wie dieses instructable verbessert werden kann! Viel Spaß mit Ihrem AVR!

Empfohlen: