Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Breadboard-Computerprogrammierer

Komponenten und Verbrauchsmaterialien

Arduino UNO
× 1

Über dieses Projekt

Was ist dieses Projekt?

Dies ist eine Erweiterung des 8-Bit-Breadboard-Computerprojekts von Ben Eater. Ich habe es sehr genossen, Bens Videos zu folgen, wie man einen Breadboard-Computer baut und meine eigene Version davon baut. Wenn Sie Ben nicht gefolgt sind, empfehle ich dringend, sich seine Videos vor dem Lesen anzusehen - dieses Projekt wird ohne den Kontext sehr wenig Sinn machen.

Nach dem Aufbau des Computers wurde schnell klar, dass es nicht viel nützen würde, wenn ich bei jedem Einschalten ein Programm über DIP-Schalter manuell umschalten müsste. Selbst das Umschalten in nur 16 Bytes immer wieder wird schnell alt. Außerdem hatte ich vor, den Speicher auf 256 Bytes zu erweitern, und das würde nur nützlich sein, wenn sich Programme irgendwie laden und speichern ließen.

Was kann ich damit machen?

  • Speichern Sie ein Programm aus dem RAM des Steckbrettcomputers
  • Laden Sie ein Programm in das RAM des Steckbrett-Computers
  • Automatisches Ausführen eines gespeicherten Programms beim Starten des Steckbrettcomputers
  • Überprüfen und ändern Sie den Speicherinhalt über eine serielle Verbindung
  • Programmieren Sie den Steckbrettcomputer in Assembler
  • Speicherinhalt zerlegen
  • Einzelschritt-Anleitung für Anleitung
  • Setze Haltepunkte und fahre bis zum Haltepunkt

Hier ist ein Video, das diese Funktionen demonstriert. Bitte entschuldigen Sie die Videoqualität - ich bin keineswegs ein professioneller Ersteller von Videoinhalten:

Wie funktioniert es?

Ich hatte ein paar Ziele vor Augen, als ich dieses Projekt machte:

  • So wenig wie möglich Hardware zum Erstellen erforderlich
  • So wenig Änderungen wie möglich am Steckbrettcomputer selbst

Am Anfang dachte ich darüber nach, ein EEPROM zum Speichern von Programmen zu verwenden und dann eine Art Logik, um Programme vom EEPROM in den RAM des Steckbrettcomputers zu übertragen. Die Übertragungslogik zu entwickeln erwies sich jedoch als komplizierter, als ich bewältigen konnte (ich bin eher ein Software-Typ, obwohl ich es wirklich genieße, nah an der Hardware zu arbeiten). Ich bin zufällig ein großer Arduino-Fan und habe irgendwann darüber nachgedacht, die Übertragungslogik durch ein Arduino zu ersetzen. Es hat einige Zeit gedauert, bis ich mich davon überzeugt habe, dass die Verwendung eines Arduino kein Betrug ist (schließlich ist sogar der Arduino UNO viel leistungsfähiger als der Breadboard-Computer selbst), aber ich bin mit dem Ergebnis zufrieden, also habe ich meinen Frieden geschlossen.

Was muss der Arduino also können? Nun, es muss in der Lage sein, Daten aus dem Speicher zu lesen und Daten in den Speicher zu schreiben. Der einfachste und (für den Steckbrett-Computer) am wenigsten aufdringliche Weg, dies zu tun, besteht darin, dieselbe Schnittstelle zu verwenden, die das Speichermodul bereits hat:die Bus- und Steuersignale. Die digitalen I/O-Pins von Arduino sind bidirektional, sodass der Arduino durch direktes Anschließen von 8 an den Bus vom Bus lesen und darauf schreiben kann. Um das RAM-Modul vom Bus lesen oder schreiben zu lassen, müssen nur die MI/RI/RO-Signale entsprechend gesetzt werden. Jetzt werden diese Signale normalerweise von den EEPROMs der Steuerlogik angesteuert, so dass die Kontrolle durch den Arduino zu Konflikten und möglichen Kurzschlusssituationen führen würde. Die von Ben verwendeten AT28C16 EEPROMs verfügen jedoch über einen Chip Enable (CE)-Eingang, der alle Datenausgänge in einen High-Z-Zustand versetzt - der es dem Arduino dann ermöglicht, die Signale zu manipulieren. Um den RAM auszulesen, muss der Arduino Folgendes tun:

  • Setzen Sie das CE-Signal des EEPROM auf High (d. h. deaktivieren Sie die Steuerlogik)
  • die erste zu lesende Adresse auf den Bus ausgeben
  • Setzen Sie das MI-Signal hoch und warten Sie auf einen Takt-Low-High-Übergang
  • MI auf niedrig und RO auf hoch setzen und auf einen Takt-Low-High-Übergang warten
  • das Datenbyte vom Bus lesen
  • Wiederholen Sie ab Schritt 2 für alle 16 Adressen
  • Setze das CE-Signal des EEPROM auf Low (d.h. reaktiviere die Steuerlogik)

