Forum: Mikrocontroller und Digitale Elektronik Rechnen mit Assembler


von Uwe O. (schwede)


Lesenswert?

Hallo,
ich musste feststellen das das Rechnen eine richtig harte Nuss ist und
könnte ein wenig Hilfe gebrauchen. Ich will die Luftfeuchtigkeit messen
und den Wert dann anzeigen. Dazu lese ich die Spannung des Sensors über
den TWI-Bus vom AD-Wandler (PCF8591) ein und schicke den Anzeigewert
zum LED-Treiber SAA1064.
kurze Info:
der Sensor liefert eine Spannung von 0,8..4,0V = 1..100% Feuchte,
daraus ergibt sich eine Nullpunktverschiebung von 0,8V und 0,032V je 1%
Feuchte
ein Beispiel:
ich lese ein Byte mit dem Wert 163 - multipliziere mit 0,0196 und
erhalte 3,2V (gerundet), entspricht der gemessenen Sensorspannung am
AD-Wandler - subtrahiere 0,8V für die Nullpunktverschiebung und teile
durch 0,032 dann erhalte ich 75% Feuchte. Diese zwei Zahlen muss ich
als zwei Bytes an die Anzeige senden.
Zahl 1: 7 = LED-Segmente: a, b, f = bitfolge: 00100011 = 0x23
Zahl 2: 5 = LED-Segmente: b, c, e, f, g = bit: 01110110 = 0x76
Ich krieg das alleine nicht gebacken. Wäre nicht schlecht wenn wir
dieses Beispiel mal komplett durchrechnen könnten.

Gruss   Uwe

von Hannes L. (hannes)


Lesenswert?

- Welcher Controller soll das tun?
- Wie hoch ist die Auflösung des Signals vom Sensor?
- Brauchst du den Zwischenwert in Volt?
- Hast du an eine Lookup-Tabelle mit den Bitmustern gedacht?

von senex24 (Gast)


Lesenswert?

meine 2ct (solange sich von den Cracks keiner rührt):

in 16-bit-Ganzzahl:
-41
*5
/2                  (1mal rechts schieben)
*125
/512                (1mal rechts schieben, high-byte)
dual->BCD wandeln
BCD->LED

falls Atmel-AVR:
falls tiny: MUL-Routinen siehe AVR200.asm oder AVR200B.asm
dual->BCD: siehe AVR204.asm
BCD->LED: selbst schreiben, Stelle für Stelle

Die genannten Routinen gab es mal für die classics, sind hoffentlich
noch bei Atmel zu finden.


Oder Tabelle: 256 Bytes sollten reichen.

von Mario (Gast)


Lesenswert?

Hi,

also sowas macht man am besten mit fixed-point arithmetik. Dein
Wertebereich ist 0,8..4V, d.h. Du brauchst zwei Bit um die Vorkommazahl
darzustellen. Das wiederrum läßt 14-bit für die Kommastellen einer 16bit
Zahl übrig. Die Auflösung ist damit 1/2^14.

Also: 0,032 = 525/2^14
      0,8   = 13107/2^14

Wenn Du nun 3,2*0,8 berechnen musst (3,2=52429/2^14), gehtst Du wie
folgt vor:

Berechne 13107*52429*(2^14*2^14) und dividiere anschließend durch 2^14
(Das rechtsschieben sollte direkt in der Multiplikation erfolgen damit
Du keinen Überlauf hast).
Das sollte 41943(*2^14) ergeben.

Das richtige Ergebniss ist damit: 41943/2^14 = 2,55...

D.h. Du kannst mit ganzen Zahlen rechnen, hast am Ende aber doch eine
Kommazahl vorliegen.

Gruß
Mario

von Winfried (Gast)


Lesenswert?

Vielleicht gehts ja auch mit einer Tabelle, wo du für entsprechende
Spannungen die %-Werte der Luftfeuchte ablegst. Es reicht ja eine
Auflösung von 1-2%, dann reichen 50-100 Werte.

von Karl H. (kbuchegg)


Lesenswert?

Warum so kompliziert ueber die Spannung rechnen.
Letztendlich brauchst Du eine Umrechnung vom ADC-Wert
zu Luftfeuchte. Bestimme die entsprechenden Konstanten
und rechne direkt vom ADC-Wert zur Luftfeuchte um.
(Nimm alles mal 10 und arbeite komplett in den ganzen
Zahlen).

von Uwe O. (schwede)


Lesenswert?

