Forum: Mikrocontroller und Digitale Elektronik Problem mit Programm für ATmega8


von Chris H. (chrismaik)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich habe mir zu Weihnachten ein STK500 zulegen lassen und komme soweit 
(d.h. das was ich mache verstehe ich auch ^^) klar damit. Ich scheitere 
aber bei den logischen Verknüpfung. Das liegt aber wohl eher daran dass 
ich in der Ausbildung mit der Simatic S7 zu tun hatte und da war das 
alles anders.

Meine Zielstellung ist eigentlich ziemlich simpel: 2 Taster werden 
gedrückt, solange diese 2 Taster gedrückt sind leuchtet 2 LEDs auf dem 
STK.
Ich habe einen ATmega8 und habe mit Assembler angefangen. Das Programm 
von dem ich mir denke, dass es eigentlich Funktionieren müsste ist im 
Anhang (AND.asm).

Wenn ich die ganze Sache in den Speicher geladen habe, dann passiert 
aber nicht das was ich beabsichtige. In der Simulation passiert aber das 
richtige.
Ich brauche bitte eure Hilfe, ich verzweifel hier sonst noch.

Wenn ich irgendwo was vergessen hab, dann sagt bescheid. Und wenn ihr 
Tipps für einen Anfänger habt, dann immer her damit :)

Mit freundlichen Grüßen
Chris Maik

von Danny (Gast)


Lesenswert?

sorry hab hier kein STK rumliegen. An welchen Pins hängen die Taster? An 
welchen die Leds? Soll ein Taster eine Led ansteuern oder sollen beide 
Leds angehen, wenn beide Knöpfe gedrückt sind?

von Oliver J. (skriptkiddy)


Lesenswert?

1
cpi r16, 0x0A    ;Inhalt von r16 mit der Konstanten

hier liegt der Hund begraben. Diese Bedingung ist nur wahr, wenn alle 
anderen Pins des Ports wirklich auf Low liegen. Das wird aber fast immer 
nicht der Fall sein.

Also wenn nicht am Port folgendes anliegt, ist es immer ungleich:
00001010


Gruß Oliver

von Klaus W. (mfgkw)


Lesenswert?

Du meinst die Taster auf dem STK500, die man erst mit Kabeln mit einem 
der Ports verbinden muß?

von Oliver J. (skriptkiddy)


Lesenswert?

Außerdem sind die Taster low-aktiv zu interpretieren.

von Chris H. (chrismaik)


Lesenswert?

@Danny:
Die LEDs sind an Port B und die Taster an Port D. Nochmal zur Funktion: 
Wenn beide Taster gedrückt sind (also wirklich nur diese beiden Taster), 
dann sollen die LEDs angehen. Ich nutze NUR die sache die auf dem STK 
drauf sind (Taster, LEDs).

@Oliver:
Und wie bekomme ich ein klares Low auf alle anderen Pins? Kommt das 
nicht durch die Pullups?

von Peter R. (pnu)


Lesenswert?

Du willst doch nur die bits 1 und 3 von portd abfragen.

1. Schritt Pin lesen:

 in r16,pind

2. Schritt: nicht benutzte Pins maskieren:

 andi r16,0x0a

dann sind alle nicht benutzten bits zu Null gemacht

3. Schritt: eigentliche Abfrage für die bits 1 und 3: cpi r16,0x0a

von Oliver J. (skriptkiddy)


Lesenswert?

Chris Hilarius schrieb:
> Und wie bekomme ich ein klares Low auf alle anderen Pins?
Du brauchst kein klares low auf den anderen Pins. Dein Programm muss so 
gestrickt sein, dass es die anderen Pins einfach ignoriert.

>Kommt das nicht durch die Pullups?
Pullups ziehen den Pegel gegen VCC und erzeugen ein High am 
entsprechenden Pin.

Gruß Oliver

von Danny (Gast)


Lesenswert?

Chris Hilarius schrieb:
> Die LEDs sind an Port B und die Taster an Port D

Mannomann. Den Unterschied zwischen Pin und Port kennst
auch noch nicht, heh?

von Klaus W. (mfgkw)


Lesenswert?

woraus schließst du das?

Wenn die LEDs an Port B sind und die Taster an Port D, dann heißt das 
doch nicht, daßer nicht zwischen Pin und Port unterscheiden kann?
Oder was habe ich übersehen?

