Ausgang auf "1" schalten, wenn Eingang auf "0" ist

Gast #5715944
Lesenswert?

Hallo zusammen,

ich habe folgendes Problem:
Ich benutze einen ATMEga32

Nun würde ich gerne PB0 auf "1" setzen wenn der Eingang PC6 auf "0" 
geht.
Mein Programmcode sieht wie folgt aus:

#ifdef F_CPU
#undef F_CPU
#define F_CPU 8000000UL
#endif


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

int main(void){
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRB &= ~(1 << PC6);      // damit ist dann PB1 ein Eingang

    while(1){

      if(!(PINC & (1 << PINC6)))
      {
        PORTB |= (1 << PB0);  //PB0 im PORTB setzen
        delay_ms(250);       //250ms warten
      }

    }

    return 0;
}


kann mir jemand sagen, was ich falsch mache?

vielen Dank
#5715948
Lesenswert?

Susanne schrieb:
> DDRB &= ~(1 << PC6);      // damit ist dann PB1 ein Eingang

Nein, Pin 6 und das auch noch von PortB

Susanne schrieb:
> if(!(PINC & (1 << PINC6)))

PINC6 ist schon geschoben
pub const PINC6: u8 = 1 << 6

Susanne schrieb:
> PORTB |= (1 << PB0);  //PB0 im PORTB setzen

Und wann willst du ihn wieder ausschalten ?

Susanne schrieb:
> kann mir jemand sagen, was ich falsch mache?

So ziemlich alles. Keine Aufmerksamkeit.
#5715975
Lesenswert?

Philipp G. schrieb:
> PORTB ^= (1 << PB0);
> delay_ms(250);

Das toogelt den Ausgang. Das ist aber nicht das, was Susanne will:

Susanne schrieb:
> Nun würde ich gerne PB0 auf "1" setzen wenn der Eingang PC6 auf "0"
> geht.

Allerdings hat sie nicht geschrieben, was bei PC6="1" passieren soll, 
also ob
- PC6 den Eingang PB0 invertiert abbilden oder
- PB0 beim ersten Auftreten von PC6="0" auf "1" gehen und dann so 
bleiben soll.
Gast #5715986
Lesenswert?

Eine "else" brauch ich hier nicht unbedingt.
Es soll ja nur ein Testprogramm sein.

Will ja nur, dass Wenn am Pin 28 ein "0" Signal anliegt. Pin 1 auf "1" 
geht.

#ifdef F_CPU
#undef F_CPU
#define F_CPU 8000000UL
#endif


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

int main(void){
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRC &= ~(1 << PC6);      // damit ist dann PC6 ein Eingang

    while(1)
    {
      if(PINC & (1 << PINC6)) // Wenn am Port C Pin 6 = "1" ist, wird 
PB0 gesetzt
      {
        PORTB |= (1 << PB0);  //PB0 im PORTB setzen
      }
    }
    return 0;
}
#5715995
Lesenswert?

Susanne schrieb:
> Eine "else" brauch ich hier nicht unbedingt.
> Es soll ja nur ein Testprogramm sein.
>
> Will ja nur, dass Wenn am Pin 28 ein "0" Signal anliegt. Pin 1 auf "1"
> geht.

Wechsel mal nicht dauernd die Bezeichnungen. Die physikalischen 
Pinnummern deines Gehäuses sind was anderes als die logischen Pinnamen.

