Nach dieser Lektion sollten Sie:
6. Wuerfel und Zufall.hex
als firmware auf den 88 Chip1
) oder gestoppt (4
) werden. Die Augenzahl des Würfels ist in der Mitte der unteren Zeile dargestellt.
/*============================================================================= 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 <avr/io.h> // I/O-Konfiguration (intern weitere Dateien) #include <avr/interrupt.h> // Definition von Interrupts #include <util/delay.h> // 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<<CS01); // mit Prescaler /8 betreiben TIMSK0 |= (1<<TOIE0); // Overflow-Interrupt aktivieren sei(); // generell Interrupts einschalten // Hauptprogrammschleife while(1) // unendliche Warteschleife { if (cycle10msActive) // alle 10ms: { cycle10msActive = 0; // Botschaft "10ms" loeschen castCounting(); // Tasten abfragen, Wuerfel zaehlen } if (cycle100msActive) // alle 100ms: { cycle100msActive = 0; // Botschaft "100ms" loeschen castDisplay(); // Wuerfelwert ausgeben } } return 0; } // Interrupt-Routine ========================================================== ISR (TIMER0_OVF_vect) /* In der Interrupt-Routine sind die Softwareteiler für die Taktbotschaften (10ms, 100ms) realisiert. Die Interrupts stammen von Timer 0 (Interrupt 1) Verwendete Variable: vorteiler hunderstel Ausgangsvariable: takt10ms takt100ms */ { --softwarePrescaler; // Vorteiler dekrementieren if (softwarePrescaler==0) // wenn 0 erreicht: 10ms abgelaufen { softwarePrescaler = PRESCALER_VAL; // Vorteiler auf Startwert cycle10msActive = 1; // Botschaft 10ms senden --cycle10msCount; // Hunderstelzaehler dekrementieren if (cycle10msCount==0) // wenn 0 erreicht: 100ms abgelaufen { cycle10msCount = CYCLE10MS_MAX; // Teiler auf Startwert cycle100msActive = 1; // Botschaft 100ms senden } } } // Wuerfelfunktion ============================================================ void castCounting(void) { DDRC = DDRC &~INPUT_PIN_MASK; // Port C auf Eingabe schalten PORTC |= INPUT_PIN_MASK; // Pullup-Rs eingeschaltet _delay_us(1); // Wartezeit Umstellung Hardware-Signal buttonState = (PINC & INPUT_PIN_MASK) ; // Hole den Schalterstatus von C0..C3, 0b1 ist hier offener Schalter DDRC |= INPUT_PIN_MASK; // Port C auf Ausgabe schalten // Einlesen der Tastensignale button1 = (buttonState & (1 << PC0)); button4 = (buttonState & (1 << PC3)); // Auswertung der Tasten if (button1==0) // solange Taste 1 gedrueckt: castBit = 1; // Flip-Flop "Wuerfeln" Setzen if (button4==0) // solange Taste 4 gedrueckt: castBit = 0; // Flip-Flop "Wuerfeln" Ruecksetzen if (castBit) // Solange Flip-Flop "Wuerfeln" gesetzt { castVar++; // Wurfelwert hochzaehlen im Takt 10ms if (castVar>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 ===================================
castBit
entsprechen denen der letzten Programme. castBit
ist ein „Merker“, bzw. Flipflop welches das Würfeln aktiviert oder deaktiviert
Hauptprogramm =========================
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.TIMSK0
durch das Bit TOIE0
(„Timer Overflow Interrupt Enable“) der Interrupt bei Überlauf aktiviert.sei()
wird die Bearbeitung von Interrupts aktiv takt10ms
und takt100ms
zu finden. castCounting()
aufgerufen castDisplay()
aufgerufen
Interrupt Routine =========================
ISR()
wird eine Interrupt Service Routine für den OVerFlow Interrupt für TIMER0 angelegt. TCCR0A
und TCCR0B
) eine Periode von $T_{\rm ISR}= 0,16\bar{6}~\rm ms$.Timertick
, vorteiler
, takt10ms
, hundertstel
und takt100ms
ist hier wieder gleich dem im Up/Down Counter. readButton()
aufgerufen wird.
Funktion Tasten einlesen ==============
counterCounting(void)
bei Up/down Counter). castBit
setzen. Falls dieses gesetzt ist, wird die Variable castVar
hochgezählt. Falls diese 6 überschreitet wird sie auf 1 zurückgesetzt.
Anzeigefunktion Wuerfel =========================
Initialisierung Display-Anzeige =========================
initDisplay()
wird zu Beginn des Programms aufgerufen und führt zunächst die Initialisierung des Displays aus.
Bitte arbeiten Sie folgende Aufgaben durch: