Forum: Compiler & IDEs Pin Abfragen


von Gast (Gast)


Lesenswert?

Hallo,

ich möchte zwei Gabellichtschrenken an PB0 und PD5 abfragen. Beide 
liefern im offenen Zustand etwa 5V (High-aktiv). Ist ein Gegenstand in 
der Lichtschranke, kann am Ausgang des Transistors etwa 2mV gemessen 
werden.
Um nun eine Aktion auszuführen, muss man auf LOW-Abfragen. Ist das 
richtig?

Hier sind die entsprechenden Codezeilen:
1
...
2
DDRB |= (1<<PB3) | (1<<PB4);
3
  
4
  DDRB &= ~(1<<PB0);        // PB0 als Eingang
5
  //PORTB |= (1<<PB0);        // Pull-up an PD5
6
  DDRD &= ~(1<<PD5);        // PD5 als Eingang
7
  //PORTD |= (1<<PD5);            // Pull-up an PD5
8
    
9
  if(!(PINB&(1<<PINB0)))       // Führe aus, wenn PB0 gesetzt ist
10
  {    
11
    PORTB |=(1<<PB4);        // LED gelb an
12
    PORTB &= ~(1<<PB3);      // LED rot aus
13
  }
14
  if(!(PIND&(1<<PIND5)))       // Führe aus wenn PD5 gesetzt ist
15
  {
16
    PORTB |=(1<<PB3);        // LED rot an
17
    PORTB &= ~(1<<PB4);      // LED gelb aus
18
  }
19
...

nun zum Problem:
Es tut sich nicht.
Was mache ich falsch?

Danke

von Matrix (Gast)


Lesenswert?

Hast du Opencollektor Ausgänge an deinen Lichtschranken? Wenn ja musst 
du die Auskommentierten Pull-Up Aktivieren reinmachen.

Die Eingänge der Lichtschranken musst du eigentlich nicht extra auf 
Eingang setzten. Das ist nacht dem POR immer auf 0 gesetzt.
1
DDRB |= (1<<PB3) | (1<<PB4);
2
  
3
  PORTB |= (1<<PB0);            // Pull-up an PB0
4
  PORTD |= (1<<PD5);            // Pull-up an PD5
5
    
6
  if(!(PINB&(1<<PB0)))       // Führe aus, wenn PB0 gesetzt ist
7
  {    
8
    PORTB |=(1<<PB4);        // LED gelb an
9
    PORTB &= ~(1<<PB3);      // LED rot aus
10
  }
11
  if(!(PIND&(1<<PD5)))       // Führe aus wenn PD5 gesetzt ist
12
  {
13
    PORTB |=(1<<PB3);        // LED rot an
14
    PORTB &= ~(1<<PB4);      // LED gelb aus
15
  }


Sonnst fallen mir aber keine Fehler auf. Gehen die LEDs selber? Also 
wenn du nur die LEDs einschaltest zb?

von technikus (Gast)


Lesenswert?

1
DDRB |= (1<<PB3) | (1<<PB4);
2
  
3
  PORTB |= (1<<PB0);            // Pull-up an PB0
4
  PORTD |= (1<<PD5);            // Pull-up an PD5
5
    
6
while(1)
7
{
8
  if(!(PINB&(1<<PB0)))       // Führe aus, wenn PB0 gesetzt ist
9
  {    
10
    PORTB |=(1<<PB4);        // LED gelb an
11
    PORTB &= ~(1<<PB3);      // LED rot aus
12
  }
13
  if(!(PIND&(1<<PD5)))       // Führe aus wenn PD5 gesetzt ist
14
  {
15
    PORTB |=(1<<PB3);        // LED rot an
16
    PORTB &= ~(1<<PB4);      // LED gelb aus
17
  }
18
}

Hauptschleife vergessen ???

Mit deinen Informationen bist du ja sparsam, da kann man nur raten...


technikus

von Gast (Gast)


Lesenswert?

Hallo und danke schon mal für die Hilfe.