Und das ist es. Das Schreiben von RAM-Inhalten ist sehr ähnlich, der Arduino muss nur in den Bus schreiben und RI anstelle von RO hoch setzen. Natürlich sind einige technische Probleme zu lösen, aber der obige grundlegende Mechanismus ist das Herzstück dieses Projekts.

Welche Änderungen muss ich am Steckbrettcomputer vornehmen?

Es müssen zwei Änderungen vorgenommen werden:

  • Pull-Down-Widerstände auf die Datenausgänge des EEPROMs der Steuerlogik setzen
  • Deaktivieren (oder ständig zurücksetzen) des Ringzählers, während das EEPROM deaktiviert ist

Pull-Down-Widerstände

Die Pull-Down-Widerstände sind erforderlich, da die Pull-Up-Widerstände der Logikgatter, mit denen die Steuersignale (wie AO/AI/EO...) verbunden sind, diese Signale hochziehen, sobald das EEPROM deaktiviert ist. Das würde bedeuten, dass mehrere Register auf den Bus schreiben würden, was zu Konflikten führen würde.

Die Pull-Up-Widerstände an den Eingängen der 74LS-Gates betragen etwa 10k. Daher müssen die Pull-Down-Widerstände klein genug sein, um die Spannung in den niedrigen Bereich zu bringen. Für die meisten Signalleitungen habe ich 3,3 kOhm Widerstände verwendet. Es gibt jedoch zwei Ausnahmen:Erstens wird das Signal "SU" mit 8 exklusiven ODER-Gattern verbunden, was bedeutet, dass der effektive Pullup-Widerstand 10kOhm/8 =1,25kOhm beträgt. Ein Pull-Down-Widerstand müsste deutlich kleiner als 1k sein, um dies niedrig zu ziehen. Glücklicherweise steuert das SU-Signal (Subtraktion) keine Interaktion mit dem Bus, so dass wir es einfach ignorieren können und keinen Pull-Down-Widerstand haben. Zweitens benötigte das CE (Zählerfreigabe) einen 1k-Pulldown-Widerstand - größere Werte verursachten in einigen Fällen ein zufälliges Programmzählerverhalten.

Ich fand es am einfachsten, die Pull-Down-Widerstände auf dem Steckbrett hinzuzufügen, das alle blauen LEDs hält, dh zwischen den LED-Anoden (die mit den EEPROM-Ausgängen verbunden sind) und GND.

[Ich konnte die Widerstände hier für die HLT/MI/RI-Signale nicht einbauen, also habe ich diese an anderen Stellen auf dem Steckbrett hinzugefügt]

Ringzähler zurücksetzen

Die andere Modifikation ist das Zurücksetzen des Klingelzählers. Technisch ist dies nicht wirklich notwendig, um das Speichern/Laden von Programmen zu ermöglichen, aber es ermöglicht eine reibungslose Übergabe der Steuerung vom Arduino zurück an die Steuerlogik. Der Punkt besteht darin, den Ringzähler auf 0 zu halten, solange CE hoch ist (d. h. die Steuerlogik ist deaktiviert). Wenn der Arduino CE wieder auf niedrig schaltet (wodurch die Steuerlogik aktiviert wird), steht der Ringzähler auf Null und der Steckbrettcomputer beginnt mit der Ausführung des nächsten Befehls.

