====== 6 Würfel und Zufall ====== ==== Ziele ==== Nach dieser Lektion sollten Sie: - wissen, wie man Zufallswerte in einem deterministischen System einfach erstellen kann. ==== Übung ==== --> I. Vorarbeiten # - Laden Sie folgende Datei herunter: - {{microcontrollertechnik:6. Wuerfel und Zufall.sim1}} - {{microcontrollertechnik:6. Wuerfel und Zufall.hex}} - {{microcontrollertechnik:lcd_lib_de.h}} <-- --> II. Analyse des fertigen Programms # - Initialisieren des Programms - Öffnen Sie SimulIDE und öffnen Sie dort mittels {{microcontrollertechnik:simulide_open.jpg?25}} die Datei ''6. Wuerfel und Zufall.sim1'' - Laden Sie ''6. Wuerfel und Zufall.hex'' als firmware auf den 88 Chip - Zunächst wird eine Startanzeige mit dem Namen des Programms dargestellt. - Als nächstes ist im Display ein Menu zu sehen. Durch Tastendruck kann ein Würfel gestartet (Druch auf Taste ''1'') oder gestoppt (''4'') werden. Die Augenzahl des Würfels ist in der Mitte der unteren Zeile dargestellt. - Das Programm zu diesem Hexfile soll nun erstellt werden <-- --> III. Eingabe in Microchip Studio # /*============================================================================= Experiment 6: MEXLEcast Elektronischer Wuerfel auf dem MEXLE ============= ============================================== Dateiname: MEXLEcast_de.c Autoren: Peter Blinzinger Prof. G. Gruhler (Hochschule Heilbronn) D. Chilachava (Georgische Technische Universitaet) Version: 1.2 vom 30.04.2020 Hardware: MEXLE2020 Ver. 1.0 oder höher AVR-USB-PROGI Ver. 2.0 Software: Entwicklungsumgebung: AtmelStudio 7.0 C-Compiler: AVR/GNU C Compiler 5.4.0 Funktion: Es wird ein elektronischer Wuerfel mit Anzeige auf dem Display realisiert. Mit zwei Tasten S1 = Start und S4 = Stop wird der Wuerfel gesteuert. Der Wuerfel wird mit 10ms-Takt gezaehlt. Die Anzeige erfolgt als Ziffer im 100ms-Takt. Displayanzeige: Start (fuer 2s): Betrieb: +----------------+ +----------------+ |- Experiment 6 -| |Electronic Cast | |Electronic Cast | |Start 1 Stop | +----------------+ +----------------+ Tastenfunktion: S1: Start (Set-Funktion Flip-Flop) S4: Stop (Reset-Funktion Flip-Flop) Jumperstellung: keine Auswirkung Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) Header-Files: lcd_lib_de.h (Library zur Ansteuerung LCD-Display Ver. 1.3) =============================================================================*/ // Deklarationen ============================================================== // Festlegung der Quarzfrequenz #ifndef F_CPU // optional definieren #define F_CPU 18432000UL // ATmega 88 mit 18,432 MHz Quarz #endif // Include von Header-Dateien #include // I/O-Konfiguration (intern weitere Dateien) #include // Definition von Interrupts #include // Definition von Delays (Wartezeiten) #include "lcd_lib_de.h" // Header-Datei fuer LCD-anzeige // Makros #define SET_BIT(BYTE, BIT) ((BYTE) |= (1 << (BIT))) // Bit Zustand in Byte setzen #define CLR_BIT(BYTE, BIT) ((BYTE) &= ~(1 << (BIT))) // Bit Zustand in Byte loeschen #define TGL_BIT(BYTE, BIT) ((BYTE) ^= (1 << (BIT))) // Bit Zustand in Byte wechseln (toggle) // Konstanten #define PRESCALER_VAL 90 // Faktor Vorteiler (Timerticks 0,111 ms) #define CYCLE10MS_MAX 10 // Faktor Hunderstel (1/100 s) #define INPUT_PIN_MASK 0b00001111 #define ASC_NULL 0x30 // Variable unsigned char softwarePrescaler = PRESCALER_VAL; // Zaehlvariable Vorteiler unsigned char cycle10msCount = CYCLE10MS_MAX; // Zaehlvariable Hunderstel unsigned char castVar = 1; // Variable für Wuerfel-Zaehler bool cycle10msActive = 0; // Bit-Botschaft alle 10ms bool cycle100msActive = 0; // Bit-Botschaft alle 100ms bool button1 = 0; // Bitspeicher fuer Taste 1 bool button4 = 0; // Bitspeicher fuer Taste 4 bool castBit = 0; // Flip-Flop-Bit fuer Start/Stop uint8_t buttonState = 0b00001111; // Bitspeicher fuer Tasten // Funktionsprototypen void timerInt0(void); // Init Zeitbasis mit Timer 0 void castCounting(void); // Zaehlfunktion Wuerfel void castDisplay(void); // Anzeige Wuerfel void initDisplay(void); // Initialisierung Display // Hauptprogramm ============================================================== int main() { // Initialisierung initDisplay(); // Initialisierung LCD-Anzeige TCCR0A = 0; // Timer 0 auf "Normal Mode" schalten TCCR0B |= (1<6) // groesser als 6? castVar=1; // => auf 1 setzen } } // Anzeigefunktion Wuerfel ==================================================== void castDisplay(void) { lcd_gotoxy(1,7); // Cursor auf Ausgabeposition lcd_putc(castVar+ASC_NULL); // ASCII-Wert des Wuerfelzaehlers ausgeben } // Initialisierung Display-Anzeige ============================================ void initDisplay() // Start der Funktion { lcd_init(); // Initialisierungsroutine aus der lcd_lib lcd_gotoxy(0,0); // Cursor auf 1. Zeile, 1. Zeichen lcd_putstr("- Experiment 6 -"); // Ausgabe Festtext: 16 Zeichen lcd_gotoxy(1,0); // Cursor auf 2. Zeile, 1. Zeichen lcd_putstr("Electronic Cast "); // Ausgabe Festtext: 16 Zeichen _delay_ms(2000); // Wartezeit nach Initialisierung lcd_gotoxy(0,0); // Cursor auf 1. Zeile, 1. Zeichen lcd_putstr("Electronic Cast "); // Ausgabe Festtext: 16 Zeichen lcd_gotoxy(1,0); // Cursor auf 2. Zeile, 1. Zeichen lcd_putstr("Start 1 Stop "); // Ausgabe Festtext: 16 Zeichen } // Ende der Funktion ''/*============================================================================='' Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ ''Deklarationen ==================================='' \\ \\ - Hier wird wieder geprüft ob die Frequenz des Quarz bereits eingestellt wurde und - falls nicht - dessen Frequenz eingestellt. \\ \\ - Die Header-Dateien entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ - Auch die Makros entsprechen denen der letzten Programme. \\ \\ \\ \\ - Die Konstanten entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ - Alle Variablen außer ''castBit'' entsprechen denen der letzten Programme. ''castBit'' ist ein "Merker", bzw. Flipflop welches das Würfeln aktiviert oder deaktiviert \\ \\ - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. \\ \\ \\ \\ \\ ''Hauptprogramm ========================='' - Das Hauptprogramm ähnelt sehr stark dem [[4_up_down_counter|Up/Down Counter]]. - Zunächst werden zwei Initialisierungsroutinen aufgerufen (siehe weiter unten) - Dann werden wieder die "__T__imer/__C__ounter __C__ontrol __R__egister" des Timers __0__ ''TCCR0A'' und ''TCCR0B'' gesetzt. Der 8-Bit Timer und auch hier im "Normal Mode" zum hochzählen genutzt. Auch hier gibt das Register ''TCCR0B'' den Prescaler an. - Auch hier wird über die "__T__imer __I__nterrupt __M__a__SK__" ''TIMSK0'' durch das Bit ''TOIE0'' ("__T__imer __O__verflow __I__nterrupt __E__nable") der Interrupt bei Überlauf aktiviert. - Mit dem Befehl ''sei()'' wird die Bearbeitung von Interrupts aktiv \\ \\ \\ - In der Endlosschleife sind auf der ersten Ebene wieder nur If-Abfragen zu den Flags ''takt10ms'' und ''takt100ms'' zu finden. \\ \\ - Alle $10~\rm ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm ''castCounting()'' aufgerufen \\ \\ \\ - Alle $100~\rm ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm ''castDisplay()'' aufgerufen \\ \\ \\ \\ \\ ''Interrupt Routine ========================='' - Mit dem Befehl ''ISR()'' wird eine Interrupt Service Routine für den __OV__er__F__low Interrupt für __TIMER0__ angelegt. - Der Überlauf-Interrupt durch den Timer0 wird erst bei Überlauf des 8-Bit Wert ausgeführt. Auch hier ergibt sich durch den Prescaler und Modus (''TCCR0A'' und ''TCCR0B'') eine Periode von $T_{\rm ISR}= 0,16\bar{6}~\rm ms$. - Die Ermittlung von ''Timertick'', ''vorteiler'', ''takt10ms'', ''hundertstel'' und ''takt100ms'' ist hier wieder gleich dem im [[4_up_down_counter|Up/Down Counter]]. - Eine große Änderung ist, dass bereits im Interrupt alle 10ms die Unterfunktion ''readButton()'' aufgerufen wird. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ '' Funktion Tasten einlesen =============='' \\ \\ \\ \\ \\ - In dieser Funktion werden zunächst die Stellungen aller Taster eingelesen (vgl. ''counterCounting(void)'' bei [[4_up_down_counter|Up/down Counter]]). \\ \\ \\ - Neu hier ist, dass die Bedienung der Schalter nur das Flag ''castBit'' setzen. Falls dieses gesetzt ist, wird die Variable ''castVar'' hochgezählt. Falls diese 6 überschreitet wird sie auf 1 zurückgesetzt. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ ''Anzeigefunktion Wuerfel ========================='' - Hierüber wird die Augenzahl in der zweiten Zeile an Position 7 ausgegeben. \\ \\ ''Initialisierung Display-Anzeige ========================='' - Die Funktion ''initDisplay()'' wird zu Beginn des Programms aufgerufen und führt zunächst die Initialisierung des Displays aus. - Danach wird der erste Text auf den Bildschirm geschrieben und damit der Programmname dargestellt. - Nach zwei Sekunden wird der Auswahlbildschirm angezeigt. <-- --> IV. Ausführung in Simulide # - Geben Sie die oben dargestellten Codezeilen ein und kompilieren Sie den Code. - Öffnen Sie Ihre hex-Datei in SimulIDE und testen Sie, ob diese die gleiche Ausgabe erzeugt <-- \\ Bitte arbeiten Sie folgende Aufgaben durch: --> Aufgabe# - Darstellung des Augenwerts ändern - Laden Sie folgende Dateien herunter: {{microcontrollertechnik:6_mexle_cast_extern.sim1}}, {{microcontrollertechnik:6a_mexlecast_extern.hex}} - Simulieren Sie die Schaltung mit der beigefügten hex-Datei - Ändern Sie das bisherige Programm so, dass Sie das gleiche Ergebnis erhalten, bzw. zumindest die Ansteuerung der LEDs. <--