Halli Hallo zusammen!
Ich habe da ein kleines Problem. Und zwar suche ich nach der
intelligentesten Lösung für folgendes Problem:
Ich will eine Steuerung mit Hilfe eines AtMega8 erstellen, die folgende
Kriterien erfüllt: 4 Taster (PINC0-3) sollen den Ablauf der Steuerung
beeinflussen (es handelt sich um eine Lichtsteuerung). Es dürfen niemals
2 Taster gleichzeitig als aktiv erkannt werden.
Ich habe das Problem so versucht zu lösen:
Alle Pins haben einen PULL-UP Widerstand. Zusätzlich zu den 4 Eingängen
habe ich den INT0 Interrupt aktiviert. Betätige ich jetzt einen Taster,
so wird auch der INT0 auf Masse gezogen (Eingänge sind von INT0 mit
Dioden getrennt). Bei fallender Flanke ließt das Programm die Eingänge
aus. Damit der nächste Interrupt ausgelöst werden kann, müssen zuerst
alle Taster wieder inaktiv sein, damit eine neue Flanke da möglich ist.
Da es praktisch unmöglich ist, 2 Taster gleichzeitig zu drücken, bevor
eine Flanke ausgelöst wird, kann immer nur ein Taster gleichzeitig
eingelesen werden.
So weit meine Überlegungen.
In der Praxis funktioniert das Programm leider nicht. Das Programm
funktioniert solange, bis ich den Interrupt auslöse, dann passiert nur
noch unsinn. Hat vielleicht jemand eine bessere Idee mein Taster Problem
umzusetzen?
Danke im voraus!
timo k. schrieb:> Ich will eine Steuerung mit Hilfe eines AtMega8 erstellen, die folgende> Kriterien erfüllt: 4 Taster (PINC0-3) sollen den Ablauf der Steuerung> beeinflussen (es handelt sich um eine Lichtsteuerung). Es dürfen niemals> 2 Taster gleichzeitig als aktiv erkannt werden.
Na ja. Das ist ja programmtechnisch nicht besonders anspruchsvoll
> Alle Pins haben einen PULL-UP Widerstand. Zusätzlich zu den 4 Eingängen> habe ich den INT0 Interrupt aktiviert. Betätige ich jetzt einen Taster,> so wird auch der INT0 auf Masse gezogen (Eingänge sind von INT0 mit> Dioden getrennt).
Wozu der Interrupt?
kein Mensch kann eine Taste so schnell drücken bzw. Loslassen, dass ein
µC, wenn er alle 50 Millisekunden mal kurz auf die Tasten linst, jemals
einen Tastendruck übersehen würde.
Alle x Zeiteinheiten mal auf die Tasten linsen, alle 4 Eingänge abfragen
und wenn mehr als 1 Taste gedrückt ist, dann wird der komplette
Datensatz ignoriert. Nur wenn 1 Taste gedrückt ist, dann gilt die auch
und der Rest des Pgm reagiert darauf.
Wäre zb eine Möglichkeit.
Problem: Das ist eine Lichtsteuerung bei der ein Durchlauf mehrere
Sekunden dauert, da ich delay.h verwende. Dann müsste man Glück haben,
dass das Programm beim drücken der Taster genau an der Stelle im Code
ist, wo die Eingänge abgefragt werden.
Zu Electronics'n Stuff:
Kann leider kein Bild posten, da Aufbau nicht mehr da.
Habe ebenfalls kein Programm, um ebend schnell lesbare Schaltpläne zu
zeichnen... vllt hast ja ein Tipp ;)
Code kommt sofort...
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<stdint.h>
4
#include<util/delay.h>
5
6
volatileuint8_tprogramm;
7
volatileuint8_tgeschwindigkeit;
8
volatileuint8_tein;
9
10
//Funktion long_delay(); für Zeitverzögerung
11
voidlong_delay(uint16_tms)
12
{
13
for(;ms>0;ms--)_delay_ms(1);
14
}
15
16
17
//Interrupt INT0
18
ISR(INT0_vect)
19
{
20
cli();
21
/* Interrupt Code */
22
// EIN/AUS variable
23
24
if(PINC&(1<<PINC0))
25
{
26
if(ein==0)
27
{
28
ein=1;
29
}
30
31
if(ein==0)
32
{
33
ein=1;
34
}
35
}
36
37
// Programm variable
38
39
if(PINC&(1<<PINC1))
40
{
41
if(programm==4)
42
{
43
programm=1;
44
}
45
46
else
47
{
48
programm=programm+1;
49
}
50
}
51
52
// geschwindigkeit variable
53
54
if(PINC&(1<<PINC2))
55
{
56
if(geschwindigkeit==0)
57
{
58
geschwindigkeit=0;
59
}
60
61
else
62
{
63
geschwindigkeit=geschwindigkeit-1;
64
}
65
}
66
67
if(PINC&(1<<PINC3))
68
{
69
if(geschwindigkeit==10)
70
{
71
geschwindigkeit=10;
72
}
73
74
else
75
{
76
geschwindigkeit=geschwindigkeit+1;
77
}
78
}
79
sei();
80
}
81
82
intmain()
83
{
84
/* Setzt das Richtungsregister des Ports B auf 0xff
85
(alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */
Hi
>Problem: Das ist eine Lichtsteuerung bei der ein Durchlauf mehrere>Sekunden dauert, da ich delay.h verwende.
Dann wird es Zeit sich mit den Timern zu beschäftigen.
MfG Spess
timo k. schrieb:> Problem: Das ist eine Lichtsteuerung bei der ein Durchlauf mehrere> Sekunden dauert, da ich delay.h verwende.
Tja.
Damit hast du schon dein Hauptproblem gefunden
Ich verstehe, dass man mal irgendwo anfangen muss und man nicht alles
auf einmal lernen kann. Für Zeitsteuerungen in realen Programmen ist
_delay_ms aber denkbar ungeeignet. Du bist an einem Punkt angelangt, an
dem du _delay_ms wieder 'ent-lernen' musst. Zeitsteuerungen sind
praktisch immer eine Timer-Sache.
FAQ: Timer
Aber um bei deinem Programm zu bleiben
1
ISR(INT0_vect)
2
{
3
cli();
4
/* Interrupt Code */
5
// EIN/AUS variable
6
7
if(PINC&(1<<PINC0))
8
9
...
frag halt nicht jeden Pin einzeln ab
1
ISR(INT0_vect)
2
{
3
uint8_tTasten=PINC&0x0F;// nur PC0, PC1, PC2, PC3 sind interssant
4
5
if(Tasten==(1<<PINC0)||
6
Tasten==(1<<PINC1)||
7
Tasten==(1<<PINC2)||
8
Tasten==(1<<PINC3))// es darf nur eine EINZIGE Taste gedrueckt sein ....
9
{
10
if(Tasten&(1<<PINC0))
11
...
und lass die cli() bzw. sei() innerhalb der ISR weg.
Du brauchst sie nicht und der sei() ist sogar kontraproduktiv.
wenn 'ein' nur die beiden Möglichkeiten 1 und 0 hat, dann erfüllt
ein = 1 - ein;
genau denselben Zweck, wie deine ganze große und langatmige if-then
Konstruktion. Denn 1 - 1 ergibt 0. Und 1 - 0 ergibt wieder die 1. Mit
jeder Ausführung von
ein = 1 - ein;
wechselt ein daher von 1 auf 0 bzw. beim nächsten mal von 0 auf 1.
1
if(geschwindigkeit==10)
2
{
3
geschwindigkeit=10;
4
}
es ist zwar nicht falsch in dem Sinne, aber ein bischen sinnlos. Denn
wenn eine Variable sowieso schon einen Wert hat, brauchst du ihn nicht
zuweisen. Was du wirklich an dieser Stelle wolltest:
1
if(Tasten&(1<<PINC3))
2
{
3
if(geschwindigkeit<10)
4
geschwindigkeit=geschwindigkeit+1;
5
}
Achte immer auch ein wenig darauf, dass sich dein Code nicht
unnötigerweise zu sehr in die Länge zieht. Du verlierst sonst rein
aufgrund der Codelänge die Übersicht.
1
ISR(INT0_vect)
2
{
3
uint8_tTasten=PINC&0x0F;// nur PC0, PC1, PC2, PC3 sind interssant
4
5
if(Tasten==(1<<PINC0)||
6
Tasten==(1<<PINC1)||
7
Tasten==(1<<PINC2)||
8
Tasten==(1<<PINC3))// es darf nur eine EINZIGE Taste gedrueckt sein ....
9
{
10
if(Tasten&(1<<PINC0))
11
ein=1-ein;
12
13
elseif(Tasten&(1<<PINC1))
14
{
15
programm++;
16
if(programm==4)
17
programm=1;
18
}
19
20
elseif(Tasten&(1<<PINC2))
21
{
22
if(geschwindigkeit>0)
23
geschwindigkeit--;
24
}
25
26
elseif(Tasten&(1<<PINC3))
27
{
28
if(geschwindigkeit<10)
29
geschwindigkeit++;
30
}
31
}
32
}
Dann kannst du dir auch so Kommentare wie
1
...
2
// Programm variable
3
...
sparen, denn dass es an dieser Stelle genau um diese Varible geht, dass
kann auch ein Blinder in den 3 Zeilen Code problemlos erkennen.
PS: Sagtest du nicht, dass deine Tasten einen PULL-UP Widerstand hätten?
Wieso fragst du dann ab, ob der jeweilige Portpin auf 1 ist? Die Logik
ist ja in dem Fall genau anders rum. Alle Portpins sind auf 1 bis auf
jenen Pin an dem die Taste gedrückt ist. Der weist dann eine 0 auf.
Ich glaube man merkt, dass das mein erster C geschriebener Code ist :)
Danke daher für die schnelle Hilfe!
So ich habe es jetzt soweit mit Timer aktualisiert und die anderen
Sachen eingefügt. Die Geschwindigkeit ist in diesem Programm noch nicht
mit einbezogen.
Die einzelnen Programme funktionieren soweit, aber ich kann mit den
Tastern immer noch nichts erreichen...
Verzeiht mir die umständliche Art mit dem Timerzyklus. Ich wollte das
Programm heute noch zum laufen bringen und mir ist so schnell kein
anderer Weg eingefallen...
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<stdint.h>
4
#include<util/delay.h>
5
6
volatileuint8_tprogramm;
7
volatileuint8_tgeschwindigkeit;
8
volatileuint8_tein;
9
volatileuint16_ttimerzyklus;
10
11
//Funktion long_delay(); für Zeitverzögerung
12
voidlong_delay(uint16_tms)
13
{
14
for(;ms>0;ms--)_delay_ms(1);//ms in Klammer vergessen?
15
}
16
17
18
voidtimer()
19
{
20
timerzyklus=timerzyklus+1;
21
TCNT0=0x01;
22
}
23
24
//Interrupt Timer
25
ISR(TIMER0_OVF_vect)
26
{
27
/* Interrupt Code */
28
if(ein==0)
29
{
30
timer();
31
}
32
33
else
34
{
35
if(programm==1)//Programm "EIN"
36
{
37
PORTB=0xff;
38
timer();
39
}
40
41
if(programm==2)//Programm "Wechsel"
42
{
43
if(timerzyklus>=120)
44
{
45
timerzyklus=0;
46
}
47
if(timerzyklus<=29)
48
{
49
PORTB=0x01;
50
timer();
51
}
52
if(timerzyklus>=30&&timerzyklus<=59)
53
{
54
PORTB=0x02;
55
timer();
56
}
57
if(timerzyklus>=60&&timerzyklus<=89)
58
{
59
PORTB=0x04;
60
timer();
61
}
62
if(timerzyklus>=90&&timerzyklus<=119)
63
{
64
PORTB=0x08;
65
timer();
66
}
67
68
}
69
70
if(programm==3)//Programm "Blinken"
71
{
72
if(timerzyklus>=60)
73
{
74
timerzyklus=0;
75
}
76
if(timerzyklus<=29)
77
{
78
PORTB=0x00;
79
timer();
80
}
81
if(timerzyklus>=30&&timerzyklus<=60)
82
{
83
PORTB=0xFF;
84
timer();
85
}
86
}
87
88
if(programm==4)//Programm "Blinken und Wechsel"
89
{
90
if(timerzyklus>=240)
91
{
92
timerzyklus=0;
93
}
94
if(timerzyklus<=29)
95
{
96
PORTB=0x01;
97
timer();
98
}
99
if(timerzyklus>=30&&timerzyklus<=59)
100
{
101
PORTB=0x00;
102
timer();
103
}
104
if(timerzyklus>=60&&timerzyklus<=89)
105
{
106
PORTB=0x02;
107
timer();
108
}
109
if(timerzyklus>=90&&timerzyklus<=119)
110
{
111
PORTB=0x00;
112
timer();
113
}
114
115
if(timerzyklus>=120&&timerzyklus<=149)
116
{
117
PORTB=0x04;
118
timer();
119
}
120
if(timerzyklus>=150&&timerzyklus<=179)
121
{
122
PORTB=0x00;
123
timer();
124
}
125
if(timerzyklus>=180&&timerzyklus<=209)
126
{
127
PORTB=0x08;
128
timer();
129
}
130
if(timerzyklus>=210&&timerzyklus<=239)
131
{
132
PORTB=0x00;
133
timer();
134
}
135
}
136
}
137
}
138
139
voidcheck_input()
140
{
141
142
uint8_tTasten=PINC&0x0F;// nur PC0, PC1, PC2, PC3 sind interssant
143
144
if(Tasten==(0<<PINC0)||
145
Tasten==(0<<PINC1)||
146
Tasten==(0<<PINC2)||
147
Tasten==(0<<PINC3))// es darf nur eine EINZIGE Taste gedrueckt sein ....
148
{
149
if(Tasten&(0<<PINC0))
150
ein=1-ein;
151
152
elseif(Tasten&(0<<PINC1))
153
{
154
programm++;
155
if(programm==4)
156
programm=1;
157
}
158
159
elseif(Tasten&(0<<PINC2))
160
{
161
if(geschwindigkeit>0)
162
geschwindigkeit--;
163
}
164
165
elseif(Tasten&(0<<PINC3))
166
{
167
if(geschwindigkeit<10)
168
geschwindigkeit++;
169
}
170
}
171
172
long_delay(100);// Wartzeit zwischen einzelnen Signalen bei dauerhaftem Drücken der Taster
173
}
174
175
intmain()
176
{
177
/* Setzt das Richtungsregister des Ports B auf 0xff
178
(alle Pins als Ausgang, vgl. Abschnitt Zugriff auf Ports): */
timo k. schrieb:> Ich glaube man merkt, dass das mein erster C geschriebener Code ist :)
Du willst zu viel auf einmal. Das macht keinen Sinn, denn wenn man die
Dinge nicht von Grund auf lernt, dann versteht man nichts, wenn es
wirklich kompliziert wird.
> else if( Tasten & (0<<PINC1) )
Nein.
Bitmanipulation
Tu dir selbst einen Gefallen und stell dein 'Projekt' erst mal zurück.
Experimentiere mit
Bit setzen
Bit löschen
Bit abfragen (sowohl auf 1 als auch auf 0)
Das sind die Grundbausteine eines µC-Programms. Sozusagen das kleine
Einmal Eins. Solange diese 4 Dinge nicht 100% sicher sitzen und du auch
verstehst was du da tust, hat es keinen Sinn da weiter zu machen. 'Malen
nach Zahlen' ist gut. Aber es hat nichts damit zu tun, selbst mal in der
Lage zu sein, Bilder zu malen.
Wenn Du schon Spagetti Code in einem Interrupt einbaust, dann spendiere
den Sequenzen doch einen Notausgang.
Zum Bleistift:
timerzyklus ist 179
if(timerzyklus >=150 && timerzyklus <=179) ==> moag i
innerhalb dieses Zyklusses gibt es durch den Aufruf von "timer();"
eine Erhöhung von timerzyklus um eins auf 180.
Die darauf folgende Abfrage:
if(timerzyklus >=180 && timerzyklus <=209) ==> ist toll
somit wird dieser Abschnitt ebenfalls durchlaufen.
Also Abteilung: Nix gut
Spendiere deinen positiven Abfragen durch ein return einen
Lieferantenausgang
da im positiven Falle alle anderen if's nur Zeit verschwenden.
Alternativ beschäftige Dich mal mit der lieben Else.
@kbuchegg
ich kann mich soweit darin eindenken, dass ich alles schon mal in
Assembler hinbekommen habe. Da ich allerdings auch beim Telefon nicht
mehr am Rad drehen muss um zu wählen, will ich mich anpassen und mit C
programmieren. C Kenntnisse habe ich allerdings nicht so viele,
praktisch gesehen grenzt es gegen 0. Das Programm ist vom Aufbau jetzt
nicht kompliziert. Der Programm Ablauf funktioniert sogar sehr gut. Mein
einziges Problem ist, dass die Taster nicht erkannt werden...
@amateur
danke, gute Idee. Hätt ich selbst drauf kommen sollen, so viel weiß ich
doch noch noch C. Verschönert allerdings nur das Programm, macht es
nicht funktioneller (Die 3ms die er da zu früh schaltet fallen kaum auf
:) ).
Ich verstehe nur nicht, wieso die Eingänge nicht richtig verarbeitet
werden...
timo k. schrieb:> Der Programm Ablauf funktioniert sogar sehr gut. Mein> einziges Problem ist, dass die Taster nicht erkannt werden...
Dein Problem ist, dass dir nicht klar ist, dass
0 << PINC0
eine sinnlose Operation ist. Denn da kommt wieder 0 raus. Eine 0 kannst
du nach links schieben sooft du willst, das Ergebnis ist wieder 0.
Und das ist in Assembler auch nicht anders als in C. Denn überall im
Universum gilt: 0 mal irgendeine Zahl ergibt 0.
Und wenn du 'egal was' mit 0 UND-verknüpftst, dann kommt da ebenfalls 0
raus. Und erst jetzt kommt wieder C ins Spiel, in dem ein 0-Ergebnis als
ein logisches FALSE gewertet wird.
Das hier
if ( Tasten & (0<<PINC0) )
kann im gesamten bekannten Universum zu keinem einzigen Zeitpunkt jemals
TRUE ergeben!
Und jetzt schluck deinen Stolz runter und lies den Link über
Bitmanipulation bzw. die ersten Basis-Abschnitte über I/O im
AVR-GCC-Tutorial und wie man low-aktive Tasten korrekt auswertet.
Karl Heinz beruhig dich! Ich verstehe dich ja. Ich hatte das verändert,
nachdem mir geschrieben wurde, das ich bei Pull-up Widerständen eine
logische 0 erwarte, was nätürlich stimmt und ich aus Hektik übersehen
habe. Programmiere eben auch nur einfache Steuerungen aus Hobby.
Habe mir die Bitmanipulation durchgelesen (was ich auch damals schon
gemacht hatte). Mein Fehler war halt, dass ich anstatt
1
elseif(!(Tasten&(0<<PINC1)))
2
elseif(Tasten&(0<<PINC1))
hatte.
Danke an alle die mir halfen! Programm läuft