@Matrix:
die Lichtschranke haben keine Opencollektor Ausgänge. ich betreibe sie 
wie in der Skizze beschrieben. Auch mit den Pull-ups.
Die LED´s sind ok. Habe zB. auf High abgefragt ( if(PINB&(1<<PB0)){...} 
). Das Verhalten war wie erwartet. Dadurch dass sich kein Gegenstand in 
der Lichtschranke befindet und der Transistor am Emitter etwa 5V hat, 
wird die "if(PINB&(1<<PB0)){...}" ausgeführt und die entsprechende LED 
leuchtet.
Wie erwehnt, fallst sich ein Gegenstand in der Schranke befindet macht 
der Tansistor zu und am Emitter sind nur noch etwa 2mV zu messen.
Ich frage mich nun ob diese 2mV immer noch zu hoch sind damit der uC am 
Pin einen Unterschied merkt um es als Schaltschwelle zu erkennen.

@technikus:
der Code befindet sich in einer Funktion. Die while(1) ist somit in der 
main().
Ich verwende übrigens einen Atmega48. Allerdings glaube ich nicht dass 
die Pinabfrage Controllerspezifisch ist.

Vielen Dank noch mal

von Karl H. (kbuchegg)


Lesenswert?

Gast wrote:

> Ich frage mich nun ob diese 2mV immer noch zu hoch sind damit der uC am
> Pin einen Unterschied merkt um es als Schaltschwelle zu erkennen.

Mit Sicherheit nicht.

> der Code befindet sich in einer Funktion. Die while(1) ist somit in der
> main().

Poste es trotzdem.
Kannst ja ruhig mal das Programm abspecken, so dass es den Fehler immer 
noch zeigt aber kleiner ist. Aber poste was komplettes und nicht nur 
Fragmente!

von Gast (Gast)


Lesenswert?

...
1
ISR(INT0_vect)             
2
{
3
  DDRB |= (1<<PB3) | (1<<PB4);
4
  
5
    PORTB |= (1<<PB0);             // Pull-up an PB0
6
    PORTD |= (1<<PD5);             // Pull-up an PD5
7
    
8
    if(!(PINB&(1<<PB0)))           // Führe aus, wenn PB0 gesetzt ist
9
    {    
10
      PORTB |=(1<<PB4);          // LED gelb an
11
      PORTB &= ~(1<<PB3);        // LED rot aus
12
   }
13
    if(!(PIND&(1<<PD5)))           // Führe aus wenn PD5 gesetzt ist
14
    {
15
      PORTB |=(1<<PB3);          // LED rot an
16
      PORTB &= ~(1<<PB4);        // LED gelb aus
17
    }
18
}
...

von Walter (Gast)


Lesenswert?

sei halt nicht so geizig,
oder ist dein Programmcode streng geheim?

von Karl H. (kbuchegg)


Lesenswert?

Ach, komm.
Schön langsam wirds fad. Du willst Hilfe, nicht wir!
Poste doch mal was komplettes, mit dem man auch was anfangen kann. Dein 
Code-Fragment ist erst mal so in Ordnung, aber das weißt du selber auch. 
Also muss das Problem woanders sitzen. Nur wenn du nichts herzeigst, 
kann dir auch keiner helfen das Problem zu identifizieren.

Der Interrupt wird ausgelöst? Vielleicht ist ja auch die Konfiguration 
des Int0 Interrupts fehlerhaft.


Edit: Ich mag nicht mehr. Ich bin raus.

von Matrix (Gast)


Lesenswert?

Hast du Interrupts aktiviert?

von Michael U. (amiga)


Lesenswert?

Hallo,

Gast wrote:
...
> ). Das Verhalten war wie erwartet. Dadurch dass sich kein Gegenstand in
> der Lichtschranke befindet und der Transistor am Emitter etwa 5V hat,
> wird die "if(PINB&(1<<PB0)){...}" ausgeführt und die entsprechende LED
> leuchtet.
> Wie erwehnt, fallst sich ein Gegenstand in der Schranke befindet macht
> der Tansistor zu und am Emitter sind nur noch etwa 2mV zu messen.

Am Emitter? Also Kollektor des Kopplers an +5V?
Dann solltest Du auch einen Pulldown-Widerstand einlöten, der den 
Eingang auf L zieht, wenn der Transistor im Koppler sperrt.
Üblicher wäre wohl, den internen PullUp einschalten und den Koppler an 
AVR- Pin und den Emitter an GND zu schalten.

