Forum: Mikrocontroller und Digitale Elektronik Assembler - Erste Schritte - I/O ansteuern


von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Leute,
erst mal vielen Dank für die Hilfe die Ihr mir bis jetzt geboten habt.
Ich habe es etwas schwer mit Assembler (Anfänger) und möchte eine kleine 
Sache lösen, weiss aber nicht wie ich genau dran gehen soll.
Also falls jemand Zeit/Lust hat hier meine "einfache" Sache:
Möchte einen MUX mit einem Mega8/16/32/8535 ansteuern und dafür benötige 
ich 3 Ausgänge des megaxx um die 3 Steuereingänge des MUX anzusteuern.
Diese Ausgänge müssten sozusagen alle Zustände einer Wahrheitstabelle 
für eine 3bit-Zahl durchlaufen.
Also als Beispiel:
Ausgänge: 0 1 2
Zustand:  0 0 0 -> MUX Eingang 1
Zustand:  0 0 1 -> MUX Eingang 2
Zustand:  0 1 0 -> MUX Eingang 3
usw.
Das Ganze muss in einer Schleife durchlaufen bis man es per Taster 
beendet/startet.
Ich muss auch bedenken dass auch eine gewisse Zeit benötigt wird biss 
der MUX tatsächlich geschaltet wird und der Eingang gelesen wird.
Ich habe 8 solcher MUX an 8 ADC-Eingänge des Mega angeschlossen, habe 3 
Ausgänge parallel an alle MUX-Steuereingänge angeschlossen.
Jetzt will ich diese ADCs einlesen, habe also 8x8=64 Eingänge....
Benutze AVR-Studio, PonyProg2000, die Hardware ist ein Board von Pollin 
mit eingesetztem mega8 (werde aber auf mega8535 oder mega16/32 
umstellen).
Die MUX sind 74hc4851 für Analogsignale, an den Eingängen sollen 
Thermofühler drankommen.
Wie packt man sowas an?
Hat jemand so einen Beispielcode ?
Vielen Dank

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Welchen Grund hast du, um dieses Programm ausgerechnet in Assembler zu 
schreiben? Platznot beim Programmcode oder Datenaufkommen kann es ja 
nicht sein, mit den von dir ausgesuchten Atmegas...

von spess53 (Gast)


Lesenswert?

Hi

An welchem Port sind die Multiplexer angeschlossen?

@Stefan: Was soll die überflüssige Frage?

MfG Spess

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ Spess

Interessiert das dich wirklich oder willst du mir anmachen?

von W. B. (wb1)


Lesenswert?

Hallo
Dein Problem ist anscheinend nicht die ADC-Wandlung, sondern wie du das 
Multiplexen händeln willst.
Teste mal den anhängenden Schnipsel, ich glaube du wirst ihn verstehen 
und dann kannst du es auch selbst.
Das schalten des MUX geht mit einer maximalen Latenz von 125 nano-sec. 
Das sind 8 MHz. Also eigentlich unkritisch
Problem ist das einschwingen des ADC nach Kanalwechsel.
Ich hab das immer so gemacht, das ich zweimal gewandelt habe. Den ersten 
Wert habe ich garnicht erst ausgelesen, dann sofort eine neue Wandlung 
gestartet und den Wert verwendet.
Besten Gruß



.include "m16def.inc"
.equ tabelle = 0x100
.def adc_ergebnis_low = r16
.def adc_ergebnis_high = r17
.def mux_zeiger = r18
.def adc_kanal = r19
.equ dein_port = portb

init:
  ldi r16,low(ramend)
  out spl,r16
  ldi r16,high(ramend)
  out sph,r16
  ldi zl,low(tabelle)
  ldi zh,high(tabelle)
  clr mux_zeiger  ;Zeiger für den MUX
  clr adc_kanal   ;zeiger auf den ADC-Kanal, kannst ihn noch mit gain 
oder so verknüpfen
; ab hier
eine_runde_fertig:
  out dein_port,mux_zeiger
laufende_runde:
  call adc_wandlung
  in adc_ergebnis_low, adcl
  in adc_ergebnis_high, adch
  st z+,adc_ergebnis_low
  st z+,adc_ergebnis_high
  inc adc_kanal
  cpi adc_kanal,8
  brne laufende_runde
  clr adc_kanal
  inc mux_zeiger
  cpi mux_zeiger,8
  brne eine_runde_fertig
  clr mux_zeiger
  ldi zl,low(tabelle)
  ldi zh,high(tabelle)
  rjmp eine_runde_fertig
adc_wandlung:       ;deine ADC-Routine
  nop
  ret

von Hauke S. (hauke)


Lesenswert?

Erstmal ein wenig ruhe hier.
Wenn man gleich anfängt rumzu"flamen" schreck man anfänger eher ab. Und 
die Fragen beantwortet der Scheiß auch nicht.

Was mir aufgefallen ist das du (Robert) je 8 Eingange an einen Ausgang 
geschaltet hast. Das könnte zu Problemen mit Fan-IN bzw. Fan-OUT führen.

Aber das übersehen wir erstmal.

Idealer setzt man sich am Anfang des Programms Konstanten.
1
.equ MUX0 = 0
2
.equ MUX1 = 1
3
.equ MUX2 = 2
4
.equ MUX3 = 3
5
.equ MUX4 = 4
6
.equ MUX5 = 5
7
.equ MUX6 = 6
8
.equ MUX7 = 7
9
10
.def work = r16     ;work ist immer mein Arbeitsregister

Bei der Initialisierung definiert man die entsprechenden Ports erstmal 
als Ausgang. (Ich nehme mal einfach PC0, PC1 und PC2)
1
ldi work,0b00000111
2
out DDRC,work       ;setze PC0-PC2 als Ausgang

um dann hinterher die Mux umzuschalten (z.B. auf Mux 2) verwendet man:
1
ldi work,mux2
2
out PORTC,work      ;setze PC0-PC2 auf auf mux2

Jetzt kommt evt noch eine kleine Warteschleife (je nach dem wie lang die 
Muxe zum umschalten brauchen) und danach führt man die ADC Messung 
durch.

bis dann
cu
Hauke

von Michael U. (amiga)


Lesenswert?

Hallo,

was mich mehr verwirrt: Temperaturfühler...

Wie schnell ändern sich die Temparaturen im ungünstigsten Fall und wie 
schnell reagieren die Sensoren?

Bei z.B. 5ms Timer-IRQ wären es 64*5 = 320ms für alle Wandler, also rund 
eine Messung/Sekunde nacj meinem Vorschlag.

Wenn das reicht:
 IRQ - wenn Hilfsflag gelöscht:
     ADC lesen, MUX neu setzen, ADC neu starten, Hilfsflag setzen
   wenn Hilfsflag gesetzt:
     nur ADC neu starten, Hilfsflag löschen
usw.
Möglich ist hier auch free-running, es finden nach dem Umschalten 
mehrere Wandlungen statt, wenn der Takt nicht allzu langsam ist.
Dann nur Flag behandeln und entweder MUX umschalten oder ADC lesen.

Das Hauptprgramm kömmert sich um die Verarbeitung der Werte, wenn alle 
10Bit genutzt werden, muß der Zugriff auf die Werte dort mit CLI/SEI 
atomar gehalten werden.

Solche reöativ langsamen Sachen hänge ich meist in einen 
Timer-Interrupt, den ich wegen Uhrzeit und Tasten-Entprellen sowieso 
brauche.

Gruß aus Berlin
Michael

von spess53 (Gast)


Lesenswert?

Hi

@Stefan
Nein, ich will DIR nicht anmachen. Aber wenn er es in Assembler machen 
will, finde ich das in Ordnung. Dann lernt er wenigsten von der Pike auf 
und stellt später keine dummen Fragen.


Eine Bemerkung zum obigen Programm:

>out dein_port,mux_zeiger

Damit wird der ganze Port überschrieben. Besser ist es, die Portbelegung 
einzulesen, mit der Multiplexeradresse zu verknüpfen und dann erst den 
Port beschreiben.
Beispiel: MUX-Adresse Pin 0,1,2

    in r16,PortX             ; Portbelegung einlesen
    andi r16,0b11111000      ; Adressbits löschen
    ldi r17,MUXAdresse
    andi r17,0b00000111      ; nur Adressbits (zur Sicherheit)
    or r16,r17               ; PortPins und Adressbits zusammensetzen
    out PortX,r16            ; ausgeben

