Forum: Mikrocontroller und Digitale Elektronik Input mit Attiny12 abfragen


von Niklas B. (niklas90)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Niklas Beuster schrieb:
> IN temp, PORTB          ;PortB als Eingang lesen

PINB

von Niklas B. (niklas90)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Niklas B. (niklas90)


Lesenswert?

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.

von Niklas B. (niklas90)


Lesenswert?

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
20
RJMP loop

von Karl H. (kbuchegg)


Lesenswert?

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.

von Niklas B. (niklas90)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

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.