Forum: Mikrocontroller und Digitale Elektronik Finde Fehler nicht !


von Eduard ". (edtheb)


Lesenswert?

Moin,

bin wieder an meinem MK2-Board am Gange.
Ich habe im Vorfeld ein funktionierendes Programm geschrieben, dass 
einen Taster als Schalter verwendet, um eine LED ein- bzw. 
auszuschalten. Es soll auch nichts anderes passieren, auch wenn ich die 
Taste gedrückt halte. Dazu habe ich die negative Flanke verwendet. Ich 
erwähne es deshalb, weil ich Teile davon in meinem neuen Programm 
verwende. Nun bin ich mutiger geworden:

Neues Projektchen:
Verwendung von 8 Tastern um 8 LEDs ein-auszuschalten (wie oben). Aber 
die 8 Taster sollen nicht 8 Inputbits belegen, sondern nur 4. Ich wollte 
es binär lösen.

Taster 1 = Bit 0
Taster 2 = Bit 1
Taster 3 = Bit 0 + Bit 1
etc.


Hier der Code:
1
/*-----------------------------------------------------------------------------
2
3
ON - OFF switch with pushbutton
4
5
8 pushbuttons for switching 8 different LEDs by using only 4 input bits
6
7
Negative slope is used for changing LED status
8
9
-----------------------------------------------------------------------------*/
10
11
12
13
// pushbutton on PORTB 0-3
14
// LED on PORTC 0-5 und PORTA 2-3
15
16
17
#include <avr/io.h>
18
#include <util/delay.h>
19
20
int t=0;
21
int sig0=1;
22
int sig1=1;
23
int sig2=1;
24
int sig3=1;
25
int sig_alt0=1;
26
int sig_alt1=1;
27
int sig_alt2=1;
28
int sig_alt3=1;
29
30
int main (void)
31
{
32
33
DDRB &= ~( (1<<DDB0) | (1<<DDB1) | (1<<DDB2) | (1<<DDB3) ); // set PORT B 0,1,2 and 3 for input other keep unchanged
34
DDRC = 0xFF; // set PORTC as OUTPUT for LED
35
DDRA |= (1<<DDA2) | (1<<DDA3); // // set PORTCA 2-3 as OUTPUT for LED
36
PORTB |= (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3); // set PullUp for INPUT
37
38
39
while(1)
40
{
41
42
sig0=(PINB & (1<<PB0)); // Read signal of PIN0
43
sig1=(PINB & (1<<PB1)); // Read signal of PIN1
44
// sig2=(PINB & (1<<PB2)); // Read signal of PIN2
45
// sig3=(PINB & (1<<PB3)); // Read signal of PIN3
46
47
48
if ((sig0==0 && sig_alt0!=0) && sig1==1 && sig2==1 && sig3==1) t=1; // negative slope of signal? --> pushbutton No.1 pressed
49
if ((sig1==0 && sig_alt1!=0) && sig0==1 && sig2==1 && sig3==1) t=2;
50
// if ((sig0==0 && sig_alt0!=0) && (sig1==0 && sig_alt1!=0) && sig2==1 && sig3==1) t=3; // negative slope on PINB0 AND PINB1 ?
51
// if ((sig2==0 && sig_alt2!=0) && sig0==1 && sig1==1 && sig3==1) t=4;
52
// if ((sig0==0 && sig_alt0!=0) && (sig2==0 && sig_alt2!=0) && sig1==1 && sig3==1) t=5;
53
// if ((sig1==0 && sig_alt1!=0) && (sig2==0 && sig_alt2!=0) && sig0==1 && sig3==1) t=6;
54
// if ((sig0==0 && sig_alt0!=0) && (sig1==0 && sig_alt1!=0) && (sig2==0 && sig_alt2!=0) && sig3==1) t=7;
55
// if ((sig0==0 && sig_alt0!=0) && (sig1==0 && sig_alt1!=0) && (sig2==0 && sig_alt2!=0) && (sig3==0 && sig_alt3!=0)) t=8;
56
57
58
59
switch (t)
60
{
61
case 1:
62
_delay_ms(20);
63
if ((PINC & (1<<PC0))==0 ) // status of green LED
64
{ // if OFF
65
PORTC |= (1<<PC0); // green LED ON
66
_delay_ms(100);
67
}
68
69
else
70
{ // if ON
71
PORTC &= ~(1<<PC0); // green LED OFF
72
_delay_ms(100);
73
}
74
break;
75
76
case 2:
77
_delay_ms(20);
78
if ((PINC & (1<<PC1))==0 ) // status of yellow LED
79
{ // if OFF
80
PORTC |= (1<<PC1); // yellow LED ON
81
_delay_ms(100);
82
}
83
84
else
85
{ // if ON
86
PORTC &= ~(1<<PC1); // yellow LED OFF
87
_delay_ms(100);
88
}
89
break;
90
91
92
/* case 3:
93
_delay_ms(20);
94
if ((PINC & (1<<PC2))==0 ) // status of red LED
95
{ // if OFF
96
PORTC |= (1<<PC2); // red LED ON
97
_delay_ms(100);
98
}
99
100
else
101
{ // if ON
102
PORTC &= ~(1<<PC2); // red LED OFF
103
_delay_ms(100);
104
}
105
break;
106
*/
107
} // end of switch
108
109
t=0;
110
sig_alt0=sig0;
111
sig_alt1=sig1;
112
sig_alt2=sig2;
113
sig_alt3=sig3;
114
115
} // end of while(1)
116
} // end of main


Ich bin mir sicher, dass es eleganter und kürzer geht. Aber mir geht es 
darum, meine Ausführung zum Funktionieren zu kriegen und zu verstehen, 
warum etwas nicht funktioniert. Wenn alles klappt, dann wollte ich mich 
ransetzen und Kürzungen etc. einbringen.

Ich bin Schritt für Schritt vorgeangen. Wenn ich die Zeile 43 durch // 
rausnehme, dann funktioniert das Ganze. Eben nur mit einem Taster1 
(PINB0) und einer LED (PINC0).

Wenn ich aber den Code, so wie er oben ist abrabeiten lasse, dann 
funktioniert die Sache mit Taster2 (PINB1) und LED (PINC1) aber der 
Taster1 funktioniert nicht mehr.

Wenn ich die Zeile 50 aktiv mache, dann funktioniert kein Taster mehr.

Laut Simulation springt der Controller immer zwischen den Zeilen 42 und 
59. Es scheint ihn nicht zu interessieren, dass sich sig0 bzw. sig1 
geändert haben.

Ich hoffe, es kann mir jemand helfen. Ich sitze bereits seit gestern 
dran und finde einfach den Fehler nicht.

Danke im Voraus.

_______________
Tue deinem Körper etwas Gutes, damit die Seele Lust hat darin zu wohnen 
!

von Sam .. (sam1994)


Lesenswert?

Wie sieht denn deine Schaltung aus? Binär kann immer nur einer gedrückt 
sein. Außerdem müsste man viele Dioden brauchen. Und die ersten 4bits 
eines Ports einlesen geht so: uint8_t key = PORTB & 0x0F. Die letzten 4 
mit 0xF0.

von Stefan E. (sternst)


Lesenswert?

Dein Code funktioniert nicht, weil dies
1
sig1==1
nach einfügen dieser Zeile
1
sig1=(PINB & (1<<PB1));
immer false ist.

sig1 ist entweder 0 (Taste gedrückt) oder 2 (Taste nicht gedrückt), aber 
nie 1.

von oldmax (Gast)


Lesenswert?

Hi
Wenn du dies nur machst, um dir Eingänge zu sparen, ist es vielleicht 
eine bessere Lösung, die Taster über eine Matrix einzulesen. Allerdings 
brauchst du dafür auch einen Ausgang und einen Inverter oder 2  Ausgänge 
zusätzlich. Macht aber Sinn, wenn es mehrere Eingänge braucht, als IO' 
vorhanden sind.
Dazu legst du deine Taster Parallel auf die Eingänge, z. B. in 4er 
Gruppen. Jede Gruppe steuerst du mit einem Ausgang an. Im Programm weist 
du ja, welche Gruppe grad selektiert ist und du brauchst die Eingänge 
nun nur noch entsprechend zu behandeln. Andere Alternative ist 
tatsächlich sowas wie 8 zu 3 Decoder. gibt es in der 74er IC-Serie 
(Oktaldecoder oder so ) Hier kannst du deine Taaster an die 8 Eingänge 
schalten und das IC bereitet einen Code aus drei Bits auf.
Such mal nach Oktaldecoder, vielleicht weiß Google da was.
Gruß oldmax

von Eduard ". (edtheb)


Angehängte Dateien:

Lesenswert?

