Forum: Mikrocontroller und Digitale Elektronik Einfachen Wert von I/O-Port einlesen klappt nicht


von Joschua C. (Gast)


Lesenswert?

Moin

Ich arbeite gerade das AVR-Tutorial hier von Mikrocontroller.net durch 
(hab von null angefangen und ja, das soll so ne Art Entschuldigung sein 
;D) und bin grad beim Thema Vergleiche (also breq, cp, brlo, bla blubber 
und so weiter) und wollte einfach mal einen davon ausprobieren. Also hab 
ich an mein myAVR-Board light mit nem Atmega8A Controller einfach mal 
einen Taster und eine LED angeklemmt. Die LED ist an PORTB5 dran und der 
Taster an PORTD7.

Jetzt soll in einer Dauerschleife immer wieder das Signal an PIND mit 
der Konstanten 0b10000000 verglichen werden, die nur dann vorliegt, wenn 
amn den Taster loslässt. Glaube ich jedenfalls. =D

Bei meinem Programm leuchtet diese LED aber einfach durchgehend. Wie ich 
auf den Taster hämmer ist der rotzegal. Wenn ich den Taster an PORTD5 
anschließe und einfach in einer Dauerschleife das Signal an PIND in 
PORTB (wo ja die LED rumoxidiert) schiebe, geht die LED beim drücken des 
Tasters aus. Also müsste die Verkabelung doch korrekt sein.
1
.EQU XTAL=3686400
2
.include "m8def.inc"
3
.include "Initial.asm"
4
.org 0x000          ; Interruptvektoren
5
.org INT0addr                 ; External Interrupt0 Vector Address              
6
.org INT1addr                 ; External Interrupt1 Vector Address      
7
.org OC2addr                  ; Output Compare2 Interrupt Vector Address                  
8
.org OVF2addr                 ; Overflow2 Interrupt Vector Address                  
9
.org ICP1addr                 ; Input Capture1 Interrupt Vector Address              
10
.org OC1Aaddr                 ; Output Compare1A Interrupt Vector Address            
11
.org OC1Baddr                 ; Output Compare1B Interrupt Vector Address            
12
.org OVF1addr                 ; Overflow1 Interrupt Vector Address          
13
.org OVF0addr                 ; Overflow0 Interrupt Vector Address            
14
.org SPIaddr                  ; SPI Interrupt Vector Address            
15
.org URXCaddr                 ; USART Receive Complete Interrupt Vector Address           
16
.org UDREaddr                 ; USART Data Register Empty Interrupt Vector Address         
17
.org UTXCaddr                 ; USART Transmit Complete Interrupt Vector Address          
18
.org ADCCaddr                 ; ADC Interrupt Vector Address            
19
.org ERDYaddr                 ; EEPROM Interrupt Vector Address         
20
.org ACIaddr                  ; Analog Comparator Interrupt Vector Address             
21
.org TWIaddr                  ; Irq. vector address for Two-Wire Interface            
22
.org SPMRaddr                 ; SPM complete Interrupt Vector Address  
23
.org INT_VECTORS_SIZE
24
RESET:
25
26
27
28
29
  stack_init    ;Makro aus Initial.asm, setzt Stackpointer
30
  
31
  ldi r16, 0x00    ;PORTB wird als Ausgang geschaltet
32
  out DDRD, r16    ;PORTD wird als Eingang mit Pullups geschaltet
33
  
34
  ldi r16, 0xFF
35
  out DDRB, r16
36
  
37
  ldi r16, 0xFF
38
  out PORTD, r16
39
  
40
  
41
loop_betrieb:      ;Startpunkt der Dauerschleife
42
43
  in r16, PIND    ;PIND einlesen (hier klemmt der Taster dran)
44
  cpi r16, 0b10000000  ;Diesen Wert mit dem vergleichern, der ohne Drücken vorliegt
45
  
46
breq led_off      ;Stimmen diese überein, wird zum Label led_off gesprungen, wo die LED ausgeschaltet wird
47
  
48
  ldi r16, 0xFF    ;Sonst wird sie hier eingeschaltet
49
  out PORTB, r16
50
rjmp loop_betrieb    ;und das Programm springt wieder zum Anfang der Dauerschleife
51
52
led_off:      ;Hier landet man wenn von breq weitergeleitet wird
53
  ldi r16, 0x00    ;Die LED wird ausgeschaltet
54
  out PORTB, r16
55
  
56
rjmp loop_betrieb    ;Und das Programm springt zurück zum Anfang der Schleife

Naja. Das wars. Für mehr Infos, natürlich einfach fragen. Das fällt mir 
jetzt so ein.

Grüße
Joschua

von Maik M. (myco)


Lesenswert?

an dieser Stelle:
1
in r16, PIND    ;PIND einlesen (hier klemmt der Taster dran)
2
cpi r16, 0b10000000  ;Diesen Wert mit dem vergleichern, der ohne Drücken vorliegt

gehst du davon aus, das alle anderen Pins des Ports low sind. Hast du 
dafür durch externe Beschaltung gesorgt? Deine Pullups sind high, also 
wenn du die anderen Pins nicht beschaltet hast, ließt der AVR immer 
0bX1111111 wo X für deinen Button steht.

Entweder du machst noch ein AND rein, zB:
1
in r16, PIND    ;PIND einlesen (hier klemmt der Taster dran)
2
andi r16, 0b10000000  ;andere Bits entfernen
3
cpi r16, 0b10000000  ;Diesen Wert mit dem vergleichern, der ohne Drücken vorliegt

oder du schaust dir mal andere Instructions an, wie zB: SBRC, SBRS, 
SBIC, SBIS

von Dietrich L. (dietrichl)


Lesenswert?

Joschua Conrad schrieb:
> .org 0x000          ; Interruptvektoren

Fehlt da nicht noch ein
   rjmp RESET           ?

von Stefan F. (sfrings)


Lesenswert?

Nein, da fehlt kein RJUMP. Sofern man nichts besonderes angibt, fängt 
das Programm an Adresse 0 an, und das ist bereits der Reset Vektor.

Erst wenn er Interrupts verwendet, wird ein Sprung nötig, weil sich 
sonst das Programm mit dem Interrupt-Vektoren überlappt.

von 006 mit der Lizenz zum Trollen (Gast)


Lesenswert?

Stefan Frings schrieb:
> Erst wenn er Interrupts verwendet, wird ein Sprung nötig, weil sich
> sonst das Programm mit dem Interrupt-Vektoren überlappt.
Er hat ja .org INT_VECTORS_SIZE angegeben und eine Sprungmarke Reset ist 
auch vorhanden, da würde ich dann schon einen rjmp an Pos. 0 spendieren. 
Nötig ist es wohl nicht, der Prozessor arbeitet halt die leere Tabelle 
ab (NOP oder was da auch drin liegt) bevor er anfängt.

von Sebastian S. (amateur)


Lesenswert?

Eigentlich ist in dem Beispiel sehr viel in die Hose gegangen:
1. Die Interrupttabelle ist falsch.
Zugegeben, wenn diese nicht genutzt wird steht in der ganzen Tabelle
0x00 oder 0xFF (FLASH=Leer) - dem nach je.
0x00 wird, so glaube ich als NOP interpretiert
0xFF - keine Ahnung
Solltest du aber den einmal angefangenen Quellcode erweitern wollen,
so wirst Du aber bald darüber stolpern, dass die ganze Folge von orgs
keine Funktion hat, solange Du nichts einfügst (Code oder Konstanten).
Nur die Zeile: ".org INT_VECTORS_SIZE" hat zur Folge das die 
Stackinitialisierung
an der angegebenen Stelle erfolgt.

Also unbedingt:
org 0x0
jmp  reset  ; bei kurzen Strecken auch rjmp

Solltest Du nämlich einmal die Strungtabelle nutzen, so wird die CPU bei 
ihrem "Durchmarsch" durch die Tabelle mit ihren Vektoren, diese als 
Befehle interpretieren.
Das Ergebnis dürfte recht interessant, aber kaum verhersagbar, sein.

Übrigends: Solange Du nur herum'jumptst', kannst Du dir auch die 
Initialisierung des Stacks sparen. Der wird meist bei call oder echten 
Unterbrechungen benötigt.

Die Problematik der Bit-Behandlung bzw. Maskierung mit UND wurde ja 
schon von anderer Seite angesprochen.

'nen Amateur

von Joschua C. (Gast)


Lesenswert?

Moin
Also erstmal danke für die vielen Antworten.

In der Interrupttabelle stand mal nach jeder Marke rjmp RESET, im 
Tutorial stand aber, dass man das bei angabe von allen .org auch 
weglassen kann.

Den Stack bereite ich jedes mal vor. Ich vergesse es sonst nämlich immer 
und wunder mich dann wieso rcall nett läuft. Passiert mir öfter. Und 
sind ja nur ein paar Takte.

Und zu guter letzt vielen dank Maik. Ich hab die Zustände der anderen 
Pins voll verpeilt. Man. Echt peinlich.

Vielen Dank Leute
Joschua

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.