Forum: Compiler & IDEs Atmel Mega 8 verhält sich nicht wie in AVR Studio Simulation


von Tobias (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe Forenteilnehmer,

ich beschäftige mich zum ersten Mal mit GCC zur Programmierung eines µC 
und brauche Hilfe, der Quelltext ist angehängt.

Das Programm soll später einmal ein externes Zeitsignal bekommen und 
dieses per multigeplexten 7-Segmentanzeigen ausgeben und außerdem zwei 
Stoppuhren (eine für kurze Zeiten im 2h-Bereich und eine für Zeiten bis 
24h) betreiben.

Das angehängte Programm enthält alles notwendige, außer dem 
UART-Empfang, jedoch habe ich wieder vieles auskommentiert um dem Fehler 
auf die Schliche zu kommen, es sind also nur noch die konkreten Teile 
vorhanden und der Fehler tritt immer noch auf.

Ich teste im Augenblick noch auf einem myAVR-Board, da die Schaltung 
noch nicht fertig ist. Daran überprüfe ich die Pegel des Ports C mit den 
LEDs, in der Simulation schaue ich sie mir direkt an. Die Taster habe 
ich an Port-D 3 und 4 angeschlossen.

In der Simulation zeigt der Code das gewünschte Verhalten, nach der 
Initialisierung bleibt Port-C dauerhaft auf 0x04, nach Setzen von PIN 3/ 
springt er auf 0x01 bzw. 0x02.

Das ganze auf den Atmel geflasht, leuchtet ganz kurz PORTC2 (Also Wert 
4) auf, dann springt er auf PORTC0 (Also Wert 1), das Setzen von PIN4 
führt zu einem Sprung auf PORTC1 (Also Wert 2), jedoch nur so lange, wie 
der Taster gedrückt wird, danach erfolgt wieder der Sprung auf PORTC0 
(Also Wert 1). PIN3 hat gar keinen Einfluss, offensichtlich wird also 
immer zu Beginn eines Schleifendurchlaufs der Wert geändert und ich weiß 
nicht warum.

Was ich mich frage, wieso funktioniert es im Simulator, aber nicht auf 
dem Chip und was mache ich falsch? Ich habe die Funktionen auch schon 
alle eingegliedert gehabt, ich habe die If-Funktionen umgekrempelt, etc. 
aber ich komme auch mit verschiedenen Optimierungsoptionen nicht zum 
gewünschten Ergebnis auf der Hardware.

Für eure Hilfe bedanke ich mich im Voraus, ich hoffe es ist ein simpler 
Anfängerfehler, dem ihr schnell auf die Sprünge helfen könnt, falls ihr 
weitere Infos braucht, lasst es mich wissen, dann versuche ich das nach 
bestem Wissen bereitzustellen.

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Die Abfrage der Taster ist nicht gerade übersichtlich und wie ich es, 
ohne es komlett gelesen zu haben, sehe, auch ohne wirksame Entprellung.

keys = keys & PIND;
keycounter = keycounter + 1;
// CHR RESET
if(keycounter > 7)
{
if(keys & (1<<PIND3))
   {
  chr_reset();
   }

usw...

Warum legst du nicht einfach für jede Taste eine Variable an, die du 
runterzählst, wenn die Taste gedrückt ist. Wenn sie weit genug 
runtergezählt ist, wertest du die Taste aus und zählst noch einmal 
weiter runter, was signalisiert, dass sie nicht nocheinmal ausgewertet 
werden soll. Wenn die Taste losgelassen wird, wird die Variable 
zurückgesetzt. So mach ich das immer.

Beispielcode von einem MSP430 mit 4 Tasten; P5IN entspricht in deinem 
Fall dem PIND, TasterXX sind Variablen mit 8 bit (unsigned char). Man 
kann für jede Funktion zwischen edge_detect und level_detect auswählen. 
Edge_detect wertet nur einmal aus beim Drücken, level_detect immer 
wieder, solange man gedrückt hält.
1
#include "binary_numbers.h"
2
#define edge_detect 1
3
#define level_detect 0
4
5
  for (;;)
6
  {
7
    if (((P5IN & b00000010) == 0) & (TasterRU != 0)) TasterRU--;
8
    if (((P5IN & b00000100) == 0) & (TasterRO != 0)) TasterRO--;
9
    if (((P5IN & b00001000) == 0) & (TasterLO != 0)) TasterLO--;
10
    if (((P5IN & b00010000) == 0) & (TasterLU != 0)) TasterLU--;
11
    if ((P5IN & b00000010) == b00000010) TasterRU = 0xFF;
12
    if ((P5IN & b00000100) == b00000100) TasterRO = 0xFF;
13
    if ((P5IN & b00001000) == b00001000) TasterLO = 0xFF;
14
    if ((P5IN & b00010000) == b00010000) TasterLU = 0xFF;
15
16
    if (TasterRO == edge_detect) //1 = Flankenauswertung
17
      {
18
        display_frame(1);
19
      }

Ich hoffe, das hilft etwas, den Code zu strukturieren.

Grüße,

Peter

von Tobias (Gast)


Lesenswert?

>Die Abfrage der Taster ist nicht gerade übersichtlich und wie ich es,
>ohne es komlett gelesen zu haben, sehe, auch ohne wirksame Entprellung.
>
>keys = keys & PIND;
>keycounter = keycounter + 1;
>// CHR RESET
>if(keycounter > 7)
>{
>if(keys & (1<<PIND3))
>   {
>  chr_reset();
>   }
>
>usw...

Ich bin dabei dem Beispiel von hier gefolgt: 
http://www.mikrocontroller.net/articles/Entprellung#Warteschleifenvariante_mit_Maske_und_Pointer_.28nach_Christian_Riggenbach.29

Was findest du daran unübersichtlich?

Die Funktion habe ich ursprünglich auch ausgegliedert gehabt, dann aber 
für Testzwecke wieder in den Programmcode aufgenommen, in der Simulation 
funktioniert sie auch, die Entprellung geschieht ja darüber, dass keys 
in jedem Schleifendurchlauf mit dem Bit-Zustand logisch UND-verknüpft 
wird, also bleibt ein Bit in keys nur eins, wenn der Taster gedrückt 
war. Dies muss 8 mal hintereinander passieren, ist er in einem dieser 
Durchläufe nicht gedrückt, wird keys ja einmal mit 0 verknüpft und 
bleibt dann bis zum Reset (bei keycounter>7 wird keys=0xff und 
keycounter=0 gesetzt). Durch den geschrumpften Programmcode ist die 
Ausführzeit soweit zurückgegegangen, dass ich bei dem im Link 
angegebenen Mindestwert von 150us rauskomme, doch auch mit dem gesamten 
Code (dann liegt die Zeit bei etwa 1ms) tritt der exakt gleiche Effekt 
auf.

Er springt offensichtlich in jedem Durchlauf in die Schleife und setzt 
die Werte auf 1, auch wenn der Taster gar nicht angeschlossen ist, d.h. 
da kann dann die Entprellung gar nicht Schuld sein.

Jedenfalls habe ich deinen Vorschlag aufgenommen, eingebaut und es 
funktioniert jetzt auch, wie es soll, doch mir ist weiterhin 
unerklärlich, weshalb der obige Code von mir nicht geht. Danke für die 
Hilfe und falls mir jemand noch erklären kann, was da oben schiefläuft, 
bin ich ihm auch dankbar.

von Karl H. (kbuchegg)


Lesenswert?

Dein Code entprellt mich.
Dein Code überprüft lediglich bei jedem 7-ten Schleifendurchlauf, ob 
eine Taste gedrückt ist. Das ist aber viel zu wenig, die Schleife läuft 
viel zu schnell durch, als das dieses Zählen bis 7 irgendwas bewirken 
würde.

Ich nehm immer die PeDa Methode (ebenfalls auf der von dir verlinkten 
Seite). Die würde ich dir auch empfehlen. Hauptsächlich deshalb, weil du 
ja sowieso zum Multiplexen der Anzeige einen regelmässigen Interrupt 
einsetzen wirst. In dieser ISR kannst du dann nebenbei auch noch die 
Tasten entprellen und hast dann auch noch den Vorteil, dass du zwischen 
langen und kurzen Tastendrücken auch noch unterscheiden kannst.

von Rolf Magnus (Gast)


Lesenswert?

> Ich bin dabei dem Beispiel von hier gefolgt:
> http://www.mikrocontroller.net/articles/Entprellun...

Lies die Seite bitte ganz.

> die Entprellung geschieht ja darüber, dass keys
>  in jedem Schleifendurchlauf mit dem Bit-Zustand logisch UND-
>verknüpft wird, also bleibt ein Bit in keys nur eins, wenn der Taster
> gedrückt war. Dies muss 8 mal hintereinander passieren,

Was dann nach einer einstelligen Zahl an Mikrosekunden erledigt sein 
dürfte - lange bevor das Prellen überhaupt richtig begonnen hat.

von Tobias (Gast)


Lesenswert?

>Dein Code entprellt mich.
>Dein Code überprüft lediglich bei jedem 7-ten Schleifendurchlauf, ob
>eine Taste gedrückt ist. Das ist aber viel zu wenig, die Schleife läuft
>viel zu schnell durch, als das dieses Zählen bis 7 irgendwas bewirken
>würde.
Die Überprüfung findet doch bei keys = keys & PIND statt, das wird doch 
in jedem Durchlauf aufgerufen, nach dem siebten Schleifendurchlauf wird 
dann nur überprüft, welche Taster in jedem der vergangenen Durchläufe 
gedrückt war, ist das keine Entprellung? Oder habe ich da jetzt

>Lies die Seite bitte ganz.
Das habe ich getan, mit
>Entprellzeit von durchschnittlich 1-3ms (mindestens 8*150us = 1ms)
im Hinterkopf habe ich dann ja diese Auslegung gemacht:
>Was dann nach einer einstelligen Zahl an Mikrosekunden erledigt sein
>dürfte - lange bevor das Prellen überhaupt richtig begonnen hat.
Laut der Simulation in AVR Studio nicht, ohne Optimierung brauchte da 
der Code etwa 1000us, die kurze Fassung etwa 150us, also genau die im 
Artikel erwähnte Zeit.

Deswegen jetzt nochmal der Hinweis, auch ganz ohne Schalter sprang er in 
die Funktion die den Wert geändert hat, wenn ich diese rausgeworfen habe 
sprang er in die nächste, wie kann es ganz ohne die entsprechenden Pins 
überhaupt mit etwas zu belegen zu einem Input kommen, das verstehe ich 
einfach nicht.

von Karl H. (kbuchegg)


Lesenswert?

Tobias wrote:

> Die Überprüfung findet doch bei keys = keys & PIND statt, das wird doch
> in jedem Durchlauf aufgerufen, nach dem siebten Schleifendurchlauf wird
> dann nur überprüft, welche Taster in jedem der vergangenen Durchläufe
> gedrückt war, ist das keine Entprellung? Oder habe ich da jetzt

Stell dir jetzt einfach mal vor, du drückst die Taste genau in dem 
Moment, in dem keycdount gleich 6 (oder 7) ist. Bewirkt dein Konstrukt 
dann noch irgendwas?

Entprellung bedeutet immer, dass beim ersten Erkennen einer Flanke 
irgendein Prozess gestartet werden muss, der nach einer bestimmten Zeit 
den endgültigen Tastenzustand feststellt.
Beim Erkennen einer Flanke muss eine Programmlogik starten. In deinem 
Code ist nichts davon zu sehen.

> der Code etwa 1000us, die kurze Fassung etwa 150us, also genau die im
> Artikel erwähnte Zeit.

Beim Prellen reden wir über Millisekunden, nicht µs!
Das ist ein mechanischer Vorgang! Die Kontaktzungen, die den Kontakt 
herstellen, schwingen nach! Millisekunden sind für einen µC eine halbe 
Ewigkeit.

von Karl H. (kbuchegg)


Lesenswert?

> Deswegen jetzt nochmal der Hinweis, auch ganz ohne Schalter sprang
> er in die Funktion die den Wert geändert hat


>  DDRD  = 0x00; /* alle Pins von Port D als Eingang */

Ich weiß zwar nicht, wie deine Taster angeschlossen sind. Aber wenn du 
keine Pullups aktiviert hast, bzw. extern keine Pullup oder Pulldown 
Widerstände angeschlossen jast, darfst du dich nicht wundern, wenn sich 
die Eingänge so ziemlich jede elektromagnetische Störung aus der näheren 
Umgebung reinziehen und als Signal werten

von Klaus (Gast)


Lesenswert?

> Dein Code entprellt mich.

Cool =) Kannst du mal beschrieben wie sich das anfühlt? Ich bin da mal 
neugierig :D

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.