Für meinen Build musste ich dafür nichts tun, da ich einen EEPROM-Ausgang verwende, um den Ringzähler zurückzusetzen. Dies verbessert die Leistung, indem der Ringzähler zurückgesetzt wird, sobald eine Anweisung beendet ist. Außerdem wird der Klingelzähler automatisch zurückgesetzt, wenn das EEPROM der Steuerlogik deaktiviert wird:Der Pull-Down-Widerstand am Ausgang des EEPROM zieht das Signal auf Low, wodurch der Klingelzähler zurückgesetzt wird.

Wenn Sie Bens Implementierung eines festen 5-Stufen-Ringzählers verwenden, sollte die folgende Erweiterung seiner Reset-Schaltung den Zähler meiner Meinung nach zurücksetzen, wenn CE hoch ist (klicken Sie unten auf die Pfeile nach links/rechts, um zwischen Bens ursprünglichem Schaltkreis und dem zu wechseln erweiterte Version):

Wie Sie sehen, sind 3 weitere NAND-Gatter erforderlich, dh ein weiterer 74LS00-Chip. Beachten Sie, dass ich diesen Ansatz nicht getestet habe, aber soweit ich sehen kann, sollte er funktionieren.

Diese Modifikation ist nicht zwingend erforderlich - Sie können sie am Anfang weglassen. Das Laden und Speichern sowie der Monitor/Assembler/Disassembler funktionieren weiterhin einwandfrei. Jede Aktion, die eine Übertragung der Steuerung vom Arduino an die Steuerlogik erfordert, funktioniert jedoch nicht. Dies ist vor allem das automatische Ausführen gespeicherter Programme beim Start sowie das Ausführen von Einzelschritten und Ausführen im Debugger.

Wie richte ich das Arduino ein?

Laden Sie die Skizze aus dem GIT-Archiv auf das Arduino hoch und verbinden Sie das Arduino wie folgt mit dem Steckbrett-Computer:

  • Arduino-5V-Pin (nicht Vin!) auf 5V-Schiene auf dem Steckbrett
  • Arduino GND-Pin zu GND-Pin auf dem Steckbrett
  • Arduino Digital Pins 2-9 an Bus 0-7
  • Arduino digitaler Pin 10 zur Steuerung des logischen EEPROM-Ausgangs, der RO steuert
  • Arduino Digital Pin 11 zur Steuerung des logischen EEPROM-Ausgangs, der RI steuert
  • Arduino digitaler Pin 12 zur Steuerung des logischen EEPROM-Ausgangs, der MI steuert
  • Arduino-Analog-Pin 0 zum CLOCK-Signal
  • Arduino Analog Pin 3 an CE (Pin 18) von allen Steuerlogik-EEPROMs und über einen 10k Widerstand an +5v

Abgesehen davon müssen Sie die analogen 1 und analogen 2 Eingangspins des Arduino wie in den Schaltplänen gezeigt mit den DIP-Schaltern und Drucktasten verbinden (weitere Details finden Sie in der beigefügten Fritzing-Datei).

Für eine absolut minimale (aber immer noch funktionsfähige) Version können Sie Folgendes tun:

  • Fügen Sie 3,3-kOhm-Pulldown-Widerstände zu den EEPROM-Ausgangspins hinzu, die AO, CO, EO, IO, RO steuern
  • Überspringe die Anweisungen zum Zurücksetzen des Klingelzählers oben
  • Führen Sie die Verdrahtung von Arduino zum Steckbrett-Computer wie oben gezeigt durch (Sie können den 10k-Widerstand im letzten Schritt weglassen, wenn Sie möchten)
  • Verbinde sowohl den analogen Pin 1 als auch den analogen Pin 2 mit GND

Um die Laden/Speichern-Tasten zu verwenden, müssen Sie nur die Tasten, DIP-Schalter und die zugehörigen Widerstände gemäß den Schaltplänen an die analogen Pins 1 und 2 anschließen.

