Hallo,
ja, ich weiß, der Attiny12 ist out, aber ich hatte noch einen rumliegen
und wollte ihn für ein kleines Projekt verwenden. Da ich noch relativer
Anfänger bin, wollte ich erst einmal ein paar grundlegende Sachen
testen, bevor ich mein Projekt starte.
Und zwar geht es um eine Inputabfrage. Leider funktioniert nichts was
ich bis jetzt ausprobiert habe: Einen externen Interrupt abfragen (ich
habe den Code leider schon wieder gelöscht) und einfach während der
Laufzeit PORTB auslesen. Letzte Variante poste ich hier.
Der Code ist in Assembler im AVR-Studio geschrieben und der Chip wird
über das mySmartUSB light programmiert.
1
.INCLUDE "tn12def.inc"
2
3
.def temp = R16
4
5
.org 0x000
6
RJMP main
7
8
main:
9
LDI temp, (1<<PINB0)|(1<<PINB2)
10
OUT DDRB, temp ;nur PB0 und PB2 für Output
11
LDI temp, (1<<PINB1)
12
OUT PORTB, temp ;internen Pullup für den Eingang (PB1) hoch
13
14
CLR temp
15
16
loop:
17
IN temp, PORTB ;PortB als Eingang lesen
18
CLR R17
19
CPI temp, 2 ;PB1 vergleichen
20
BRNE nichtAn
21
LDI R17, (1<<PINB0)|(1<<PINB2)
22
nichtAn:
23
OUT PORTB, R17 ;wenn an PB1 ein Signal anliegt, schalte PB0 und PB2 an, sonst nicht
24
RJMP loop
Die Led's an PB0 und PB2 bleiben leider die ganze Zeit aus, egal was ich
probiere. (Die sollten doch angehen, wenn ich PB1 mit Minus verbinde?)
Ich hoffe jemand kann mir helfen.
Eieiei, so einen dummen Fehler hätte ich jetzt net erwartet, aber ok,
DANKE!!! Es funktioniert jetzt :) Achso und ich habe natürlich An/Aus
verwechselt, die Led's gehen jetzt an, wenn ich ein positives Signal
anlege, dass kriege ich aber hin.
Dafür
IN temp, PORTB ;PortB als Eingang lesen
CPI temp, 2 ;PB1 vergleichen
musst du dir noch was anderes einfallen lassen
Wenn du am Port für Ausgabezwecke ein paar Bits setzt, dann 'siehst' du
diese gesetztn Bits auch beim Einlesen vom Pin Register wieder.
D.h. In dem Moment, in dem du am Port B
LDI R17, (1<<PINB0)|(1<<PINB2)
die Bits 0 und 2 setzt, wirst du vom Pin Register keine exakte 2 mehr
einlesen können, selbst wenn du den Pin mittels Draht immer noch auf 5V
hältst.
Hm, wie meinst du das jetzt? Also wenn du auf dieses
Zeitverzögerungsproblem hinaus willst, wie es in IO-Grundlagen
beschrieben wird...ich habe mal aus Spaß ein NOP nach dem IN
geschrieben, aber da ändert sich auch nichts.
Achja, 2 Dinge, die mir jetzt noch komisch vorkommen:
Also nach dem ich den Fehler mit dem PINB berichtigt hatte,
funktionierte der Aufbau erstmal, aber jetzt leuchten die LED's alle und
es ändert sich nichts wenn ich am Eingang was mache, ich habe sogar
nochmal den alten Code draufgebrannt, aber es ändert sich nichts :(
Desweiteren bringt es irgendwie nichts die internen Pull-Ups hoch zu
ziehen, d.h. ich konnte (bevor der Chip jetzt nur noch die LED's
leuchten lässt) den Eingang aktivieren, wenn ich meinen Finger dran
gehalten habe.
Nun habe ich mal die Abfrage direkt per Bit-Test gemacht, es
funktioniert auch, aber die internen Pull-ups scheinen immer noch nicht
zu funktionieren, oder muss ich die IMMER setzen, also vor jedem Input,
quasi in der loop-Schleife?
1
.INCLUDE "tn12def.inc"
2
3
.def temp = R16
4
.def output = R17
5
6
.org 0x000
7
RJMP main
8
9
main:
10
LDI temp, (1<<PINB0)|(1<<PINB2)
11
OUT DDRB, temp ;nur PB0 und PB2 für Output
12
LDI temp, (1<<PINB1)
13
OUT PORTB, temp ;internen Pullup für den Eingang (PB1) hoch
14
15
loop:
16
CLR output
17
SBIC PINB, 1
18
LDI output, (1<<PINB0)|(1<<PINB2)
19
OUT PORTB, output ;wenn an PB1 ein Signal anliegt, schalte PB0 und PB2 an, sonst nicht
Niklas Beuster schrieb:> Nun habe ich mal die Abfrage direkt per Bit-Test gemacht, es> funktioniert auch, aber die internen Pull-ups scheinen immer noch nicht> zu funktionieren, oder muss ich die IMMER setzen, also vor jedem Input,> quasi in der loop-Schleife?
Was du noch nicht verinnerlicht hast ist, dass du mittels
OUT PORTB, .....
immer alle 8 Bit des Port Registers setzt. Jedes Bit entweder auf 0 oder
1. Aber es sind immer alle 8!
Das heisst
Du schaltest zwar hier
> LDI temp, (1<<PINB1)> OUT PORTB, temp ;internen Pullup für den Eingang (PB1) hoch
korrekt den Pullup Widerstand für PB1 ein.
Aber hier
> LDI output, (1<<PINB0)|(1<<PINB2)> OUT PORTB, output ;wenn an PB1 ein Signal anliegt, schalte PB0 und
schaltest du ihn wieder ab, weil das Bit für PINB1 auf 0 steht.
Achso, ok. Danke. Ich hatte es mir dann schon fast gedacht, weil sonst
würde ja auch nicht LDI, Rxy (1<<Bitsowieso) korrekt funktionieren,
nämlich das alle anderen, nicht erwähnten Bits auf 0 geschalten werden.
Jetzt ist mir alles klar, danke nochmal.
mfg, Niklas
Niklas Beuster schrieb:> Hm, wie meinst du das jetzt? Also wenn du auf dieses> Zeitverzögerungsproblem hinaus willst, wie es in IO-Grundlagen> beschrieben wird...ich habe mal aus Spaß ein NOP nach dem IN> geschrieben, aber da ändert sich auch nichts.
Nein, das meine ich nicht.
PORTB und PINB hängen zusammen.
Wenn du an PORTB das Bit 0 setzt, dann wirst du beim Abfragen von PINB /
Bit 0 diese von dir selbst gesetzte 1 auch wieder erhalten.
Dein eigentlicher Input ist auf Bit 1. Du vergleichst den kompletten
Wert den du von PINB erhältst mit 2.
IN temp, PINB
CPI temp, 2
Nehmen wir mal an, dieser Input Pin wäre tatsächlich auf 1.
Dann kriegst du auch tatsächlich von PINB die Zahl 2 zurück. Denn in
dezimal 2 ist ja genau das Bit 1 gesetzt.
2 = 00000010
Jetzt setzt du aber am PORTB das Bit 0.
Was passiert?
Beim Einlesen von PINB (sonst hat sich nichts verändert, Bit 1 ist immer
noch 1) kriegst du jetzt aber nicht mehr die Zahl 2, sondern du kriegst
die Zahl 3.
3 deshalb, weil das ja in Binärschreibweise
00000011
ist
Diese 1
00000011
^
|
die ist da, weil dein Eingangspin ja extern tatsächlich auf 1 gezogen
wurde
und diese 1
00000011
^
|
die ist da, weil dein Programm selber am PortB Bit 0 eine 1 ausgegeben
hat.
Das heisst: Wenn du mittels CPI eine Eingabe prüfen willst, die du
dadurch erhalten hast, dass du das komplette PIN Register ausgelesen
hast, dann musst du auch dafür sorgen, dass du auch tatsächlich nur die
Bits überprüfst, die du auch prüfen willst. In deinem Fall eben das Bit
1. Welchen Zustand Bit 0 hat, darf deine Abfrage nicht tangieren.
Am einfachsten erreicht man das, in dem man einfach die nicht
interessierenden Bits auf 0 setzt
IN temp, PINB
ANDI temp, 2
CPI temp, 2
durch die UND-Verknüpfung werden die restlichen Bits in temp, die dich
nicht interessieren, gezielt auf 0 gesetzt
00000011 das hast du vom PINB eingelesen
00000010 das ist die 2 in Binär
-----------
00000010 und das ist das Ergebnis der UND-Verknüpfung
Die 1 an Bitposition 1 ist da deswegen drinnen, weil in dem von PINB
Ausgelesenen ebenfalls an dieser Stelle eine 1 war. Im Vergleich
00000001 wieder: das hat man vom PINB bekommen. Beachte Bit 1
ist hier nicht gesetzt
00000010 wieder die 2 als Binärzahl
-----------
00000000 und das ganze UND-Verknüpft
Jetzt ist auch an Bitposition 1 keine 1 mehr vorhanden. Dies deshalb,
weil in dem vom PINB ausgelesenen Wert ebenfalls an Bitposition 1 eine 0
stand.
In Summe bildet diese UND-Verknüpfung also so etwas wie eine Maske. Alle
Bits, die in der Maske auf 1 sind lassen die entsprechende Bitposition
von der anderen Zahl ungehindert 'passieren'. Dort wo in der Maske ein
0-Bit steht, wird auch im Ergebnis eine 0 auftauchen. Und genau das
brauchst du, um gezielt ein einziges Eingansbit aus den 8 Bit, die du
vom Port gelesen hast, zu extrahieren. Denn du willst ja, dass deine
Abfrage (der Vergleich) auch tatsächlich nur auf dieses eine Bit
reagiert, ganz egal was die anderen Bits für Zustände haben.