Hi,
besser kann ich den Titel nicht formulieren, wahrscheinlich steh ich
einfach nur völlig auf dem Schlauch.
Folgendes Programm soll beim einfachen Druck auf einen Taster einen
Ausgang einschalten und beim Loslassen wieder abschalten. Falls man
jedoch innerhalb 1 Sekunde ein zweites mal drückt soll der Ausgang nicht
wieder abgeschaltet werden.
Drückt man nun den Taster wird dabei justreleased=1 gesetzt. Lässt man
ihn los wird geprüft ob justreleased gesetzt war und die variable wird
resettet, ebenso auch hebercounter. Solange der Taster nicht gedrückt
ist zählt diese Variable hoch. Wenn ich nun innerhalb dieser Zeitspanne
auf den Taster drücke sollte heber=1 gesetzt werden.
heber=1 wird aber IMMER gesetzt, egal wie flott ich auf den taster
drücke.
Noch dazu kommt: Wenn ich das Programm so kompiliere ergibt das 130
Bytes. Wenn ich die Variablendeklarierung in die main reinpacke ist das
Programm nur 68 Bytes groß aber tut genau das gleiche. Was ist denn da
los?
1
#include<avr/io.h>
2
#include<util/delay.h>
3
4
uint8_tjustreleased;
5
uint8_theber;
6
uint16_thebercounter;
7
8
intmain(void)
9
{
10
PORTB=0b00000100;
11
DDRA=0b01000000;
12
13
while(1)
14
{
15
if(bit_is_clear(PINB,PB2))
16
{
17
if(hebercounter<100)
18
{
19
heber=1;
20
}
21
22
PORTA|=(1<<PA6);
23
24
justreleased=1;
25
}
26
else
27
{
28
if(justreleased)
29
{
30
hebercounter=0;
31
justreleased=0;
32
}
33
34
if(!heber)
35
{
36
PORTA&=~(1<<PA4);
37
}
38
39
hebercounter++;
40
}
41
}
42
}
Übrigens kann ich das Programm nicht so einfach anders aufbauen weil
zeitgleich noch ein zweiter Taster abgefragt wird, welcher einen zweiten
Ausgang nach dem gleichen Prinzip schaltet. Den Code dafür habe ich hier
aber weggelassen.
Danke für jede Hilfe, ich dreh wieder am Rad an so einem einfachen mist
hängen zu bleiben.
Ist übrigens ein ATtiny24 @ 1Mhz.
Grüße, PoWl
Oh sorry, kurz vorm Ende der Schleife fehlt noch ein
_delay_ms(10);
Das hatte ich versehentlich wohl rausgelöscht. Dennoch funktioniert es
weiterhin nicht.
Paul Hamacher schrieb:> Folgendes Programm soll beim einfachen Druck auf einen Taster einen> Ausgang einschalten und beim Loslassen wieder abschalten. Falls man> jedoch innerhalb 1 Sekunde ein zweites mal drückt soll der Ausgang nicht> wieder abgeschaltet werden.
Sondern?
Wie wird der Ausgang dann abgeschaltet?
> Übrigens kann ich das Programm nicht so einfach anders aufbauen weil> zeitgleich noch ein zweiter Taster abgefragt wird, welcher einen zweiten> Ausgang nach dem gleichen Prinzip schaltet.
Würde ich mit einem Timer machen.
Timer ISR ist so eingestellt, dass die ISR zb alle 1/100 Sekunde
aufgerufen wird. In der ISR wird eine Variable runtergzeählt (wenn sie
nicht sowieso schon 0 ist).
Bei einem Tastendruck wird die Variable geprüft. Ist sie 0 dann lag der
letzte Tastendruck schon länger als 1 Sekunde zurück. Ist sie nicht 0,
dann war der Tastendruck noch keine Sekunde her.
Entsprechend dieser Information wird dann der Ausgang geschaltet, bzw.
die Timer Variable auf 100 gesetzt, damit die Stoppuhr anfängt zu
laufen.
Mit deinem Schleifen Countern da oben, wirst du nie ein vernünftiges
Timing hinkriegen. Mach dir zur Maxime: Wenn irgendwo Zeiten im Spiel
sind, dann ist ein Timer nicht weit.
Und 'Stoppuhren' die eine bestimmte Zeitspanne abzählen, baut man am
einfachsten eben genau so.
1
volatileuint8_tticksRemaining;
2
3
ISR(....)// wird regelmässig alle x Millisekunden aufgerufen
4
{
5
if(ticksRemaining>0)
6
ticksRemaining--;
7
}
8
9
intmain()
10
{
11
....
12
13
14
ticksRemaining=50;// Stoppuhr starten, so dass sie nach
Danke für die Antwort, aber auf mein Problem bist du nicht so ganz
eingangen :(
> Sondern?> Wie wird der Ausgang dann abgeschaltet?
Das ist ein anderes Fass Bier, das mach ich später auf.
> Mit deinem Schleifen Countern da oben, wirst du nie ein vernünftiges> Timing hinkriegen. Mach dir zur Maxime: Wenn irgendwo Zeiten im Spiel> sind, dann ist ein Timer nicht weit.
Der hebercounter zählt erstmal bis um die 65000. Und das von Beginn an,
wenn ich den AVR einschalte. D.h. wenn ich das Teil einschalte und nach
mehreren Sekunden(!) das erste mal auf den Taster klicke kann es
unmöglich sein, dass heber=1 gesetzt wird. Der hebercounter müsste schon
viel weiter gezählt haben. Das kann auch unmöglich am "ungenauen
timinig" liegen. (meinetwegen werde ich es nochmal mit timern probiern,
aber zuerst will ich dieses Problem gelöst haben weil ich da scheinbar
grundlegend was nicht ganz verstanden habe oder mein compiler falsch
kompiliert. Unter der Bedingung brauch ich garnicht erst weitermachen)
> Ausserdem musst du deinen Taster entprellen. Sonst triggert dir das> Prellen ständig den 2.ten Tastendruck
Der prellt sicher keine 10ms. Ich kanns ja nochmal mit 100ms delay
probieren und if(hebercounter < 3)
Paul Hamacher schrieb:> Danke für die Antwort, aber auf mein Problem bist du nicht so ganz> eingangen :(
Weißt du.
Dein Problem ist insofern nicht wirklich relevant, weil der ganze Ansatz
schon nicht stimmt. Er ist kompliziert, unübersichtlich und
fehlerträchtig.
1
volatileuint8_tticksRemaining;
2
3
ISR(....)// wird regelmässig alle x Millisekunden aufgerufen
4
{
5
if(ticksRemaining>0)
6
ticksRemaining--;
7
}
8
9
intmain()
10
{
11
timeraufsetzen
12
13
sei
14
15
keyPrevious=bit_is_clear(PINB,PB2);
16
17
while(1){
18
19
keyNow=bit_is_clear(PINB,PB2);
20
21
if(keyNow!=keyPrevious){// Taste hat sich verändert
22
23
if(keyNow){// Taste wurde gedrückt
24
if(ticksRemaining==0){// war das erste mal bzw. schon
25
// länger als 1 Sekunde her
26
ticksRemaining=SEC_1;// Stoppuhr starten
27
PORTA|=(1<<PA6);
28
allowShutdown=TRUE;
29
}
30
else{// die 1 Sekunde ist noch nicht um
31
// 2. Druck innerhalb der Zeit
32
allowShutdown=FALSE;
33
}
34
}
35
36
else{// Taste wurde losgelassen
37
if(allowShutdown)
38
PORTA&=~(1<<PA6);
39
}
40
41
keyNow=keyPrevious;
42
}
43
}
44
}
ungetesteter Code. Aber so in etwas müsste das klappen
Das verstehe ich nicht. Ich habe doch gerade erklärt warum es nicht sein
kann, das mein Phänomen auftritt. Widerlege meine Erklärung bitte. Das
hast du nicht damit getan indem du behauptest, das Timing sei völlig
daneben. So daneben kann das garnicht sein. Da können sich doch
unmöglich mehrere Sekunden aufsummieren, findest du nicht?
Und erkläre mit bitte noch gleich folgendes: Ich habe grade mal
1
if(hebercounter<100)
2
{
3
heber=1;
4
}
zu
1
if(hebercounter)
2
{
3
heber=1;
4
}
umgeändert. Ja ich weiß, das macht keinen Sinn. Resultiert aber in der
gleichen Codegröße, und in gleichem Verhalten. Das mit der Codegröße ist
seltsam, das Verhalten muss nun so sein da hebercounter ja definitiv
gesetzt und >0 ist. Und danach zu
1
if(!hebercounter)
2
{
3
heber=1;
4
}
Wieder gleiche Codegröße, gleiches Verhalten. Wie kann das denn nun aber
sein?
Grüße, PoWl
Paul Hamacher schrieb:> Das verstehe ich nicht. Ich habe doch gerade erklärt warum es nicht sein> kann, das mein Phänomen auftritt. Widerlege meine Erklärung bitte.
Ich mag da jetzt aber nicht nachvollziehen, wie sich 3 Variablen in
verschiedenen Programmteilen gegenseitig beeinflussen, wenn ich es
einfacher haben kann (Siehe code weiter oben)
Paul Hamacher schrieb:> Wieder gleiche Codegröße, gleiches Verhalten. Wie kann das denn nun aber> sein?
Auf Assemblerebene mündet das alles in konzeptionell dem gleichen Code
vergleiche mit einem Wert (0 oder 100)
Springe wenn gleich/kleiner/größer
Egal welche Kombination jetzt zum Einsatz kommt, es sind immer 2
Befehle. Nur eben unterschidedliche Befehle, je nachdem wie du deine
Abfrage jetzt konkret formulierst.
ok, aber wie erklärst du dir den Logikfehler? Bei beiden Kompilaten
absolut gleiche Bedingungen und gleicher Versuchsaufbau. Aber wie kann
die if sowohl bei (!hebercounter) als auch (hebercounter) denn true
werden? Oder bin ich denn jetzt ganz dappisch und (!variable) ist keine
gängige Schreibweise um diese Variable auf 0 zu prüfen und (variable)
ist keine gängige Schreibweise um zu prüfen ob die Variable nicht 0 ist?
Ich werde jetzt erstmal ins Bett gehen und meinen Kopf freischlafen.
Morgen verwende ich gerne den von dir gemachten Codevorschlag. Trotzdem
möchte ich wissen warum mein Code nicht funktioniert obwohl er es
offensichtlich tun müsste und wie dieser Logikfehler zustande kommen
kann und auch, warum die Codegröße fast doppelt so groß wird, wenn ich
die Variablen innerhalb der main-funktion deklariere.
Danke soweit!
Paul Hamacher schrieb:>> Wie wird der Ausgang dann abgeschaltet?>> Das ist ein anderes Fass Bier, das mach ich später auf.
Das ist Quatsch. Ehe Du etwas anfängst zu programmieren, mußt Du es
erstmal zuende denken.
Man macht sich erstmal nen vollständigen und vor allem logischen
Ablaufplan, z.B. auf Papier und erst dann fängt man an, Code
reinzuhacken.
Peter
Paul Hamacher schrieb:> ok, aber wie erklärst du dir den Logikfehler? Bei beiden Kompilaten> absolut gleiche Bedingungen und gleicher Versuchsaufbau. Aber wie kann> die if sowohl bei (!hebercounter) als auch (hebercounter) denn true> werden? Oder bin ich denn jetzt ganz dappisch und (!variable) ist keine> gängige Schreibweise um diese Variable auf 0 zu prüfen und (variable)> ist keine gängige Schreibweise um zu prüfen ob die Variable nicht 0 ist?>> Ich werde jetzt erstmal ins Bett gehen und meinen Kopf freischlafen.> Morgen verwende ich gerne den von dir gemachten Codevorschlag. Trotzdem> möchte ich wissen warum mein Code nicht funktioniert obwohl er es> offensichtlich tun müsste und wie dieser Logikfehler zustande kommen> kann und auch, warum die Codegröße fast doppelt so groß wird, wenn ich> die Variablen innerhalb der main-funktion deklariere.>> Danke soweit!
schau dir doch einfach mal das Assembler-Listing zu deinem Programm(en)
an...bei so kurzen Programmen sind die ja noch sehr übersichtlich. Sowas
hilft oft weiter...
Justus Skorps schrieb:> schau dir doch einfach mal das Assembler-Listing zu deinem Programm(en)> an...bei so kurzen Programmen sind die ja noch sehr übersichtlich. Sowas> hilft oft weiter...
Aua...
Zur Lösung solcher Probleme wurden vor geschätzen 30 zillionen Jahren
Debugger erfunden.
Lade das Programm in den Simulator, und step Schritt für Schritt durch.
Und wenn das alles im Simulator funktioniert, in der Realität aber
nicht, dann solltest du über das entprellen der Taste nachdenken.
Oliver