Gruß aus Berlin
Michael

von Gast (Gast)


Lesenswert?

Hallo zusammen,

hier ist der gesamte Code:
1
#define F_CPU 20000000UL       
2
3
#include <stdio.h> 
4
#include <avr/io.h>           
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#include <stdlib.h>
8
#include <stdbool.h>  
9
10
//************************* ISR INT1 ***************************
11
ISR(INT0_vect)             
12
{   
13
    //PORTB |= (1<<PB0);                   // Pull-up an PB0
14
    //PORTD |= (1<<PD5);                   // Pull-up an PD5    
15
    if(!(PINB&(1<<PB0)))           // Führe aus, wenn PB0 gesetzt ist
16
    {    
17
      PORTB |=(1<<PB4);          // LED gelb an
18
      PORTB &= ~(1<<PB3);        // LED rot aus
19
    }
20
    if(!(PIND&(1<<PD5)))           // Führe aus wenn PD5 gesetzt ist
21
    {
22
      PORTB |=(1<<PB3);          // LED rot an
23
        PORTB &= ~(1<<PB4);        // LED gelb aus
24
    }
25
}
26
27
//************************* ISR INT1 ***************************
28
ISR(INT1_vect)             
29
{  
30
  for(int i=0; i<10; i++)
31
  {
32
    PORTB |=(1<<PB4);   
33
    _delay_ms(500);
34
    PORTB &= ~(1<<PB4);
35
    _delay_ms(500);
36
  }
37
}  
38
  
39
int main() 
40
{              //Hauptfunktion
41
//***************** Initialisierung I/O *********************************
42
  DDRB |= (1<<PB3) | (1<<PB4) | (1<<PB5);     // Ausgang für LED´s
43
  
44
  DDRD &= ~(1<<PD2);               // INT0 links/rechts-LS
45
  DDRD &= ~(1<<PD3);               // INT1 LS3
46
47
  DDRD |= (1<<PD5);               // LS  LINKS
48
  DDRB |= (1<<PB0);              // LS  RECHTS  
49
50
  PORTB |= (1<<PB0);                   // Pull-up an PB0
51
  PORTD |= (1<<PD5);                   // Pull-up an PD5      
52
53
//*********************** Interrupt - Register *******************************    
54
  EICRA |= (1<<ISC11) | (1<<ISC01);       // fallende Flanke lösßt ISR INT0/ INT1 aus
55
  EIMSK |= (1<<INT1) | (1<<INT0);       // INT0/ INT1 Enable 
56
  
57
  sei();                     // Global Intruppt Enable
58
59
  while(1)
60
  {
61
    PORTB |=(1<<PB5);              // LED setzen
62
    _delay_ms(50);              // Warte
63
    PORTB &= ~(1<<PB5);           // LED löschen
64
    _delay_ms(50);              // Warte
65
  }                       // End while(1)
66
  return 0;
67
}                         // End main

INT1 funktioniert
INT0 funktioniert nicht

von Johannes M. (johnny-m)


Lesenswert?

Ich habe den Thread jetzt dreimal durchgeblättert und nirgends ein 
Wort darüber gefunden, um was für ein Controller es überhaupt geht...

von Justus S. (jussa)


Lesenswert?

Gast wrote:

> Ich verwende übrigens einen Atmega48. Allerdings glaube ich nicht dass
> die Pinabfrage Controllerspezifisch ist.

wobei ich gerne wissen würde, wie die Interruptpins beschaltet sind...

von Johannes M. (johnny-m)


Lesenswert?

Justus Skorps wrote:
> Gast wrote:
>
>> Ich verwende übrigens einen Atmega48. Allerdings glaube ich nicht dass
>> die Pinabfrage Controllerspezifisch ist.
Aaah, jetzt habe ich es auch gefunden. Gut versteckt!

BTW:
10 Sekunden Delay in einem Interrupt Handler sind einfach nur 
grottenschlechter Programmierstil...

von Gast (Gast)


Angehängte Dateien:

Lesenswert?

@ Johannes M.
1
10 Sekunden Delay in einem Interrupt Handler sind einfach nur
2
grottenschlechter Programmierstil...
es geht hierbei nicht um die Zeitdauer oder um den Programmierstil...

