Hallo,
ich betreibe einen ATmega16 in einer selbst entworfenen Schaltung und
habe Probleme mit der Funktion. Konkret soll der Mega von Port C alle
acht Pins einlesen, was praktischer weise gleich ein ganzes Byte ergibt.
Jetzt habe ich aber durchgehend Probleme, das Byte richtig einzulesen,
bzw. die gewünschte Funktion stellte sich nicht ein.
Um den Mega nicht wieder ausbauen zu müssen, habe ich nun ein zweites
Programm geschrieben, welches mangels anderer Schnittstelle das Byte von
Port C ausgibt, indem es jedes Bit nacheinander in verschiedenen
Pulsbreiten ausgibt. (Schema in Skizze, ich wüsste nicht ob das
Verfahren einen eigenen Namen hat).
Wenn ich nun an alle Pins jeweils Spannung anlege (oder nicht), brauche
ich nur am Oszilloskop Hold drücken, und kann mit die Ausgabe ansehen -
nach dem Startblock die einzelnen Bits der Reihe nach (LSB -> MSB).
Dabei stelle ich fest, dass der dritte bis sechste Pin (Bit 2-5) immer
einen kuzen Puls haben, also vom Mega als 0 behandelt werden.
Die Spannungen habe ich bis zu den Beinchen gemessen, selbst wenn
überall die selbe Spannung anliegt, die 4 mittleren Pins am Port C sind
immer null.
Das Programm habe ich mit Cut&Paste erstellt, und inzwischen mehrmals
gurchgesehen, da kann ich keinen Fehler feststellen (der Vollständigkeit
gebe ich es mal mit an).
1
.INCLUDE "m16def.inc" ;Includes the mega16 definitions file
2
3
4
5
.def temp = R16
6
.def tmp2 = R17
7
.def stat = R18
8
.def loop = R19
9
10
11
.CSEG
12
RESET:
13
rjmp INITIAL ; Einsprung ins Programm
14
15
;.ORG INT_VECTORS_SIZE ; dadurch wird für die Vektoren Platz gelassen
16
17
INITIAL:
18
ldi temp, 0x01 ; Pulsausgang auf Pin0 an Port B
19
out DDRB, temp ;
20
ldi temp, 0x00 ; Dateneingang, ein Byte
21
out DDRC, temp ;
22
23
ldi temp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
24
out SPL, temp
25
ldi temp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
26
out SPH, temp
27
28
29
30
Hauptschleife:
31
; Startsignal durchgeben
32
rcall Pause
33
ldi stat, 1
34
out PORTB, stat
35
rcall Pause
36
rcall Pause
37
rcall Pause
38
ldi stat, 0
39
out PORTB, stat
40
rcall Pause
41
; Startsignal fertig
42
43
; Bit 0
44
ldi stat, 1
45
out PORTB, stat
46
rcall Pause
47
in temp, PINC
48
andi temp, 0b00000001
49
brne Weiter0
50
ldi stat, 0
51
out PORTB, stat
52
Weiter0:
53
rcall Pause
54
ldi stat, 0
55
out PORTB, stat
56
rcall Pause
57
; Bit 0 fertig
58
59
60
; Bit 1
61
ldi stat, 1
62
out PORTB, stat
63
rcall Pause
64
in temp, PINC
65
andi temp, 0b00000010
66
brne Weiter1
67
ldi stat, 0
68
out PORTB, stat
69
Weiter1:
70
rcall Pause
71
ldi stat, 0
72
out PORTB, stat
73
rcall Pause
74
; Bit 1 fertig
75
76
77
; Bit 2
78
ldi stat, 1
79
out PORTB, stat
80
rcall Pause
81
in temp, PINC
82
andi temp, 0b00000100
83
brne Weiter2
84
ldi stat, 0
85
out PORTB, stat
86
Weiter2:
87
rcall Pause
88
ldi stat, 0
89
out PORTB, stat
90
rcall Pause
91
; Bit 2 fertig
92
93
94
; Bit 3
95
ldi stat, 1
96
out PORTB, stat
97
rcall Pause
98
in temp, PINC
99
andi temp, 0b00001000
100
brne Weiter3
101
ldi stat, 0
102
out PORTB, stat
103
Weiter3:
104
rcall Pause
105
ldi stat, 0
106
out PORTB, stat
107
rcall Pause
108
; Bit 3 fertig
109
110
; Bit 4
111
ldi stat, 1
112
out PORTB, stat
113
rcall Pause
114
in temp, PINC
115
andi temp, 0b00010000
116
brne Weiter4
117
ldi stat, 0
118
out PORTB, stat
119
Weiter4:
120
rcall Pause
121
ldi stat, 0
122
out PORTB, stat
123
rcall Pause
124
; Bit 4 fertig
125
126
127
; Bit 5
128
ldi stat, 1
129
out PORTB, stat
130
rcall Pause
131
in temp, PINC
132
andi temp, 0b00100000
133
brne Weiter5
134
ldi stat, 0
135
out PORTB, stat
136
Weiter5:
137
rcall Pause
138
ldi stat, 0
139
out PORTB, stat
140
rcall Pause
141
; Bit 5 fertig
142
143
144
; Bit 6
145
ldi stat, 1
146
out PORTB, stat
147
rcall Pause
148
in temp, PINC
149
andi temp, 0b01000000
150
brne Weiter6
151
ldi stat, 0
152
out PORTB, stat
153
Weiter6:
154
rcall Pause
155
ldi stat, 0
156
out PORTB, stat
157
rcall Pause
158
; Bit 6 fertig
159
160
161
; Bit 7
162
ldi stat, 1
163
out PORTB, stat
164
rcall Pause
165
in temp, PINC
166
andi temp, 0b10000000
167
brne Weiter7
168
ldi stat, 0
169
out PORTB, stat
170
Weiter7:
171
rcall Pause
172
ldi stat, 0
173
out PORTB, stat
174
rcall Pause
175
; Bit 7 fertig
176
177
178
rjmp Hauptschleife
179
180
181
182
Pause:
183
ldi loop, 160
184
Loop1:
185
dec loop
186
brne Loop1
187
ret
Woran kann es liegen, dass ich nicht den ganzen Port C einlesen kann?
Danke im voraus.
Auf den mittleren 4 Pins liegt das JTAG-Interface, das standardmäßig
aktiviert ist. Hast du es deaktiviert? Sonst könntest du diese Pins
nicht nutzen..
Ähm...
JTAG war tatsächlich eingeschaltet, damit als Fehlerquelle hätte ich
auch nicht mehr gerechnet.
Damit hat sich das Problem schon erledigt - Danke :)
Hi
Endlich mal einer, der in ASM programmiert.. und ich dachte schon, ich
gehör zu den ausgestorbenen.....
Mir ist nur aufgefallen, das du einen sehr langen Code in die
Hauptschleife packst. Dein Programm muß auch durch die vielen Pausen
ziemlichlangsam sein. Vielleicht muß es so sein, aber nur mal ein Tip:
1
Loop: RCALL Daten_Lesen
2
RCALL Statusbits_Setzen
3
RCALL Weitere_Bearbeitung
4
RCALL Ausgabe_vorbereiten
5
RCALL Daten_Ausgeben
6
RJMP Loop
7
8
Daten_Lesen:
9
in temp, PINC ; Wenn keine Variable benutzt wird,
10
; dann ein Register "Eingang" nennen
11
STS Eingaenge, Temp ; oder besser in Variable schreiben
12
RET
13
14
Statusbits_Setzen:
15
.... ; Hier setzt du Bits, die du nach den Inputs direkt
16
.... ; oder in einer Timer-ISR auswertest
17
RET
18
etc.
19
Daten_Ausgeben:
20
LDS stat, Ausgaenge ; auch hier setz ich immer eine Variable ein
21
out PORTB, stat
22
RET
23
24
Timer_ISR:
25
.... ; hier erfolgt z.B. der Aufruf, um ms zu zählen
26
; und zeitbedingte Signale zu setzen oder löschen
27
RETI
Diese Vorgehensweise macht dein Programm flott und unabhängig von
irgendwelchen Zeiten. Die Benutzung von Variablen hat auch einen anderen
Vorteil. Erstens, du erwischt nicht mal aus versehen ein Register und
zweitens kannst du dir mit einem geeigneten Programm über RS 232 die
Variablen in den PC holen.
Ich war es auch leid, ständig den Code nachzurechnen, daher habe ich mir
ein solches Tool geschrieben. Es ist hier unter OpenEye mit einer
Anleitung zu finden.
Gruß oldmax
@oldmax:
Ich schreibe für µC ASM rein aus Gewohnheit, allerdings werde ich
langsam müde damit, grade bei grösseren Projekten wenn die
Übersichtlichkeit schwindet.
Auf dem PC mache ich fast alles mit Perl, da ist schon das Schreiben von
C wieder eine Pein.
Das Beispielprogramm von mir oben ist nur eine zusammengestrichene
Version des Hauptprogramms und soll tatsächlich langsam sein damit die
Ausgabe am Oszilloskop gut ablesbar ist. Dazu ist sogar der interne
Oszillator wieder in Betrieb gegangen.
Die Ausgabe über RS232 ist natürlich fein, das werde ich mir mal
ansehen, bisher habe ich immer einzelne Pins mit LEDs versehen, wenn
noch welche frei waren. So macht das Debuggen natürlich keinen Spaß.
Hi
Versuchs mal, und du wirst es nicht mehr missen wollen...
übrigends, ich wollte nicht klugsch...
>Das Beispielprogramm von mir oben ist nur eine zusammengestrichene>Version des Hauptprogramms und soll tatsächlich langsam sein damit die>Ausgabe am Oszilloskop gut ablesbar ist. Dazu ist sogar der interne>Oszillator wieder in Betrieb gegangen.
Schau dir mein Beispiel an. Natürlich kannst du Wartezeiten einsetzen,
aber wenn du Timer benutzt und mit Flags arbeitest, brauchst du nicht
immer das Rad neu zu erfinden. Außerdem sind Flags auch gut
kontrollierbar, zumindest durch OpenEye, da du den Zustand jedes
einzelnen Bits dir anschauen kannst. Du hast die richtige Reaktion der
Ausgänge, kannst sogar die Frequenz bestimmen, wenn du die Flags in
andere Zeitbasen einsetzt.
Leider sieht man allzuoft solche langen Programmgebilde. Auch nur kurz
zusammengeschusterte Zeilen sind einfach per C&P machbar, wenn in einen
Word oder Editor schon fertige Routinen vorliegen. Das ist der Vorteil
solcher Vorgehensweise, wenn mit kleinen Programmblöcken gearbeitet
wird. Schnell hat man ein Verzeichnis für verschiedene Aufgaben erstellt
und hat sie dann auch zur Hand. Durch Verwendung von Variablen kann man
sich komplett aus dem Programmrumpf lösen. z. B. ist eine Usart- Routine
einfach, wenn man weiß, das zu sendende Byte heißt Send_Var und das
empfangene wird mit Read_Var geliefert.
So kann ein Aufruf aus dem Programm
1
STS Send_Var, Register
2
RCALL Send_UPrg
immer auf ein vorliegendes Unterprogramm Send_UPrg zugreifen.
Bei Empfang nutzt man natürlich die ISR. Also muß die ISR entweder einen
Buffer beschreiben oder ein Byte liefern. Ich bevorzuge den Buffer, ein
Schreib- und ein Lesezeiger signalisieren wenn unterschiedlich neue
Zeichen. Auch das ist mit OpenEye anzusehen. Solltest du Fragen haben,
vielleicht kann ich weiterhelfen.
Gruß oldmax
Timer habe ich noch nicht angefaßt, bisher war ich erstmal dabei
überhaupt eine Funktion zu erhalten.
Sobald ich mal die Zeit habe, erkunde ich natürlich auch andere
Funktionen des AVR, da gibt es ja laut Datenblatt noch eine ganze Menge.
Was aber Timer/Pausen-Konstruktionen angeht, ich benötige in meinem
orginalen Programm einen 24-Bit-Timer, weswegen ich drei ineinander
verschachtelte Schleifen nehme.
Jedenfalls untersuche ich demnächst mal OpenEye, damit ich beim Debuggen
nicht mehr so ganz auf dem Schlauch stehe, das weitere ergibt sich dann.
Gruß Meiermann