Hallo und dank für die Tipps,
die Berechnung geht wirklich viel einfacher. (Byte vom ADC - 41) / 1,63
= %rF.
Allerdings können die Bytes für die Anzeige nicht berechnet werden, die
muss ich mit Hilfe einer Tabelle o.ä. zuweisen. Und da kam der Vorschlag
das ganze gleich mit einer Tabelle zu machen. So werd ichs machen.
Könnte aber noch mal Hilfe gebrauchen.
Und B I T T E - - mit Beispiel wie ich das im Studio schreiben muss.
Ich bin noch nicht so lange dabei!

Also wenn ich z.B. vom AD-Wandler 165 (=76%) lese muss ich die Bytes 35
und 126 zur Anzeige schreiben und wenn ich 166 oder 167 (=77%) lese muss
ich die Bytes 35 und 35 schreiben.

Vielleicht kann man die Tabelle auch im Eeprom unterbringen, dass muss
ich nämlich auch noch lernen.

Gruss Uwe

von Hannes L. (hannes)


Lesenswert?

Ich würde die Werte erstmal auf 0..99 skalieren (versuchen mit einer
Zahl (Konstante) zu multiplizieren, so, dass beim Weglassen des/der
unteren Bytes (Division durch 256 bzw. 65536) das obere Byte im
gewünschten Bereich von 00..99 liegt. Dann die Zahl in BCD zerlegen und
zu jeder Ziffer (0..9) mittels LookUp-Tabelle (über Z-Pointer und Flash)
das Bitmuster holen und ausgeben.
Schau mal in die Codesammlung, da gibt es glaube was mit Drehzahlmesser
oder Tacho und 7-Segment-Anzeige.

...

von Uwe O. (schwede)


Lesenswert?

Hallo,
so weit, so gut, lassen wir mal das Rechnen beiseite. Ich glaub ich
krieg das jetzt hin. Aber wie legt man so eine Lookup-Tabelle im Studio
an? Ich konnte bisher nichts passendes finden, was mir weiter hilft. Und
der erwähnte Drehzahlmesser ist mit Basic geschrieben.
Vielleicht könnte mir jemand ein paar Code-Zeilen schreiben nur so als
Beispiel.
Gruss Uwe

von Hannes L. (hannes)


Lesenswert?

> Aber wie legt man so eine Lookup-Tabelle im Studio an?

Man legt die Tabelle am Programmende an, indem man ein Label setzt und
danach mit der Direktive ".db" die Datenbytes anlegt.

tabelle1:
.db 0b11000000,0b11111001   ;0,1
.db 0b10100100,0b10110000   ;2,3
und so weiter, wobei 0 für ein leuchtendes Segment steht. Da müssen
also deine Bitmuster rein. Und darauf achten, dass immer eine
geradzahlige Anzahl Bytes in einer Zeile steht, da der Flash 16 Bit
breit adressiert ist.

Um darauf zuzugreifen, muss man zuerst den Z-Pointer auf den Anfang der
Tabelle setzen. Da das Lesen byteweise erfolgt, muss der Pointer auf den
doppelten Wert der Adresse gesetzt werden:

 ldi zl,low(2*tabelle1)     ;Low-Byte setzen,
 ldi zh,high(2*tabelle1)    ;High-Byte setzen

Nun wird zum Z-Pointer der Index addiert, damit er auf das gesuchte
Byte zeigt. Da hierbei ein Übertrag stattfinden kann, sollte es ein
Register mit dem Namen 'null' geben, dass 0 enthält.

 add zl,zahl                ;Zahl (Wert 0..9) addieren
 adc zh,null                ;Übertrag addieren

Der Z-Pointer zeigt nun auf das gesuchte Byte.

 lpm                        ;liest den Inhalt der per Z-Pointer
                            ;adressierten Zelle nach r0

Das gesuchte Bitmuster steht nun im Register r0.

 out portb,r0               ;an Port ausgeben

...

von Uwe O. (schwede)


Lesenswert?

Hallo,

D A N K E genau das war es, was mir gefehlt hat.
Ich liebe es wenn ein Programm funktioniert !!!

Gruss Uwe

von Uwe O. (schwede)


Angehängte Dateien:

Lesenswert?

Zu früh gefreut...
in der Simulation sah es gut aus, aber als ich es auf dem STK500 testen
wollte, tat sich gar nix.
Wäre vielleicht mal jemand so nett sich das anzugucken. Da ich es
dokumentiert habe sollten die Funktion zu verstehen sein.
War nur mal so ein Test - immer wenn ich eine Taste drücke soll die
entsprechende Nummer angezeigt werden. Sollte mein erstes Programm sein
was auch praktisch funktionieren sollte !!!
Ist aber typisch -- nichts geht beim ersten Mal.

Gruss Uwe

von Uwe O. (schwede)


Lesenswert?

Hallo, Jungs und Mädels...seid ihr alle im Urlaub...lasst mich doch
bitte nicht im Regen stehen !!!
Die Sache ist folgende:
der Eingang PortD tut was er soll Spannung 4,98V und wenn ich aufs
Knöpfchen drücke geht er auf 0V.
Aber der Ausgang PortB ärgert mich. Wenn ein Bit auf 1 gesetzt wird,
dann erreicht die Spannung des Pins gerade mal 0,5 .. 1V. Im
unbelasteten Zustand direkt am Pin gemessen. Meine 7-Segm-Anzeige hat
eine gemeinsame Anode. Die Katode liegt über Vorwiderstand am Mega8.
Bei Bit=0 soll das Segment leuchten.
Habe ich den Port nicht richtig initialisiert, oder können es falsche
Einstellungen am STK500 sein? Das Teil habe ich gebraucht gekauft und
weiss nicht, ob mein Vorgänge irgendwelche Einstellungen verändert
hat.
Bitte gebt mir doch nen Tipp.

Gruss  Uwe

von Ludwig W. (lordludwig)


Lesenswert?

kann es sein das du portB als eingang konfiguriert hast und das was du
misst nur die pullups sind???

von Uwe O. (schwede)


Lesenswert?

Hallo... die beiden Ports habe ich folgendermassen konfiguriert:

; PortB auf Ausgang setzen
ldi    temp, 0xFF
out    DDRB, temp

; PortD auf Eingang setzen
ldi    temp, 0x00
out    DDRD, temp

ist meiner Meinung nach richtig so. Der Kontroller (Mega8) ist auch
neu, dürfte also nicht kaputt sein.
Kann mir keiner einen Tipp geben, warum der den Pegel bei "1" nicht
auf 5V zieht?

Gruss  Uwe

von Hannes L. (hannes)


Lesenswert?

Hast du auch am Eingang die internen PullUp-Widerstände eingeschaltet?
1
; PortD auf Eingang setzen
2
 ldi    temp, 0x00
3
 out    DDRD, temp
4
; PullUps an PortD einschalten
5
 ldi    temp, 255
6
 out    PORTD,temp

Wenn du das nicht tust, sind die Eingänge hochohmig...

...

von Uwe O. (schwede)


Lesenswert?

hab ich gerade eben ausprobiert...keine Veränderung. Die Spannung der
einzelnen Pins ist unterschiedlich, geht aber nicht über 1,2V bei Pin=1
und im unbelastetem Zustand.
Ich bin am Verzweifeln !
Können es vielleicht noch irgendwelche "Fuse-Einstellungen" sein?

Gruss Uwe

von Hannes L. (hannes)


Lesenswert?

> geht aber nicht über 1,2V bei Pin=1
> und im unbelastetem Zustand.

Was verstehst du unter Pin=1???

Das Register pind ist beim Mega8 ein reines Leseregister, da wird nix
reingeschrieben. Beim Mega48/88/168 ist das anders, aber hier geht es
wohl um den Mega8.

Also:
- in ddrx die Datenrichtung schreiben
- in portx die Ausgänge schreiben bzw. PullUps schalten, wenn
  ddrx als Eingang geschaltet ist
- aus pinx die extern angelegten Daten einlesen.

...

von Conlost (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Uwe,

ich habe mir erlaubt deinen Code etwas abzuändern.
Ich denke, so sollte es gehen.
Geänderter Code im Anhang.

Es grüsst,
Arno

von Uwe O. (schwede)


Lesenswert?

Hallo...
Arno danke für die Mühe, die du dir gemacht hast, hat aber nichts
gebracht...selbes Resultat. Aber jetzt weiss ich, der Fehler liegt
nicht im Programm.
@...HanneS - richtig hier geht es um den Mega8 und mit "Pin=1" meine
ich: wenn ich z.B. am Ausgang PortB 0b00000001 habe, dann sind die
Pins1..7 = 0 also 0V und Pin0 = 1 also 5V. Die Spannung kommt aber nur
auf max. 1,2V (ohne angeschlossene LED), was bedeutet, bei 5V sollten
die LED's ausgehen da ich aber nur ca. 1V habe werden sie nur ein
klein wenig dunkler - bei genauem Hinsehen.

Vielleicht sollte ich mal PortC als Ausgang benutzen, um den Fehler
weiter einzugrenzen?

Kann man, mal abgesehen von der ext. Beschaltung, einen Port oder sogar
den ganzen Kontroller durch falsche Programmierung o.ä. zerstören?

Gruss Uwe

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.