@ Justus Skorps:
eine handskizzierte Pinbeschaltung ist im Dateianhang zu finden.

von MWS (Gast)


Lesenswert?

Damit der Int0 einen eindeutigen Zustand erhält, musst dort einen 
Pulldown Widerstand rein, sonst funktioniert das so aufgebaute 
Dioden-Oder nicht

von Karl H. (kbuchegg)


Lesenswert?

Wobei:

Die Lichtschranken liefern, wenn nicht unterbrochen 5V, also logisch 1.
Ich behaupte mal, dass hinter dem Dioden-Or immer eine 1 vorhanden ist, 
weil eine der beiden Lichtschranken nicht unterbrochen ist.

Erst wenn beide Lichtschranken gleichzeitig unterbrochen werden, müsste 
der INT0 auslösen. Ich denke aber, dass genau das nicht passiert, denn 
die eine ist mit Links und die andere mit Rechts beschriftet :-)

von MWS (Gast)


Lesenswert?

Karl Heinz,

das mit logisch 1 ist schon richtig, das ist ein eindeutig definierter 
Zustand. Aber wenn da kein Pulldown dran ist, wie soll denn der Int0 
Eingang auf 0 gehen ? Der ist dann einfach ohne Signal, also hochohmig 
floatend.

von Karl H. (kbuchegg)


Lesenswert?

MWS wrote:
> Karl Heinz,
>
> das mit logisch 1 ist schon richtig, das ist ein eindeutig definierter
> Zustand. Aber wenn da kein Pulldown dran ist, wie soll denn der Int0
> Eingang auf 0 gehen ? Der ist dann einfach ohne Signal, also hochohmig
> floatend.

Yep. Daran hab ich noch gar nicht gedacht (jetzt versteh ich auch deine 
Anmerkung von vorher mit dem Pulldown). Über die Dioden kann ja der 
Eingang gar nicht auf 0 gezogen werden.

von MWS (Gast)


Lesenswert?

Karl Heinz,

ich glaube es handelt sich um eine bunte Mischung verschiedener Fehler, 
denn was Du geschrieben hast stimmt ja auch. Meines Erachtens würde es 
funktionieren, wenn die Dioden umgedreht werden und gegen einen 
eingeschalteten Pullup des PD2/Int0 arbeiten, das ist dann ein 
UND-Ersatz.

Damit würde ein Int0 ausgelöst, sobald eine der Lichtschranken 
unterbrochen würde und auf Low geht.

Wobei
> Beide liefern im offenen Zustand etwa 5V (High-aktiv).
und
>die Lichtschranke haben keine Opencollektor Ausgänge. ich betreibe sie
> wie in der Skizze beschrieben. Auch mit den Pull-ups.
ich keine Skizze sehe und die Aussagen nicht eindeutig sind. Was aber 
entscheidend wäre.

Liefern sie aktive Low, oder ziehen Pulldown Widerstände bei 
unterbrochenem Lichtstrahl den Ausgang auf Low ?

Ist letzteres der Fall, müssen die Pulldowns deutlich kleiner als der im 
µC integrierte Pullup bei beschriebener UND-Ersatzschaltung sein, sonst 
gibt das einen ungünstigen Spannungsteiler.

@Gast, poste doch mal die Verschaltung der Gabellichtschranken.

von Gast (Gast)


Angehängte Dateien:

Lesenswert?

...
die Pulldowns sind bei den Lichtschranken mitverschaltet.
siehe Anhang

