Forum: Mikrocontroller und Digitale Elektronik Ein- und Ausgangspins definieren und bedingen


von Andyloco (Gast)


Lesenswert?

Hi Leute,
bin rel. neu im Bereich der µC-Programmierung und hoffe bei euch ein 
bissl Unterstützung zu finden :)
Muss für meinen Opa die Steuerelektronik für seinen Treppenlift 
reparieren und habe daher leider nicht die Zeit alles (netz, Literatur) 
zu durchstöbern und mir selbst anzueignen. kommt aber alles noch... :)

Habe folgendes Problem:

Möchte am PORTB die Bits 0-3 abfragen und je nachdem wie sie geschaltet 
sind in PORTA die Bits 0-3 schalten.

Arbeite mit dem ATMEGA16 und benutze das AVR ISP mkII als 
Programmierschnittstelle.
Habe unten meinen Code gepostet. Da seht ihr bestimmt direkt den Mist 
den ich verzapft hab ;)

Vielen Dank schonmal im Vorraus.


#include <avr/io.h>
#include <stdint.h>

int main (void) {

   DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (1 << DDA3);
// PortA auf Ausgang
  DDRB = (0 << DDB0) | (0 << DDB1) | (0 << DDB2) | (0 << DDB3);
// PortB auf Eingang

while (1) {

// solange PINB0 und PINB1 == HIGH sollen PINA0, PINA1 und PINA3 HIGH 
sein
while (PINB & (1<<PINB0 & 1<<PINB1)) {
  PORTA |= (1<<PORTA0 & (1<<PORTA1 & 1<<PORTA3);
};

while ( PINB & (1<<PINB0 & 1<<PINB3) ) {
  PORTA |= (0<<PORTA0 & 0<<PORTA3);
};

while ( PINB & (1<<PINB2 & 1<<PINB3) ) {
  PORTA |= (1<<PORTA0 & (1<<PORTA2 & 1<<PORTA3);
};


};

  return 0;
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Andyloco wrote:
> // solange PINB0 und PINB1 == HIGH sollen PINA0, PINA1 und PINA3 HIGH
> sein
> while (PINB & (1<<PINB0 & 1<<PINB1)) {
>   PORTA |= (1<<PORTA0 & (1<<PORTA1 & 1<<PORTA3);
> };

Laut Kommentar ist die Logikabfrage so zu machen

while (PINB & ((1<<PINB0) | (1<<PINB1))) {
  PORTA |= ((1<<PORTA0) | ((1<<PORTA1) | (1<<PORTA3));
};

Die anderen Bedingungen habe ich nicht geprüft, weil keine Kommentare da 
sind und ich nicht weiss, was du machen willst.

von Freakazoid (Gast)


Lesenswert?

Du weißt aber schon, daß ein while (a) {x} x erst verläßt, wenn a unwahr 
ist?
Damit dürften Deine anderen 'whiles' erst abgearbeitet werden, wenn das 
vorherige while unwahr ist. Das wird so nix ;-)

Grüße,
Freakazoid

von Andyloco (Gast)


Lesenswert?

Vielen Dank für eure schnelle Hilfe!!!

@Stefan "stefb" B.
Habe deine Überarbeitung meines Codes ausprobiert, aber egal ob ich die 
Spannung an den beiden Pins anlege oder nicht ändert das nichts an den 
Ausgangspins, die bleiben auf 5V.
Oder habe ich einen kompletten Denkfehler in der Struktur meines 
Programmes???
Das Programm soll nur die Zustände an den 4 Eingangspins prüfen und wenn 
eine der vorgegebenen Kombinationen (durch die unteren 3 while 
Bedingungen gegeben) eintritt die Ausgänge entsprechend schalten.


@Freakazoid
>Du weißt aber schon, daß ein while (a) {x} x erst verläßt, wenn a unwahr
>ist?

aber "a" wird doch durch die Spannung an den pins vorgegeben. Ich hatte 
mir gedacht, solange die Spannung an beiden Pins anliegt, dann soll die 
Bedingung erfüllt sein und sobald einer der beiden Pins LOW ist sollte 
die Bedingung nicht mehr erfüllt sein. Oder kann man das nicht auf diese 
Weise machen?


Vielen Dank

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Oder habe ich einen kompletten Denkfehler in der Struktur meines
> Programmes???

Yes!

Wie oben beschrieben kann ich zum Rest nichts schreiben, weil du nicht 
angibst, was die Ausgangspins machen sollen, wenn die Bedingung nicht 
erfüllt ist.

Ich schlage vor, dass du alle Zustände, die seine Steuerung annehmen 
kann zunächst mit Worten beschreibst.

Beispiel:
1/ Lift wartet unten
2/ Lift fährt hoch
3/ List wartet oben
4/ Lift fährt runter
5/ Lift wartet mitten auf der Treppe
6/ Lift stoppt sofort
...

Ein Schaltplan ist auch nützlich, in dem steht, wo welche Taster 
angeschlossen sind und welche PORTPINS zur Steuerung welcher Funktion 
benutzt werden.

Daraus lässt sich ein Zustandsdiagramm (state machine) machen, bei dem 
exakt festgelegt ist, wie man mit welchen Aktionen von einem Zustand in 
den anderen kommt.

Beispiel:
A/ 6/ wenn nicht mindestens zwei Tasten gedrückt
B/ Von 1/ nach 2/, wenn Taste PINB0 UND PINB1 gedrückt
...

Erst wenn das steht, kann man eigentlich ein sinnvolles und sicheres 
Programm für alle denkbaren Zustände machen.

von Andyloco (Gast)


Lesenswert?

Die Ausgangspins sollen auf LOW sein.
Wenn eine Bedingung erfüllt ist sollen die entsprechenden Pins auf HIGH 
geschaltet werden bis die Bedingung nicht mehr erfüllt ist.

PB0..3 sollen die Eingänge sein
PA0..3 sollen die Ausgänge sein

Bed.1: PB0 und PB1 gehen beide auf HIGH
         => PA0, PA1 und PA3 sollen daraufhin auf HIGH gehen

Bed.2: PB0 und PB3 gehen beide auf HIGH
         => PA0 und PA3 sollen auf HIGH gehen

Bed.3: PB2 und PB3 gehen beide auf HIGH
         => PA0, PA2 und PA3 sollen auf HIGH gehen


@Stefan "stefb" B.
Kommt diese Aufstellung Deiner Vorstellung näher?

MfG

von Karl H. (kbuchegg)


Lesenswert?

Andyloco wrote:
> Wenn eine Bedingung erfüllt ist sollen die entsprechenden Pins auf HIGH
> geschaltet werden bis die Bedingung nicht mehr erfüllt ist.
>
> PB0..3 sollen die Eingänge sein
> PA0..3 sollen die Ausgänge sein

Formuliere deine Bedingungen in der Programmiersprache im
ersten Anlauf in der Langversion
>
> Bed.1: PB0 und PB1 gehen beide auf HIGH

Aha: Also genau dann, wenn PB0 auf High ist UND PB1
auf Hight ist.

In C

    if( ( PINB & ( 1 << PB0 ) )  &&
        ( PINB & ( 1 << PB1 ) ) {

    }

Deine bisherigen Abfragen

while (PINB & (1<<PINB0 & 1<<PINB1)) {

bzw.

while (PINB & (1<<PINB0 | 1<<PINB1)) {

sind andere Abfragen. Im ersten Fall kann die Bedingung
überhaupt nie erfüllt werden, weil ( 1 << PINB0 & 1 << PINB1 )
immer den Wert 0 ergibt.
Im zweiten Fall ist das immer noch eine andere Abfrage, weil
es hier bereits reicht, wenn einer der beiden Eingänge
entweder PINB0 oder PINB1 oder beide 1 sein können, damit
die Bedingung wahr ergibt.

-> Formuliere deine Logik zunächst mal einfach und überlege
dir welche Verknüpfung (und oder oder) du brauchst.
Wenn du dir nicht sicher bist, dann stell dir Tabellen auf, in
denen du alle Möglichkeiten der Eingangspins aufschreibst und
dann den Ausdruck auswertest

> // solange PINB0 und PINB1 == HIGH sollen

Das ist die falsche Denkweise. Deine Bedingungen sind
grundsätzlich immer von dieser Natur

     Variable == Wert

aber nicht

     Variable und eine andere Variable == Wert

statt dessen muss es lauten:

     Variable == Wert  UND  andere Variable == Wert

und genau so musst du es auch programmieren.

von Andyloco (Gast)


Lesenswert?

Habe mein Programm erstmal vereinfacht, weil (so denke ich)in der 
Bedingung irgendwo ein Fehler steckt. Ich habe eure Verbesserungen 
ausprobiert aber hat nicht so funktioniert wie ich das gerne hätte.
Das Programm reagiert nicht so auf Änderungen der Eingangspins wie ich 
das vorgesehen habe.
Die if-Bedingung soll prüfen ob PINB0 UND PINB1 HIGH sind und dann 
PORTA0 UND PORTA1 UND PORTA3 auf HIGH schalten ansonsten PORTA auf LOW.
Das Ergebnis dieser Programmierung ist allerdings, dass wenn der Taster 
am Eingang nicht gedrückt ist (es ist nur ein Taster angeschlossen sonst 
nix; also keine 5V anliegen) die 3 Ausgänge schon auf HIGH sind und sich 
auch nicht ändern wenn die Eingänge auf HIGH gesetzt werden.
Dagegen wenn einer der beiden Eingänge auf Masse gelegt wird dann gehen 
die Ausgänge auf LOW...
Kann ich leider überhaupt nicht nachvollziehen...
Ich hoffe einer von euch kann mir da weiterhelfen.

Vielen Dank. MfG Andyloco


#include <avr/io.h>
#include <stdint.h>


int main (void)
{

  DDRA  = 0xff;  // alle Pins von Port A als Ausgang
  DDRB  = 0x00;  // alle Pins von Port B als Eingang
  PORTB = 0xff;  // interne Pull-Ups an allen Port-Pins
                 //  aktivieren

      while (1)
      {
           if( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB1)) )
          PORTA |= (1<<PORTA0) | (1<<PORTA1) | (1<<PORTA3);
           else PORTA = 0x00;
      }

      return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

Andyloco wrote:
> Die if-Bedingung soll prüfen ob PINB0 UND PINB1 HIGH sind und dann
> PORTA0 UND PORTA1 UND PORTA3 auf HIGH schalten ansonsten PORTA auf LOW.
> Das Ergebnis dieser Programmierung ist allerdings, dass wenn der Taster
> am Eingang nicht gedrückt ist (es ist nur ein Taster angeschlossen sonst
> nix; also keine 5V anliegen)

Die Taster schalten also nach Masse.

Das heist aber auch:
  Ist keine Taste gedrückt, dann liegt an diesem Eingang eine 1
  an. Wird dies Taste gedrückt, dann liegt an diesem Eingang eine
  0 an.


 die 3 Ausgänge schon auf HIGH sind und sich
> auch nicht ändern wenn die Eingänge auf HIGH gesetzt werden.
> Dagegen wenn einer der beiden Eingänge auf Masse gelegt wird dann gehen
> die Ausgänge auf LOW...
> Kann ich leider überhaupt nicht nachvollziehen...

Ja. Ist logisch. Das ist genau das erwartete Verhalten, wenn die
Tasten nach Masse durchschalten.
1
> #include <avr/io.h>
2
> #include <stdint.h>
3
> 
4
> 
5
> int main (void)
6
> {
7
> 
8
>   DDRA  = 0xff;  // alle Pins von Port A als Ausgang
9
>   DDRB  = 0x00;  // alle Pins von Port B als Eingang
10
>   PORTB = 0xff;  // interne Pull-Ups an allen Port-Pins
11
>                  //  aktivieren
12
> 
13
>       while (1)
14
>       {
15
>            if( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB1)) )
16
17
            if( !(PINB & (1<<PINB0))  && !( PINB & (1<<PINB1)) )

Jetzt wird der if Teil nur dann genommen, wenn beide Taster
geschaltet sind, also beide Eingangspins eine 0 liefern.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Andyloco wrote:
> Kommt diese Aufstellung Deiner Vorstellung näher?

Nicht wirklich. Du bist schon am Dachdecken, aber die Fundamente sind 
noch nicht betoniert ;-)

von Andyloco (Gast)


Lesenswert?

So habs fertig gekriegt so wie es mir vorgestellt habe. Funzt erste 
Sahne ;) zumindest wenn man davon absieht das ich an den Ausgängen nur 
3,3V bzw 2,1V habe... :(
Muss wohl noch n bissl an meiner Hardware basteln (ohne angeschlossene 
Relais waren es 5V).
Hatte auch das mit den Widerständen für Active-High-Schaltung mit Taster 
noch nicht verstanden gehabt... Dachte die internen Pull-Down 
Widerstände würden reichen.

Ich möchte euch noch mal sehr für eure Hilfe danken!!! Ihr habt mir sehr 
geholfen!!!

MfG Andyloco


#include <avr/io.h>
#include <stdint.h>


int main (void)
{

  DDRA  = 0xff;  /* alle Pins von Port A als Ausgang */
  DDRB  = 0x00;  /* alle Pins von Port B als Eingang */
  PORTB = 0x00;  /* interne Pull-Ups an allen Port-Pins aktivieren */

      while (1)
      {
      if( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB1)) )
          {  PORTA |= (1<<PORTA0) | (1<<PORTA1) | (1<<PORTA3);
             PORTA &= ~(1<<PORTA2);
          }

      if( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB3)) )
          {  PORTA |= (1<<PORTA0) | (1<<PORTA3);
             PORTA &= (~(1<<PORTA1) | ~(PORTA2));
          }

      if( (PINB & (1<<PINB2))  && ( PINB & (1<<PINB3)) )
          {  PORTA |= (1<<PORTA0) | (1<<PORTA2) | (1<<PORTA3);
             PORTA &= ~(1<<PORTA1);
          }

      if( !( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB1)) ) ||
          !( (PINB & (1<<PINB0))  && ( PINB & (1<<PINB3)) ) ||
          !( (PINB & (1<<PINB2))  && ( PINB & (1<<PINB3)) ) )
          PORTA = 0;
      }

      return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

Andyloco wrote:
> So habs fertig gekriegt so wie es mir vorgestellt habe. Funzt erste
> Sahne ;) zumindest wenn man davon absieht das ich an den Ausgängen nur
> 3,3V bzw 2,1V habe... :(
> Muss wohl noch n bissl an meiner Hardware basteln (ohne angeschlossene
> Relais waren es 5V).

Du wirst doch nicht die Relais direkt an die Pins geschaltet haben?

> Hatte auch das mit den Widerständen für Active-High-Schaltung mit Taster
> noch nicht verstanden gehabt... Dachte die internen Pull-Down
> Widerstände würden reichen.

Das sind keine Pull-Downs. Im AVR sind Pull-Ups integriert.
Sie sorgen dafür, dass der Eingangspin definiert auf 1
gezogen wird, solange der Taster nicht geschlossen ist.

> #include <avr/io.h>
> #include <stdint.h>
>
>
> int main (void)
> {
>
>   DDRA  = 0xff;  /* alle Pins von Port A als Ausgang */
>   DDRB  = 0x00;  /* alle Pins von Port B als Eingang */
>   PORTB = 0x00;  /* interne Pull-Ups an allen Port-Pins aktivieren */

Der Kommentar stimmt nicht.
Die Pullups sind hier deaktiviert.

Dein resltiches Programm stimmt damit überein, dass du keine
Pull-Ups brauchst.
Dann brauchst du aber externe Pull-down Widerstände. Ein
auf Eingang geschalteter Pin darf niemals einfach nur offen sein!
Du fängst dir sonst an diesem Pin jede Menge Störungen ein.

Es muss also so aussehen:

                   +--------------o   +5V
                   |
                      /
                     /  Taster
                    /
                   |
                   |
       PB0 --------+
                   |
                  ---
                  | |
                  | |   10k
                  | |
                  ---
                   |
       GND --------+---------------o GND


Und sieh dir an, wie man ein Relais korrekt an einen µC
anschliesst. Sonst wird dein Opa nicht lange Freude an deiner
Elektronik haben.

http://www.mikrocontroller.net/articles/Relais_mit_Logik_ansteuern

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.