von Danny (Gast)


Lesenswert?

weil er die Frage nach den Pins mit den Ports beantwortet?

von Hans O. (piwibit)


Lesenswert?

Danny schrieb:
>weil er die Frage nach den Pins mit den Ports beantwortet?

Danny schrieb:
> An welchen Pins hängen die Taster? An welchen die Leds?

Nix für ungut Danny, aber
du wirfst auch PIN (=Eingang =Taster )
und PORT ( =Ausgang =LED) durcheinander.

von Klaus W. (mfgkw)


Lesenswert?

Danny schrieb:
> weil er die Frage nach den Pins mit den Ports beantwortet?

ok, ist ein Argument.

Wobei die Pins auch aus dem Quelltext ersichtlich wären, aber egal.

Hans O. schrieb:
>> An welchen Pins hängen die Taster? An welchen die Leds?
>
> Nix für ungut Danny, aber
> du wirfst auch PIN (=Eingang =Taster )
> und PORT ( =Ausgang =LED) durcheinander.

äh, Pin ist gleich PIN (PINA/PINB/PINC/PIND)?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Das schon, aber das ist auch nicht verwunderlich. Liegt doch der 
Port(Ausgang) auf  bis zu Acht Pin's (Stiften) welche per 
Daterichtungsregister ebenso als PIN (Eingänge) geschaltet werden 
können, Das ist sogar der Defaultzustand.

Also Termini und Mnemonic studieren insbesondere solche Feinheiten

von Max (Gast)


Lesenswert?

Ich weiss nicht was ihr habt.

Der Ausdruck "Port" ist vollkommen richtig in der Verwendung, die er 
gewählt hat und stimmt in der Verwendung mit dem Datenblatt (vrgl. 
Block-Diagramm) überein.

Register-Naming (PINx/PORTx) würde ich nicht als Termini/Mnemonic 
bezeichnen. Es ist eine rein controllerspezifische Nomenklatur und wurd' 
nichtmal angesprochen vom TE

von Danny (Gast)


Lesenswert?

um das nochmal aufzuklären:

PIN ist das Eingangsregister
PORT ist das Ausgangsregister

Pin ist ein kleines Stückchen Draht am IC.

Natürlich kann man die Pins aus dem Quelltext
lesen. Aber der Quelltext scheint ja in der
ursprünglichen Fassung noch fehlerhaft zu sein.

von Oliver J. (skriptkiddy)


Lesenswert?

OT: Mann sind hier spitzfindige Leute unterwegs.

von Jobst M. (jobstens-de)


Lesenswert?

1
    ...
2
    breq gleich      ;wenn r16=0xA springe zu gleich
3
    brne ungleich    ;wenn r16=/=0xA springe zu ungleich
4
5
ungleich:          
6
    ...

Also, wenn Du schon feststellst, daß r16 gleich 0x0A ist und verzweigst, 
dann brauchst Du anschliessend nicht nochmal zu überprüfen, ob r16 nun 
nicht 0x0A ist, denn es kann es ja nicht sein. Wenn es doch so sein 
sollte, solltest Du danach noch den möglichen Fehler abfangen und nicht 
einfach in den nächsten Programmteil laufen lassen.

Ansonsten ist der Hinweis, die anderen Eingänge auszumaskieren der 
richtige.

Du kannst zur Probe in Deinem Programm auch mal die 0x0A durch 0xF5 
ersetzen.


Gruß

Jobst

von Peter ⛄ W. (Firma: Huddel und Brassel Ltd.) (jaffel) Benutzerseite


Lesenswert?

Oliver J. schrieb:
> OT: Mann sind hier spitzfindige Leute unterwegs.

Lol, Du kennst mikrocontroller.net noch nicht. Lies mal ein paar Monate 
mit, wirst Dich wundern was hier so abgeht. Und meist sind es dann jene, 
die keine Eier haben, ihren Unsinn angemeldet zu posten.

von oldmax (Gast)


Lesenswert?