MfG Spess

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Leute,
erst mal an alle vielen Dank.
Ich habe gestern Abend die Anfrage gestellt und weiter an meinem Problem 
gebastelt, heute hat es mich fast erschlagen welches Echo meine Frage 
hatte.
Vielen Dank für die Hilfe.
Ich muss jetzt erst mal alles verdauen...
Also:
Ich will/muss dass in Assembler machen da ich für das Studium Assembler 
benötige und so gleich 2 Fliegen mit einer Klappe.....
Das Thermometer benötige ich um einen Rechner zu überwachen der in der 
Entwicklung ist und Themparaturprobleme hat.
Wie "wb1" es richtig erkannt hat ist mein Problem wie steuere ich den 
MUX an,  wie macht man sowas...
An dieser Stelle danke an "wb1".
Ich werde versuchen Deinen Code zu verstehen und anwenden.
Danke auch an Haucke, die Ruhe hat mir gut getan und den Weg den Du mir 
angegeben hast ist für mich auch händelbar.
Dank auch an Michael, nur Deine Ausführung ist mir zur Zeit etwas zu 
"hoch", ich muss da noch langsam vieles Wissen erarbeiten, werde mir 
aber langsam das beibringen um auch fachlichere Angaben zu verstehen.
Wie immer ist auch "spess53" hilfsbereit und hat wie auch in der nahen 
Vergagenheit eine Hilfe angeboten. Danke Dir.
Jetzt werde ich mich an die Arbeit machen und Euere Beiträge 
abarbeiten....
Mühsam geht es weiter.....
Vielen Dank
PS:
Hallo "wb1", ist es Dir möglich den Code mit Kommentare zu "bespicken"?
Es würde mir sehr helfen zu verstehen was genau da passiert und wie es 
gemeint ist.
Nebenbei, ich muss/will 256 Werte/Kanal einlesen, daraus den Mittelwert 
errechnen der dann ausgegeben wird. Es muss doch von der Zeit möglich 
sein wenn ich den megaxxx mit 16MHz per ext. Quarz betreibe...oder ?
Danke

von Hauke S. (hauke)


Lesenswert?

Den Mittelwert aus 256 Werten erechnen ist relativ einfach.

Es gibt eine Option (Ein Steuerungsflag) im ADC, welches bewirkt das die 
ermittelten Analogwerte linksbündig in die beiden ADC Register 
geschrieben werden.
danach nimmt man nur noch den Inhalt von ADCH und adiert diesen auf eine 
16 Bit Variable. Nach den 256 Duchgängen befindet sich der Mittelwert 
aus den Messungen dann in den oberen 8 Bit der 16 Bit Variable.

bis dann
cu
Hauke

von W. B. (wb1)


Lesenswert?

Hallo Robert
Ich weiß, man sollte die Quelle kommentieren.
Aber es gibt da einsn inneren Schweinehund, sich dagegen zu wehren ist 
schwer.
Ein paar Kommentare hab ich eingefügt. Vieleicht helfen sie dir.
Du mußt dich da durchbeißen und wenn man alles vorgekaut bekommt, lernt 
man es nicht.
Du hast geschrieben, du hättest avr-studio.
Füge die Quelle in dein projekt ein und simuliere sie. Führe die 
Simulation schrittweise aus. Ich glaube, dann wirst du es verstehen.
In der Hauptschleife habe ich ein paar Anweisungen auskommentiert. Die 
hatte ich eingesetz, um deine Frage nach der Laufzeit bei 256 Wandlungen 
je Kanal zu ermitteln.
Die Durchlaufzeit für die 64 Wandlungen ist abhängig vom Vorteiler des 
ADC.
Bei dem gewählten Vorteiler ergibt sich für 64 Wandlungen inclusive der 
verworfenen ersten Wandlung bei einem Takt von 16 MHz eine Laufzeit von 
3,4millisekunden. Bei 256 Wandlungen je Kanal und 64 Kanälen ergigt sich 
eine Laufzeit von knapp 0,9 sekunden.
Die Mehrfachwandlung sowie die Addition der Werte habe ich weggelassen. 
Wenn du es machen willst, brauchst du in der Ergebnistabelle 3 
Speicherzellen.
Natürlich kannst du es machen, wie hauke beschrieben hat, dann reichen 
auch die Werte in der Tabelle. Aber du hast dann von Haus aus einen 
Wandlungsfehler von 20%, weil du ja nur 8bit statt 10 bit auswertest.