durch die Codeänderung der DDRD und DDRB zu Eingängen, hat es mit beiden 
INT0 und INT1 funktioniert. Allerdings verstehe ich nicht warung Matrix 
(2. Beitrag von oben) meinte:
1
Die Eingänge der Lichtschranken musst du eigentlich nicht extra auf
2
Eingang setzten. Das ist nacht dem POR immer auf 0 gesetzt.
1
..
2
DDRD &= ~(1<<PD2);      // INT0 links/rechts-LS
3
DDRD &= ~(1<<PD3);      // INT1 LS3
4
5
DDRD &= ~(1<<PD5);      // LS  LINKS
6
DDRB &= ~(1<<PB0);      // LS  RECHTS  
7
..

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> ...
> die Pulldowns sind bei den Lichtschranken mitverschaltet.
> siehe Anhang
Da nützen die aber nichts. Es muss zwischen den Dioden und den Portpins 
für ein definiertes Potenzial gesorgt werden!
>
> durch die Codeänderung der DDRD und DDRB zu Eingängen, hat es mit beiden
> INT0 und INT1 funktioniert. Allerdings verstehe ich nicht warung Matrix
> (2. Beitrag von oben) meinte:
>
1
> Die Eingänge der Lichtschranken musst du eigentlich nicht extra auf
2
> Eingang setzten. Das ist nacht dem POR immer auf 0 gesetzt.
Er meint damit, dass nach dem (Power On-) Reset praktisch alle 
I/O-Register (inkl. der DDR-Register) sowieso Null sind. Man sollte 
allerdings (auch wenn Matrix was anderes behauptet) die Register 
trotzdem explizit setzen.

Es ist allerdings schwierig, ohne die Anordnung der Lichtschranken zu 
kennen, etwas über mögliche Denkfehler im Programm zu sagen.

Die Anordnung, wie Du sie bei den Lichtschranken gewählt hast, ist auch 
ziemlich unüblich. Die Widerstände dort könntest Du Dir sparen, wenn Du 
einfach die Controller-Pins an die (offenen) Kollektoren anschließt und 
im Controller die Pull-Ups aktivierst. Die Dioden dann einfach umdrehen 
und schon sollte es gehen.

von Karl H. (kbuchegg)


Lesenswert?

Johannes M. wrote:
> Gast wrote:
>> ...
>> die Pulldowns sind bei den Lichtschranken mitverschaltet.
>> siehe Anhang
> Da nützen die aber nichts. Es muss zwischen den Dioden und den Portpins
> für ein definiertes Potenzial gesorgt werden!

Yep.

Siehs mal so:
Über die Dioden kann Strom von der Lichtschrankenschaltung zum Pin 
laufen.
Aber so eine Diode ist wie ein Einwegventil. Wenn von der Lichtschranke 
nichts mehr kommt, heist das nicht, das der Spannungssstand (Analaogie 
zu einem Wasserstand. Man möge es mir verzeihen) automtisch sinkt. Da 
ist nichts was einen definierten 0-Pegel rechts von den Dioden erzeugen 
würde.

Widerstand nach Masse würde genau das bewerkstelligen: Bildlich 
gesprochen macht der den Abfluss auf, sodass rechts von den Dioden das 
Wasser (eh: der Strom) abfliessen kann.


Aber auch dann wäre die beabsichtigte Wirkung noch nicht erreicht.
Wieder das Analogon:
Die Dioden seien Ventile, durch die Wasser zum Pin strömt (der den 
Wasserstand misst.
Wenn deine Lichtschranken nicht unterbrichen sind, dann liefern sie 
jeweils Wasser. Soweit so gut.
Wird eine Lichtschranke unterbrochen, dann liefert sie zwar kein Wasser 
mehr. Aber die andere tut es! Wenn von 2 Wasserhähnen einer kein Wasser 
liefert, wird das Becken trotzdem voll. Und der Wasserstandssensor (der 
µC-Pin) registriert natürlich nach wie vor, dass da eine 1 anliegt.

(Nimm die Analogie mit dem Wasser nicht allzu wörtlich. Manchmal 
funktioniert das überraschen gut, manchmal weniger. Aber vom Prinzip 
her, kommt man mit so einem Wassermodell schon recht weit)

Das Ganze ist ausserdem eine schöne Demonstration der De-Morgan regel

  Nicht( A und B )  <==>  Nicht A ODER Nicht B

von MWS (Gast)


Lesenswert?

Gast:
> Ist ein Gegenstand in der Lichtschranke, kann am Ausgang des
> Transistors etwa 2mV gemessen werden. Um nun eine Aktion
> auszuführen, muss man auf LOW-Abfragen.

Aus diesen Worten entnehme ich, daß Du eine Aktion, bzw. den Int0 
ausführen möchtest, wenn ein Gegenstand die Lichtschranke unterbricht.
Ist das richtig ?

Wenn ja: lass die Schaltung wie sie ist, pole nur die Dioden um und 
setze den internen Pullup an PD2:
1
DDRD |= (1<<PD2);

Lösche diese beiden Zeilen, die brauchst Du nicht wegen der 
Pulldown-Widerstände an den Fototranistoren:
1
PORTB |= (1<<PB0);                   // Pull-up an PB0
2
PORTD |= (1<<PD5);                   // Pull-up an PD5

Dann sollte es funktionieren. Wird der Lichtstrahl unterbrochen, wird 
der Fototransistor hochohmig, der Pulldown zieht den Ausgang des 
Fototransitors und damit den Pin auf Minus. Gleichzeitig wird auch der 
Int0 über die Diode, die nun andersrum leitet, auf Minus gezogen. Damit 
triggert der Int0, der auf fallende Flanke reagiert.

Du kannst auch alles umstricken, die Fototransistoren nach Minus 
schalten lassen, und dann die internen Pullups des µC verwenden. Dann 
brauchst Du dennoch einen externen Widerstand für die Dioden auf Minus 
gehend, die dann wieder andersrum (also wie jetzt) reingehören würden. 
Auch müsstest Du auf steigende Flanke triggern. Insgesamt könnntest Du 3 
Widerstände einsparen. Du musst selber wissen, ob's Dir den Aufwand wert 
ist.

von Gast (Gast)


Lesenswert?

Erst mal vielen Dank an Karl Heinz für die bildhafte Erklärung. Man kann 
sich das ganze sehr gut Vorstellen.

In der Zwischenzeit habe ich
- die Dioden umgelötet,
- DDRD |= (1<<PD2) als Ausgang und
- PORTD |= (1<<PD2) den internen Pull-up geschaltet
- die anderern internen Pull-up an PD5 und PD0 sind auskommentiert

@ MWS:
die theoretische Beschreibung leuchtet mir ein. Durch den zugeschalteten 
internen Pull-up an PD2 und dem DDRD als Ausgang, messe ich etwa 5V am 
PD2. Soweit so gut. Nun müsste die PD2 Spannung, durch den Widerstand am 
Fototransistor, gegen Masse abfallen.
Leider verhält sich das Ding nicht so wie grad beschrieben. Die Spannung 
sinkt lediglich um etwa 0,5V ab.

Wie schon
Was mache ich falsch?
1
...
2
int main() 
3
{              
4
//***************** Initialisierung I/O *********************************
5
DDRB |= (1<<PB3) | (1<<PB4) | (1<<PB5);     // Ausgang für LED´s
6
  
7
DDRD |= (1<<PD2);   // INT0 links/rechts-LS  -Ausgang
8
PORTD |= (1<<PD2);   // Pull-up an PD2
9
10
//DDRD &= ~(1<<PD3);   // INT1 LS3 
11
12
//DDRD |= (1<<PD5);   // LS  LINKS
13
//DDRB |= (1<<PB0);  // LS  RECHTS  
14
15
  
16
//PORTB |= (1<<PB0);    // Pull-up an PB0
17
//PORTD |= (1<<PD5);    // Pull-up an PD5      
18
  
19
...

der Rest des Codes ist der Gleiche wie oben

von MWS (Gast)


Lesenswert?

Tschuldige, bin auch ein Depp.
1
DDRD |= (1<<PD2);

ist falsch. Muss ein Eingang bleiben, wollte den internen Pullup setzen, 
und hab' Dir in temporärer Verwirrung das Datenrichtungsregister 
genannt. Ließ sich so schön aus Deinem Text kopieren, und ich hab's dann 
auch noch auf ODER geändert. Unwillentlich, aber wissentlich 
herbeigeführter Murks ;-)

Also nimm obigen Befehl raus, damit's wieder ein Eingang wird, DANN 
sollte es gehen, die Logik des Rests meiner Post ist trotzdem ok.

von Gast (Gast)


Lesenswert?

dafür muss man sich nicht entschuldigen.
ich habe schon gewusst was du gemeint hast.

Nun funktioniert alles so wie ich es mir vorstelle.

Vielen Dank noch mal an alle.

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.