> int main(void){
>     DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
>     DDRC &= ~(1 << PC6);      // damit ist dann PC6 ein Eingang

Stimmt.

>
>     while(1)
>     {
>       if(PINC & (1 << PINC6)) // Wenn am Port C Pin 6 = "1" ist, wird
> PB0 gesetzt

Das ist aber was anderes, als du in deinem 1. Betriag geschrieben hast? 
Ja was denn nun?

"Nun würde ich gerne PB0 auf "1" setzen wenn der Eingang PC6 auf "0"
geht."

Ansonsten ist das eher trivial, siehe Bitmanipulation.
Gast #5716037
Lesenswert?

Michael B. schrieb:
> Susanne schrieb:
>> if(!(PINC & (1 << PINC6)))
>
> PINC6 ist schon geschoben
> pub const PINC6: u8 = 1 << 6

Imho ist PINC6 nicht geschoben. Das findet man in den *.h-Files:
1
#define PINC _SFR_IO8(0x06)
2
#define PINC0 0
3
#define PINC1 1
4
#define PINC2 2
5
#define PINC3 3
6
#define PINC4 4
7
#define PINC5 5
8
#define PINC6 6
9
#define PINC7 7
Wo hast du deine Info her?
Gast #5716153
Lesenswert?

Hallo Susanne,

womit setzt du den PINC6 denn auf 0? Mit einem Taster?
Dann am Besten mit einem Pullup den Pin gegen Vcc ziehen und mit dem 
Taster gegen Masse!
Dann hast du schon mal einen definierten Eingangszustand!

Den Rest kannst du dir hier mal anschauen:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Zugriff_auf_IO-Ports

Ansonsten:
Was genau funktioniert denn nicht?
Gast #5716274
Lesenswert?

Michael B. schrieb:
> HildeK schrieb:
>> Wo hast du deine Info her
>
> https://docs.rs/arduino/0.1.0/arduino/constant.PINC6.html
Wir sind hier in C, oder C++ ... nix Rust.
Also falsche Baustelle.


-------------



Jörg B. schrieb:
> du weist schon, dass man für das Arduino Framework die Arduino.h
> incluidiert
Richtig!
bzw. passiert das meist automatisch

Jörg B. schrieb:
> und nicht die avr/io.h?
Falsch!
In der Arduino.h wird die  avr/io.h eingebunden.

Also Gesamtmaussage leider falsch.

Jörg B. schrieb:
> Letzteres ist namlich die avr-libc.
Die AVR-LIBC steht vollumfänglich in Arduino bereit.
Wird intensiv genutzt.
(natürlich nur für die AVRs)
Gast #5717458
Lesenswert?

Susanne schrieb:
> #include <avr/io.h>
> #include <util/delay.h>
>
> int main(void){
>     DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
>     DDRC &= ~(1 << PC6);      // damit ist dann PC6 ein Eingang
>
>     while(1)
>     {
>       if(PINC & (1 << PINC6)) // Wenn am Port C Pin 6 = "1" ist, wird
> PB0 gesetzt
>       {
>         PORTB |= (1 << PB0);  //PB0 im PORTB setzen
>       }
>     }
>     return 0;
> }


Dieser Code setzt, wie korrekt im Kommentar steht, PB0, wenn PINC6 auf 1 
ist.
Also genau das umgedrehte verhalten. Der Pin wird allerdings nie mehr 
zurückgesetzt.

Susanne schrieb:
> #ifdef F_CPU
> #undef F_CPU
> #define F_CPU 8000000UL
> #endif

Das ist auch komisch. Wenn F_CPU gesetzt ist, wird es überschrieben. 
Wenn es nicht gesetzt ist, passiert nichts.
Gast #5721664
Lesenswert?

Habe den Programmcode angepasst.
funktioniert leider immer noch nicht.

kann mir jemand sagen, was ich genau falsch mache?
eventuell Berichtigen, bekomme es alleine nicht hin :-(

#define F_CPU 8000000UL



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

int main(void)
{
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRC &= ~(1 << PC6);      // damit ist dann PC6 ein Eingang

    while(1)
    {
        if(PINC & (0 << PINC6)) // Wenn am Port C Pin 6 = "0" ist, wird 
PB0 gesetzt
        {
            PORTB |= (1 << PB0);  //PB0 im PORTB setzen
        }
    }
     return 0;
}
Gast #5721702
Lesenswert?

Susanne schrieb:
> meinst du in der If Anweisung oder bei der Initalisierung?
Schon in der if-Anweisung.
Dieser Befehl
> if(PINC & (0 << PINC6))
macht folgendes:
- in ein temporäres Register wird eine Null hineingeschrieben
- diese Null wird dann um den Wert von PINC6, also um 6 Stellen nach 
links geschoben.
- was bleibt: Null!
- UND-Verknüpfung einer Null mit irgendwas bleibt Null. Die if-Abfrage 
ist immer falsch. Wobei es mit PORTC verknüpft werden muss!

Der Befehl müsste lauten:
if ( !(PORTC & (1<<PINC6)))
Da passiert dann:
- in ein temporäres Register wird eine Eins hineingeschrieben
- diese Eins wird um 6 Stellen nach links geschoben
- es steht dann drin 0b01000000
- und das wird UND-Verknüpft mit dem PORTC ergibt dann eine Eins, wenn 
der Pin C8 HIGH ist. Deshalb die Invertierung ("!") bei der Abfrage, 
'if' also dann wahr, wenn der Pin Null ist.

Andernfalls: es gibt hier im Forum das AVR-GCC-Tutorial. Das sagt dir 
alles!
Gast #5721801
Lesenswert?

ok, ich hätte nun gedacht, dass wenn ich den Taster drücke, dass dann 
der Ausgang auf "1" geht, wenn ich den Taster wieder los lassen, dann 
geht der Ausgang wieder auf "0".
Leider funktioniert dies nicht.
Es hat keinen wechsel zur folgen wenn ich den Taster drücke:

#define F_CPU 8000000UL



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

int main(void)
{
  DDRC &= (1 << PC6);       // damit ist dann PC6 ein Eingang
  DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang


    while(1)
    {
      if ( !(PORTC & (1<<PINC6))) // Wenn am Port C Pin 6 = "0" ist, 
wird PB0 gesetzt
        {
        PORTB |= (1 << PB0);  //PB0 High
        }
      else
    {
        PORTB &= ~(1 << PB0); //PB0 Low
    }
    }
     return 0;
}
#5721836
Lesenswert?

Susanne schrieb:
> DDRC &= (1 << PC6);       // damit ist dann PC6 ein Eingang

Ist falsch und sinnlos. Funktioniert nur, weil DDRC6 sowieso 0 ist.
1
DDRC &= ~(1 << 6);

wäre richtig. Ist aber unnötig, da der Port sowieso auf Eingang steht.

Wie ist der Taster angeschlossen? Wahrscheinlich wie 99,99% aller Taster 
gegen GND. Deshalb: Wo ist der PullUp? Ohne Pullup kannst du darauf 
rumdrücken bis du schwarz wirst.
1
PORTC |= (1 << 6);  //Pullup ein


Susanne schrieb:
> if ( !(PORTC & (1<<PINC6)))

Ist falsch. Es muß:
1
if ( !(PINC & (1 << 6)))

heissen. Das war ursprünglich aber schon mal richtig.
Gast #5726467
Lesenswert?

Hab mir gerade den Thread von Susanne angeschaut.
Da ich auch Anfänger bin, wäre ich für eine kleine Hilfe sehr Dankbar.

Meines erachtes müsste dies so heißen:
wenn am PINC6 eine "0" anliegt, dann schaltet der Ausgang PB0 und PB1 
auf "1"

sehe ich das richtig?

#define F_CPU 8000000UL


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

int main(void)
{
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRB |= (1 << PB1);       // damit ist dann PB1 ein Ausgang
    DDRB &= ~(1 << PINC6);      // damit ist dann PINC6 ein Eingang

    while(1)
    {
        if(!(PINC & (1<<PINC6)))
        {
            PORTB |= (1 << PB0);  //PB0 im PORTB setzen
            PORTB |= (1 << PB1);  //PB0 im PORTB setzen
        }
        else
        {
          PORTB |= (0 << PB0);  //PB0 im PORTB setzen
          PORTB |= (0 << PB1);  //PB0 im PORTB setzen
        }
    }
    return 0;
}
Gast #5726471
Lesenswert?

also so:

#ifdef F_CPU
#undef F_CPU
#define F_CPU 8000000UL
#endif


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

int main(void)
{
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRB |= (1 << PB1);       // damit ist dann PB1 ein Ausgang
    DDRB &= ~(1 << PINC6);      // damit ist dann PINC6 ein Eingang

    while(1)
    {
        if(!(PORTC &= ~(1<<PINC6)))
        {
            PORTB |= (1 << PB0);  //PB0 im PORTB setzen
            PORTB |= (1 << PB1);  //PB0 im PORTB setzen
        }
        else
        {
          PORTB |= (0 << PB0);  //PB0 im PORTB setzen
          PORTB |= (0 << PB1);  //PB0 im PORTB setzen
        }
    }
    return 0;
}
#5726494
Lesenswert?

Dass es falsch ist.

Deine if-Bedingung war schon richtig. Nur eben die Stelle, an der du die 
LEDs wieder ausschalten möchtest (Bits im Register löschen) ist falsch 
und muss durch meine Variante ausgetauscht werden.

Weil |= beinhaltet unter anderem eine logische Oder-Operation. Und wenn 
das Bit schon gesetzt ist, kann man es durch Oder nicht wieder auf null 
bringen.
Gast #5726495
Lesenswert?

Andreas schrieb:
> quengel schrieb:
>> Andreas schrieb:
>>>         if(!(PORTC &= ~(1<<PINC6)))
>>
>> Ohne Worte
>
> was bedeutet das jetzt? Ist es nun richtig oder falsch?

Ist nicht richtig. Der Pin 6 auf Portc ist als Eingang konfiguriert und 
du möchtest doch wissen, wie der Pegel auf dem Eingang ist. Um das 
festzustellen, mußt du das PINC und nicht das PORTC Register abfragen. 
Das war schon mal weiter oben richtig.
#5726500
Lesenswert?

PORTB |= (1 << PB0);
Entspricht: PORTB = PORTB oder 0b00000001.

Ist das letzte Bit in PORTB eine Null, dann ergibt 0 oder 1 eine 1. Also 
wird die LED eingeschaltet.


PORTB |= (0 << PB0);
Entspricht: PORTB = PORTB oder 0b00000000.

Wenn das Bit in PORTB schon gesetzt ist, dann ist die Operation 1 oder 
0. Was immer noch 1 ist, also bleibt die LED an.

PORTB &= ~(1<<PB0)
Entspricht: PORTB = PORTB und 0b11111110.

1 und 1 = 1, 0 und 1 = 0, 0 und 0 = 0.

Damit behalten andere 0 und 1 in dem Register ihren Wert und nur PB0 
wird durch "1 und 0" auf 0 gesetzt.
Gast #5726520
Lesenswert?

Andreas schrieb:
> if(!(PORTC &= ~(1<<PINC6)))
       ^
 muss PINC heißen (da hatte ich oben was falsches behauptet, aber 
korrigiert).
>         {
>             PORTB |= (1 << PB0);  //PB0 im PORTB setzen
>             PORTB |= (1 << PB1);  //PB0 im PORTB setzen
                                    //PB1 ....
>         }
ok, bis auf Kommentar :-)
>         else
>         {
>           PORTB |= (0 << PB0);  //PB0 im PORTB setzen
            PORTB &= ~(1<<PB0);
>           PORTB |= (0 << PB1);  //PB0 im PORTB setzen
            PORTB &= ~(1<<PB1);       ^
                                  //PB1
>         }

Du musst dir überlegen, was in der Operation
   PORTB |= (0 << PB1);
passiert und damit herausfinden, warum es so nicht geht.

PB1 ist eine Defnition und steht für die Zahl 1.
Deine Anweisung nimmt also 0b00000000 und schiebt sie um eine Stelle 
nach links. Bleibt Null.
Im if-Zweig hatte der Befehl PORTB |= (1<<PB1) das IO-Register mit dem 
Wert 0b00000010 gefüllt.
Jetzt machst du eine bitweise ODER-Verknüpfung von PORTB=0b00000010 mit 
0b00000000. Das ändert aber nichts!
Deshalb kann man so keine Null an eine bestimmte Stelle schreiben!

Was muss passiern:
Du hast also in PORTB 0b00000010 stehen.
(1<<PB1) ist immer noch 0b00000010 und ~(1<<PB1) ergibt 0b11111101.
Jetzt erfolgt eine bitweise UND-Verknüpfung von PORTB und 0b11111101.
Durch die eine Null wird exakt diese Stelle zu Null, die Einsen lassen 
das, was vorher in PORTB stand, unverändert. In dem Fall trivial, aber 
es hätten  noch andere Ausgänge gesetzt gewesen sein können, je nach 
Programm.
Würde also aus eine vorherigen Operation PORTB = 0b01100011 sein, dann 
wird es nach dem Befehl PORTB &= ~(1<<PB1)zu PORTB = 0b01100001 werden.
Gast #5726526
Lesenswert?

Ich gebe es auf:

nach meinem Verständnis ist es nun so:
liegt am Eingang PINC6 = 0 (! = Negation)
wird der Ausgang PB0 und PB1 auf 1 gesetzt.

liegt dagegen eine "1" am PINC6 wird der Ausgang PB0 auf "0" gesetzt

es geht aber nicht.

kann mir bitte jemand den code so berichtigen, dass es klappt, würde es 
dann gerne nachvollziehen können. alles andere frustiriert gerade :-(


#define F_CPU 8000000UL

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

int main(void)
{
    DDRB |= (1 << PB0);       // damit ist dann PB0 ein Ausgang
    DDRB |= (1 << PB1);       // damit ist dann PB1 ein Ausgang
    DDRB &= ~(1 << PC6);      // damit ist dann PINC6 ein Eingang

    while(1)
    {
      if(!(PORTC &= ~(1<<PINC6)))
        {
        PORTB &= ~(1<<PB0);  //PB0 im PORTB setzen
        }
      else
      {
        PORTB &= ~(0<<PB0);  //PB0 im PORTB setzen
      }
    }
    return 0;
}
Gast #5726577
Lesenswert?

Klasse. 50 Mann bemühen sich seit 8 Tagen, in C ein Programm zu 
schreiben, was ein invertiertes Eingangssignal an einem anderen Portpin 
ausgibt.

Das nenne ich eine effektive Programmiersprache.
Gast #5726588
Lesenswert?

Andreas schrieb:
> nach meinem Verständnis ist es nun so:
> liegt am Eingang PINC6 = 0 (! = Negation)
So ist es aber nicht.
Du prüfst das falsche Register!

Andreas schrieb:
> if(!(PORTC &= ~(1<<PINC6)))

Du möchtest PINC6 prüfen.
Prüfst aber in Wirklichkeit den Zustand von PORTC6
Das bringt dich aber nicht zum Ziel.

Andreas schrieb:
> wird der Ausgang PB0 und PB1 auf 1 gesetzt.
PB0 sehe ich, PB1 nicht

1
#define F_CPU 8000000UL
2

3
#include <avr/io.h>
4
#include <util/delay.h>
5

6
int main(void)
7
{
8
    DDRB |= (1 << DDB0)|(1 << DDB1);       // damit ist dann PB0 und PB1 ein Ausgang
9
    DDRC &= ~(1 << PC6);      // damit ist dann PINC6 ein Eingang
10

11
    while(1)
12
    {
13
      if(!(PINC &= ~(1<<PINC6))) // teste Eingang auf Low
14
        {
15
        PORTB |= (1<<PORTB0)|(1<<PORTB1);  //PB0 und PB1 im PORTB setzen
16
        }
17
      else
18
      {
19
        PORTB &= ~((1<<PORTB0)|(1<<PORTB1));  //PB0 und PB1 im PORTB löschen
20
      }
21
    }
22
    return 0;
23
}
Gast #5726590
Lesenswert?

Susanne schrieb:
> ok, ich hätte nun gedacht, dass wenn ich den Taster drücke, dass dann
> der Ausgang auf "1" geht, wenn ich den Taster wieder los lassen, dann
> geht der Ausgang wieder auf "0".

Nein, es wurde bereits ganz zu Beginn erwähnt, dass in deinem code 
vergessen wurde ihn wieder auszuschalten.

Andreas schrieb:
> Meines erachtes müsste dies so heißen:
> wenn am PINC6 eine "0" anliegt, dann schaltet der Ausgang PB0 und PB1
> auf "1"

Hier gibt es wenigstens code zum Ausschalten, aber er ist falsch. Es 
wurde weit vorher schon erwähnt, dass es nichts bringt, eine 0 zu 
schieben.

Arduino wäre einfacher gewesen.
Gast #5727062
Lesenswert?

Effektiver schrieb:
> Klasse. 50 Mann bemühen sich seit 8 Tagen, in C ein Programm zu
> schreiben, was ein invertiertes Eingangssignal an einem anderen Portpin
> ausgibt.
>
> Das nenne ich eine effektive Programmiersprache.

Das hat gar nichts mit der Programmiersprache zu tun, nur mit der 
Unfähigkeit von (mehreren) Fragenden das umzusetzen, was mehrfach 
ausführlich und korrekt geantwortet wurde. Immerhin scheint Susanne seit 
Sonntag zufrieden zu sein, es ist Andreas, der das selbe nochmals.

Da kommt dann nach rund 50 Antworten in drei Zeilen Code noch immer drei 
Fehler, siehe:
1
    while(1)
2
    {
3
      if(!(PORTC &= ~(1<<PINC6)))  // FALSCH ist PORTC, richtig wäre PINC
4
        {
5
        PORTB &= ~(1<<PB0);  //PB0 im PORTB setzen //FALSCH: hier wird rückgesetzt, richtig wäre '|= (1<<PB0)'
6
        }
7
      else
8
      {
9
        PORTB &= ~(0<<PB0);  //PB0 im PORTB setzen // FALSCH ist (0<<PB0), weil wirkungslos, richtig wäre '(1<<PB0)'
10
      }
11
    }
Andreas, vergleich einfach mal den nächsten Block mit deinem Code:
1
    while(1)
2
    {
3
      if(!(PINC &= ~(1<<PINC6))) // der erste Fehler: muss PINC sein!
4
        {
5
        // zweiter Fehler: Setzen tut man mit dem Kommando
6
        PORTB |= (1<<PB0);  //PB0 im PORTB setzen
7
        }
8
      else
9
      {
10
        // dritter Fehler: '0' schieben nützt nichts und du willst eigentlich rücksezten
11
        PORTB &= ~(1<<PB0);  //PB0 im PORTB rücksetzen 
12
      }
13
    }
Gast #5727252
Lesenswert?

HildeK schrieb:
1
> if(!(PINC &= ~(1<<PINC6))) // der erste Fehler: muss PINC sein!
2
            ^^ vierter Fehler

Das ist gleichzeitig der einzige Fehler, zu dem ich C eine kleine 
Teilschuld geben würde - eine strenger typisierte Sprache könnte hier 
einen Programmierfehler erkennen. Müsste dann aber auch ein
1
if( (PINC & (1<<PINC6) )

verbieten.

Die anderen drei Fehler sind dagegen wahrscheinlich typische "erst 
kopieren dann kapieren"-Fehler - ohne irgendeine Ahnung davon, was PINC, 
PORTC, PINC6, PB0 und die verschiedenen Operatoren bedeuten, einfach mal 
irgendwas irgendwoher kopiert und leicht geändert und dann gewundert, 
dass es nicht funktioniert.

Solche Fehler kann keine Programmiersprache auffangen.

MfG, Arno

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren