PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Taster an Attiny45



frankz
03.03.2007, 19:56
Hallo,

irgendwie verstehe ich die Welt nicht mehr. Ich möchte einen Taster an einen Attiny45 anschliessen und den Status abfragen oder einen Interrupt bekommen. Aber weder das eine noch das andere funktioniert.

Taster ist am PB1 angeschlossen. Led ist ist an PB4 angeschlossen.

DDRB &= ~(1<<DDB1);
PORTB |= (1 << PB1);

if( bit_is_clear(PORTB, PINB1) )
PORTB |= (1 << PINB4);
else
PORTB &= ~(1 << PINB4);

Den Interrupt habe ich wie folgt initialisiert
PCMSK |= (1 << PB1);
MCUCR = (0<<ISC01) | (0<<ISC00);
GIFR |= (1 << INTF0);
GIFR = 0x40;

ISR(INT0_vect)
{
PORTB |= (1 << PINB4);
}

Kann mir da einer weiterhelfen, welches Register ich vergessen habe oder geht das nicht über den PIN?

Gruß

Frank

linux_80
03.03.2007, 23:14
Hallo,

Im ersten Beispiel ist PB4 nicht als Ausgang definiert,
und beim einlesen von PB1 wird PinB verwendet und nicht PortB !


Im 2. Beispiel hast Du das mit dem PinChange-Interrupts verwechselt (PCINT), bzw. alles auf einmal gesetzt, das führt i.d.R zu einem Reset und der AVR beginnt von vorne, und man sieht nix.
Also erstmal die Zeile mit PCMSK weglassen.

Um den INT0 zu aktivieren musst Du im Register GIMSK das Flag INT0 setzen.
Dann wird die ISR auch verwendet, die Du schon angelegt hast.

bL1nK
04.03.2007, 12:22
der pull-up ist schon beabsichtigt? sprich dein taster zieht auf masse oder?

frankz
04.03.2007, 20:54
Hallo,

richtig den PB1 habe ich an die Taste angeschlossen und er Taster liegt an Masse. Ich habe auch noch einen Pullup Widerstand von 1kOhm zusätzlich an PB1 angeschlossen, aber das bringt auch nicht. Hier mal der ganze Code. Wenn ich den Interrupt einschalte geht das LED aus und leutet kurz auf. Egal ob ich den Taster drücke oder nicht. Habe auch PCMSK mal rausgeschmissen und den Attiny gewechselt. Überall das gleiche. Keine Reaktion auf einen Tastendruck.https://www.roboternetz.de/phpBB2/images/smiles/eusa_wall.gif
Brick wall


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

int main( void )
{

DDRB = 0xFF; // Alles als Ausgang deklarieren
DDRB &= ~(1<<PORTB1); // PB1 als Input setzen
PORTB |= (1 << PB1); // Pin 1 auf High
PORTB |= (1 << PINB4); // LED an

/* PCMSK |= (1 << PB1);
MCUCR &= ~(1<<ISC01) & ~(1<<ISC00);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
sei(); // Globalen Interrupt zulassen
*/
while(1)
{

if( bit_is_clear(PINB, PB1))
PORTB |= (1 << PB4);
else
PORTB &= ~(1 << PB4);
}
}

ISR(INT0_vect)
{
int i;
PORTB &= ~(1 << PINB4);
for(i = 0;i <10; i++)
_delay_ms(10);
}


Gruß

Frank

bL1nK
04.03.2007, 21:21
hast nen logik fehler, schau dir nochmal die if-else an und was du im interrupt machst.

wenn du nicht drauf kommst meld dich nochmal ;) aber aus fehlern lernt man(n), also frohes tüfteln *daumendrück*

frankz
05.03.2007, 18:16
hi blink,

anscheinend habe ich eine Brett vor dem Kopf.

if( bit_is_clear(PINB, PB1)) -> Wenn das Pin PB1 auf Low
PORTB |= (1 << PB4); -> Dann LED an
else
PORTB &= ~(1 << PB4); -> Sonst aus.

Im Interrupt mache ich immer das LED aus. Dann einen Delay.

Wo ist da der Fehler???????

Gruß

Frank

bL1nK
05.03.2007, 19:14
- taster nicht gedrückt: PB1 high
- setzte PB4 low

- taster gedrückt PB1 low
- setze PB4 high
- taster logelassen -> rising edge -> interrupt -> lösche PB4

frankz
05.03.2007, 22:23
schade, dass ist es nicht. Hatte den Interrupt ja auskommentiert. Ich verstehe einfach nicht, warum das Ding mir nicht den Wert zurück gibt, der an dem PB1 anliegt. Was ich auch nicht verstehe ist, dass wenn ich den Interrupt rein nehme er immer dort rein geht, ohne das ich den Taster drücke. Selbst wenn ich den Taster drücke geht er auch rein. Bin voll am verzeifeln.

Gruss

Frank

bL1nK
06.03.2007, 06:34
du willst den wert an PB1? dann nimmst einfach das macro.



#define VALUEPB1 ((PINB & (1<<PB1)) > 0 ? (1):(0))

switch(VALUEPB1)
{
case 0: //bit is cleared
break;
case 1: //bit is set
break;
default: //fallthru
break;
}

robocat
06.03.2007, 12:37
hallo frankz,
das ist seltsam.. ich habe eben mit deinem code gespielt, und dabei festgestellt, dass es funktioniert, wenn man das hier macht:

DDRB = (1<<PORTB1)|(1<<PORTB3);
oder DDRB = (1<<DDB1)|(1<<DDB3);

pb1 ist bei mir die led, pb3 der taster, beide gehen auf masse.

kann mir das jmd erklären? steh irgendwie aufm schlauch..

im datenblatt steht doch explizit:

The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written logic one, Pxn is configured as an output pin. If DDxn is written logic zero, Pxn is configured as an input pin.

gruesse von der etwas verwirrten katz

bL1nK
06.03.2007, 12:46
im DDRx stellst du die 'richtung' des pins ein

setzt (shiftest) du im DDRx an die stelle vom pin ne 1 hast du ihn als output deklariert, bei 0 (default) hast du ihn als input.

@cat was kappierst du nicht?

robocat
06.03.2007, 12:51
dass ich mit DDRB = (1<<DDB1)|(1<<DDB3); led und taster als ausgang deklariere, der taster aber dann funktioniert. setze ich ihn mit DDRB=~(1<<DDB3); als eingang und schalte den pullup ein, klappt es nicht.

bL1nK
06.03.2007, 12:56
weil der taster am int0 hängt du du wahrscheinlich den int0-interrupt eingeschalten hast. sprich der interrupt wird wohl den pin, egal was im DDR steht, als input deklarieren sonst macht der int0 doch keinen sinn?

robocat
06.03.2007, 13:05
keine interrupts. hier der komplette code:

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

int main( void )
{
DDRB = (1<<DDB1)|(1<<DDB3); // pin 1 & 3 als ausgang (!?)
PORTB |= (1 << PB1); //pullup
PORTB |= (1 << PINB3); //pullup

while(1)
{

if( bit_is_clear(PINB, PB3))
PORTB |= (1 << PB1); // led an
else
PORTB &= ~(1 << PB1); // led aus
}
}

//EOF
man kann zwar den status eines pins auch auslesen, wenn er als ausgang geschaltet ist, aber DDxn verhält sich irgendwie genau umgekehrt, als im datenblatt beschrieben.

gruesse

bL1nK
06.03.2007, 13:19
DDRB |= (1<<PB4) //output LED
PORTB &= ~(1<<PB4) //set PB4 low, LED off

DDRB &= (1<<PB1) //input switch
PORTB != (1<<PB1) //pullup for switch

while(1)
{
if (bit_is_clear(PINB, PB1)
PORTB |= (1<<PB4); //turn LED on
else
PORTB &= ~(1<<PB4); //turn LED off
}

robocat
06.03.2007, 13:36
ich will jetzt keinen streit mit dir, deshalb nur kurz:
1. strichpunkte dazugemacht
2. klammer geschlossen bei if()
3. test: led 'glimmt' wegen pullup, taster hat keine wirkung

dass du den code nicht getestet hast, liegt aufgrund der fehler nahe. woher nimmst du also die gewissheit, recht zu haben?

bL1nK
06.03.2007, 13:44
boah, wenn schon jemand copy&paste macht... für sowas hat man nen compiler :P

1. hab nix da zum testen
2. durch logisches denken

versuch mal statt dem bit_is_clear () mein makro von oben


VALUEPB1 ((PINB & (1<<PB1)) > 0 ? (1):(0))

irgendwo muss ja der fehler sein :P

robocat
06.03.2007, 14:33
soweit ich es jetzt (endlich) begreife, kann man die internen pull-ups nur verwenden, wenn der port als ausgang geschalten ist (a8 datasheet tabelle 20 seite 53). ansonsten ist ein externer pullup nötig.

was soll eigentlich das hier bewirken?

PORTB != (1<<PB1) //pullup for switch
damit vergleichst du die werte und verwirfst das ergebnis. erzähl den leuten halt bitte nicht so nen quark!

bL1nK
06.03.2007, 15:09
substituiere ! mit | :D tippfehler

frankz
06.03.2007, 19:44
Hallo,

also ich könnte schwören, dass ich das auch schon ausprobiert habe den Eingang als Ausgang zu initialisieren. Aber es funktioniert jetzt zumindestens mit der Abrage des PB1.

Taster nicht gedrückt -> Led an
Taster gedrückt -> Led aus

Komisch - verstehen tue ich das nicht, da ich einen exteren Pull Up Widerstand angeschlossen hatte, aber das Ergebnis zählt ja nur;-). Ich denke ich verzichte vorerst auf den Interrupt.

Vielen Dank.

bL1nK
06.03.2007, 19:58
äh welche lösung hast du jetzt genommen?

frankz
06.03.2007, 20:16
Hallo, die Lösung mit dem Markro funktioniert auch nur, wenn ich auch den PIN mit den Taster als Ausgang initialisiere. Wenn ich den PB1 als Input initialisiere, klappt auch die Makro Lösung nicht (ich wunder mich immer noch). Genauso gut klappt aber auch die auskommentierte Lösung mit der If-Anweisung.

Hier das was klappt:

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

#define VALUEPB1 ((PINB & (1<<PB1)) > 0 ? (1):(0))

int main( void )
{

DDRB = 0xFF; // Alles als Ausgang deklarieren

PORTB |= (1 << PB1); // Pin 1 auf High
PORTB |= (1 << PINB4); // LED an

while(1)
{
switch(VALUEPB1)
{
case 0: //bit is cleared
PORTB |= (1 << PB4);
break;
case 1: //bit is set
PORTB &= ~(1 << PB4);
break;
default: //fallthru
break;
}

/*
if( bit_is_clear(PINB, PB1))
PORTB |= (1 << PB4);
else
PORTB &= ~(1 << PB4);

*/

}
}

noch einmal vielen Dank.
Gruß Frank

wkrug
06.03.2007, 21:47
Interupt aktiv bei Port als Ausgang:
Das die Interupts INT0 bei dem entsprechenden Pin funktionieren auch wenn dieser als Ausgang definiert ist, ist kein Bug sondern ein Feature.

Man kann nämlich dadurch einen Software Interrupt auslösen.

Wenn Du das PORTx Register auf 1 setzt und DDRx auf 0, dann wird der Pullup aktiviert, wie Du schon richtig erkannt hast.
Änderst Du aber im nachhinein das DDRx Register auf 1 wird der entsprechende Pin fest auf 1 gesetzt weil PORTx ja immer noch 1 ist.