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