Um die Autostart-Funktion zu verwenden, muss das Arduino den Programmzähler und den Ringzähler während des Zurücksetzens und während der Übertragung des Programms auf 0 halten. Der Pull-Up-Widerstand zwischen analogem Pin 3 und +5V hält die Steuerlogik deaktiviert (und damit den Programmzähler auf 0), während das Arduino zurückgesetzt wird. Befolgen Sie für den Ringzähler die Anweisungen zum Zurücksetzen des Ringzählers oben.

Wie lade und speichere ich Programme?

Das obige minimale Setup ermöglicht es Ihnen, den Arduino über die serielle Schnittstelle zu steuern. Zur Kommunikation mit dem Arduino benötigen Sie ein Terminalprogramm wie Putty oder TeraTerm. Der serielle Monitor in der Arduino-Software funktioniert auch, aber die Trennung zwischen Eingabe- und Ausgabebereich im seriellen Monitor macht es in diesem Szenario etwas klobig.

  • Schalte den Steckbrettcomputer ein
  • Verbinden Sie einen PC über das USB-Kabel mit dem Arduino
  • Starten Sie das Terminalprogramm und konfigurieren Sie auf 9600 Baud, 8 Bit, keine Parität, 1 Stoppbit
  • Drücken Sie ESC im Terminalfenster, um in den Monitor-Modus zu gelangen
  • Sie sollten ein "." sehen. als Eingabeaufforderung
  • Geben Sie "h" ein und drücken Sie die Eingabetaste, um eine Liste der unterstützten Befehle zu erhalten

Mit dem minimalen Setup sollten Sie die Befehle "m", "M", "C", "l" und "s" verwenden können. Mit diesen können Sie den Speicherinhalt anzeigen, den Speicherinhalt ändern und Programme laden und speichern.

Um ein Programm über die Schaltfläche zu speichern oder zu laden:

  • Schalte die Uhr des Steckbrettcomputers aus
  • Stellen Sie die DIP-Schalter ein, um die Dateinummer auszuwählen, unter der die Daten gespeichert werden sollen.
  • Drücken Sie auf die Schaltfläche "Speichern" oder "Laden". Die an CE angeschlossene LED leuchtet auf und zeigt an, dass der Arduino die Kontrolle übernommen hat
  • Schalten Sie die Uhr des Steckbrettcomputers ein. Sie sollten sehen, wie das Arduino die Adressen durchläuft (beobachten Sie die LEDs des Speicheradressregisters)
  • Warten Sie, bis die Bus-LEDs aufhören zu blinken und die LEDs des Speicheradressenregisters 1111 anzeigen
  • Schalten Sie die Uhr des Steckbrettcomputers aus. Die an CE angeschlossene LED erlischt und zeigt damit an, dass die Steuerung an die Steuerlogik zurückgegeben wurde

Um ein Programm beim Start automatisch auszuführen (stellen Sie sicher, dass alle erforderlichen Schaltkreise vorhanden sind), stellen Sie einfach die DIP-Schalter auf die Dateinummer, unter der das Programm gespeichert ist, und schalten Sie den Steckbrettcomputer ein (oder drücken Sie die Reset-Taste). Es gibt zwei Sonderfälle:Sind alle DIP-Schalter aus, startet der Rechner regelmäßig, ohne Autostart. Wenn alle DIP-Schalter eingeschaltet sind, geht das Arduino direkt beim Start in den Monitor-Modus.

Wie verwende ich den Assembler und Disassembler?

Um die Assembler-/Disassembler- und Debugger-Funktionen zu verwenden, müssen Sie zuerst das Programm auf dem Arduino ändern, um es an Ihr spezifisches Setup anzupassen. Suchen Sie den Abschnitt im Quellcode, der die opcodes_4bit-Struktur definiert:

struct opcodes_struct opcodes_4bit [] ={ {"NOP", B00000000, 0, false}, {"LDA", B00010000, 2, true}, ... {".OR ", B11111110, 0, true}, // setze Startadresse {".BY ", B11111111, 0, true}, // definiere ein Datenbyte {NULL, 0, 0, false} }; 

Jede Zeile spezifiziert einen Opcode:

  • Erstes Feld ist die Mnemonik ("LDA"). Zur sofortigen Adressierung fügen Sie ein "#" in die Mnemonik ein. Was Ben "LDI" nennt, würde hier also "LDA #" heißen. Kannst du sagen, dass ich mit 6510 Assembler auf einem C64 aufgewachsen bin?
  • Zweites Feld ist der Opcode selbst. Die unteren vier Bits sollten immer 0 sein. (außer bei den speziellen Opcodes .OR und .BY, siehe unten)
  • Drittes Feld ist die Anzahl der Zyklen, die der Opcode zur Ausführung benötigt (zusätzlich zu den Abrufzyklen). In meiner Implementierung hat LDA beispielsweise den Opcode 0001 und benötigt insgesamt vier Zyklen zur Ausführung, von denen zwei der Abrufzyklus sind. Wenn Sie Bens Anweisungen befolgt haben (wobei alle Opcodes 5 Zyklen verwenden), sollte dies immer 3 sein.
  • Letztes Feld gibt an, ob dieser Opcode ein Argument erfordert. Zum Beispiel erfordert LDA ein Argument, aber OUT nicht.

Sie müssen diese Liste anpassen, um die Opcodes widerzuspiegeln, die Sie für Ihren Breadboard-Computer implementiert haben. Die letzten beiden Zeilen sind spezielle Opcodes, die vom Assembler verwendet werden und sollten so belassen werden, wie sie sind.

Nachdem Sie alle Ihre Opcodes eingegeben haben, laden Sie die Software auf das Arduino hoch. Schließen Sie Ihr Terminal an und gehen Sie in den Monitor-Modus (entweder durch Drücken von ESC im Terminalfenster oder indem Sie alle DIP-Schalter auf On stellen). Sie sollten jetzt in der Lage sein, Ihr Programm zu zerlegen. Wenn Sie nur "d" in den Monitor eingeben, beginnt die Demontage bei Adresse 0.

Der Assembler ist minimal, funktioniert aber ziemlich gut. Geben Sie "a" ein, um mit der Montage bei Adresse 0 zu beginnen. Konventionen sind:

  • Wenn eine Zeile nicht mit einem Leerzeichen beginnt, muss sie mit einer Label-Definition beginnen. Labels müssen mit einem alphabetischen Zeichen beginnen, gefolgt von alphanumerischen Zeichen, dürfen maximal 3 Zeichen lang sein und beachten die Groß-/Kleinschreibung.
  • Nach dem ersten Whitespace in einer Zeile erwartet der Assembler eine Mnemonik (LDA, STA, OUT...).
  • Spezielle mnemonische ".BY" gibt direkt ein Datenbyte an, das an der aktuellen Position gespeichert werden soll.
  • Spezielles mnemonisches ".OR" weist den Assembler an, mit der Assemblierung an einer neuen Adresse fortzufahren.
  • Wenn ein Argument mit einem alphabetischen Zeichen beginnt, wird davon ausgegangen, dass es sich um ein Label handelt.
  • Jedes numerische Argument muss eine Dezimalzahl sein. Um hexadezimal anzugeben, stellen Sie dem Argument ein "$" voran. Um beispielsweise eine hexadezimale FF-Zahl in das A-Register zu laden, verwenden Sie "LDA #$FF".
  • Alles nach einem ";" wird als Kommentar angesehen und ignoriert.

Der Fibonacci-Code kann beispielsweise wie folgt eingegeben werden:

erste LDA #0; x =0 STA x LDA #1; y =1 STA y lp ADD x; z =y + x STA z JC zuerst; Neustart bei Überlauf OUT; drucken z LDA y; x =ySTA x LDAz; y =z STA y JMP lp; Schleife x .BY 0 y .BY 0 z .BY 0  

Welche Einschränkungen gibt es?

Um RAM-Speicher auf dem Arduino zu sparen, arbeitet der Assembler als 1-Pass-Assembler (ansonsten müsste der Arduino den gesamten Quellcode puffern). Der Assembler schreibt die Opcodes bei der Eingabe in den Speicher des Steckbrettcomputers. Dies bedeutet, dass die Montage durch die Taktrate des Steckbrettcomputers verlangsamt wird. Wenn Sie Text in das Terminalfenster kopieren und einfügen, kann dies zu verlorenen Zeichen führen, da das Arduino mit den Zeichen, die bei 9600 Baud eingehen, nicht mithalten kann (weil es zu viel Zeit damit verbringt, auf die Uhr des Steckbrettcomputers zu warten). Um dies zu umgehen, reduzieren Sie entweder die Baudrate oder verwenden Sie TeraTerm, das eine Einstellung bietet, um eine Verzögerung zwischen gesendeten Zeichen anzugeben. Die andere Problemumgehung besteht darin, die Taktfrequenz des Steckbrettcomputers zu erhöhen. Mein Takt geht auf 160kHz und bei dieser Geschwindigkeit kann ich ohne Probleme Code mit 9600 Baud kopieren und einfügen.

In der Standardkonfiguration kann die Arduino-Skizze Taktfrequenzen auf dem Steckbrett-Computer von bis zu 1-2 kHz (vielleicht etwas mehr) verarbeiten. Beachten Sie, dass Bens Takt in seiner Standardkonfiguration nicht schneller als 500 Hz geht. Wenn Ihre Uhr schneller ist, suchen Sie nach dem #ifdef FAST_IO im Code wechseln. Das Einschalten von FAST_IO sollte das Arduino mit Taktraten von bis zu 250 kHz arbeiten lassen. Ich habe es bis 160kHz getestet. Es wäre wahrscheinlich möglich, höhere Geschwindigkeiten zu unterstützen, indem man die zeitkritischen Schleifen direkt im Assembler implementiert, aber ehrlich gesagt fühlt sich ein 160kHz-Takt auf dem Breadboard-Computer mit seinen sonst begrenzten Fähigkeiten bereits zu schnell an. Lesen Sie unbedingt die entsprechenden Kommentare im Code, bevor Sie FAST_IO aktivieren.

Der Arduino hat 1k EEPROM und kann daher 1024/16=64 verschiedene Programme aufnehmen. Tatsächlich sind es 63, da 16 Bytes zum Speichern von Konfigurationsdaten reserviert sind. Das ist nicht viel, aber wahrscheinlich genug, um alle Programme aufzunehmen, die Sie sich ausdenken können. Nur die Programme mit den Nummern 0-15 können über die Dip-Schalter (1-14 für Autostart) ausgewählt werden, aber die Befehle "s" und "l" funktionieren mit dem vollen Bereich von 0-62.

Es sieht etwas unordentlich aus. Kannst du es aufräumen?

Ja! In meiner endgültigen Version hier habe ich eigentlich nur den nackten Atmega 328P-Chip (zusammen mit einem 16-MHz-Kristall und Kondensatoren) anstelle eines Arduino UNO verwendet. Der Spannungsregler am UNO ist hier nicht notwendig, da der Arduino sowieso direkt die 5V von unserem Netzteil verwendet. Der einzige Verlust ist, dass wir jetzt einen separaten USB-zu-Seriell-Konverter (FTDI oder ähnlich) verwenden müssen, um mit dem Atmega zu kommunizieren. Das Gesamtbild passt viel besser zum Rest des Steckbrettcomputers:

Eine weitere Optimierung besteht darin, den Bootloader vom Arduino/Atmega zu entfernen. Dadurch wird die 2-Sekunden-Verzögerung beim Starten des Arduino-Bootloaders beseitigt. Ich werde eine Anleitung dazu posten, wenn die Leute interessiert sind. Lass es mich in den Kommentaren wissen!

Code

Breadboard-Computerprogrammierer
Die Arduino-Skizze für den Breadboard-Computerprogrammiererhttps://github.com/dhansel/programmer

Schaltpläne

drive_pD8k28E85v.fzz

Herstellungsprozess

  1. Computermaus
  2. Kontrollieren eines Effekts mit echten Sensoren
  3. Arduino Spybot
  4. FlickMote
  5. Selbstgemachter Fernseher B-Gone
  6. Hauptuhr
  7. Finde mich
  8. Arduino-Power
  9. Tech-TicTacToe
  10. Arduino-Vierbeiner