Hi Chris
Es sind zwar schon die richtigen Antworten gegeben, aber ich 
denke,trotzdem, das nochmal eine Antwort hilfreich ist. Wenn du in der S 
7 Welt ausgebildet wurdest, dann sind Signalzustände "0" und "1" 
bekannt. Des weiteren auch, auf welches Spannungspotential sie sich 
beziehen. Nun ist ein µC keine S 7 und der Taster hinterläßt im offenen 
Zustand kein Potential, er ist ja offen. Hochohmig würde aber ein 
Controller mit allem möglichen definieren. Deshalb hast du richtiger 
Weise auch die pull-Ups zugeschaltet. Somit liest du bei jedem Durchgang 
"11111111! ein. Also alle Eingänge des Ports sind "1". Wenn du nun die 
Taster drückst, legst du den Eingang auf "0" weil er gegen GND schalten 
sollte. (bei einer solchen Konfiguration. ob es das STK auch so macht, 
weiß ich nicht, da ich ihn nicht habe.)
Domit liegt dann im Register "11110101" vor, also, nicht "0A"hex, 
sondern "F5"hex. Setz mal direkt hinter den Einlesebefehl einen "COM" 
Befehl. Der invertiert die Bits und du erhälst für einen betätigten 
Schalter auch die gewünschte "1". Des weiteren darfst du auch ruhig eine 
Maske mit einem "And" Befehl anwenden, um z. B. unerwünschte Bits 
auszublenden. Hier mal ein bearbeiteter Auszug aus deinem Programm:
1
.include "m8def.inc"
2
;**********************************
3
;*  --- Initialisierung Port ---  *
4
;**********************************
5
    ldi r16, 0xff    ;0xff definiert PortB
6
    out DDRB, r16    ;als Ausgang
7
8
    ldi r16, 0x00    ;0x00 definiert PortD
9
    out DDRD, r16    ;als Eingang
10
11
    ldi r16, 0xff    ;0xff aktiviert die Pull Up
12
    out PORTD, r16    ;Widerstaende fuer PortD
13
;*********************************
14
15
Main:        ;Beginn des Hauptprogramms
16
    
17
  in r16, PIND    ;Eingaenge an PORTD nach r16 einlesen
18
; ------------------------ Ergänzung --------------------------------
19
  COM r16      ;Bits in r16 "drehen"
20
  AndI r16, 0b00001010  ;Bit 1 und 3 in r16 ausmaskieren
21
; -------------------------------------------------------------------  
22
  cpi r16, 0x0A    ;r16 mit der Konstanten            ;0xA vergleichen
23
  breq gleich    ;wenn r16=0xA springe zu gleich
24
25
;------ diese Zeile ist über ! Wo sonst soll das Programm hin ? -----
26
  brne ungleich    ;wenn r16=/=0xA springe zu ungleich
27
;--------------------------------------------------------------------
28
29
ungleich:          
30
  ldi r17, 0x00    ;Alle Ausgangspins an
31
  out PORTB, r17    ;PORTB auf LOW schalten
32
  rjmp Main
33
34
gleich:            
35
  ldi r17,0b00100001  ;Ausgangspins an PORTB
36
  out PORTB, r17    ;auf HIGH schalten
37
38
  rjmp Main

Auch wenn es hier keine Rolle spielt und den Code unnütz aufbläht, 
erinner ich dich trotzdem mal, wie eine SPS ihr Programm bearbeitet.
Eingänge lesen
bearbeiten
Ausgänge setzen
Wen du mit den ersten Programmen beginnst, dann solltest du dir 
folgendes angewöhnen, auch wenn es etwas Rechenleistung kostet.
Programm Start mit Aufruf von Initialisierungsroutinen
Danach die Schleife:
Zuerst einlesen der Eingänge und Ablegen in einer Variablen mit 
richtiger Signallage
Dann bearbeitungsroutinen
dann eine Ausgaberoutine mit einer Variablen, in der die Bits für die 
Ausgänge gesetzt sind. Ich halte es speziell bei Assembler für sehr 
hilfreich, in der Schleife nur Unterprogrammaufrufe zu haben. Die 
Routinen sind somit u.U. für andere Programme Nutzbar.
Etwa so:
1
.include "m8def.inc"       ; Definitionen für ATMEGA8
2
3
;****************************************************************
4
; Beginne mit der Namensgebung für Register und Variablen
5
;****************************************************************
6
7
.DEF   Access  = R0   ; Speicherzugriffsregister
8
.DEF   Zero  = R1   ; Zwischenspeicher aus anderen Merkern
9
.DEF   Ablage  = R2   ; Zwischenspeicher aus anderen Merkern
10
 etc
11
12
13
.def  Reg_A  = r16    ; Register mit erweiterten Funktionen
14
;etc  
15
16
; Register 26- 31 sind bereits vergeben
17
; X = XL + XH = R 26 + R 27
18
; Y = YL + YH = R 28 + R 29
19
; Z = ZL + ZH = R 30 + R 31
20
21
22
;**************************************************************
23
;* Im Datensegment werden die Variablen hinterlegt.             *
24
;**************************************************************
25
.DSEG
26
27
New_In_A:  .Byte 1    ; Eingänge A aktuell
28
New_In_B:  .Byte 1    ; Eingänge B aktuell
29
Old_In_A:  .Byte 1    ; Ablage Eingänge A
30
Old_In_A:  .Byte 1    ; Ablage Eingänge B
31
Out_A:    .Byte 1    ; Aufgearbeitete  Ausgänge A
32
Out_B:    .Byte 1    ; Aufgearbeitete  Ausgänge B
33
34
;weitere VAriablendefinitionen
35
36
;**************************************************************
37
;*     Begin des Codesegmentes       *
38
;**************************************************************
39
.CSEG
40
.org 0000
41
Reset:  RJMP   Start  ; überspringen der Interrupt Vector Tabelle
42
;**************************************************************
43
;* -------------- Interruptvektortabelle ---------------------*
44
;*            Es macht Sinn, sie immer mitzuführen            *
45
;**************************************************************
46
.ORG INT_VECTORS_SIZE 
47
48
.org INT0addr   RETI  ; External Interrupt0 Vector Address    
49
.org INT1addr  RETI  ; External Interrupt1 Vector Address       
50
.org OC2addr  RETI  ; Output Compare2 Int. Vector Address       
51
.org OVF2addr  RETI  ; Overflow2 Interrupt Vector Address       
52
.org ICP1addr  RETI  ; Input Capture1 Int. Vector Address       
53
54
.org OC1Aaddr  RJMP   isrTimer1   ; Einsprungadresse ISR Timer0
55
56
.org OC1Baddr  RETI    ; Output Compare1B Int. Vector Address       
57
.org OVF1addr  RETI    ; Overflow1 Interrupt Vector Address       
58
.org OVF0addr  RETI    ; Overflow0 Interrupt Vector Address       
59
.org SPIaddr  RETI    ; SPI Interrupt Vector Address       
60
                    
61
.org URXCaddr  RJMP  int_rxc  
62
; USART Rec. Compl. Int. Vector Address       
63
       
64
.org UDREaddr  RETI    ; USART Data Reg. Empty Int. Vect. Addr.       
65
.org UTXCaddr  RETI     ; USART Transmit Compl. Int. Vect. Addr.       
66
.org ADCCaddr  RETI    ; ADC Interrupt Vector Address       
67
.org ERDYaddr  RETI    ; EEPROM Interrupt Vector Address       
68
.org ACIaddr  RETI    ; Analog Comparator Int. Vector Address       
69
.org TWIaddr  RETI    ; Irq. vect. addr. for Two-Wire Interface       
70
.org SPMRaddr  RETI    ; SPM complete Interrupt Vector Address       
71
         
72
73
Start:  
74
  LDI  Reg_A ,high(RAMEND)  ; Stack Pointer auf  RAMEND
75
  OUT  SPH, Reg_A    ; definiert in m8def.inc 
76
  LDI  Reg_A, low(RAMEND)  ; 
77
  OUT  SPL, Reg_A  
78
; Stackpointer ist u.a.  wichtig für Rücksprungadressen bei CALL-Anweisung
79
  RCALL  INIT_Timer    ; Initialisierungen in 
80
  RCALL  INIT_IO      ; Unterprogramme verpacken
81
  RCALL  INIT_Ser_Com     ; besser korrigierbar und
82
  RCALL  INIT_Variablen    ; exportierbar
83
LOOP:          ; Programmschleife
84
  RCALL  Read_IO      ; Eingänge lesen
85
  RCALL  Chk_Event      ; bearbeiten
86
  RCALL  Chk_Spezial     ; auswerten
87
  RCALL  Write_IO      ; Ausgabe an Port zuweisen