Ach ja, mach immer einen Schritt nach dem anderen.
Wenn du die Wandlung in der Hardware funktionsfähig hast, stelle die 
Software auf Mehrfachwandlung um.
Wenn du von vornherein immer neue Ideen einbringst, ohne die 
Ausgangsidee realisiert zu haben, verzettelst du dich und schmeißt dann 
alles in die Ecke.
Das wäre schade.
Mach erst einmal die einfache Wandlung, dort wirst du schon auf Probleme 
treffen, zum Beispiel das die Meßwerte flattern. Dann mußt du 
Hardwareseitig etwas tun, um das Flattern (es ist natürlich, weils ja 
kein 0,5 also halbe bits gibt) so klein wie möglich zu halten. Wenn du 
das erreicht hast, mach deine Mehrfachwandlung.

Besten Gruß aus Eberswalde



.include "m16def.inc"
.equ tabelle = 0x100
.def adc_ergebnis_low = r16
.def adc_ergebnis_high = r17
.def mux_zeiger = r18
.def adc_kanal = r19
.equ dein_port = portb

init:
;setze den Stapelzeiger
  ldi r16,low(ramend)
  out spl,r16
  ldi r16,high(ramend)
  out sph,r16
;setze den Tabellenanfang
  ldi zl,low(tabelle)
  ldi zh,high(tabelle)

;setze das Richtungsregister bit0 bis 2 auf Ausgang
;das Datenrichtungsregister ist dein Port minus1
  ldi mux_zeiger,0b00000111
  out dein_port-1,mux_zeiger

;initialisiere den ADC
  ldi mux_zeiger,0b10000101 ;hier wird Vorteiler eingestellt
  out adcsra,mux_zeiger

;loesche die zeiger
  clr mux_zeiger
  clr adc_kanal

Hauptschleife:
;  clr r10
  s1:
  call wandlung_64_eingaenge
;  dec r10
;  brne s1
  rjmp Hauptschleife

wandlung_64_eingaenge:
eine_runde_fertig:
  out dein_port,mux_zeiger
laufende_runde:
  call adc_wandlung
  in adc_ergebnis_low, adcl
  in adc_ergebnis_high, adch
  st z+,adc_ergebnis_low
  st z+,adc_ergebnis_high
  inc adc_kanal
  cpi adc_kanal,8
  brne laufende_runde
  clr adc_kanal
  inc mux_zeiger
  cpi mux_zeiger,8
  brne eine_runde_fertig
  clr mux_zeiger
  ldi zl,low(tabelle)
  ldi zh,high(tabelle)
  ret

adc_wandlung:
;erste Wandlung ist fehlerbehaftet, also verwerfen
  sbi adcsra,6
warte_fehlwandlung_fertig:
  sbic adcsra,6
  rjmp warte_fehlwandlung_fertig
  sbi adcsra,6
warte_wandlung_fertig:
  sbic adcsra,6
  rjmp warte_wandlung_fertig
  ret

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo Hauke,
danke für Deine Hilfe.
Ich benutze den Demo-Code aus dem Tutorial (ADC) und versuche den soweit 
umzustellen um ein wenig zu verstehen wie das funktioniert.
Wenn ich es richtig verstanden habe dann muss ich gucken wie dieser 
Mittelwert errechnet wird anhand einer Option im ADC.
OK, werde ich gucken und testen.
Danke Dir & schöne Feiertage

von Robert B. (Firma: Privat) (eshidata)


Lesenswert?

Hallo "wb1",
noch mal danke für Deine Zeilen, ja das stimmt, der Schweinehund, den 
kenne ich auch :-)
Werde aber dennoch Deinen Code bearbeiten um zu verstehen wie das 
funktioniert, jetzt kommen die Feiertage, also ein wenig Zeit zum 
basteln.
Bedanke mich bei Dir und wünsche noch ein frohes Fest.
Vielen Dank
PS:
Bei Fragen weiß ich wo ich Hilfe erhalten kann....
Vielen Dank an alle !!

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.