für dazu, dass die Funktion 1 zurückliefert, auch wenn der Taster nicht
gedrückt ist.
Der Pegel am Pin des µC ist ungedrückt 5V, gedrückt 1-2mV.
Hat jemand eine Ahnung wo hier das Problem liegt?
DISP_CNTRL_DDR und BTN_DDR sind identisch (PORTD)
Auf den Port wird zudem in folg. Programmteil zugegriffen.
1
if(disp==1)DISP_CNTRL_PORT=(1<<DISP1);
2
elseif(disp==2)DISP_CNTRL_PORT=(1<<DISP2);
3
elseDISP_CNTRL_PORT=(1<<DISP3);
Dieser wird in main() bei jedem durchlauf dür die Anzeige auf 7-Segment
anzeigen verwendet (Steuerung der Anode).
Dann habe ich noch folgende Funktion, welche die 7-Seg.-Anzeigen
ausschaltet (wird nur gelegentlich aufgerufen):
Poste doch bitte der Einfachheit halber ALLES!
Manchmal steckt der Fehler gar nicht dort, wo du ihn vermutest. Zb die
Fragestellung: Woher weißt du eigentlich, dass die Funktion immer 1
liefert?
> Dieser wird in main() bei jedem durchlauf dür die Anzeige> auf 7-Segment anzeigen verwendet (Steuerung der Anode).
Hä?
Du hast die gemeinsame Anoden von irgendwelchen 7-Segment auf denselben
Pins wie die Taster? Oder wie? Oder was?
Wie geht das, ohne dass sich die gegenseitig ins Gehege kommen?
(Schaltplan)
An die Experten: Fehlt da nicht eine Klammer vor dem ~?
Die Auswertungsreihenfolge in C wertet doch den ~-Operator vor dem
|-Operator aus, oder?
Das müsste meiner Meinung nach so geschrieben sein:
Hier mal der gesamte Code inkl. Schaltplan.
Der Tiny soll als Timer fungieren. Die Zeit soll runtegzählt werden und
dabei einen Pin (RL) auf high legen und diesen nach Ablauf der Zeit
wieder ausschalten.
Die Zeitanzeige funktioniert auch, jetzt hängts halt am Polling der
Taster.
>Das müsste meiner Meinung nach so geschrieben sein
Nein, C-Code ist rechtsassoziativ. Das heisst, dass der Code von rechts
an interpretiert wird. Es wird also zuerst das Bitmuster erstellt und
dieses dann invertiert und dann zugewiesen.
Das hat bisher auch so funktioniert und ist auch so im AVR-GCC-Tutorial
zu finden.
Hannes E. schrieb:
> Nein, C-Code ist rechtsassoziativ. Das heisst, dass der Code von rechts> an interpretiert wird. Es wird also zuerst das Bitmuster erstellt und> dieses dann invertiert und dann zugewiesen.
Aber was Operatorprioritäten sind, weißt du schon, oder?
Hannes E. schrieb:
> Das hat bisher auch so funktioniert und ist auch so im AVR-GCC-Tutorial> zu finden.
An welcher Stelle?
Ich habe gerade mal das Tutorial überflogen, und
bei allen Beispielen in denen mehr als 1 Bit
zurückgesetzt wird ist die Klammer um den ganzen Ausdruck.
tatsache. komisch nur, dass es bei anderen beispielen klappt.
habe den code jetzt ensprechend angepasst. zudem noch folg.Änderung in
disp_send_data(), damit nur die Bits für die 7-Seg.-Anz. geändert
werden.
1
if(disp==1){
2
DISP_CNTRL_PORT|=(1<<DISP1);
3
DISP_CNTRL_PORT&=~((1<<DISP2)|(1<<DISP3));
4
}
5
elseif(disp==2){
6
DISP_CNTRL_PORT|=(1<<DISP2);
7
DISP_CNTRL_PORT&=~((1<<DISP1)|(1<<DISP3));
8
}
9
else{
10
DISP_CNTRL_PORT|=(1<<DISP3);
11
DISP_CNTRL_PORT&=~((1<<DISP1)|(1<<DISP2));
12
}
Das Problem ist damit aber noch nicht verschwunden.
Dein Code ist ziemlich unübersichtlich
Das Ansteuern der 7-Segment ist nicht sehr glücklich gemacht. So etwas
macht man in einer Timer ISR, die bei jedem Aufruf die nächste Stelle
aktiviert.
Ausserdem hast du ziemlich viele ! in deinen Code eingestreut, die jetzt
erst einmal alle untersucht werden müssten.
Alles in allem denke ich, du hast den Code zu verzahnt aufgebaut mit
viel zu vielen Status und sonstigen Flags und dabei hast du dich
irgendwo verzettelt.
AUch ist mir gerade aufgefallen, dass deine ganzenn ISR-main globalen
Variablen nicht volatile sind.
Zb hier
1
ISR(TIMER0_OVF_vect){
2
3
// Zeit-Timer
4
staticuint8_tstep=0;
5
staticuint8_tcnt=0;
6
7
if(step>=122){
8
9
if(cnt)cnt=0;
10
elsecnt=1;
11
12
step=0;
13
14
if(time_left&&status==1)time_left--;
15
16
}
17
else{
18
19
step++;
20
21
}
22
23
if(!time_left&&!cnt){
24
25
show=0;
26
disp_off();
27
28
}
29
elseshow=1;
30
31
}
Was ist der Sinn von cnt? Ich glaube herausgelesen zu haben, dass du
damit die ISR Frequenz halbieren möchtest, also nur bei jedem 2.ten
Aufruf etwas tun willst. Richtig?
Warum nicht so
1
ISR(TIMER0_OVF_vect)
2
{
3
// Zeit-Timer
4
staticuint8_tstep=0;
5
staticuint8_tcnt=0;
6
7
cnt=1-cnt;
8
9
if(cnt==0)// nur bei jedem 2.ten Aufruf wird überhaupt etwas getan
10
return;
11
12
step++;
13
if(step>=122){
14
step=0;
15
16
if(time_left!=0&&status==1)
17
time_left--;
18
19
show=1;
20
if(time_left==0){
21
show=0;
22
disp_off();
23
}
24
}
25
}
Deine ganze Verwendung von 'status' und 'show' und was weiß ich was es
da noch so alles gibt, ist mir auch nicht ganz koscher. Warum da in der
ISR der status überhaupt abgefragt wird ... ich habs auf die Schnelle
nicht rausgefunden.
Das Hauptproblem dürfte sein, dass deine ISR-Main globalen Variablen
alle nicht volatile sind.
Damit ist
if ( btn_check(&BTN_PORT, BTN_UP) ) time_left = 10;
wirklungslos. Die Änderung wird wahrscheinlich in der ISR nie ankommen.
Die Zeit abgelaufen ist und status auf 1 ist ....
(Bitte, bitte, bitte. Benutze für Zählvariablen kein logisches !. Sei
explizit:
1
if(time_left==0&&status==1)status=0;
dann braucht man nicht um die Ecke denken
)
.... dann wird status soweit ich das gesehen habe, nie wieder auf 1
gesetzt. Noch nicht mal dann, wenn du den Button drückst
Offenbar wird 'status' als eine Art 'Die Uhr läuft' Variable benutzt.
Die brauchst du aber im Grunde nicht.
Entweder time_left ist ungleich 0, dann läuft die Uhr. Oder aber
time_left ist gleich 0, dann läuft die Uhr nicht. Und schon hast du
wieder ein Flag wegrationalisiert, das nur Gefahr läuft, nicht mit dem
time_left konsistent zu sein.
Edit: Selbiges für das show-Flag
Mal etwas zum studieren.
Bitte beachten:
Da ich die reale Hardware nicht hier habe, muss ich blind programmieren.
Ich hab zwar versucht im Simulator das meiste zu fixen, aber 100%
sicher, ob das auf der Hardware läuft bin ich natürlich nicht.
Auch: Für deine Tastenabfragen musst du dir noch was besseres suchen.
Such in der Artikelsammlung nach "Entprellung". Dort findest du
Komfortroutinen.
Ansonsten:
Sieh dir an und versuch zu verstehen, wie ich die 7-Segmentanzeige
multiplexe. Es gibt eine Funktion dafür, die nur dafür zuständig ist,
reihum immer 1 Anzeige einzuschalten und mit dem richtigen Muster zu
beschicken. Dynamik bekommt das ganze dadurch, dass diese Funktion aus
dem Timer Interrupt immer wieder aufgerufen wird.
Dadurch brauchst du dich im restlichen Programm nicht mehr um die
7-Segment kümmern. Alles was du in die Variablen DigitCode[0..3]
hineinschreibst, landet magisch auf der Anzeige.
1
// TIMER ATtiny 2313
2
// Rev. 0.1
3
// by Hannes Eilers
4
5
6
#define F_CPU 8000000UL // CPU-Geschwindigkeit
7
8
#include<stdint.h>
9
#include<stdio.h>
10
#include<stdlib.h>
11
#include<avr/io.h>
12
#include<avr/interrupt.h>
13
#include<avr/eeprom.h>
14
#include<util/delay.h>
15
16
#ifndef TRUE
17
#define TRUE 1
18
#define FALSE 0
19
#endif
20
21
//
22
// LED
23
//
24
#define LED_PORT PORTA
25
#define LED_DDR DDRA
26
#define LED PA0
27
28
//
29
// Relais
30
//
31
#define RL_PORT PORTA
32
#define RL_DDR DDRA
33
#define RL PA1
34
35
//
36
// Buttons
37
//
38
#define BTN_PORT PIND
39
#define BTN_DDR DDRD
40
41
#define BTN_UP PD0
42
#define BTN_DOWN PD1
43
#define BTN_START PD2
44
45
//
46
// 7-Segment
47
//
48
#define DISP_CNTRL_PORT PORTD
49
#define DISP_CNTRL_DDR DDRD
50
#define DISP1 PD6
51
#define DISP2 PD5
52
#define DISP3 PD4
53
#define DISP_PORT PORTB
54
#define DISP_DDR DDRB
55
56
uint8_tSegCodes[]={
57
0b00010001,// 0
58
0b01111101,// 1
59
0b00100011,// 2
60
0b00101001,// 3
61
0b01001101,// 4
62
0b10001001,// 5
63
0b10001001,// 6
64
0b00111101,// 7
65
0b00000001,// 8
66
0b00001001,// 9
67
};
68
69
volatileuint8_tDigitCode[3]=// Das Bitmuster für die 7-Seg Datenleitungen
70
{0xFF,0xFF,0xFF};
71
volatileuint8_tDigitControlCode[3]=// welcher Pin muss auf Low für welche Anzeige
72
{1<<DISP1,1<<DISP2,1<<DISP3};
73
uint8_tactualDigit=0;// welche Anzeige ist zur Zeit aktiv
Dein Code funktioniert super!
Danke schön.
Ledeglich die Anzeige flackert ein wenig und wenn die Zeit abgelaufen
ist, blinkt die Anzeige nicht mehr, aber das sollte ich hinbekommen :-)
Vielen Dank für die Mühe!
Hannes E. schrieb:
> Dein Code funktioniert super!> Danke schön.>> Ledeglich die Anzeige flackert ein wenig
Das kann schon sein.
Die ISR wird 122 mal in der Sekunde aufgerufen.
Es sind 4 7-Segment Anzeigen.
D.h. jede 7-Segment geht in der Sekunde 122/4, also ungefähr 30 mal
ein/aus.
30Hz ist ein bischen wenig für eine 7-Segment. Da sieht man das noch
flackern
ISR Frequenz hochziehen!