Tastenabfrage in C Atmega32

Im Unterforum Microcontroller - Beschreibung: Hardware - Software - Ideen - Projekte

Elektronik Forum Nicht eingeloggt       Einloggen       Registrieren




[Registrieren]      --     [FAQ]      --     [ Einen Link auf Ihrer Homepage zum Forum]      --     [ Themen kostenlos per RSS in ihre Homepage einbauen]      --     [Einloggen]

Suchen


Serverzeit: 27 9 2024  06:27:59      TV   VCR Aufnahme   TFT   CRT-Monitor   Netzteile   LED-FAQ   Osziloskop-Schirmbilder            


Elektronik- und Elektroforum Forum Index   >>   Microcontroller        Microcontroller : Hardware - Software - Ideen - Projekte


Autor
Tastenabfrage in C Atmega32

    







BID = 918518

peterschrott

Gesprächig



Beiträge: 167
Wohnort: Düsseldorf
 

  


Hallo Leute,
ich brauch mal wieder eure Hilfe bei der Programmierung eines Atmega32.
Vorab:Ich fange gerade erst an, mit der Programmierung in C.
Ich benutze AStudio 6.1 und versuche mit Jtag ICE3 zu debuggen.
Es geht um Tastenabfrage. Ich benutze zum Üben das Pollin Board.
Die Software die ich benutze ist aus dem Netz und ist unter
"Tastenabfrage in C" auf www.rn-wissen.de zu finden.
Der Timer0 soll jede msec einen Interrupt erzeugen und alle 10msec die Tasten
abfragen.
Hier tritt jedoch folgendes Problem auf:
Die Zählvariable "ovl0" im Interrupt wird nicht hochgezählt.
Sie bleibt letztendlich auf 255 bei Eintritt in den Interrupt, wird incrementiert und landet dann wieder auf 0.
Das bedeutet, daß die Tasten nie abgefragt werden.
Wenn ich die Sache richtig verstanden habe, sollte die Variable, da sie "volatile und auch static"ist, ihren Wert bei Eintritt in den Interrupt beibehalten haben.
Die Compiler Optimierung habe ich vorerst auf keine Optimierung eingestellt.
Ich versuche mal, den betreffenden Abschnitt zu posten.
Vielleicht hat jemand noch eine Idee dazu.



[code]
/* ISR für Timer 0
(16000000/64/256 Hz = 976,5Hz = 1,02ms)
Bei 16MHz Grundtakt läuft Timer0 alle 1,02ms über.
* Um auf rund 10ms zu kommen, rufen wir get_taster nur
* jedes 10. mal auf. */


ISR (TIMER0_OVF_vect)
{
volatile static unsigned char count_ovl0;
volatile unsigned char ovl0 = count_ovl0 +1;

if (ovl0 >= 10)

{
get_taster (0,PIND & (1<<PD2));
get_taster (1,PIND & (1<<PD3));
get_taster (2,PIND & (1<<PD4));

ovl0 = 0;
}

}
[code]

BID = 918522

der mit den kurzen Armen

Urgestein



Beiträge: 17433

 

  

Wenn du jede ms einen Interrupt (Aufforderung das Programm zu unterbrechen und in die Interuptroutine zu springen) auslöst kommt die gar nicht dazu auf 10 ms hoch zu zählen. Also nur alle 10 ms einen Interrupt auslösen und dann die Tasten abfragen. Nach der Abfrage springt das Programm zurück zum Hauptprogramm und macht da weiter wo es unterbrochen wurde.

_________________
Tippfehler sind vom Umtausch ausgeschlossen.
Arbeiten an Verteilern gehören in fachkundige Hände!
Sei Dir immer bewusst, dass von Deiner Arbeit das Leben und die Gesundheit anderer abhängen!

BID = 918556

peterschrott

Gesprächig



Beiträge: 167
Wohnort: Düsseldorf

Also ich hab den Fehler jetzt gefunden.
Es fehlt lediglich eine ganze Zeile in Code !!
Den Timer Interrupt nur alle 10msec ausführen zu lassen ist keine so gute Idee. Es wird unter anderem geprüft wie lange eine Taste gedrückt wurde. Dazu dient als Zeitgeber dieser Interrupt (Ticks). Bei einer lang gedrückten Taste gibt es z.B. eine variable 60Ticks. Wären bei 10msec dann 600msec. Das ist zu lange.
Aber so funktionierts:



Code :

// Interruptserviceroutine für Timer 0

// hier 1ms

ISR( TIMER0_OVF_vect ) // every 1ms
{
TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 + 0.5); // preload for 1ms

volatile static unsigned char count_ovl0;
volatile unsigned char ovl0 = count_ovl0 +1;

if (ovl0 >= 10)

{
get_taster (0,PIND & (1<<PD2));
get_taster (1,PIND & (1<<PD3));
get_taster (2,PIND & (1<<PD4));

ovl0 = 0;
}

count_ovl0 = ovl0;
}




BID = 918625

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika


Zitat :
Wenn du jede ms einen Interrupt (Aufforderung das Programm zu unterbrechen und in die Interuptroutine zu springen) auslöst kommt die gar nicht dazu auf 10 ms hoch zu zählen.

Wos?


Dein zweiter Quellcode ist besser, wobei ovl0 nicht volatile sein muss sondern nur der Zähler.
ovl0 als temporäre Variable zu benutzen ist aber eine gute Idee, dann muss der Zählerwert nicht jedes mal aus dem RAM zurückgelesen werden (bzw. auch beim Inkrementieren geschrieben werden). Das kostet geringfügig mehr Zeit und Platz.



_________________

BID = 918704

perl

Ehrenmitglied



Beiträge: 11110,1
Wohnort: Rheinbach


Zitat :
Dein zweiter Quellcode ist besser,
...Aber dies ist bei Timern extrem schlecht:
Zitat :

TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 + 0.5); // preload for 1ms

Da man nicht genau weiss, wie lange vor der Ausführung dieses Befehls der Überlauf passiert ist, lädt man den Wert für den Timer nicht einfach in das Register, sondern man addiert ihn besser zum aktuellen Registerinhalt.

BID = 920322

peterschrott

Gesprächig



Beiträge: 167
Wohnort: Düsseldorf

Hab diese Zeile nicht verstanden.
Erklär mir doch bitte mal was da passiert ?
den zweiten Teil kann ich ja noch ausrechnen, doch was bedeuten hier die
Deklariationen uint8_t und uint16_t ?
Ist das die Subtraktion des aktuellen Zählerstandes von TCNT0 vom max Zählerstand ?


BID = 920326

perl

Ehrenmitglied



Beiträge: 11110,1
Wohnort: Rheinbach


Zitat :
doch was bedeuten hier die Deklariationen uint8_t und uint16_t ?
Das siehst du am besten in der Dokumentation deines C-Komplizierers nach (und lernst es), oder du lässt es übersetzen und schaust dir den erzeugten Maschinencode an (sicherer, wenn man nah an der Hardware programmiert).

BID = 920427

peterschrott

Gesprächig



Beiträge: 167
Wohnort: Düsseldorf

@Perl
Hab letztendlich doch noch eine Erklärung, sogar vom Autor persönlich verfasst, im Netz gefunden.
Für mich als Anfänger wäre es fast unmöglich diese Notation zu verstehen.
Es handelt sich um einen CAST, bzw zwei CASTS. Der Ausdruck rechts wird erst in eine 16bit unsigned int und dann in eine 8bit unsigned int gewandelt. Timer 0 hat nur 8bit.
Nach der Umwandlung wird der Wert ins TCNT0 Register geladen (hier 6).
Ich werde die Routine so abändern, daß ich vorher noch den Wert des Registers TCNT0 auslese und dann den Rest zuaddiere.
Das hilft mir jetzt weiter.
LG
Peterschrott





BID = 920434

perl

Ehrenmitglied



Beiträge: 11110,1
Wohnort: Rheinbach


Zitat :
Nach der Umwandlung wird der Wert ins TCNT0 Register geladen (hier 6)
Ja, der ganze lange Ausdruck lädt nur eine Konstante ins Register, d.h. zur Laufzeit wird da gar nichts mehr gerechnet.


Zitat :
Ich werde die Routine so abändern, daß ich vorher noch den Wert des Registers TCNT0 auslese
Mach das lieber nicht explizit, sondern addiere einfach die Konstante zum Register.
Mit etwas Glück, d.h. wenn der aktuelle Wert von TCNT0 nicht noch woanders gebraucht wird, optimiert der Compiler das vorige Auslesen sowieso weg.


Zurück zur Seite 1 im Unterforum          Vorheriges Thema Nächstes Thema 


Zum Ersatzteileshop


Bezeichnungen von Produkten, Abbildungen und Logos , die in diesem Forum oder im Shop verwendet werden, sind Eigentum des entsprechenden Herstellers oder Besitzers. Diese dienen lediglich zur Identifikation!
Impressum       Datenschutz       Copyright © Baldur Brock Fernsehtechnik und Versand Ersatzteile in Heilbronn Deutschland       

gerechnet auf die letzten 30 Tage haben wir 16 Beiträge im Durchschnitt pro Tag       heute wurden bisher 0 Beiträge verfasst
© x sparkkelsputz        Besucher : 182080678   Heute : 1304    Gestern : 5794    Online : 430        27.9.2024    6:27
2 Besucher in den letzten 60 Sekunden        alle 30.00 Sekunden ein neuer Besucher ---- logout ----viewtopic ---- logout ----
xcvb ycvb
0.0950908660889