Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
microcontrollertechnik:7_uhr_und_zeitraster [2020/05/14 01:07] tfischer |
microcontrollertechnik:7_uhr_und_zeitraster [2024/01/22 13:46] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | <code c> | + | ====== 7 Uhr und Zeitraster ====== |
- | / | + | ==== Ziele ==== |
- | Experiment 5: Programm-Menu | + | Nach dieser Lektion sollten Sie: |
- | ============= ============= | + | |
- | Dateiname: | + | - wissen, wie man aus den auf Interupt-basierten Zeitrastern langsamere Raster umsetzt. |
- | Autoren: | + | ==== Übung ==== |
- | Prof. G. Gruhler (Hochschule Heilbronn) | + | |
- | D. Chilachava (Georgische Technische Universitaet) | + | |
- | Version: 1.2 vom 29.04.2020 | + | --> I. Vorarbeiten # |
+ | - Laden Sie folgende Datei herunter: | ||
+ | - {{microcontrollertechnik: | ||
+ | - {{microcontrollertechnik: | ||
+ | - {{microcontrollertechnik: | ||
- | Hardware: MEXLE2020 Ver. 1.0 oder höher | + | <-- |
- | AVR-USB-PROGI Ver. 2.0 | + | --> II. Analyse des fertigen Programms # |
+ | - Initialisieren des Programms | ||
+ | - Öffnen Sie SimulIDE und öffnen Sie dort mittels {{microcontrollertechnik:simulide_open.jpg?25}} die Datei '' | ||
+ | - Laden Sie '' | ||
+ | | ||
+ | - Als nächstes ist im Display eine Uhr mit dem Format HH:MM:SS Menu zu sehen | ||
+ | - Die Tasten '' | ||
- | Software: | + | <-- |
- | C-Compiler: AVR/GNU C Compiler 5.4.0 | + | |
- | Funktion: | + | --> III. Eingabe in Microchip Studio # |
- | programme verwaltet. Dies sind: | + | <WRAP group>< |
- | P1: Blinking LED | + | |
- | P2: Creating Sound | + | |
- | P3: Logic Functions | + | |
- | P4: Up/ | + | |
- | Der Start der Teilprogramme erfolgt den zugeordneten Funktions- | + | |
- | tasten. Nach dem Abbruch eines Teilprogramms (immer mit S1) | + | |
- | wird wieder die Programmauswahl gestartet. | + | |
- | Displayanzeige: | + | /* ============================================================================ |
- | +----------------+ +----------------+ | + | |
- | |- Experiment | + | Experiment 7: |
- | | | + | ============= |
- | +----------------+ +----------------+ | + | |
+ | Dateiname: | ||
+ | |||
+ | Autoren: | ||
+ | Prof. G. Gruhler (Hochschule Heilbronn) | ||
+ | D. Chilachava | ||
+ | |||
+ | Version: | ||
+ | |||
+ | Hardware: | ||
+ | AVR-USB-PROGI Ver. 2.0 | ||
+ | |||
+ | Software: | ||
+ | C-Compiler: AVR/GNU C Compiler 5.4.0 | ||
+ | |||
+ | Funktion: | ||
+ | einfache Stellfunktion ist mit den Tasten S2 und S3 realisiert. | ||
+ | |||
+ | Displayanzeige: | ||
+ | +----------------+ | ||
+ | |- Experiment | ||
+ | | Digital Clock | ||
+ | +----------------+ | ||
+ | |||
+ | Tastenfunktion: | ||
+ | S3: Min (zaehlt Minuten bei Flanke aufwaerts. Überlauf bei 60) | ||
+ | (setzt Sekunden beim Druecken zurueck auf 00) | ||
+ | |||
+ | Jumperstellung: | ||
+ | |||
+ | Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) | ||
+ | |||
+ | Header-Files: | ||
+ | |||
+ | Module: | ||
+ | 2) Zaehler fuer Uhr (Takt: 1 s) | ||
+ | 3) Anzeigetreiber | ||
+ | 4) Stellfunktion | ||
+ | |||
+ | Modul 1: Das Modul " | ||
+ | Zusaetzliche Takte: 10 ms fuer Stellfunktion | ||
+ | 100 ms fuer Anzeige. | ||
+ | |||
+ | Verwendung von Hardware-Timer 0 und T0 Overflow-Interrupt. | ||
+ | Frequenzen: Quarzfrequenz | ||
+ | Timer-Vorteiler | ||
+ | Hardware-Timer | ||
+ | Software-Vorteiler | ||
+ | Hundertstel-Zaehler / 10 => 10 Hz / 100 ms | ||
+ | Zehntel-Zaehler | ||
+ | |||
+ | Modul 2: Das Modul " | ||
+ | Sekunden, Minuten und Stunden werden als Binaerzahlen gezaehlt | ||
+ | Sekunden und Minuten zaehlen 00..59, die Stunden 00..23. | ||
+ | Ein " | ||
+ | |||
+ | Modul 3: Das Modul " | ||
+ | Hintergrundinformationen und die aktuelle Uhrzeit aus. | ||
+ | Darstellung auf der Anzeige (mittig in Zeile 1): [23: | ||
+ | |||
+ | Modul 4: Das Modul " | ||
+ | Es dient 1. zum Einlesen und Entprellen der Stelltasten | ||
+ | - Auswertung der fallenden Flanke 1=> 0 | ||
+ | 2. zum Ausfuehren der Stellfunktion: | ||
+ | - S2 zaehlt die Stunden aufwaerts | ||
+ | - S3 zaehlt die Minuten aufwaerts | ||
+ | - solange Taste S3 gedrueckt: Sekunden = 00 | ||
+ | (einfache Synchronisierung der Uhr!) | ||
+ | Beim Stellen kein Uebertrag von den Minuten auf die Stunden. | ||
+ | |||
+ | Die Kopplung der Module wird ueber global definierte Variable realisiert: | ||
+ | |||
+ | 1-Bit-Variable: | ||
+ | takt100ms: | ||
+ | takt1s: | ||
+ | |||
+ | 8-Bit-Variable: | ||
+ | minuten | ||
+ | stunden | ||
+ | |||
+ | =============================================================================*/ | ||
+ | |||
+ | // Deklarationen ============================================================== | ||
+ | |||
+ | // Festlegung der Quarzfrequenz | ||
+ | #ifndef F_CPU // optional definieren | ||
+ | #define F_CPU 18432000UL | ||
+ | # | ||
+ | |||
+ | // Include von Header-Dateien | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | |||
+ | // Makros | ||
+ | #define SET_BIT(BYTE, | ||
+ | #define CLR_BIT(BYTE, | ||
+ | #define TGL_BIT(BYTE, | ||
+ | |||
+ | // Konstanten | ||
+ | #define PRESCALER_VAL 90 | ||
+ | #define CYCLE10MS_MAX 10 | ||
+ | #define CYCLE100MS_MAX | ||
+ | |||
+ | #define SPEAK_PORT | ||
+ | #define SPEAK_BIT | ||
+ | |||
+ | #define ASC_NULL | ||
+ | #define ASC_COLON | ||
+ | #define INPUT_PIN_MASK 0b00001111 | ||
+ | |||
+ | // Variable | ||
+ | unsigned char softwarePrescaler = PRESCALER_VAL; | ||
+ | unsigned char cycle10msCount = CYCLE10MS_MAX; | ||
+ | unsigned char cycle100msCount | ||
+ | unsigned char seconds = 56; // Variable Sekunden | ||
+ | unsigned char minutes = 34; // Variable Minuten | ||
+ | unsigned char hours = 12; // Variable Stunden | ||
+ | |||
+ | bool timertick; | ||
+ | bool cycle10msActive; | ||
+ | bool cycle100msActive; | ||
+ | bool cycle1sActive; | ||
+ | |||
+ | bool button2_new = 1; // Bitspeicher fuer Taste 2 | ||
+ | bool button3_new = 1; // Bitspeicher fuer Taste 3 | ||
+ | bool button2_old = 1; // alter Wert von Taste 2 | ||
+ | bool button3_old = 1; // alter Wert von Taste 3 | ||
- | Anzeige | + | uint8_t buttonState |
+ | |||
+ | // Funktionsprototypen | ||
+ | void initDisplay(void); | ||
+ | void setTime(void); | ||
+ | void showTime(void); | ||
+ | void refreshTime(void); | ||
+ | |||
+ | // Hauptprogramm ============================================================== | ||
+ | int main() | ||
+ | { | ||
+ | // Initialisierung | ||
+ | initDisplay(); | ||
+ | |||
+ | TCCR0A = 0; // Timer 0 auf " | ||
+ | SET_BIT(TCCR0B, | ||
+ | SET_BIT(TIMSK0, | ||
+ | |||
+ | SET_BIT(DDRD, | ||
+ | |||
+ | sei(); | ||
+ | |||
+ | // Hauptprogrammschleife | ||
+ | |||
+ | while(1) | ||
+ | // Funktionen abhaengig von Taktbotschaften | ||
+ | { | ||
+ | if (cycle10msActive) | ||
+ | { | ||
+ | cycle10msActive = 0; // | ||
+ | setTime(); | ||
+ | } | ||
+ | if (cycle100msActive) | ||
+ | { | ||
+ | cycle100msActive = 0; // Botschaft " | ||
+ | showTime(); | ||
+ | } | ||
+ | if (cycle1sActive) | ||
+ | { | ||
+ | cycle1sActive = 0; // | ||
+ | refreshTime(); | ||
+ | } | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | // Interrupt-Routine ========================================================== | ||
- | Tastenfunktion: Im Hauptprogramm rufen S1 .. S4 die 4 Teiprogramme auf. | + | ISR (TIMER0_OVF_vect) |
- | Im Teilprogramm | + | /* In der Interrupt-Routine sind die Softwareteiler realisiert, die die Takt- |
+ | botschaften (10ms, 100ms, 1s) fuer die gesamte Uhr erzeugen. Die Interrupts | ||
+ | werden von Timer 0 ausgeloest (Interrupt Nr. 1) | ||
+ | |||
+ | */ | ||
+ | { | ||
+ | timertick = 1; // Botschaft 0,166ms senden | ||
+ | --softwarePrescaler; | ||
+ | if (softwarePrescaler==0) | ||
+ | { | ||
+ | softwarePrescaler = PRESCALER_VAL; | ||
+ | cycle10msActive = 1; // | ||
+ | --cycle10msCount; | ||
+ | |||
+ | if (cycle10msCount==0) | ||
+ | { | ||
+ | cycle10msCount = CYCLE10MS_MAX; | ||
+ | cycle100msActive = 1; // Botschaft 100ms senden | ||
+ | --cycle100msCount; | ||
+ | |||
+ | if (cycle100msCount==0) | ||
+ | { | ||
+ | cycle100msCount = CYCLE100MS_MAX; | ||
+ | cycle1sActive = 1; // | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Stellfunktion ============================================================== | ||
+ | void setTime(void) | ||
+ | /* Die Stellfunktion der Uhr wird alle 10ms aufgerufen. Dadurch wir eine | ||
+ | Entprellung der Tastensignale realisiert. Das Stellen wir bei einer | ||
+ | fallenden Flanke des jeweiligen Tastensignals durchgefuehrt. Darum | ||
+ | muss fuer einen weiteren Stellschritt | ||
+ | |||
+ | Eine Flanke wird durch (alter Wert == 1) UND (aktueller Wert == 0) erkannt. | ||
+ | |||
+ | Mit der Taste S2 werden die Stunden aufwaerts gestellt. | ||
+ | Mit der Taste S3 werden die Minuten aufwaerts gestellt (kein Uebertrag) | ||
+ | Solange Taste S3 gedrueckt | ||
+ | |||
+ | Veraenderte Variable: stunden | ||
+ | minuten | ||
+ | sekunden | ||
+ | |||
+ | Speicher fuer Bits: | ||
+ | sw3Alt | ||
+ | */ | ||
+ | { | ||
+ | DDRC = DDRC & | ||
+ | PORTC |= INPUT_PIN_MASK; | ||
+ | _delay_us(1); // Wartezeit Umstellung Hardware-Signal | ||
+ | buttonState | ||
+ | DDRC |= INPUT_PIN_MASK; | ||
- | Jumperstellung: Auswirkung nur im Teilprogramm | + | // Einlesen der Tastensignale |
- | Schalter muss fuer des Buzzer zwischen geschlossen sein | + | button2_new = (buttonState & (1 << PC1)); |
+ | button3_new = (buttonState & (1 << PC2)); | ||
+ | |||
+ | |||
+ | if ((button2_new==0)& | ||
+ | { | ||
+ | hours++; | ||
+ | if (hours==24) | ||
+ | hours = 00; | ||
+ | } | ||
+ | if ((button3_new==0)& | ||
+ | { | ||
+ | minutes++; | ||
+ | if (minutes==60) | ||
+ | minutes = 00; | ||
+ | } | ||
+ | if (button3_new==0) | ||
+ | seconds = 00; // Sekunden auf 00 setzen | ||
+ | |||
+ | button2_old = button2_new; | ||
+ | button3_old = button3_new; | ||
+ | } | ||
+ | |||
+ | // Anzeigefunktion Uhr ======================================================== | ||
+ | void showTime(void) | ||
+ | /* Die Umrechnung der binaeren Zaehlwerte auf BCD ist folgendermaßen geloest: | ||
+ | Zehner: einfache Integer-Teilung (/10) | ||
+ | Einer: | ||
+ | */ | ||
+ | { | ||
+ | lcd_gotoxy(0, | ||
+ | |||
+ | lcd_putc(ASC_NULL + hours/ | ||
+ | lcd_putc(ASC_NULL + hours%10); | ||
+ | lcd_putc(ASC_COLON); | ||
+ | |||
+ | lcd_putc(ASC_NULL + minutes/ | ||
+ | lcd_putc(ASC_NULL + minutes%10); | ||
+ | lcd_putc(ASC_COLON); | ||
+ | |||
+ | lcd_putc(ASC_NULL + seconds/ | ||
+ | lcd_putc(ASC_NULL + seconds%10); | ||
+ | } | ||
+ | |||
+ | // Initialisierung Display-Anzeige ============================================ | ||
+ | void initDisplay() | ||
+ | { | ||
+ | lcd_init(); | ||
+ | |||
+ | lcd_gotoxy(0, | ||
+ | lcd_putstr(" | ||
+ | |||
+ | lcd_gotoxy(1, | ||
+ | lcd_putstr(" | ||
+ | |||
+ | _delay_ms(2000); | ||
+ | |||
+ | lcd_gotoxy(0, | ||
+ | lcd_putstr(" | ||
+ | |||
+ | lcd_gotoxy(1, | ||
+ | lcd_putstr(" | ||
+ | } // Ende der Funktion | ||
+ | |||
+ | // Zaehlfunktion Uhr ========================================================== | ||
+ | void refreshTime (void) | ||
+ | /* Die Uhr wird im Sekundentakt gezaehlt. Bei jedem Aufruf wird auch ein | ||
+ | | ||
+ | die Minuten, die Ueberlaeufe der Minuten die Stunden hoch. | ||
+ | |||
+ | Veraenderte Variable: sekunden | ||
+ | | ||
+ | stunden | ||
+ | */ | ||
+ | { | ||
+ | TGL_BIT (SPEAK_PORT, | ||
+ | // durch Invertierung | ||
+ | |||
+ | seconds++; | ||
+ | if (seconds==60) | ||
+ | { | ||
+ | seconds = 0; // | ||
+ | minutes++; | ||
+ | if (minutes==60) | ||
+ | { | ||
+ | minutes = 0; // Minuten auf 00 setzen | ||
+ | hours++; | ||
+ | if (hours==24) | ||
+ | hours = 0; // Stunden auf 00 setzen | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
- | Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) | + | ''/ |
- | Header-Files: | + | Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln |
+ | '' | ||
+ | \\ \\ | ||
+ | - 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. \\ Zusätzlich wird der Ausdruck '' | ||
+ | - Bei den Variablen entsprechen einige denen der letzten Programme. | ||
+ | - Für die Uhr werden Stunden, Minuten, Sekunden und Zehntelsekunden mit Anfangswerten deklariert. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | ||
+ | | ||
- | =============================================================================*/ | + | '' |
+ | - Das Hauptprogramm ähnelt sehr stark dem [[4_up_down_counter|Up/ | ||
+ | - In der Endlosschleife sind auf der ersten Ebene wieder nur If-Abfragen zu den Flags '' | ||
+ | - Alle $10~\rm ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' | ||
+ | - Alle $100~\rm ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' | ||
+ | - Alle $1~\rm s$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' | ||
+ | '' | ||
+ | - Auch die Interrupt Routine ist dem Programm [[4_up_down_counter|Up/ | ||
- | // Deklarationen ============================================================== | + | '' |
+ | \\ \\ | ||
+ | - In dieser Funktion werden zunächst die Stellungen aller Taster eingelesen (vgl. '' | ||
+ | - Neu hier ist, dass die Bedienung der Schalter die Variablen für Stunden, Minuten um eins hochsetzen, bzw. bei Überlauf wider zurück auf 0 setzen. Zusätzlich wird bei eine Änderung des Minuten-Werts der Sekunden-Wert auf 0 gesetzt. | ||
- | // Festlegung der Quarzfrequenz | + | '' |
- | #ifndef F_CPU // | + | - Hierüber wird die Uhrzeit in der ersten Zeile im Format hh:mm:ss ausgegeben. |
- | #define F_CPU 12288000UL // | + | - Ähnlich zum Counter werden die zweistelligen Werte mit Division durch 10 und dessen Rest in zwei einzelne Ziffern gewandelt |
- | # | + | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ |
+ | '' | ||
+ | - Die Funktion '' | ||
+ | - Danach wird der erste Text auf den Bildschirm geschrieben und damit der Programmname dargestellt. | ||
+ | - Nach zwei Sekunden wird der Auswahlbildschirm angezeigt. | ||
- | // Include von Header-Dateien | + | \\ \\ \\ \\ \\ \\ \\ \\ \\ |
- | #include < | + | |
- | #include < | + | |
- | #include < | + | |
- | #include < | + | |
- | #include " | + | |
+ | '' | ||
+ | - Die Zähl-Funktion '' | ||
+ | - Zunächst wird ein Schaltwechsel am Ausgang mit dem Lautsprecher ausgegeben, um einen Knackton zu erzeugen | ||
+ | - Dann werden die Sekunden hochgezählt | ||
+ | - ist das Maximum erreicht, so wird der Sekunden-Wert zurückgesetzt und der Minuten-Wert um eins hochgezählt. | ||
+ | - ebenso wird beim Maximum des Minuten-Serts dieser zurückgesetzt und der Stundenwert hochgezählt. | ||
+ | - beim Maximum des Stunden-Werts wird dieser wieder auf Null gesetzt | ||
+ | </ | ||
- | // Makros | + | <-- |
- | # | + | --> IV. Ausführung in Simulide |
- | #define CLR_BIT(PORT, | + | |
- | #define TGL_BIT(PORT, | + | - Öffnen Sie Ihre hex-Datei in SimulIDE und testen Sie, ob diese die gleiche Ausgabe erzeugt |
+ | <-- | ||
- | // Konstanten | + | \\ |
- | #define VORTEILER_WERT 60 // Faktor Vorteiler = 60 | + | |
- | #define HUNDERTSTEL_WERT 10 // Faktor Hundertstel = 10 | + | |
- | #define ZEHNTEL_WERT 10 // Faktor Zehntel = 10 | + | |
- | #define ON_TIME 100 // | + | Bitte arbeiten Sie folgende Aufgaben durch: |
- | #define OFF_TIME 100 // | + | |
- | + | ||
- | #define MIN_PER 59 // | + | |
- | #define MAX_PER 255 // | + | |
- | #define WAIT_TIME 2000 // | + | |
- | + | ||
- | #define NULL 0x30 // | + | |
- | #define EINS 0x31 // | + | |
- | + | ||
- | + | ||
- | // Variable | + | |
- | unsigned char vorteiler = VORTEILER_WERT; | + | |
- | unsigned char hundertstel = HUNDERTSTEL_WERT; | + | |
- | unsigned char modus = 0; // Programmmodus | + | |
- | int counter = 0000; // Variable fuer Zaehler | + | --> Aufgabe# |
- | bool timertick; | + | |
- | bool takt10ms; | + | - Es sollen nicht nur Stunde, Minute, Sekunde dargestellt werden und veränderbar sein, sondern auch Tag, Monat und Jahr im Format dd:mm:yy |
- | bool takt100ms; | + | |
+ | - Erweitern Sie den Kalender auf vierstellige Jahresangabe. | ||
+ | - Überlegen Sie sich, wie man Ihre Programme testen kann. | ||
+ | - BONUS: Wie kann der Wochentag bestimmt werden? | ||
- | bool sw1_neu = 1; // Bitspeicher fuer Taste 1 | + | <-- |
- | bool sw2_neu = 1; // Bitspeicher fuer Taste 2 | + | |
- | bool sw3_neu = 1; // Bitspeicher fuer Taste 3 | + | |
- | bool sw4_neu = 1; // Bitspeicher fuer Taste 4 | + | |
- | bool sw1_alt = 1; // alter Wert von Taste 1 | ||
- | bool sw2_alt = 1; // alter Wert von Taste 2 | ||
- | bool sw3_alt = 1; // alter Wert von Taste 3 | ||
- | bool sw4_alt = 1; // alter Wert von Taste 4 | ||
- | bool sw1_slope = 0; // Flankenspeicher fuer Taste 1 | ||
- | bool sw2_slope = 0; // Flankenspeicher fuer Taste 2 | ||
- | bool sw3_slope = 0; // Flankenspeicher fuer Taste 3 | ||
- | bool sw4_slope = 0; // Flankenspeicher fuer Taste 4 | ||
- | </ |