88
RJMP Loop
89
;*************************************
90
; beginne mit Initialisierungen      *
91
;*************************************
92
INIT_Timer:
93
RET
94
95
INIT_IO:
96
RET
97
98
INIT_Ser_Com:
99
RET
100
101
Init_Variablen:
102
RET
103
;************************************
104
; Unterprogramme in den Schleifen   *
105
;************************************
106
107
Read_IO:
108
RET
109
110
Chk_Event:
111
RET
112
113
Chk_Spezial:
114
RET
115
116
Write_IO:
117
RET

Nun kannst du nach und nach die Unterprogramme füllen.
Gruß oldmax

von Jürgen W. (juergen_w) Benutzerseite


Lesenswert?

Hallo,

Ich habe das mal im Simulator laufen lassen.
Beachte, das beim STK500 die LEDs bei Low leuchten !
So wie unten, müsste das Programm nach deinen wünschen laufen.



1
.include "m8def.inc"
2
;**********************************
3
;*  --- Initialisierung Port ---  *
4
;**********************************
5
    ldi r16, 0x00    ;0x00 definiert PortD
6
    out DDRD, r16    ;als Eingang
7
8
    ldi r16, 0xff    ;0xff aktiviert die Pull Up
9
    out PORTD, r16    ;Widerstaende fuer PortD
10
11
;   ldi r16, 0xff    ;0xff definiert PortB
12
    out DDRB, r16    ;als Ausgang
13
;*********************************
14
15
Main:        ;Beginn des Hauptprogramms
16
    
17
  in r16, PIND    ;Eingaenge an PORTD nach r16 einlesen
18
; ------------------------ Ergänzung --------------------------------
19
;fällt weg  - COM r16      ;Bits in r16 "drehen"
20
;andi setzt das Zero Flag, da braucht es kein cpi
21
  andi r16,1<<pind1|1<<pind3 ;So ist das besser lesbar
22
; -------------------------------------------------------------------  
23
;fällt weg  - cpi r16, 0x0A    ;r16 mit der Konstanten            ;0xA vergleichen
24
  breq leds_an    ;wenn r16=0xA springe zu gleich
25
26
;------ diese Zeile ist über ! Wo sonst soll das Programm hin ? -----
27
;fällt weg  brne ungleich    ;wenn r16=/=0xA springe zu ungleich
28
;--------------------------------------------------------------------
29
leds_aus:    ;beim STK500 schaltet eine 0 die LED ein !!       
30
  ldi r17, 0xff     ;Alle Ausgangspins an
31
  out PORTB, r17    ;PORTB auf High schalten
32
  rjmp Main
33
leds_an:     ;LEDs an Portb0 und 5 einschalten          
34
  ldi r17,~(1<<portb5|1<<portb0)   ;=0b11011110    ;0b00100001  ;Ausgangspins an PORTB
35
  out PORTB, r17    ;auf HIGH schalten
36
37
  rjmp Main

Grüsse Jürgen

von Jürgen W. (juergen_w) Benutzerseite


Lesenswert?

Noch eine Variante. Macht das gleiche wie oben, nur mit einer anderen 
Taktik.

1
.include "m8def.inc"
2
;**********************************
3
;*  --- Initialisierung Port ---  *
4
;**********************************
5
;Nach Reset sind alle Ports Eingang
6
;    ldi r16, 0x00    ;0x00 definiert PortD
7
;    out DDRD, r16    ;als Eingang
8
9
    ldi r16, 0xff    ;0xff aktiviert die Pull Up
10
    out PORTD, r16    ;Widerstaende fuer PortD
11
12
;   ldi r16, 0xff    ;0xff definiert PortB
13
    out DDRB, r16    ;als Ausgang
14
;*********************************
15
ser     r17             ;LEDs aus
16
ldi     r16,~(1<<portb5|1<<portb0)   ;=0b11011110 LEDs ein
17
18
Main:        ;Beginn des Hauptprogramms
19
sbic    pind,pind1      ;überspringen, wenn die Taste gedrückt ist
20
rjmp    led_aus
21
sbic    pind,pind3
22
rjmp    led_aus
23
out     portb,r16       ;LEDs 1 und 5 ein
24
rjmp    main
25
led_aus:
26
out     portb,r17
27
rjmp    main

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.