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: