www.mikrocontroller.net

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


Autor: Meiermann (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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).
.INCLUDE "m16def.inc"  ;Includes the mega16 definitions file



.def temp  = R16
.def tmp2  = R17
.def stat   = R18
.def loop  = R19


.CSEG
RESET:
  rjmp INITIAL      ; Einsprung ins Programm

;.ORG INT_VECTORS_SIZE    ; dadurch wird für die Vektoren Platz gelassen

INITIAL:
  ldi temp, 0x01       ; Pulsausgang auf Pin0 an Port B
    out DDRB, temp    ;
  ldi temp, 0x00       ; Dateneingang, ein Byte
    out DDRC, temp    ; 
  
  ldi temp, LOW(RAMEND)             ; LOW-Byte der obersten RAM-Adresse
  out SPL, temp
  ldi temp, HIGH(RAMEND)            ; HIGH-Byte der obersten RAM-Adresse
  out SPH, temp



Hauptschleife: 
  ; Startsignal durchgeben
  rcall Pause
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  rcall Pause
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Startsignal fertig

  ; Bit 0
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00000001
  brne Weiter0
  ldi stat, 0
  out PORTB, stat
Weiter0:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 0 fertig
      

  ; Bit 1
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00000010
  brne Weiter1
  ldi stat, 0
  out PORTB, stat
Weiter1:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 1 fertig
      

  ; Bit 2
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00000100
  brne Weiter2
  ldi stat, 0
  out PORTB, stat
Weiter2:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 2 fertig


  ; Bit 3
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00001000
  brne Weiter3
  ldi stat, 0
  out PORTB, stat
Weiter3:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 3 fertig
  
  ; Bit 4
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00010000
  brne Weiter4
  ldi stat, 0
  out PORTB, stat
Weiter4:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 4 fertig
      

  ; Bit 5
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b00100000
  brne Weiter5
  ldi stat, 0
  out PORTB, stat
Weiter5:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 5 fertig
      

  ; Bit 6
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b01000000
  brne Weiter6
  ldi stat, 0
  out PORTB, stat
Weiter6:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 6 fertig


  ; Bit 7
  ldi stat, 1
  out PORTB, stat
  rcall Pause
  in temp, PINC
  andi temp, 0b10000000
  brne Weiter7
  ldi stat, 0
  out PORTB, stat
Weiter7:
  rcall Pause
  ldi stat, 0
  out PORTB, stat
  rcall Pause
  ; Bit 7 fertig
  

  rjmp Hauptschleife



Pause:
  ldi loop, 160
Loop1:
  dec loop
  brne Loop1
  ret

Woran kann es liegen, dass ich nicht den ganzen Port C einlesen kann?

Danke im voraus.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if( µC == Mega 16   &&  Probleme am Port C )
  disable_fuse( JTAGEN )
:-)


http://www.mikrocontroller.net/articles/AVR_Fuses#...

Autor: Gast123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Meiermann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Paul Baumann (Gast)
Datum:

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

MfG Paul

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
Loop: RCALL Daten_Lesen
      RCALL Statusbits_Setzen
      RCALL Weitere_Bearbeitung
      RCALL Ausgabe_vorbereiten
      RCALL Daten_Ausgeben
      RJMP Loop

Daten_Lesen:
      in temp, PINC  ; Wenn keine Variable benutzt wird, 
                     ; dann ein Register "Eingang" nennen
      STS Eingaenge, Temp ; oder besser in Variable schreiben
      RET

Statusbits_Setzen:
      ....  ; Hier setzt du Bits, die du nach den Inputs direkt
      ....  ; oder in einer Timer-ISR auswertest
      RET
 etc. 
Daten_Ausgeben:
     LDS stat, Ausgaenge ; auch hier setz ich immer eine Variable ein
     out PORTB, stat
     RET

Timer_ISR:
     .... ; hier erfolgt z.B. der Aufruf, um ms zu zählen 
          ; und zeitbedingte Signale zu setzen oder löschen
     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

Autor: Meiermann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß.

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
STS Send_Var, Register
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

Autor: Meiermann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.