Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
microcontrollertechnik:4_up_down_counter [2022/04/20 16:23] tfischer |
microcontrollertechnik:4_up_down_counter [2024/03/11 00:09] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== 4. Up-Down Counter ====== | + | ====== 4 Up-Down Counter ====== |
===== Interrupts - was tun bei Unterbrechungen? | ===== Interrupts - was tun bei Unterbrechungen? | ||
Zeile 14: | Zeile 14: | ||
</ | </ | ||
==== Video ==== | ==== Video ==== | ||
- | + | ||
+ | Im Video sind nur die ersten 30 Minuten relevant. | ||
+ | Danach werden verschiedene Sleep-Modes betrachtet - diese sind für uns nicht relevant. | ||
+ | |||
+ | {{youtube> | ||
+ | |||
+ | <WRAP hide> | ||
{{youtube> | {{youtube> | ||
+ | </ | ||
</ | </ | ||
Zeile 23: | Zeile 30: | ||
--> I. Vorarbeiten # | --> I. Vorarbeiten # | ||
- Laden Sie folgende Datei herunter: | - Laden Sie folgende Datei herunter: | ||
- | - {{microcontrollertechnik: | + | - {{microcontrollertechnik: |
- | - {{microcontrollertechnik: | + | - {{microcontrollertechnik: |
- {{microcontrollertechnik: | - {{microcontrollertechnik: | ||
Zeile 31: | Zeile 38: | ||
- Initialisieren des Programms | - Initialisieren des Programms | ||
- Öffnen Sie SimulIDE und öffnen Sie dort mittels {{microcontrollertechnik: | - Öffnen Sie SimulIDE und öffnen Sie dort mittels {{microcontrollertechnik: | ||
- | - Laden Sie '' | + | - Laden Sie '' |
- Zunächst wird eine Startanzeige mit dem Namen des Programms dargestellt. | - Zunächst wird eine Startanzeige mit dem Namen des Programms dargestellt. | ||
- Als nächstes ist ein Displaybild zu sehen, in dem die Wirkung der verschiedenen Schalter in der zweiten Zeile zu sehen ist: | - Als nächstes ist ein Displaybild zu sehen, in dem die Wirkung der verschiedenen Schalter in der zweiten Zeile zu sehen ist: | ||
Zeile 41: | Zeile 48: | ||
<-- | <-- | ||
- | --> III. Eingabe in Atmel Studio # | + | --> III. Eingabe in Microchip |
<WRAP group>< | <WRAP group>< | ||
/ | / | ||
- | + | ||
- | Experiment 4: | + | Experiment 4: |
- | ============= =============== | + | ============= |
- | + | ||
- | Dateiname: Up-Down-Counter_de.c | + | Dateiname: |
- | + | ||
- | Autoren: Peter Blinzinger | + | Autoren: |
- | Marc Neumeister | + | Marc Neumeister |
- | Prof. G. Gruhler (Hochschule Heilbronn) | + | Prof. G. Gruhler (Hochschule Heilbronn) |
- | D. Chilachava (Georgische Technische Universitaet) | + | D. Chilachava |
- | + | ||
- | Version: 1.2 vom 01.05.2020 | + | Version: |
- | + | ||
- | Hardware: MEXLE2020 Ver. 1.0 oder höher | + | Hardware: |
- | AVR-USB-PROGI Ver. 2.0 | + | AVR-USB-PROGI Ver. 2.0 |
- | + | ||
- | Software: Entwicklungsumgebung: | + | Software: |
- | C-Compiler: | + | C-Compiler: |
- | + | ||
- | Funktion: Es wird ein 4-stelliger Dezimal-Zaehler (0000..9999) mit | + | Funktion: |
- | Anzeige und Ueber-/ Unterlauf realisiert. Das Aufwaerts- und | + | Anzeige und Ueber-/ Unterlauf realisiert. Das Aufwaerts- und |
- | Abwaertszaehlen wird mit zwei Tasten (S2: +) (S3: -) gesteuert. | + | Abwaertszaehlen wird mit zwei Tasten (S2: +) (S3: -) gesteuert. |
- | Es werden die Flanken beim Druecken der Tasten ausgewertet. | + | Es werden die Flanken beim Druecken der Tasten ausgewertet. |
- | Die Taste S1 dient zum Ruecksetzen des Zaehlers auf 0000. | + | Die Taste S1 dient zum Ruecksetzen des Zaehlers auf 0000. |
- | + | ||
- | Displayanzeige: | + | Displayanzeige: |
- | +----------------+ +----------------+ | + | +----------------+ |
- | |- Experiment 4 -| |Up/ | + | |- Experiment 4 -| |Up/ |
- | |Up/ | + | |Up/ |
- | +----------------+ +----------------+ | + | +----------------+ |
- | + | ||
- | Tastenfunktion: | + | Tastenfunktion: |
- | S2: (+) Aufwaerts (mit Entprellung) | + | S2: (+) Aufwaerts |
- | S3: (-) Abwaerts (mit Entprellung) | + | S3: (-) Abwaerts |
- | + | ||
- | Jumperstellung: | + | Jumperstellung: |
- | + | ||
- | Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) | + | Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) |
- | + | ||
- | Header-Files: | + | Header-Files: |
+ | |||
=============================================================================*/ | =============================================================================*/ | ||
+ | |||
// Deklarationen ============================================================== | // Deklarationen ============================================================== | ||
+ | |||
// Festlegung der Quarzfrequenz | // Festlegung der Quarzfrequenz | ||
#ifndef F_CPU // | #ifndef F_CPU // | ||
- | #define F_CPU 12288000UL // ATmega | + | #define F_CPU 18432000UL // ATmega |
- | #endif | + | # |
+ | |||
// Include von Header-Dateien | // Include von Header-Dateien | ||
#include < | #include < | ||
- | #include < | + | #include < |
#include < | #include < | ||
#include < | #include < | ||
#include " | #include " | ||
+ | |||
// Konstanten | // Konstanten | ||
- | # | + | # |
- | # | + | # |
- | # | + | # |
+ | |||
// Variable | // Variable | ||
- | unsigned char vorteiler | + | unsigned char vorteiler |
- | unsigned char hundertstel = HUNDERTSTEL_WERT; // Zaehlvariable | + | unsigned char takt10msZaehler |
- | + | ||
- | int counter = 0000; // Variable fuer Zaehler | + | int counter = 0; // Variable fuer Zaehler |
+ | |||
bool timertick; | bool timertick; | ||
- | bool takt10ms; | + | bool takt10ms; |
- | bool takt100ms; | + | bool takt100ms; |
+ | |||
bool sw1_neu = 1; // Bitspeicher fuer Taste 1 | bool sw1_neu = 1; // Bitspeicher fuer Taste 1 | ||
bool sw2_neu = 1; // Bitspeicher fuer Taste 2 | bool sw2_neu = 1; // Bitspeicher fuer Taste 2 | ||
bool sw3_neu = 1; // Bitspeicher fuer Taste 3 | bool sw3_neu = 1; // Bitspeicher fuer Taste 3 | ||
+ | |||
bool sw1_alt = 1; // alter Wert von Taste 1 | bool sw1_alt = 1; // alter Wert von Taste 1 | ||
bool sw2_alt = 1; // alter Wert von Taste 2 | bool sw2_alt = 1; // alter Wert von Taste 2 | ||
bool sw3_alt = 1; // alter Wert von Taste 3 | bool sw3_alt = 1; // alter Wert von Taste 3 | ||
+ | |||
// Makros | // Makros | ||
- | # | + | #define SET_BIT(BYTE, |
- | #define CLR_BIT(BYTE, | + | #define CLR_BIT(BYTE, |
- | #define TGL_BIT(BYTE, | + | #define TGL_BIT(BYTE, |
+ | #define GET_BIT(BYTE, | ||
+ | |||
// Funktionsprototypen | // Funktionsprototypen | ||
void initTaster(void); | void initTaster(void); | ||
Zeile 134: | Zeile 142: | ||
void counterCounting(void); | void counterCounting(void); | ||
void counterDisplay(void); | void counterDisplay(void); | ||
+ | |||
// Hauptprogramm ============================================================== | // Hauptprogramm ============================================================== | ||
int main() | int main() | ||
{ | { | ||
- | initTaster(); | + | |
- | initDisplay(); | + | |
- | + | TCCR0A = 0; // Timer 0 auf " | |
- | TCCR0A = 0; // Timer 0 auf " | + | TCCR0B |= (1<< |
- | TCCR0B |= (1<< | + | TIMSK0 |= (1<< |
- | TIMSK0 |= (1<< | + | |
- | + | sei(); | |
- | sei(); | + | |
- | + | while(1) // | |
- | while(1) // | + | |
// Funktionen abhaengig von Taktbotschaften | // Funktionen abhaengig von Taktbotschaften | ||
- | { | + | |
- | if (takt10ms) // | + | if (takt10ms) // |
- | { | + | { |
- | takt10ms = 0; // Botschaft " | + | takt10ms = 0; |
- | counterCounting(); | + | counterCounting(); |
- | + | ||
- | } | + | } |
- | if (takt100ms) // | + | if (takt100ms) // |
- | { | + | { |
- | takt100ms = 0; // Botschaft " | + | takt100ms = 0; |
- | counterDisplay(); | + | counterDisplay(); |
- | } | + | } |
- | } | + | } |
- | return 0; | + | return 0; |
} | } | ||
+ | |||
// Interrupt-Routine ========================================================== | // Interrupt-Routine ========================================================== | ||
ISR (TIMER0_OVF_vect) | ISR (TIMER0_OVF_vect) | ||
/* In der Interrupt-Routine sind die Softwareteiler für die Taktbotschaften | /* In der Interrupt-Routine sind die Softwareteiler für die Taktbotschaften | ||
| | ||
- | + | ||
- | | + | |
- | hunderstel | + | hunderstel |
- | + | ||
- | | + | |
- | takt100ms | + | takt100ms |
*/ | */ | ||
{ | { | ||
- | timertick = 1; // Botschaft 0,166ms senden | + | |
- | --vorteiler; | + | --vorteiler; |
- | if (vorteiler==0) // | + | if (vorteiler==0) // |
- | { | + | { |
- | vorteiler = VORTEILER_WERT; | + | vorteiler = VORTEILER_WERT; |
- | takt10ms = 1; | + | takt10ms = 1; |
- | --hundertstel; // Hunderstelzähler dekrementieren | + | --takt10msZaehler; // Hunderstelzähler dekrementieren |
- | + | ||
- | if (hundertstel==0) // wenn 0 erreicht: 100ms abgelaufen | + | if (takt10msZaehler==0) // wenn 0 erreicht: 100ms abgelaufen |
- | { | + | { |
- | hundertstel | + | |
- | takt100ms = 1; | + | takt100ms = 1; |
- | } | + | } |
- | } | + | } |
} | } | ||
- | + | ||
- | // Taster initialisieren ======================================================= | + | |
- | void initTaster(void) | + | |
- | { | + | |
- | DDRB = DDRB & 0xE1; // Port B auf Eingabe schalten | + | |
- | PORTB |= 0x1E; | + | |
- | _delay_us(1); | + | |
- | } | + | |
// Zaehlfunktion ============================================================== | // Zaehlfunktion ============================================================== | ||
void counterCounting(void) | void counterCounting(void) | ||
{ | { | ||
- | // Einlesen der 3 Tastensignale | + | |
- | sw1_neu | + | // |
- | sw2_neu | + | DDRC = DDRC & 0b11111000; // Zunaechst Port B auf Eingabe schalten |
- | sw3_neu = (PINB & (1 << PINB3)); | + | |
+ | | ||
- | // Auswertung der 3 Tasten | + | // Einlesen der 3 Tastensignale |
- | + | sw1_neu = GET_BIT(PINC, | |
- | if (sw1_neu==0) // | + | sw2_neu = GET_BIT(PINC, |
- | counter = 0000; | + | sw3_neu = GET_BIT(PINC, |
- | + | ||
- | if ((sw2_neu==0)& | + | |
- | { | + | |
- | counter++; | + | if (sw1_neu==0) // |
- | if (counter==10000) | + | counter = 0000; |
- | counter = 0000; | + | |
- | } | + | if ((sw2_neu==0)& |
- | if ((sw3_neu==0)& | + | { |
- | { | + | counter++; |
- | counter--; | + | if (counter==10000) |
- | if (counter< | + | counter = 0; |
- | counter = 9999; | + | } |
- | } | + | if ((sw3_neu==0)& |
+ | { | ||
+ | counter--; | ||
+ | if (counter < 0) | ||
+ | counter = 9999; | ||
+ | } | ||
+ | |||
+ | // Zwischenspeichern aktuelle Tastenwerte | ||
+ | |||
+ | sw1_alt = sw1_neu; | ||
+ | sw2_alt = sw2_neu; | ||
+ | sw3_alt = sw3_neu; | ||
- | // Zwischenspeichern aktuelle Tastenwerte | + | DDRC = DDRC | 0b00000111; |
- | + | ||
- | sw1_alt | + | |
- | sw2_alt = sw2_neu; | + | |
- | sw3_alt = sw3_neu; | + | |
} | } | ||
+ | |||
// Anzeige Zaehler ============================================================ | // Anzeige Zaehler ============================================================ | ||
void counterDisplay(void) | void counterDisplay(void) | ||
{ | { | ||
- | int temp; // lokale temporaere Variable | + | |
- | + | | |
- | lcd_gotoxy(1, | + | lcd_gotoxy(1, |
- | + | | |
- | temp = counter; | + | temp = counter; |
- | lcd_putc(temp/ | + | lcd_putc(temp/ |
- | + | ||
- | temp = temp%1000; // Divisionrest = Hunderter + Zehner + Einer | + | temp = temp%1000; // Divisionrest = Hunderter + Zehner + Einer |
- | lcd_putc(temp/ | + | lcd_putc(temp/ |
- | + | ||
- | temp = temp%100; // Divisionsrest = Zehner + Einer | + | temp = temp%100; // Divisionsrest = Zehner + Einer |
- | lcd_putc(temp/ | + | lcd_putc(temp/ |
- | lcd_putc(temp%10+0x30); // Ausgabe Einer als ASCII-Wert | + | lcd_putc(temp%10+ASC_ZERO); // Ausgabe Einer als ASCII-Wert |
} | } | ||
+ | |||
// Initialisierung Display-Anzeige ============================================ | // Initialisierung Display-Anzeige ============================================ | ||
- | void initDisplay() // Start der Funktion | + | void initDisplay() // Start der Funktion |
{ | { | ||
- | lcd_init(); | + | |
- | + | | |
- | lcd_gotoxy(0, | + | lcd_gotoxy(0, |
- | lcd_putstr(" | + | lcd_putstr(" |
- | + | ||
- | lcd_gotoxy(1, | + | lcd_gotoxy(1, |
- | lcd_putstr(" | + | lcd_putstr(" |
- | + | ||
- | _delay_ms(2000); | + | _delay_ms(2000); |
- | + | ||
- | lcd_gotoxy(0, | + | lcd_gotoxy(0, |
- | lcd_putstr(" | + | lcd_putstr(" |
- | + | ||
- | lcd_gotoxy(1, | + | lcd_gotoxy(1, |
- | lcd_putstr(" | + | lcd_putstr(" |
- | } // Ende der Funktion | + | } // Ende der Funktion |
</ | </ | ||
</ | </ | ||
Zeile 287: | Zeile 294: | ||
- Wird die Taste S1 gedrückt, so wird '' | - Wird die Taste S1 gedrückt, so wird '' | ||
- Die Makros wurden bereits erklärt \\ \\ \\ \\ | - Die Makros wurden bereits erklärt \\ \\ \\ \\ | ||
- | - Die Funktionsprototypen zeigen wieder die kommenden Unterprogramme an \\ \\ | + | - Die Funktionsprototypen zeigen wieder die kommenden Unterprogramme an \\ \\ \\ \\ \\ |
Zeile 294: | Zeile 301: | ||
- Zunächst werden zwei Initialisierungsroutinen aufgerufen (siehe weiter unten) | - Zunächst werden zwei Initialisierungsroutinen aufgerufen (siehe weiter unten) | ||
- Dann werden die " | - Dann werden die " | ||
- | - '' | + | - '' |
- erst mit dem Befehl '' | - erst mit dem Befehl '' | ||
- | - in der Endlosschleife sind zwei if-Befehle zu finden, welche über Flags prüfen, ob $10ms$ oder $100ms$ abgelaufen sind. Wenn ja, wird als erstes das Flag zurückgesetzt und dann die gewünschte Unterfunktion aufgerufen. | + | - in der Endlosschleife sind zwei if-Befehle zu finden, welche über Flags prüfen, ob $10~\rm ms$ oder $100 ~\rm ms$ abgelaufen sind. Wenn ja, wird als erstes das Flag zurückgesetzt und dann die gewünschte Unterfunktion aufgerufen. |
- | - Die Abfrage der Tasten soll entprellt geschehen. Das ist durch das Abtasten / Einlesen des Signals alle $10ms$ möglich. | + | - Die Abfrage der Tasten soll entprellt geschehen. Das ist durch das Abtasten / Einlesen des Signals alle $10 ~\rm ms$ möglich. |
- | - Für die Textanzeige ist eine keine ruckelfreie Darstellung notwendig. Damit kann für die Darstellung der Wert von $30 Hz$ unterschritten werden, über dem ein Bild als flüssig animiert | + | - Für die Textanzeige ist eine keine ruckelfreie Darstellung notwendig. Damit kann für die Darstellung der Wert von $30 ~\rm Hz$ unterschritten werden, über dem ein Bild als flüssig animiert |
'' | '' | ||
- Mit dem Befehl '' | - Mit dem Befehl '' | ||
- | - Der Überlauf-Interrupt durch den Timer0 wird erst bei Überlauf des 8-Bit Wert ausgeführt. Das entspricht einer Periode von $T_{ISR}=\frac{256 \cdot Prescaler}{f_{Quarz}} = \frac{256 \cdot 8}{12'288'000 Hz} = 0,16\bar{6}ms$. | + | - Der Überlauf-Interrupt durch den Timer0 wird erst bei Überlauf des 8-Bit Wert ausgeführt. Das entspricht einer Periode von $T_{\rm ISR}=\frac{256 \cdot \rm Prescaler}{f_{\rm Quarz}} = \frac{256 \cdot 8}{18'432' |
- Als erstes wird beim Ausführen die boole-Variable '' | - Als erstes wird beim Ausführen die boole-Variable '' | ||
- | - Die Variable '' | + | - Die Variable '' |
- | - Wenn '' | + | - Wenn '' |
- | - Erreicht '' | + | - Erreicht '' |
- Mit dieser Methode erzeugt der Interrupt nur 3 Flags, die anderweitig ausgelesen werden können, z.B. in '' | - Mit dieser Methode erzeugt der Interrupt nur 3 Flags, die anderweitig ausgelesen werden können, z.B. in '' | ||
- | '' | + | \\ \\ \\ \\ |
- | - Das Einstellen des Data Direction Registers und der Pullups wurde bereits in vorherigen Programmen erklärt. | + | |
'' | '' | ||
- | \\ \\ \\ | + | |
- | - Zunächst werden die einzelnen Tastenstellungen mittels verUNDen einer Bitmaske für den jeweiligen Taster aus '' | + | - Zunächst werden die einzelnen Tastenstellungen mittels verUNDen einer Bitmaske für den jeweiligen Taster aus '' |
- Für die Reaktion auf einen Tastendruck gibt es nun zwei Varianten: \\ a. immer wenn erkannt wird, dass die Taste gedrückt ist (der Schalter geschlossen ist), wird reagiert. \\b. nur beim Wechsel von ' | - Für die Reaktion auf einen Tastendruck gibt es nun zwei Varianten: \\ a. immer wenn erkannt wird, dass die Taste gedrückt ist (der Schalter geschlossen ist), wird reagiert. \\b. nur beim Wechsel von ' | ||
- Im Falle das Heraufzählens, | - Im Falle das Heraufzählens, | ||
- Zum Ende dieser Funktion müssen die Schalterstellungen in die Variablen '' | - Zum Ende dieser Funktion müssen die Schalterstellungen in die Variablen '' | ||
- | \\ \\ | + | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ |
'' | '' | ||
- Zur Ausgabe des Zählerwerts wird eine Hilfsvariable angelegt und auf eine Position unten rechts auf dem Display gesprungen | - Zur Ausgabe des Zählerwerts wird eine Hilfsvariable angelegt und auf eine Position unten rechts auf dem Display gesprungen | ||
- Um den Wert '' | - Um den Wert '' | ||
- Für die Hunderterstelle von '' | - Für die Hunderterstelle von '' | ||
+ | \\ \\ \\ | ||
'' | '' | ||
- Hier wird wieder die Startanzeige mit dem Namen des Programms generiert | - Hier wird wieder die Startanzeige mit dem Namen des Programms generiert |