Hi,
vorab was das Programm tun sollte.
Wird er Blaue Taster (INT0, PD2) gedrückt wird die enstprechende ISR
aufgerufen dort soll immer ein Flag erhöht werden.
Beim 1. Tastendruck soll "menue" auf 1 gesetzt werden, so dass in der
Main in der switch-case der Part "Set_Time" ausgeführt wird, toogle dort
Testweise einen Portpin PD0 um zu sehen, das er auch da reinspringt.
Nur leider tut das Programm mir nicht den gefallen.
Ich weiß das der Taster prellt, und habe deswegen in der ISR die ext.
Interrupts abgeschaltet, die externen INTpins als Ausgang geschaltet und
zusätzlich die entsprechenden Flags gelöscht, da sonst ja wieder ein
neuer ISR Aufruf erfolgt.
Nur klappt das nicht und ich weiß nicht was ich falsch mache.
Prellen hardewaremäßig beheben geht leider nicht mehr.
Ich möchte das gerne mit Interrupts lösen.
Ich hoffe mir kann jemand von euch helfen.
Ich danke euch!
Hardware:
ATTiny2313, läuft mit 1MHz
Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
#include<stdint.h>
5
6
#ifndef F_CPU
7
#define F_CPU 1000000 // processor clock frequency
daniel san schrieb:>> Prellen hardewaremäßig beheben geht leider nicht mehr.>> Ich möchte das gerne mit Interrupts lösen.
Warum? Es gibt keinen Grund dafür! (So wie es meistens keinen Grund gibt
um Taster mittels Interrupt auszuwerten. Aus irgendeinem Grund hält sich
dieser Mythos beständig und ist nicht auszurotten. Der einzige Grund für
Interrupts mit Tastern wäre wenn der µC aus dem Tiefschlaf geholt werden
muss. Aber ansonsten braucht kein Mensch dafür Interrupts. Das macht
alles nur noch komplizierter)
Du hast mit
ISR(TIMER0_COMPA_vect)
einen perfekten Platz um eine softwaremässige Entprellung einzubauen
Entprellung
ganz unten, die C Routinen (das Timer Vorladen lässt du einfach weg)
Edit: Und bevor du fragst - mit diesen Entprell-Routinen kriegst du
einen automatischen Autorepeat frei Haus mitgeliefert. Gerade bei
Einstell-Dingen wie deinen, ist das sehr praktisch. Einfach auf den
Knopf drücken und die Zahl wird gemächlich ganz von alleine größer
solange du den Taster gedrückt hältst.
Hi
Karl Heinz Buchegger schrieb:> Du hast mit>> ISR(TIMER0_COMPA_vect)>> einen perfekten Platz um eine softwaremässige Entprellung einzubauen>> Entprellung> ganz unten, die C Routinen
hi ja ich kenne diese Seite,
sprichst du von der Komfortroutine?
ich finde die Entprellung vom Dannegger aufwendig und kompliziert.
Hatte mir das schon mal angeguckt, aber der Code ist verwirrend
geschrieben, finde ich. Da wird in einer Funktion noch drei weitere
Funktionen aufgerufen.
Verstanden habe ich den noch nicht...
Bevor ich das Problem auf ein anderes verlagere, würde ich trotzdem
gerne wissen was bei mir falsch ist. Vielleicht seh ich dann ein was
einfacher ist ;)
daniel san schrieb:> Hi>> Karl Heinz Buchegger schrieb:>>>> Du hast mit>>>> ISR(TIMER0_COMPA_vect)>>>> einen perfekten Platz um eine softwaremässige Entprellung einzubauen>>>> Entprellung>> ganz unten, die C Routinen>> hi ja ich kenne diese Seite,>> sprichst du von der Komfortroutine?>> ich finde die Entprellung vom Dannegger aufwendig und kompliziert.
Sie ist überhaupt nicht aufwendig.
Über kompliziert kann man streiten. Ja, sie ist nicht leicht zu
durchschauen. Das macht allerdings in diesem Falle nichts. Dafür
funktioniert sie einfach zu gut. Dieses Stück Software ist eines der
wenigen, von dem ich sagen würde: Egal ob du sie verstehst oder nicht -
nutze sie.
> Hatte mir das schon mal angeguckt, aber der Code ist verwirrend> geschrieben, finde ich. Da wird in einer Funktion noch drei weitere> Funktionen aufgerufen.
Das zentrale Element ist das hier
1
i=key_state^~KEY_PIN;// key changed ?
2
ct0=~(ct0&i);// reset or count ct0
3
ct1=ct0^(ct1&i);// reset or count ct1
4
i&=ct0&ct1;// count until roll over ?
5
key_state^=i;// then toggle debounced state
6
key_press|=key_state&i;// 0->1: key press detect
7
8
if((key_state&REPEAT_MASK)==0)// check repeat function
9
rpt=REPEAT_START;// start delay
10
if(--rpt==0){
11
rpt=REPEAT_NEXT;// repeat delay
12
key_rpt|=key_state&REPEAT_MASK;
13
}
das kommt in deine ISR ans Ende mit rein.
Und das wars dann bei dir auch schon.
Die #define davor übernimmst du noch und passt sie an deine
Gegebenheiten an#
1
#define KEY_DDR DDRD
2
#define KEY_PORT PORTD
3
#define KEY_PIN PIND
4
#define KEY_BLUE 2
5
#define KEY_RED 3
6
#define ALL_KEYS (1<<KEY_BLUE | 1<<KEY_RED)
7
8
#define REPEAT_MASK (1<<KEY_RED) // repeat: nur bei Rot
// check if a key has been pressed long enough such that the
18
// key repeat functionality kicks in. After a small setup delay
19
// the key is reported being pressed in subsequent calls
20
// to this function. This simulates the user repeatedly
21
// pressing and releasing the key.
22
//
23
uint8_tget_key_rpt(uint8_tkey_mask)
24
{
25
cli();// read and clear atomic !
26
key_mask&=key_rpt;// read key(s)
27
key_rpt^=key_mask;// clear key(s)
28
sei();
29
returnkey_mask;
30
}
Fertig ist deine Entprellung. (Portpins noch auf Eingang und
gegebenenfalls einen Pullup dafür einschalten wenn du keinen externen
hast)
In der mainloop heißt es dann
daniel san schrieb:> Bevor ich das Problem auf ein anderes verlagere, würde ich trotzdem> gerne wissen was bei mir falsch ist. Vielleicht seh ich dann ein was> einfacher ist ;)
Das müsste man jetzt genauer analysieren.
Hi ich hab das nun soweit angepasst.
Leider wird die untere if-Abfrage aus der main nie bearbeitet , kann den
blauen Taster so oft drücken wie ich will :(
Es sollte beim betätigen des blauen Tasters menue um 1 erhöht werden und
anschließend sollen nacheinanchder die Anzeigen - Werte eingestellt
werden.
1. Taster blau betätigt:
case 1:
i=1
Anzeige:
| - | 0 | 0 |
Taster rot Zahl einstellen 0-9
Solange warten bis mit Taster blau bestätigt
i=2
Anzeige:
| 2 . | - | 0
wieder die gleiche Prozedur
i=3
Anzeige:
| 2. | 1 | - |
...
1
if(get_key_press(1<<KEY_BLUE))// wird nie ausgeführt auch wenn blauer Taster mehrmals gedrückt
2
{
3
menue++;
4
5
PORTD|=(1<<PD0);
6
7
if(menue>3)
8
{
9
menue=0;
10
}
11
}
Hier der gesamte Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
#include<stdint.h>
5
6
#ifndef F_CPU
7
#define F_CPU 1000000 // processor clock frequency
> switch (menue)> {> case 1:
Wie wird die variable menu jemals wieder 0?
Dein Programm ist viel zu kompliziert und du verlierst dich jetzt in der
Komplexität.
Du brauchst eine Variation davon
d.h. es gibt nur eine einzige while Schleife und das ist die
Hauptschleife.
Innerhalb derer wickelst du alles ab. Hör auf in Dingen wie "solange
Taste gedrückt" zu denken. Dein Programm ist in einem Zustand
(ausgedrückt durch die Variable menu) und Tastendrücke
a) verändern diesen Zustand
b) lösen abhängig vom Zustand Aktionen aus.
Wenn du haben willst, dass nach einem Druck auf blau eine der Stellen
einen Strich anzeigt, dann schreib das auch so
Deine ganze for-Schleifen Konstruktion ist viel zu kompliziert.
1
for(i=0;i<3;++i){// gewöhn dir an, dass in C bei 0 begonnen
2
// wird zu zählen!
3
if(i==0)
4
machwasA
5
6
elseif(i==1)
7
machwasB
8
9
elseif(i==2)
10
machwasC
11
}
ist doch eine komplizierte Umschreibung für
1
machwasA
2
machwasB
3
machwasC
dazu brauchst du keine Schleife, wenn du dann erst recht wieder in der
Schleife je nach Schleifenvariable unterschiedliche "mach was" ausführen
lassen willst. Da kannst du einfach die nacheinander abzuarbeitenden
Teile auch untereinander schreiben und in genau der Reihenfolge werden
sie dann abgearbeitet.
Hi,
Karl Heinz Buchegger schrieb:>> while(!get_key_press(1<<KEY_BLUE))>> Du kannst das nicht so machen.> Denn der blaue Taster ist ja nur einmal gedrückt.> Das war ja der Sinn der ganzen Übung.
ok das geht bei der Funktion nicht, stimmt.
Aber das Problem ist ja was anderes er führt ja nichtmal das aus
1
if(get_key_press(1<<KEY_BLUE)){
2
menu++;
3
if(menu==4)
4
menu=0;
5
6
if(menu==1)
7
t1=10;
8
elseif(menu==2)
9
t2=10;
10
elseif(menu==3)
11
t3=10;
12
}
hab deine Main mal 1zu1 wie im obigen Beitrag drüber kopiert und
ausprobiert, bei keinem einzigen Tastendruck des blauen Tasters wird in
die if-anweisung ausgeführt.
daniel san schrieb:> Die Funktion von Dannegger geht ja vom invertierten Zustand also Pullups> aus.>> Bei tasterbetätigung liegt eine 0 am PIN-Port
Ja. Ist richtig.
So werden Tasten auch üblicherweise beschaltet. Dann braucht man nämlich
keinen externen Pullup (und drumm frag ich dich dauernd danach)
Funktionieren deine Tasten anders rum?
daniel san schrieb:> Messe direkt im Pin-Port PD3 bzw. PD2 .>> Bei unbetätigtem Taster, ein High Signal gemessen.>> Sobald ich diesen betätige wird auf Masse gezogen.
OK.
Ist schon mal die halbe Miete.
Lass mich nochmal den Code durchgehen. Ich seh mal zu, dass ich hier bei
mir was nachstellen kann.
> ausprobiert, bei keinem einzigen Tastendruck des blauen Tasters wird in> die if-anweisung ausgeführt.
OK.
dann solltest du erst mal testen, ob deine Taster überhaupt
funktionieren.
(Deine Anzeige ist ja da, d.h. der Interrupt wird aufgerufen)
In der Zwischenzeit kannst du ja mal verifizieren, ob deine Tasten auch
programmtechnisch funktionieren.
1
#include<avr/io.h>
2
3
intmain()
4
{
5
DDRB=0xFF;
6
DDRD=(1<<PD5);
7
8
PORTB=0x00;
9
PORTD=(1<<PD5);
10
11
while(1){
12
13
if(PIND&(1<<PD3))
14
PORTB=0xFF;
15
else
16
PORTB=0x00;
17
}
18
}
auf die Taste latschen und auf deiner 7-Segment müsste 1 Segment
komplett aufleuchten.
Hi ich hab mal die Taster mal ans Oszi gehängt um zu gucken ob die
Prellen, sollte doch im 200us Bereich liegen?
Ich sehe da kein Prellen...
Also nackten Pull-up mit R=10k aufgebaut und auf fallende Flanke
getriggert.
So einen Taster nutze ich, kann mir nicht vorstellen das diese prellfrei
sind.
http://www.csd-electronics.de/de/index.htm
Best.Nr.: 35-TREB01
Teste gleich ma dein Code zwecks Tastert-test
daniel san schrieb:> Hi ich hab mal die Taster mal ans Oszi gehängt um zu gucken ob die> Prellen, sollte doch im 200us Bereich liegen?>> Ich sehe da kein Prellen...
Sie werden Prellen.
Wenn nicht heute dann in 2 Wochen oder 2 Monaten.
ALso Taster geht, die 2.Anzeige die an PD5 hängt geht aus.
Ich vermute dadruch das mein Taster nicht so dolle prellt das ganze von
Dannegger nicht funktioniert. ..Vermutung
daniel san schrieb:> ALso Taster geht, die 2.Anzeige die an PD5 hängt geht aus.>> Ich vermute dadruch das mein Taster nicht so dolle prellt das ganze von> Dannegger nicht funktioniert. ..Vermutung
Nein.
:-)
Der Code geht natürlich auch, wenn die Taster nicht prellen :-)
Karl Heinz Buchegger schrieb:> Der Code geht natürlich auch, wenn die Taster nicht prellen :-)
Das mach doch richtig Lust, demnächst mal wieder einen Beitrag zu
schreiben.
Der Titel könnte lauten:
"Habe fertigen Hexcode mit Entprellroutine von Autor: peter dannegger,
.. kann Software nicht ändern , suche entsprechende Prelltasten,
.... wo bestellen ?"
Das wäre doch schön , oder ?
Gruss Klaus
Hm warum es nicht funktioniert ..hmmmm.
Taster gehen ja, habs getestet, sonst ist nicht viel an meinem Programm
dran.
Worin sich mein Code unterscheid, ISR wird alle 4ms statt 10ms
aufgerufen und folgende Zeile habe ich nicht
TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for
10ms
aber daran wirds wohl nicht liegen.
Nur gut, dass es Assembler gibt, und Peters Entprellroutine in ASM...
Da versteht man, was man tut, da macht das Programmieren Spaß...
Duck & weg...
...
Wenn dieses Testprogramm funktioniert (sollte es eigentlich), dann
arbeite damit weiter und bau es in die Richtung aus, die du haben
willst.
Irgendwo in deinem Programm hast du dich verfranst, ich seh aber nichts
augenfälliges. Das ist mir schon etwas zu verworren und ausserdem muss
ich gleich weg. Ich bin aber morgen vormittag wieder da.
Zwischendurch immer wieder testen! Nicht zuviel ungetesteten Code auf
einmal.
Hi also hab auf Basis deines Codes etwas erweitert.
Da passiert es schon wieder. Wenn ich den unteren Codeabschnitt in die
ISR packe die alle 4ms angesprungen wird, wird wie schon zuvor nicht
mehr auf Tastendruck reagiert.......
1
ISR(TIMER0_COMPA_vect)
2
// wird alle 4ms aufgerufen für 7-seg Anzeige
3
{
4
staticuint8_tct0,ct1,rpt;
5
uint8_ti;
6
7
i=key_state^~KEY_PIN;// key changed ?
8
ct0=~(ct0&i);// reset or count ct0
9
ct1=ct0^(ct1&i);// reset or count ct1
10
i&=ct0&ct1;// count until roll over ?
11
key_state^=i;// then toggle debounced state
12
key_press|=key_state&i;// 0->1: key press detect
13
14
if((key_state&REPEAT_MASK)==0)// check repeat function
15
{
16
rpt=REPEAT_START;// start delay
17
}
18
19
if(--rpt==0)
20
{
21
rpt=REPEAT_NEXT;// repeat delay
22
key_rpt|=key_state&REPEAT_MASK;
23
}
24
25
cnt++;
26
27
if(cnt==1)
28
{
29
PORTB=0;
30
PORTD&=~(1<<PD4);
31
PORTD&=~(1<<PD5);
32
// _delay_us(2);
33
34
PORTB=zahlen[t1];
35
PORTB|=(1<<PB3);
36
PORTD|=(1<<PD6);
37
}
38
elseif(cnt==2)
39
{
40
PORTD&=~(1<<PD6);
41
PORTD&=~(1<<PD4);
42
//_delay_us(2);
43
44
PORTB=zahlen[t2];
45
PORTD|=(1<<PD5);
46
}
47
elseif(cnt==3)
48
{
49
PORTD&=~(1<<PD5);
50
PORTD&=~(1<<PD6);
51
// _delay_us(2);
52
53
PORTB=zahlen[t3];
54
PORTD|=(1<<PD4);
55
}
56
elseif(cnt>3)
57
{
58
cnt=0;
59
}
60
}
Ich habe in der while nur cnt durch t1 ersetzt, sonst nichts geändert.
Ich versteh nicht woran es liegen soll...., muss was mit dem
TIMER0_COMPA_vect ISR zu tun haben da ich dort nur mein Codeabschnitt
zur aktualisierung der Anzeigen reingepackt hab.
Hier der gesamte Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<stdint.h>
4
5
#ifndef F_CPU
6
#define F_CPU 1000000 // processor clock frequency
Hi, also hab grad ein volatile vor der deklaration der globalen
Variablen: uint8_t t1,t2,t3 gesetzt nun funktionierts aber warum??
volatile uint8_t t1,t2,t3;
volatile uint8_t cnt;
Kannst du mir das vielleicht erklären?