@ sam1994

Hallo,

das ist richtig. Es soll immer nur einer gedrückt werden. Mit Dioden
meinst du sicherlich Halbleiterdiode (und nicht LED). Das stimmt, aber
es soll letztendlich erstmal die Umsetzung und das Verständnis in
C-Programmierung im Vordergrund stehen. Natürlich hat das ein sinnvollen
Hintergedanken. Und zwar die Verwendung von z.B. Tastern auf
Folientasterturen.

Das Schaltbild habe ich hochgeladen.

Du hast geschrieben: "... Ports einlesen geht so: uint8_t key = PORTB &
0x0F"

Hmm, damit lese ich doch den Port aus, richtig? Ich benötige doch den
Pin, um die Änderung festzustellen, oder?

Wie im ersten "Aufsatz" erwähnt, habe ich ein Programm das funktioniert,
wo ich den PIN (wo der Taster angeschlossen ist) abfrage:

[c]
/*---------------------------------------------------------------------- 
-------

                             ON - OFF switch with pushbutton

 Pushbutton with no change if keep holding pushbutton.
 Can be used for selection button (if holding button longer, the output
status
 won't change.



------------------------------------------------------------------------ 
-----*/

// pushbutton on PORTB 1
// LED on PORTC 0


#include <avr/io.h>
#include <util/delay.h>

int main (void)
{

DDRC &= ~(1<<DDC1);    // set PORTC1 for input other keep unchanged
DDRC |= (1<<DDC0);    // set PORTC0 as OUTPUT for LED
PORTB |= (1<<PORTB1);    // set PullUp for INPUT

char status=0;
uint8_t sig, sig_alt;
sig_alt=1;

while(1)
{
    sig=PINB & (1<<PB1);    // Read signal of PIN1
    if (sig==0 && sig_alt!=0)    // negative slope of signal? -->
pushbutton pressed
    {
        _delay_ms(20);
        if (status==0)
        {
            PORTC |= (1<<PC0);    // LED ON
            status=1;
            _delay_ms(100);
        }

        else
        {
            PORTC &= ~(1<<PC0);    // LED OFF
            status=0;
            _delay_ms(100);
        }
    }
    sig_alt=sig;



}    // end of while(1)
}    // end of main
[c/]

Wenn ich in Zeile 33 statt "sig=PINB & (1<<PB1);" "sig=PORTB &
(1<<PB1);" schreibe funktioniert es nicht mehr.

Vielleicht verstehe ich deinen Hinweis nicht.


@sternst
Danke. Ich werde es mir gleich mal anschauen. Aber eine Frage vorab: 
Wann soll sig1 = 2 werden? Wo siehst du das? Ich zähle doch nichts hoch 
bzw. addiere etwas zueinander. Nach meinem Verständnis haben meine sig 
bzw. sig_alt Variablen nur die Zustände 0 oder 1.


@oldmax
Danke, aber ist mir noch zu weit weg. Ich möchte erstmal meinen Mist 
hier verstehen.

EdTheB

von Eduard ". (edtheb)


Lesenswert?

@sternst

Jetzt weiss ich was du mit der 2 meinst. Ich kriege den Bit-Wert von PB1 
raus? Ich dachte, wenn ich den PIN auslese erhalte ich entweder 0 oder 1 
und nicht die Wertigkeit des PINs.
Das heißt, wenn z.B. der PIN7 auf High ist und ich den PIN abfrage, dann 
erhalte ich die Wertigkeit (hier 128) zurück?

Danke.

Werde erst heute abend oder morgen Zeit haben, diese neue Erknenntnis in 
mein Programm einbauen.

EdTheB

von Stefan E. (sternst)


Lesenswert?

Eduard "A" schrieb:
> wenn ich den PIN auslese erhalte ich entweder 0 oder 1
> und nicht die Wertigkeit des PINs.

So was wie "den PIN auslesen" tust du gar nicht. Du ließt den kompletten 
Port (alle acht Pins, also 8 Bits) und dann maskierst du ein einzelnes 
Bit aus. Und das Ergebnis ist dann halt entweder 0, oder der Wert, der 
sich ergibt, wenn nur diese eine Bit im Byte 1 ist.

von Sam .. (sam1994)


Lesenswert?

ähm Pin natürlich. sry, war vorher nicht so bei der Sache.

Mit PINB & 0x0F bekommst du die ersten 4bits aus. Mehr nicht.

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.