Forum: Mikrocontroller und Digitale Elektronik Pins am Mega16 lückenhaft


von Meiermann (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

1
if( µC == Mega 16   &&  Probleme am Port C )
2
  disable_fuse( JTAGEN )
:-)


http://www.mikrocontroller.net/articles/AVR_Fuses#Kompatibilit.C3.A4tsfuses_und_manchmal_l.C3.A4stige_Defaults

von Gast123 (Gast)


Lesenswert?

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..

von Meiermann (Gast)


Lesenswert?

Ähm...

JTAG war tatsächlich eingeschaltet, damit als Fehlerquelle hätte ich 
auch nicht mehr gerechnet.

Damit hat sich das Problem schon erledigt - Danke :)

von Paul Baumann (Gast)


Lesenswert?

@Karl-Heinz
Normalerweise hasse ich die kryptischen C-Quelltexte, aber das hier
habe ich verstanden. ;-))

MfG Paul

von oldmax (Gast)


Lesenswert?

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

von Meiermann (Gast)


Lesenswert?

@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ß.

von oldmax (Gast)


Lesenswert?

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

von Meiermann (Gast)


Lesenswert?

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

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.