Forum: Mikrocontroller und Digitale Elektronik AD Konverter beim Mega 8


von jochen (Gast)


Lesenswert?

Hallo,

ich habe mir das Tutorial über den Analog bzw. Digitalkonverter 
durchgelesen.
Leider ist das Beispiel mit dem Quelltext nicht nur auf den 
Analog/Digitalkonverter beschränkt, sondern beeinhaltet noch die UART 
Schnittstelle und die Mittelwertbildung, sodass das eigentliche 
Augenmerk nicht nur auf dem AD Konverter liegt.
Deswegen ist mir leider nicht ersichtlich, wie genau man nun eine analog 
anliegende Spanung als Wert in einem Register speichern kann.
Könntet ihr mir das erklären?

Jochen

von Dussel (Gast)


Lesenswert?

Moin,
hatte das gleiche Problem. Am besten liest du im Datenblatt nach was die 
Bits machenund setzt die nacheinenader entsprechend. Habe leider die 
Dateien nicht hier, sonst könnte ich das geanuer sagen, aber es gibt ein 
Bit, das den ADC startet und ein anderes, das gesetzt wird wenn er 
fertig ist (oder ist es sogar das gleiche?) Danach steht das Ergebnis in 
den Ergebnisregistern(Ich glaube ADCH und ADCL). Die kannst du auslesen, 
musst aber auf die Reihenfolge warten, weil sonst das Register, das du 
noch nicht auisgelesen hast überschrieben werden kann (im 
Free-Runnning-Mode).
Frag, wenn das zu ungenau war ;)
Dussel

von jochen (Gast)


Lesenswert?

Hi,

mit dem Dantenblatt komm ich garnicht zurecht.
Könntest du mir evtl. ein Beispiel geben, mit dem ein Wert eingelesen 
wird?

Jochen

von Gast (Gast)


Lesenswert?

Das ist der wsentliche Teil aus dem tutorial-Programm:

; neuen ADC-Wert lesen  (Schleife - 256 mal)
sample_adc:
    sbi  ADCSRA, ADSC       ; den ADC starten

wait_adc:
    sbic ADCSRA, ADSC       ; wenn der ADC fertig ist, wird dieses Bit 
gelöscht
    rjmp wait_adc

; ADC einlesen:
    in   adlow, ADCL        ; immer zuerst LOW Byte lesen
    in   adhigh, ADCH       ; danach das mittlerweile gesperrte High 
Byte

von Dussel (Gast)


Lesenswert?

Bei sowas lese ich im Datenblatt eigentlich immer nur, was die einzelnen 
Bits machen, den Rest, was die Batueile alles können und wie die 
funktionieren braucht man eigentlich aös Anfänger nicht. Das macht schon 
vieles einfacher. Englisch musst du natürlich ein bnisschen verstehen.

Das Beispiel oben zeigt eigentlich alles was du wissen musst.
Dussel

von jochen (Gast)


Lesenswert?

Ich danke Euch.

Wieso lieso man zuerst das "Low Byte" ? Was ist das genau?
Wieso dann das "High Byste"? Wieso wurde es mittlerweile gesperrt?

von Gast (Gast)


Lesenswert?

Zitat aus dem Tutorial:

> Die Ergebnisregister ADCL und ADCH
> Immer zuerst ADCL und erst dann ADCH auslesen. Beim Zugriff auf
> ADCL wird das ADCH Register gegenüber Veränderungen vom ADC
> gesperrt. Erst beim nächsten Auslesen des ADCH-Registers wird
> diese Sperre wieder aufgehoben.
> Dadurch ist sichergestellt, daß die Inhalte von ADCL und ADCH immer
> aus demselben Wandlungsergebnis stammen, selbst wenn der ADC im
> Hintergrund selbsttätig weiterwandelt.


Ich denke, Du hast es gründlich gelesen?

von jochen (Gast)


Lesenswert?

Ja hab ich auch.
Aber das hab ich nicht ganz verstanden.

Eine weitere Frage:
An welchem Port leg ich die Spannung denn genau an, und wie bekomm ich 
den Wert nun in ein Register, mit dem ich weiterarbeiten kann?

von Gast (Gast)


Lesenswert?

> An welchem Port leg ich die Spannung denn genau an

Steht im Tutorial: 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Beschaltung_des_ADC-Kanaleingangs



> wie bekomm ich
den Wert nun in ein Register, mit dem ich weiterarbeiten kann?


Siehe Programmbeispiel oben bei "; ADC einlesen".

adlow und adhigh sind dabei im Beispielprogramm wie folgt definiert:

.def adlow  = r20
.def adhigh = r21

von jochen (Gast)


Lesenswert?

Ich habe es jetzt ausprobiert und mit dem Auszug von "Gast" getestet.
An Pin C0 habe ich 5 V angelegt.
Port B habe ich als Ausgang konfiguriert und da einen 7 Seg. Treiber 
dran und an 7 Segmentanzeigen. Das, was an Port B binär anliegt ist 
dezimal sichtbar.

Ich habe also an Pin C0 eine Spannung anliegen.
Am Ende des Quellcodes von "Gast" sende ich noch adhigh an Port B und 
somit an die 7 Segmmentanzeige, die aber leider keine Änderung anzeigt.

Mein Programm sieht in etwa so aus:


; neuen ADC-Wert lesen  (Schleife - 256 mal)
sample_adc:
    sbi  ADCSRA, ADSC       ; den ADC starten

wait_adc:
    sbic ADCSRA, ADSC       ; wenn der ADC fertig ist, wird dieses Bit
gelöscht
    rjmp wait_adc

; ADC einlesen:
    in   adlow, ADCL        ; immer zuerst LOW Byte lesen
    in   adhigh, ADCH       ; danach das mittlerweile gesperrte High
Byte


out PortB, adhigh



Natürlich habe ich vorher PortB als Ausgang konfiguriert.

Warum zeigt die Anzeige nichts an?

von Karl H. (kbuchegg)


Lesenswert?

Weil im Highbyte nur dann ein Wert ungleich 0 anzutreffen
sein wird, wenn der Messwert größer als 256 ist.
Gib doch mal das LowByte aus.

von Karl H. (kbuchegg)


Lesenswert?

> Mein Programm sieht in etwa so aus:

'In etwa so' ist immer schlecht.
Der Teufel steckt im Detail und kann auch ganz woanders
zu finden sein.
Soo gross wird dein Programm ja nicht sein. Poste es komplett
und wenn es tatsächlich mehr als sagen wir mal 50 Zeilen hat,
dann specke vorher ab, bis nur noch die relevanten Dinge
übrig bleiben, du in etwa in diesem Zeielenbereich bist und
(ganz wichtig) das Programm das Fehlverhalten immer noch
zeigt.

Denk immer drann: Es gibt nichts besseres zur Fehlersuche
als wenn hier jedermann in der Lage ist, dein Programm
in einen Prozessor zu brennen und mal laufen zu lassen.
Das muss dein Ziel sein.

von jochen (Gast)


Lesenswert?

Hi, hier ist der Quellcode.
Wie gesagt an Port B sollten dann die Zahlen binär anliegen aber meine 
Segmentanzeige zeigt nur "0" an. AREF habe ich mit einem 100 N 
Kondensator auf Masse und testweise auch mal an 5V (Versorgungsspannung) 
angeschlossen. In beiden Fällen das gleiche Ergebnis...

.include "m8def.inc"

.def temp = r16

.def temp1=r17
.def adlow =r20
.def adhigh=r21

.org 0x0000
  rjmp main

  ldi temp1,(1<<REFS0)
  out ADMUX, temp1
  ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0)
  out ADCSRA, temp1

main:

  ldi temp, LOW(RAMEND) ;Stackpointer initalisieren
  out SPL, temp
  ldi temp, HIGH(RAMEnD)
  out SPH, temp

  sbi DDRB,0
  sbi ddrB,1
  sbi ddrB,2
  sbi ddrB,3
  ldi r22, 9

  sample_adc:
  sbi ADCSRA, ADSC

  wait_adc:
  sbic ADCSRA, ADSC
  rjmp wait_adc

  in adlow,ADCL
  in adhigh, ADCH

loop:

out PORTB, adhigh

rjmp loop

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

rjmp loop

muß

rjmp sample_adc

heißen, wenn Du ständig und nicht nur ein einziges Mal wandeln möchtest.


Außerdem muß zuerst SPH, dann SPL geschrieben werden.

von jochen (Gast)


Lesenswert?

Danke!

Mit dieser Änderung habe ich erreicht, dass manchmal etwas angezeigt 
wird. Es  ist aber eine wacklige Sache, manchmal wird auch einfach nur 
die Null ausgegeben. Habe ich möglicherweise einen Widerstand vergessen?
Was ist mit AREF? Reicht es diesen Eingang mit einem 100N Kondensator zu 
verbinden, der auch noch an der Masse angeschlossen ist?

Nichts desto troz bekomme ich, wenn ich Pin C0 auf 5 V liege an der 
Segmentanzeige die Zahl 3 ausgegeben.
Mit der Formel erhalte ich jetzt

3*5V / 1024 = 0,014 V.
Ich habe aber 5 V angelegt.

von Michael U. (Gast)


Lesenswert?

Hallo,

3 ist doch richtig...
Du gibst das H-Byte aus, der maximal mögliche Wandlerwert bei Uin >= 
Uref ist 0x3FF, H-Byte also 3.

Gruß aus Berlin
Michael

von jochen (Gast)


Lesenswert?

Hi Michael danke für deine Antwort.
Ich habe das leider nicht verstanden, könntest du mir das nochmal 
erkllären?

von jochen (Gast)


Lesenswert?

ich habe ja 5 V angelegt also würde ich am Ausgang gerne auch eine 5 
angezeigt bekommen.

von Power (Gast)


Lesenswert?

(ADChigh * 256) + ADClow = Ergebnis.
Probier mal die Betriebsart 'left-adjusted'. Dann hast du 255 als 
Ausgabe bei 5V.

von jochen (Gast)


Lesenswert?

Ich komme leider immer noch nicht auf die 5 V:

(ADChigh * 256) + ADClow = Ergebnis

ADChigh = 3
ADClow = 0 (0 wird ausgegeben, wenn ich low ausgebe)

(3 * 256) + 0 = 768 (ungleich 5)

Tut mir leid, wenn ich noch mal nachfragen muss.

Was meinst DU mit der Betriebsart 'left-adjusted'? Was bewirtkt sie? Wo 
muss ich das eingeben?

von Spess53 (Gast)


Lesenswert?

Hi

Dein elementarer Fehler : Du denkst dezimal. Der ATMega denkt aber 
binär.

MfG Spess

von jochen (Gast)


Lesenswert?

Aber ob ich doch nun z.B. 2 + 2 = 4 oder

0010 + 0010 = 0100 = 4 rechne kommt doch letzten Endes auf das gleiche 
raus ?!

von Power (Gast)


Lesenswert?

Das wird im Register ADMUX eingestellt (Datenblatt seite 206 und 208). 
das Bit 5 heißt ADLAR und schiebt die Bits einfach nach links bis zum 
Bit 7 des ADCH.
Am Besten mal das Datenblatt studieren! ;)

von Power (Gast)


Lesenswert?

Ach ja: immer zuerst ADCL auslesen, dann ADCH! Steht aber auch im 
Datenblatt!

von jochen (Gast)


Lesenswert?

und was könnte ich damit erreichen ? Wie bekomme ich hin, dass die 5 
angezeigt wird?


Wie komme ich rechnerisch von der 3 auf die 5? Die Formel funktioniert 
bei mir ja nicht (s.o)

von Power (Gast)


Lesenswert?

Also:
1. ADCL auslesen und zwischenspeichern
2. ADCH auslesen und mit 256 multiplizieren
3. ADCL und multipliziertes Ergebnis von ADCH addieren
4. Berechnung durchführen: (5 / 1023)*Summe Messwert = Spannung
                                ^^^^
NICHT 1024 ! Es wird ab 0 gezählt, also 0..1023 => 1024 Schritte.

von jochen (Gast)


Lesenswert?

1. Ergebnis ist 0
2. 3*256 = 768
3. 768 + 0 = 768

4. (768 * 5)/1023= 3,75

passt nicht.

Wo ist denn der Fehler?

von Gast (Gast)


Lesenswert?

> 3. 768 + 0 = 768

3. 768 +255 = 1023

von Spess53 (Gast)


Lesenswert?

Hi

@power: AVRs haben 8-Bit Register. Statt mit 256 zu multiplizieren 
reicht es ADCL und ADCH in zwei Register einzulesen. Mit der Berechnung 
ist Jochen mit Sicherheit überfordert.

Einfacher wäre es die Eingangsspannung (bei 5V) auf 3,125V zu teilen. 
Dann ergibt sich ein ADC-Wert von 640D ( 5*128). Dann 7 mal 
Rechtsschieben. Ergebnis: 5.

MfG Spess

von Power (Gast)


Lesenswert?

Hast du die Spannungen mal nachgemessen? Aref und die Messspannung mein' 
ich? Sind die identisch?

von Spess53 (Gast)


Lesenswert?

Hi

@jochen: bei 5V ist ADCL nicht 0 sondern 255. Also 768+255=1023.

MfG Spess

von Power (Gast)


Lesenswert?

Bist du am richtigen Eingangspin? Sind die Pullups der ADC-Eingänge 
abgeschaltet?

von Power (Gast)


Lesenswert?

>Statt mit 256 zu multiplizieren
Drum wollte ich auf 'left adjusted' raus. Erst mal mit 8 Bit rechnen ist 
einfacher.

von Johannes M. (johnny-m)


Lesenswert?

Power wrote:
> Also:
> 1. ADCL auslesen und zwischenspeichern
> 2. ADCH auslesen und mit 256 multiplizieren
> 3. ADCL und multipliziertes Ergebnis von ADCH addieren
> 4. Berechnung durchführen: (5 / 1023)*Summe Messwert = Spannung
>                                 ^^^^
> NICHT 1024 ! Es wird ab 0 gezählt, also 0..1023 => 1024 Schritte.
Mensch, Power, das ist doch hier schon zigmal durchdiskutiert worden: 
Die Formel für das Wandlungsergebnis lautet
woraus nach Umstellung folgt
Noch mal zur Verdeutlichung: Die Referenzspannung wird in 1024 Schritte 
unterteilt. Der höchste Messwert ist 1023 (die höchste in 10 Bit 
darstellbare Zahl). Die höchste messbare Spannung ist demnach
wobei das allerdings nur die letzte Digitalisierungsstufe darstellt und 
demzufolge nur bedeutet, dass alle Spannungen, die größer als V_REF - 1 
LSB sind, zum Ergebnis 1023 führen.

Das nur am Rande, um Missverständnisse zu vermeiden. Für die Berechnung 
an sich ist es zunächst mal unerheblich, da der Fehler nur bei ca. 1 
Promill liegt...

von jochen (Gast)


Lesenswert?

Ich denke, mein Fehler lag daran, dass ich ADCL an Port B ausgegeben 
habe, an dem der Dekoder und die Segmentanzeige war, 255 kann so ja 
schlecht dargestellt werden.

Wie ist denn der Assemblerbefehl für eine Division?

von Johannes M. (johnny-m)


Lesenswert?

jochen wrote:
> Wie ist denn der Assemblerbefehl für eine Division?
Die AVRs haben keinen Hardware-Divider, weshalb es auch keinen 
Divisions-Befehl gibt. Eine Division muss im AVR durch Algorithmen aus 
anderen Operationen zusammengesetzt werden. Schau mal hier in der 
Codesammlung und/oder auf der ATMEL-Homepage, da gibts eine Application 
Note mit Divisionsalgorithmen in Assembler.

Ergänzung:
Eine Division durch 2^n lässt sich durch Bit-Schiebeoperationen 
durchführen (Division durch 2^n entspricht einem Rechtsschieben um n 
Bit). Aber ich denke, Du brauchst eher etwas zur Umrechnung der 
Hex-Werte in Dezimalzahlen, also eine Division durch 10, gelle? Ich 
denke, auch dazu dürfte es in der Codesammlung etwas geben (Hex nach BCD 
o.ä.)

von Uwe .. (uwegw)


Lesenswert?

Hardware-Division können AVRs nicht, das muss man selbst aus einzelnen 
Befehlen zusammenbasteln.

http://www.avr-asm-tutorial.net/avr_de/index.html kennst du?

Besonders interessant für dich: 
http://www.avr-asm-tutorial.net/avr_de/rechnen/fpconv.html#bsp2

von jochen (Gast)


Lesenswert?

Dann werde ich mir das mal erarbeiten - danke soweit!

von Thilo M. (Gast)


Lesenswert?

@  Johannes M.:
(sorry für den neuen Nick, hab' endlich Zeit gefunden mich anzumelden 
;))

(5/1023) * 1023 = 5
und
(5/1023) * 0 = 0
oder?

Also decke ich somit den tatsäclichen Bereich ab.
Nachgemessenermaßen (mit Kalibrierquelle) ist das auch so.

von jochen (Gast)


Lesenswert?

Ahja dann hab ich noch eine Frage und zwar zu dem Wackelkontakt von 
oben:
Die Bauteile sind alle fest auf den Steckbrett also ein mechanischer 
Fehelr wird es kaum sein.
Es wird meistens eine 0 angezeigt, nur mit Glück und nach ein paar 
Versuchen schaffe ich es, dass die 3 auf der Segmentanzeige steht.

AREF habe ich mit einem 100 N Kondensator gegen Masse und sonst VXX auf 
Plus und GND auf Minus und auch ein 100 N dazwischen.

von jochen (Gast)


Lesenswert?

Können in einem Register eigentlich auch Bruchzahlen stehen also z.B. 
4,2
oder sogar irrationale Zahlen?

von Johannes M. (johnny-m)


Lesenswert?

Thilo M. wrote:
> @  Johannes M.:
> (sorry für den neuen Nick, hab' endlich Zeit gefunden mich anzumelden
> ;))
Na, so lange dauert das aber auch nicht...;-)

> (5/1023) * 1023 = 5
> und
> (5/1023) * 0 = 0
> oder?
Nö, eben nicht! Am besten schauste Dir mal eine Beschreibung der 
Funktion des Successive Approximation Converters an (konkrete Quelle im 
Netz hab ich grad nicht parat, sollte aber mit "Ole Friend" Google o.ä. 
zu finden sein). Da steht erstens die korrekte Formel (mit 1024!) und 
außerdem, warum das so ist (das gehört imho nicht hierher, zumal es wie 
gesagt hier schon einige Threads zu dem Thema gab, in denen der ADC 
quasi totdiskutiert wurde).

> Also decke ich somit den tatsäclichen Bereich ab.
> Nachgemessenermaßen (mit Kalibrierquelle) ist das auch so.
Wer viel misst, misst viel Mist... Im Ernst: Ein SAR-Wandler kann 
nicht VREF wandeln. Gründe siehe voriger Absatz. Dass bei der Messung 
eine (scheinbare) Übereinstimmung herauskommt, liegt erstens an der 
Auflösung (1 LSB ist bei VREF = 5 V grad mal bei knapp 50 mV) und an der 
Digitalisierung (siehe mein vorletztes Posting). Und ja: Bei VREF = 5 V 
und VIN = 5 V kriegst Du (aus o.g. Gründen) selbstverständlich den 
Maximalwert raus! Aber eben (bei gleichem VREF) auch bei VIN = 4,951 V 
(VREF - 1LSB). Alles, was größer ist, als VREF-1LSB gibt 1023...

EDIT: Die Formel steht übrigens auch in den Datenblättern der 
betreffenden AVRs. OK, in den ATMEL-Datenblättern sind auch von Zeit zu 
Zeit ein paar Fehlerchen drin, aber in dem Fall lügt das Datenblatt mal 
nicht...

von Thilo M. (Gast)


Lesenswert?

OK, will nicht weiter diskutieren. Tatsache ist, wenn ich 5V anlege will 
ich auch 5.000V sehen, nicht etwas kleineres. Dass die Schrittweite 
nicht 4.883mV sondern 4.888mV ist stört wohl niemanden! Der Endanschlag 
sollte jedoch 5.000 zeigen, nicht 4.995.

von Johannes M. (johnny-m)


Lesenswert?

jochen wrote:
> Können in einem Register eigentlich auch Bruchzahlen stehen also z.B.
> 4,2
> oder sogar irrationale Zahlen?
Wie man die 8 Bit in einem Register interpretiert, ist weitgehend Sache 
des Anwenders. Es steht Dir frei, Register für Deine Interpretation 
aufzuteilen. Allerdings besitzen die AVRs mit Hardware-Multiplier 
tatsächlich Multiplikations-Befehle (fmul..., fractional multiply), die 
auf eben einer solchen Aufteilung des Register-Inhalts in Vor- und 
Nachkommateil basieren.

von Simon K. (simon) Benutzerseite


Lesenswert?

Thilo M. wrote:
> OK, will nicht weiter diskutieren. Tatsache ist, wenn ich 5V anlege will
> ich auch 5.000V sehen, nicht etwas kleineres. Dass die Schrittweite
> nicht 4.883mV sondern 4.888mV ist stört wohl niemanden! Der Endanschlag
> sollte jedoch 5.000 zeigen, nicht 4.995.

Du kannst (wie schon gesagt) bei der sukzessiven Approximation keine 
VREF messen. Das ist Fakt. (<- Punkt!)


jochen wrote:
> Können in einem Register eigentlich auch Bruchzahlen stehen also z.B.
> 4,2
> oder sogar irrationale Zahlen?

Siehe Johannes oben für eine generelle Antwort. Der ADC hingegen spuckt 
in seinen Registern eine einfache natürliche Zahl aus, die umgerechnet 
werden kann. (Siehe Datenblatt...)

von jochen (Gast)


Lesenswert?

Das habe ich noch nicht ganz verstanden.
Ich verdeutliche das Problem anhand von Johannes Formel.
Wenn ich diese Formel anwende bekomme ich

1023*5 / 1024  = 4,9(95117188)
stimmt das soweit?

Wie würde diese Zahl denn jetzt konkret in einem Register aussehen? 
würde das in etwa so sein:

100,1001
4,9

von Simon K. (simon) Benutzerseite


Lesenswert?

@jochen: Nein, warum würdest du denn sonst eine Formel brauchen? Das 
macht doch null Sinn!

Du hast doch selbst ein Beispiel gegeben:

jochen wrote:
> 1023*5 / 1024  = 4,9(95117188)

1023 ist der Wert, den du aus den Beiden Registern gelesen hast. 5 ist 
die Referenzspannung in Volt und 4,9.... ist das Ergebnis in Volt. Das 
ist die Spannung, die am ADC-Pin anliegt.

von jochen (Gast)


Lesenswert?

Das ist mir schon klar. Die Frage ist was passiert, wenn bei einem 
Rechenschritt mal keine ganzen Zahlen auftreten.

z.B.

ldi r4,5
ldi r6,8

wenn ich jetzt
r4 / r6 rechne (über andere Operationen) und das Ergebnis z.B. in r8 
speicher, hat r8 ja den Wert 0,625

wie sähe aber der Inhalt des Registers nun wirklich aus ? (binär)

von Simon K. (simon) Benutzerseite


Lesenswert?

jochen wrote:
> z.B.
>
> ldi r4,5
> ldi r6,8
>
> wenn ich jetzt
> r4 / r6 rechne (über andere Operationen) und das Ergebnis z.B. in r8
> speicher, hat r8 ja den Wert 0,625
>
> wie sähe aber der Inhalt des Registers nun wirklich aus ? (binär)

Kommt drauf an. Wenn du C benutzt und einen float datentyp nimmst, wird 
die Zahl als Fließkommazahl dargestellt (Allerdings in mehr als einem 
Register...).

Divisionsfunktionen in Assembler funktionieren anders. Diese Routinen 
spucken in der Regel das Ergebnis und den Rest der Division aus. Sprich:


8/5 = 1 Rest 3
3/4 = 0 Rest 3

Dieses Gesamt-ergebnis ist aber dann auf mehrere Register aufgeteilt.

Wie also schon von dem guten johnny-m gesagt:
> Wie man die 8 Bit in einem Register interpretiert, ist weitgehend Sache
> des Anwenders.

Sprich: Wie das Ergebnis der Division aussieht ist Sache der 
Divisionsfunktion (Die ja der "Anwender" entwickelt hat).

von Johannes M. (johnny-m)


Lesenswert?

> Das ist mir schon klar. Die Frage ist was passiert, wenn bei einem
> Rechenschritt mal keine ganzen Zahlen auftreten.
Hast Du in der Schule mal schriftliche Division gelernt? Da kommt immer 
ein Divisionsergebnis und ein Rest raus. Und genau das passiert auch bei 
den Standard-Divisionsalgorithmen.

Du kannst die Formel in Assembler nicht direkt anwenden! Der Controller 
kann grundsätzlich nur mit ganzen (binär-)Zahlen rechnen. Alles 
darüberhinausgehende sind Tricks, mit denen man sich behelfen kann, 
indem man so tut als handele es sich um etwas anderes als ganze Zahlen. 
Es ist, wie oben schon gesagt, eine reine Interpretationssache. Ein 
Trick wäre z.B., die ganze Berechnung in mV durchzuführen (Faktor 1000, 
5 V wäre dann ein Wert von 5000) und erst bei der Berechnung der 
auszugebenden Ziffern an der richtigen Stelle das Dezimaltrennzeichen 
einzubauen. Das ganze lässt sich aber (wie so vieles) nicht in einem 
Register durchführen, da da nunmal nur 256 verschiedene Zustände 
reingehen.

von Thilo M. (Gast)


Lesenswert?

>5 ist die Referenzspannung in Volt und 4,9.... ist das Ergebnis in Volt.
>Das ist die Spannung, die am ADC-Pin anliegt.

FALSCH!
Es liegen 5V an.
Das ist es ja, was ich sagen will! Wenn ich dieselbe Spannung von genau 
5.000V an Uref unf den Messeingang lege, bekomme ich bei der Formel 
1023*5 / 1024  = 4,9(95117188)V raus. => passt nicht. Deshalb muss 
(5/1023)*Messwert benutzt werden.
Es liegen definitiv 5V am Eingang an, diese will ich als Ergebnis auch 
sehen, egal was die Technik der AD-Wandlung zulässt.

von Simon K. (simon) Benutzerseite


Lesenswert?

Thilo M. wrote:
>>5 ist die Referenzspannung in Volt und 4,9.... ist das Ergebnis in Volt.
>>Das ist die Spannung, die am ADC-Pin anliegt.
>
> FALSCH!
> Es liegen 5V an.
> Das ist es ja, was ich sagen will! Wenn ich dieselbe Spannung von genau
> 5.000V an Uref unf den Messeingang lege, bekomme ich bei der Formel
> 1023*5 / 1024  = 4,9(95117188)V raus. => passt nicht. Deshalb muss
> (5/1023)*Messwert benutzt werden.
> Es liegen definitiv 5V am Eingang an, diese will ich als Ergebnis auch
> sehen, egal was die Technik der AD-Wandlung zulässt.

Nein, du liegst falsch. Es liegen 5V an - soweit richtig. Aber was ist 
an folgendem, einfachen, deutschen, grammatikalisch richtigen Satz 
falsch zu verstehen:

johnny-m wrote:
> Alles, was größer ist, als VREF-1LSB gibt 1023...

Du kannst eine Spannung, die genauso groß ist wie VREF mit einem SAR 
Wandler NICHT messen.

von jochen (Gast)


Lesenswert?

Ja, das merk ich auch gerade. Wenn ich jetzt z.B.

3*256 = 768 rechnen möchte komme ich mit 8 Bit nicht aus.
Welchen Trick nimmt man denn um das doch zu berechnen?

von Thilo M. (Gast)


Lesenswert?

1023 SIND 5V. Was ist daran nicht zu verstehen?

von Johannes M. (johnny-m)


Lesenswert?

Thilo M. wrote:
>>5 ist die Referenzspannung in Volt und 4,9.... ist das Ergebnis in Volt.
>>Das ist die Spannung, die am ADC-Pin anliegt.
>
> FALSCH!
> Es liegen 5V an.
> Das ist es ja, was ich sagen will! Wenn ich dieselbe Spannung von genau
> 5.000V an Uref unf den Messeingang lege, bekomme ich bei der Formel
> 1023*5 / 1024  = 4,9(95117188)V raus. => passt nicht. Deshalb muss
> (5/1023)*Messwert benutzt werden.
> Es liegen definitiv 5V am Eingang an, diese will ich als Ergebnis auch
> sehen, egal was die Technik der AD-Wandlung zulässt.
Himmelarsch, NEIN. Deine Formel ist FALSCH!!! Wenn es DIR egal ist, was 
da rauskommt, dann ist das DEINE Sache. Erzähl aber bitte keinem 
Anfänger, dass das korrekt ist!

Vorschlag: Lies Dir bitte, bevor Du hier weiter solche Sachen 
verbreitest, in der einschlägigen Literatur durch, wie der Wandler 
funktioniert und bei welcher Spannung er 1023 ausspuckt (nämlich bei 
allem, was größer oder gleich VREF - 1 LSB ist).

von Simon K. (simon) Benutzerseite


Lesenswert?

jochen wrote:
> Ja, das merk ich auch gerade. Wenn ich jetzt z.B.
>
> 3*256 = 768 rechnen möchte komme ich mit 8 Bit nicht aus.
> Welchen Trick nimmt man denn um das doch zu berechnen?

Jou richtig erkannt. Deswegen wird das 10Bit breite Ergebnis ja auch 
nicht in einem 8-Bit Register untergebracht, sondern in zweien :-)

In C kannst du einfach einen Int-Typen nehmen. Der hat noch genug Platz 
für ein paar Berechnungen. In Assembler gibt es spezielle 
Arithmetik-befehle um eine 16-Bit (bzw 10-Bit in diesem Falle) Zahl, die 
auf 2 Registern aufgeteilt ist, als eine zu interpretieren. Diese 
Funktionen benutzen das Carry-Bit.

Zum Beispiel:
ADD - ADC
SUBI - SUBC

Erstere ist eine reine 8-Bit Funktion. Letzteres das zugehörige 
Größer-als-ein-register pendant.

Thilo M.
> 1023 SIND 5V. Was ist daran nicht zu verstehen?

Da ist alles dran zu verstehen. Das Problem ist nur - Das ist falsch :P

von Johannes M. (johnny-m)


Lesenswert?

Simon Küppers wrote:
> johnny-m wrote:
>> Alles, was größer ist, als VREF-1LSB gibt 1023...
>
> Du kannst eine Spannung, die genauso groß ist wie VREF mit einem SAR
> Wandler NICHT messen.
Genau das sage ich ja die ganze Zeit. Der letzte Digitalisierungsschritt 
ist VREF-1LSB. Alles was größer / gleich VREF-1LSB ist, ergibt 1023!

So, und jetzt mach ich Feierabend für heute...

von jochen (Gast)


Lesenswert?

@Simon, bevor ich mich damit befasse würde ich gerne wissen was du mit

"Deswegen wird das 10Bit breite Ergebnis ja auch
nicht in einem 8-Bit Register untergebracht, sondern in zweien "

meinst.

Wahrscheinlich das low und high Registern, in denen der gemessene Wert 
gespeichert wird. Leider habe ich bis jetzt noch nicht verstanden, was 
das überhaupt für Zahlen sind, die da gespeichert werden (sondern nur, 
dass sie über eine Formel in den richtigen Wert gewandelt werden 
müssen).

Was sind das für 2 Zahlen :-) ?

von Hannes L. (hannes)


Lesenswert?

Thilo M. wrote:
> 1023 SIND 5V. Was ist daran nicht zu verstehen?

Nööö, 1024 sind 5V... Das Verbiegen des Faktors ist die schlechtere 
Lösung. Die bessere Lösung ist das Addieren eines Wertes der halben 
Auflösung (Rundung)...

Wobei ich es lächerlich finde eine Genauigkeit vorzutäuschen, die 
aufgrund der anderen Gegebenheiten gar nicht möglich ist. Hier mal ein 
ganz einfaches Beispiel für ADC mit Skalierung:


;Beispiel für ADC am Mega8535...

;Es wird die Spannung eines 12V-Blei-Gel-Akkus gemessen, der über
;einen 78L05 einen Mega8535 versorgt. Als Referenz wird AVCC des
;AVRs genommen (also die 5V des 78L05), die Spannung des 12V-Akkus
;wird über einen Spannungsteiler aus drei gleichen Widerständen
;(3 x 10k) durch 3 geteilt und an ADC7 angelegt.
;Da es kein "Messgerät", sondern nur eine Akkuzustandsanzeige sein
;soll, genügt die Anzeige mit einer Nachkommastelle ("12,9V") auf
;dem LCD 8x24, das noch genügend andere Dinge anzuzeigen hat.

;ADC-Initialisierung in der Reset-Routine:
1
 ...
2
 ldi wl,(1<<adlar)|(1<<refs0)+7;ADC-Quelle 0, 
3
 out admux,wl               ;linksbuendig
4
 ldi wl,(1<<aden)|(1<<adsc)|(1<<adate)+4 ;ADC ein
5
 out adcsra,wl              ;
6
 ...

;zyklischer Aufruf in der Mainloop alle 100 ms:
1
 ...
2
 in r0,adch                 ;ADC-Wert (1/3 der Akkuspannung) einlesen
3
 ldi wl,151                 ;Skalierungsfaktor
4
 mul r0,wl                  ;auf ZehntelVolt skalieren
5
 locate 6,5                 ;Ausgabeposition Spannung
6
 print16 null,r1,1,using    ;Wert mit 1 Kommastelle ausgeben
7
 print 'V',1                ;Einheitszeichen ausgeben
8
 ...

...

von Simon K. (simon) Benutzerseite


Lesenswert?

jochen wrote:
> @Simon, bevor ich mich damit befasse würde ich gerne wissen was du mit
>
> "Deswegen wird das 10Bit breite Ergebnis ja auch
> nicht in einem 8-Bit Register untergebracht, sondern in zweien "
>
> meinst.
>
> Wahrscheinlich das low und high Registern, in denen der gemessene Wert
> gespeichert wird. Leider habe ich bis jetzt noch nicht verstanden, was
> das überhaupt für Zahlen sind, die da gespeichert werden (sondern nur,
> dass sie über eine Formel in den richtigen Wert gewandelt werden
> müssen).
>
> Was sind das für 2 Zahlen :-) ?

Die 2 Zahlen sind eigentlich eine Zahl. Und zwar eine 10-Bit breite 
Zahl. Du musst dir das so vorstellen:
Der AD-Converter hat eine bestimmte Auflösung (hier nämlich 10-Bit). Das 
heißt: Er kann einen Spannungsbereich (nämlich 0V bis VREF) in 2^10 
Stufen aufteilen. Legst du jetzt eine Spannung an den Pin an, und lässt 
den AD-Converter wandeln, so gibt er dir als Ergebnis sozusagen die 
Stufe aus, in der sich die an den AD-Pin gelegte Spannung befindet.
Das kann eine Zahl sein, die zwischen 0 (Spannung ist 0V) und 1023 
(Spannung ist VREF-1LSB) liegt.
Das ist die ganze Funktionalität des ADC-Wandlers. Was du nun mit dem 
"Stufen-Wert" anstellst, ist deine Sache. Eine Methode ist es eben diese 
Formel anzuwenden um den "Stufen-Wert" in einen absoluten Spannungswert 
umzurechnen.

Blöderweise ist die Zahl 1023 (Also der höchste Wert des ADCs) aber 10 
Bit breit. Der Controller hat aber nur 8-Bit Register. Also wird der 
Wert aufgetrennt und auf zwei Register verteilt. Eigentlich blöd - 
oder?. Nö! Denn der Mikrocontroller ist in der Lage eine Zahl, die über 
mehrere Register verteilt ist, aber eigentlich zusammengehörig ist auch 
als zusammengehörig zu behandeln. Siehe mein obiger Post mit den 
Carry-Funktionen. Wenn du nicht weißt, was es mit dem Carry-Flag auf 
sich hat, würde ich dir etwas Grundlektüre zur Funktionsweise eines 
Mikrocontrollers empfehlen.

@Hannes:
> Nööö, 1024 sind 5V... Das Verbiegen des Faktors ist die schlechtere
> Lösung. Die bessere Lösung ist das Addieren eines Wertes der halben
> Auflösung (Rundung)...

Du hast schon Recht, allerdings wird der ADC niemals 1024 ausspucken ;) 
Aber das weißt du auch selber. Nur dass das hier nicht für Verwirrung 
sorgt.

> Wobei ich es lächerlich finde eine Genauigkeit vorzutäuschen, die
> aufgrund der anderen Gegebenheiten gar nicht möglich ist.

Da hast du natürlich auch Recht (was auch sonst ;)), aber trotzdem 
sollte man immer versuchen mathematisch korrekt zu sein.

von Spess53 (Gast)


Lesenswert?

Hi

Wie das Ergebnis aussieht ist, von deiner Dividierroutine abhängig. Da 
es keinen Dividierbefehl gibt hängt die Interpretation der Zahlen und 
das Ergebnis vom Programmierer ab. Für die Floatmultiplikationen der 
AVRs wird z.B. bei 8 Bit folgendes Format verwendet:

 MSB: Vorzeichen, a*2^-1,b*2^-2, c*2^-3,d*2^-4,e*2^-5,f*2^-6,g*2^-7

wobei Vorzeichen,a..g 0 oder 1 sein können.
Daneben existieren noch eine ganze Reihe anderer Fliess- und 
Festkommaformate. Trotzdem ist allen eines gemeinsam: sie bestehen nur 
aus Bits(0/1). Nur die Bedeutung eines Bits ist unterschiedlich.
Die meisten Divierroutinen arbeiten mit Ganzzahlen. Bei deinem obigen 
Beispiel wurde 0 herauskommen (bestentfalls mit einem Rest 5).

MfG Spess

von jochen (Gast)


Lesenswert?

Danke für dei Beschreibungen, jetzt ist mir dei Funktionsweise auch 
einigermaßen klar.


"Wenn du nicht weißt, was es mit dem Carry-Flag auf
sich hat, würde ich dir etwas Grundlektüre zur Funktionsweise eines
Mikrocontrollers empfehlen."

Das Carry Flag ist doch das Flag was gesetzt ist wenn das Ergebnis nicht 
mehr in das Register passt, oder irre ich (overflow)

Könntest du / ihr mir noch sagen wie ich eine Zahl, die in mehreren 
registern ist aber eigentlich zusammengehört dann auch als 
zusammengehörig betrachtet wird?
Und andersrum wie ich mit Zahlen rechne, welche die Bitbreite 
überschreiten z.B. 256 *3. Da wurde oben zwar schon was zu gesagt aber 
das reicht mir leider nicht.

von Simon K. (simon) Benutzerseite


Lesenswert?

jochen wrote:
> Das Carry Flag ist doch das Flag was gesetzt ist wenn das Ergebnis nicht
> mehr in das Register passt, oder irre ich (overflow)
>
> Könntest du / ihr mir noch sagen wie ich eine Zahl, die in mehreren
> registern ist aber eigentlich zusammengehört dann auch als
> zusammengehörig betrachtet wird?
> Und andersrum wie ich mit Zahlen rechne, welche die Bitbreite
> überschreiten z.B. 256 *3. Da wurde oben zwar schon was zu gesagt aber
> das reicht mir leider nicht.

Ja, so in der Art. In Assembler (In C brauchst du dich darum nicht 
kümmern.) machst du das folgendermaßen:
1
; r16:r17 stellt eine 16-Bit Zahl (ABCD Hex.) dar
2
ldi r16, HIGH(0xABCD)
3
ldi r17, LOW(0xABCD)
4
5
; r18:r19 ist eine zweite 16-Bit Zahl.:
6
ldi r18, HIGH(0x1111)
7
ldi r19, LOW(0x1111)
8
9
; Addiere r18:r19 auf r16:r17. Zuerst die Low-Bytes. Dann die High-Bytes
10
add r16, r18 
11
adc r17, r19

So in der Art sollte das aussehen. Funktionsweise:
add (Erster Teil der 16-Bit Addition) setzt das Carry-Flag. Jenachdem, 
ob bei der Addition das Register übergelaufen ist.
adc (Zweiter Teil) addiert ebenfalls (wie add) die Register. ABER: Es 
wertet zudem noch das Carry-Flag aus. Ist es 1, so wird adc 1 zu dem 
High register hinzuzählen.

von jochen (Gast)


Lesenswert?

Ich danke dir, ich muss mir das jetzt in Ruhe ansehen und auch mal die 
Zahlen was verändern und mit dem Studio mal simulieren. Das könnte aber 
was dauern. Ich melde mich morgen noch einmal und möchte mich recht 
herzlich bedanken. Kennt ihr denn Bücher wo sowas alles erklärt ist? Ich 
finde  leider auch in google keine Links wo man das nachlesen kann. Wie 
habt ihr das denn gelernt?

von jochen (Gast)


Lesenswert?

(In dem Tutorial steht das ja so erkenntlich garnicht drin)

von jochen (Gast)


Lesenswert?

Ich habe mir das Beispiel nun angesehen.
Wie teilt sich eine Zahl denn in 2 Register genau auf, also wie sieht 
der low und der high Anteil aus?

Zum Beispiel

ldi r16, HIGH(1024)
ldi r17, LOW(1024)

Jetzt habe ich die 1024 aufgeteilt auf die Register r16 und r17. Ok, 
aber was genau von der 1024 ist jetzt in r16 und was genau in r17?

von Simon K. (simon) Benutzerseite


Lesenswert?

Stell dir die Zahl 1024 einfach binär vor:
1
00000100 00000000

Wenn du nun folgenden Code ausführst:
1
ldi r16, HIGH(1024)
2
ldi r17, LOW(1024)

Wird das Register r16 mit dem HIGH-Teil geladen. Das wären:
1
00000100
Das Register r17 wird mit dem LOW-Teil geladen.
1
00000000
Und schon kann der Prozessor damit rechnen.

PS: Die Makros "HIGH" und "LOW" sind nicht unbedingt notwendig, machen 
die Sache aber einfacher. Du kannst in diesem Falle hier genauso gut 
schreiben:
1
ldi r16, 0b00000100
2
ldi r17, 0b00000000

Das wäre genau das gleiche.

von jochen (Gast)


Lesenswert?

Danke, Simon!
Ich habe eben überlegt, wie die Multiplikation nach diesem Schema 
abläuft, bin  aber leider nicht darauf gekommen. Hast du dafür auch ein 
Schema?

von Johannes M. (johnny-m)


Lesenswert?

Kleiner Tip am Rande:
Es gibt bei den AVRs auch ein paar Befehle (z.B. adiw, sbiw), die 16 Bit 
(zwei hintereinander befindliche Register) gleichzeitig verarbeiten 
können. Diese Befehle funktionieren allerdings nur dann korrekt, wenn 
Low- und High-Byte des 16-Bit-Wortes in der richtigen Reihenfolge 
stehen. Die AVRs sind "Little-Endian" ("Intel-Format"), d.h. das 
Low-Byte eines Datenwortes wird an der niedrigeren Speicheradresse 
(niedrigere Registernummer) abgelegt. Um spätere Probleme damit zu 
vermeiden, ist es vielleicht sinnvoll, sich gleich die Reihenfolge 
anzugewöhnen. In dem Beispiel mit den 1024 müssten dann Low- und 
High-Byte vertauscht werden, also
1
ldi r17, HIGH(1024)
2
ldi r16, LOW(1024)

(das ganze gilt übrigens auch für Befehle, die mit indirekter 
Adressierung und den damit verbundenen Zeigern, die in speziellen 
Registerpaaren stehen, arbeiten und die sich jedem Programmierer 
irgendwann aufdrängen)

von Simon K. (simon) Benutzerseite


Lesenswert?

@Johannes M.: ouh, damit habe ich noch nie gearbeitet :-) Klingt aber 
schlüssig.

jochen wrote:
> Danke, Simon!
> Ich habe eben überlegt, wie die Multiplikation nach diesem Schema
> abläuft, bin  aber leider nicht darauf gekommen. Hast du dafür auch ein
> Schema?

Die neuen AVRs haben eine Multipliziereinheit, die 2 8-Bit-Werte 
multiplizieren können. Das Ergebnis wird aber als 16-Bit ausgegeben. 
Logisch: Der Wertebereich ist bei 8Bit * 8Bit = 16Bit.

Bei einer 16*16Bit Multiplikation muss ich leider passen.

von Johannes M. (johnny-m)


Lesenswert?

Simon Küppers wrote:
> Die neuen AVRs haben eine Multipliziereinheit,...
Genauer gesagt: Die ATMegas. Die Tinys haben sowas nicht.

> ...die 2 8-Bit-Werte
> multiplizieren können. Das Ergebnis wird aber als 16-Bit ausgegeben.
> Logisch: Der Wertebereich ist bei 8Bit * 8Bit = 16Bit.
Richtig. Und auch dabei ist die Reihenfolge zu beachten: Das Low-Byte 
des Ergebnisses liegt im Register mit der niedrigeren Adresse.

von Johannes M. (johnny-m)


Lesenswert?

Die Appnote AVR200 von ATMEL (deren Existenz ganz oben schon mal 
angedeutet wurde) beinhaltet neben Divisions- auch 
Multiplikationsroutinen für 8 und 16 Bit, mit und ohne Vorzeichen. Ist 
zwar leider auf Englisch, aber es macht jedenfalls Sinn, sich diese 
Routinen einfach mal anzusehen und zu versuchen, ihre Funktion zu 
verstehen.
http://www.atmel.com/dyn/resources/prod_documents/doc0936.pdf

von jochen (Gast)


Lesenswert?

also mein Ziel ist es ja,

1. 768 +255 = 1023

2. 1023 * 5 = 5115

3. 5115 / 1024 = 4,9

zu berechnen.
1. Hab ich ja jetzt.
Beim 2. Schritt komme ich nicht weiter.
Ich wüsste zwar, wie ich das mit 8 Bit Registern mache, aber nicht wenn 
eine Zahl, hier die 1023 auf 2 Register aufgeteilt ist. Der Link von 
Johannes hilft mir leider auch  nicht, das dzu verstehen.

von Johannes M. (johnny-m)


Lesenswert?

Überleg mal, was da jetzt explizit in den beiden Registern steht: Du 
hast ein High-Byte und ein Low-Byte. Nimm jetzt an, Du hast ein 
Zahlensystem mit der Basis 256 (also eben nicht Zehn wie im 
Dezimalsystem, sondern so viel, wie sich mit einem Byte eben darstellen 
lässt). In diesem Zahlensystem hast Du jetzt zwei Stellen: Das Low-Byte 
sind die "Einer" und das High-Byte die "256er". Für die Zahl 1023 aus 
dem Beispiel (0000 0011 1111 1111 in Binärdarstellung) hieße das jetzt, 
dass die Einer-Stelle den Wert 1111 1111 (also dezimal 255) hat, und die 
256er-Stelle den Wert 0000 0011 (dezimal 3). Daraus folgt
Nur zur Verdeutlichung: Das entspricht der Aufschlüsselung der 1023 im 
Dezimalsystem nach Einern, Zehnern, Hundertern und Tausendern (1023 = 1 
* 1000 + 0 * 100 + 2 * 10 + 3 * 1), nur dass hier jetzt jede Stelle 
nicht 10, sondern 256 Zustände annehmen kann. Und jetzt überlege mal 
(mit Schulmathematik), wie man eine Dezimalzahl multipliziert und 
versuche, das Schema auf das 256er-Zahlensystem zu übertragen.

Ich muss jetzt leider grad mal weg, schaue aber nach mittag noch mal 
rein, wenn ich Zeit hab...

von jochen (Gast)


Lesenswert?

Hi Johannes, danke auch Dir, dass du dir da so eine Mühe machst.
Ich habe dein letztes Posting soweit verstanden.

1023*5 = 5115 im 256er System:

1023 entspricht 3255
5 entspricht 5

also

3255*5
-------
15102525

es entstehen keine Überträge, da 256 nie erreicht wird.

Stimmt das bis hier hin?
Wie wäre diese Zahl zu interpretieren d.h. Wo sind die Einerstellen, die 
256er Stellen, die 256^2 Stellen usw?

von Johannes M. (johnny-m)


Lesenswert?

jochen wrote:
> Hi Johannes, danke auch Dir, dass du dir da so eine Mühe machst.
> Ich habe dein letztes Posting soweit verstanden.
>
> 1023*5 = 5115 im 256er System:
>
> 1023 entspricht 3255
> 5 entspricht 5
>
> also
>
> 3255*5
> -------
> 15102525
>
> es entstehen keine Überträge, da 256 nie erreicht wird.
>
> Stimmt das bis hier hin?
> Wie wäre diese Zahl zu interpretieren d.h. Wo sind die Einerstellen, die
> 256er Stellen, die 256^2 Stellen usw?
Nee, Du musst die einzelnen Stellen separat betrachten! 3255 muss 
eigentlich (3 255) geschrieben werden. Das sind nicht 
dreitausenzweihundertfünfundfünfzig! Worauf ich hinauswollte, war, dass 
Du die 16-Bit  8-Bit-Multiplikation durch die Summe zweier 8-Bit  
8-Bit-Multiplikationen ersetzen kannst. Wenn Du im Dezimalsystem 1023 
mit 5 multiplizierst, dann rechnest Du
1023 = 1 * 1000 + 0 * 100 + 2 * 10 + 3 * 1
1  1000  5 =           5 * 1000
0  100   5 =           0 * 100
2  10    5 = 10 * 10 = 1 * 100
3  1     5 = 15 * 1  = 1 * 10 + 5 * 1
                         --------------
                         5 * 1000 + 1 * 100 + 1 * 10 + 5 * 1 = 5115

Im 256er-System hast Du jetzt
3    256  5 =            15 * 256
255  1    5 = 1275 * 1 = 4 * 256 + 251 * 1
                           -----------------
                           19 * 256 + 251 * 1 (= 5115)
Du machst also für das Low- und das High-Byte jeweils eine separate 
Multiplikation und addierst die Ergebnisse.
Bsp.:
1
Ausgangswert, High-Byte      0000 0011 (3)
2
Ausgangswert, Low-Byte       1111 1111 (255)
3
Multiplikator                0000 0101 (5)
4
5
Ergebnis Multipl. High-Byte  0000 0000 0000 1111 (15) [16 Bit!]
6
Ergebnis Multipl. Low-Byte   0000 0100 1111 1011 (1275) [16 Bit!]
7
8
Ergebnis High-Byte * 256     0000 0000 0000 1111 0000 0000 (3840) [24 Bit!]
9
10
-> Summe High + Low (in 24 Bit):
11
                             0000 0000 0000 1111 0000 0000 (3840)
12
                          +  0000 0000 0000 0100 1111 1011 (1275)
13
                          ---------------------------------------
14
                             0000 0000 0001 0011 1111 1011 (5115)
Das wäre dann die Multiplikation.

von jochen (Gast)


Lesenswert?

Ok, danke. Das konnte ich gut nachvollziehen.
Eine Unklarheit hab ich noch.

Ergebnis Multipl. High-Byte  0000 0000 0000 1111 (15) [16 Bit!]
Ergebnis Multipl. Low-Byte   0000 0100 1111 1011 (1275) [16 Bit!]


Es entsteht bei der Multiplikation von 255 mit 4 ein 16 Bit Ergebnis. 
Wie setze ich das denn um? Müsste ich dann das high und Low bye jeweils 
wieder in ein High und Low byte unterteilen?

von jochen (Gast)


Lesenswert?

... ich meinte "255 mit 5 "

von Johannes M. (johnny-m)


Lesenswert?

jochen wrote:
> Es entsteht bei der Multiplikation von 255 mit 4 ein 16 Bit Ergebnis.
> Wie setze ich das denn um? Müsste ich dann das high und Low bye jeweils
> wieder in ein High und Low byte unterteilen?
Das ist ja bereits der Fall. Wie weiter oben schon erwähnt, legen die 
Multiplikationsbefehle das Ergebnis in zwei Registern ab (r0 und r1), 
unter Beachtung der Reihenfolge (niedrigere Adresse -> Low-Byte). Da 
musst Du sie dann abholen und weiterbearbeiten.

von Hannes L. (hannes)


Lesenswert?

jochen wrote:
> Wie setze ich das denn um?

Jochen, denke mal an das schriftliche Multiplizieren mehrstelliger 
Zahlen in der Grundschule.

Man multipliziert eine Stelle des einen Faktors nach der anderen mit dem 
anderen Faktor, schreibt die Zwischenergebnisse stellenversetzt 
untereinander und addiert sie anschließend.

Das musst Du doch iin der Grundschule gelernt haben!

Oder hast Du etwa durch den Besitz eines Taschenrechners damals in der 
Grundschule bereits geschummelt und Dich somit vor dem Erlernen 
wichtigen Grundwissens gedrückt? Dann hat das hier alles keinen Zweck, 
dann musst Du nochmal mit der Grundschule beginnen, sorry...

...

P.S.: Langsam nervt die Lernresistenz dieser Jochens und Nick-Simons...
Das spamt das ganze Forum zu...

von jochen (Gast)


Lesenswert?

Hi, danke ich rechne jetzt einfach mal, simuliere im AVR Studio um das 
zu verarbeiten. Ich melde mich dann die nächsten Tage nochmal und 
berichte von meinen Ergebnissen. Danke!

von jochen (Gast)


Lesenswert?

Wenn es nervt, wieso antwortest du dann?
Das Multiplizieren von Zahlen in anderen Zahlenformaten als dem 
Zehnersystem ist Hochschulstoff der ersten Semester. Ist der Unterschied 
Hoch und Grundschule klar? Sorry, aber ich finde deinen  Einwand einfach 
nicht berechtigt.

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
> Wenn es nervt, wieso antwortest du dann?
> Das Multiplizieren von Zahlen in anderen Zahlenformaten als dem
> Zehnersystem ist Hochschulstoff der ersten Semester.

Das Prinzip ist völlig identisch und unabhängig vom
Zahlensystem.

Jochen, ich glaube, du denkst noch viel zu kompliziert.
Das alles ist viel einfacher als du jetzt vermutest.


von jochen (Gast)


Lesenswert?

Ja ich schau mir das auch morgen in Ruhe mal an und dann denke ich 
bekomme ich das Prinzip auch raus. Nur jetzt sagen ich soll in der 
Grundschule anfangen finde ich schon ziemlich krass.

Habt ihr damit eigentlich beruflich zu tun oder macht ihr das nur 
hobbymäßig? Studiert in diesem Bereich?

von Karl H. (kbuchegg)


Lesenswert?

Du kennst das Prinzip von Low-Byte/High-Byte schon längst,
nur warst du dir nie darüber bewusst.

Nehmen wir mal das gewohnte Dezimalsystem.
Angenommen du hättest eine 2 stellige 'Maschine'

     +---+---+
     |   |   |
     +---+---+

Jede Box in dieser Maschine, kann eine Ziffer von 0 bis 9
aufnehmen. zb

     +---+---+
     | 5 | 6 |
     +---+---+

und wir interpretieren diese Zahl als 56 (also 5 Zehner und
6 Einer)

Um da jetzt 18 zu addieren, gehst du wie folgt vor:
du nimmst die rechte Box und addierst die 8:  6 + 8 = 14
Nur gibt es da jetzt ein Problem: Jede Box kann nur Ziffern
von 0 bis 9 aufnehmen. 14 geht nicht in diese Box hinein.
Also gehen wir so vor: In die Ergebnisbox kommt eine 4 und
wir merken uns, dass bei der nächsten Stelle links eine zusätzliche
Eins noch mit dazu addiert werden muss (genau: Das ist der
berühmte Carry).
Die zweite Addition lautet daher 5 + 1 + 1 (wegen dem Carry) = 7

Das Ergebnis ist daher

    +---+---+
    | 7 | 4 |
    +---+---+

und du ahnst es schon: In diesem Beispiel fungiert die linke
Box als 'High-Byte' und die rechte als 'Low-Byte'. Das Prinzip
jedoch ist völlig identisch, egal ob ich jetzt im Dezimalsystem,
oder Hex, oder Binär oder sonst irgend ein Zahlensystem benutze.

Binär ist halt besonders einfach, weil das 'kleine Einmaleins'
der Addition besonders einfach wird.

    0 + 0  = 0
    0 + 1  = 1
    1 + 0  = 1
    1 + 1  = 0  und 1 Übertrag

Aus praktischen Gründen wird allerdings nicht jede einzelne der
Binären Ziffern in einer eigenen Box gespeichert (na ja, eigentlich
schon), sondern jeweils 8 Stück davon werden zusammengefasst und
in ein 'Register' verbannt. Das ändert aber nichts am Prinzip.
Wenn du mit 16 Bit Zahlen operierst, dann sind da erst mal
16 derartige Boxen nebeneinander. Da in ein Register aber nur
8 davon hineinpassen, nimmt man einfach 2 davon her und nennt
das eine das Low-byte und das andere das High-Byte

    15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

    |                           |   |                           |
    +---------------------------+   +---------------------------+
            High Byte                      Low Byte

          gespeichert in einem          gespeichert in einem
                Register                      Register

Das alles ist nur eine ausführliche Beschreibung dafür, was du
in der Grundschule gelernt hast. Und genau so wie man sich
das für Addition überlegen kann, kann man sich das auch für
Multiplikation überlegen. Geh jeden Schritt durch, so wie du
ihn damals gelernt hat.
Multiplikation ist binär wieder ganz besonders einfach, weil
das kleine 'Einmal Eins' besonders einfach ist:
Es gibt nur 2 Möglichkeiten, entweder es wird mit 0 multipliziert,
dann ist das Ergebnis 0 oder es wird mit 1 multipliziert, dann
ist das Ergebnis identisch mit der Ursprungszahl. Der eigentliche
Rechengang ist aver genauso wie du ihn in der Grundschule
für das Zehnersystem gelernt hast, nur dass du dort das kleine
Einmal Eins für alle Multiplikatoren von 0 bis 9 auswendig
können musstest.


    10110  *  101
    -----
    10110      ( weil 10110 * 1)
     00000     ( weil 10110 * 0)
     -----
    101100     ( <- Zwischensumme )
      10110    ( weil 10110 * 1)
    -------
    1101110    ( Endsumme = Multiplikationsergebnis )

Aber genauso, wie man im Dezimalsystem eine Multiplikation
in einfachere Teilmultiplikationen zerlegen kann:

    123 * 56 = ( 100 * 56 ) + ( 23 * 56 )
(*)

kann man das auch im Binärsystem. Wenn eine Hardwaremultiplikation
zur Verfügung steht, dann wird man das auch so machen, wenn man
über mehrere Register arbeiten muss.
Hat man das nicht, dann macht man genau das was oben binär
gemacht wurde: Entweder mit 0 oder mit 1 multiplizeren und
aufaddieren. Die Stelle verschieben (ob ich den neu zu addierenden
Term um 1 Stelle nach rechts versetzte oder das Zwischenergebnis
um 1 Stelle nach links, kommt auf dasselbe hinaus) und alle Bits
des Multiplikators durchgehen: Ist er 1, wird der ursprüngliche
Multiplikand dazuaddiert, ist er 0 passiert nicht (weil
ja eine Addition von 0 nichts ändert)


(*) 100 * 56 ist besonders einfach zu rechnen, weil ich das
ja als 1 * 56 rechnen kann und nur darauf achten muss, dass
ich dieses Zwischenergebnis ins Endergebnis um die richtige
Anzahl Stellen nach links verschoben aufaddieren muss. Damit
habe ich aber erreicht, dass ich die Multiplikation einer
3 stelligen Zahl mit einer 2 stelligen Zahl auf 2 Multiplikationen
von jeweils 2 2-stelligen Zahlen, eine entsprechende Verschiebung
und eine Addition zurückgeführt wurde. Wenn ich jetzt einen Menschen
habe, der das kleine 1*1 für alle 2-stelligen Zahlen auswendig
kann, dann kann er mit diesem Kochrezept auch 3-stellige Zahlen
mit 2-stellige Zahlen multiplizieren ohne dass er auf die
ausführliche 'Grundschulmultiplikation' zurückgreifen muss.
Ein µC mit 8-Bit Hardwaremultiplikation ist aber so ein
'Mensch der das kleine 1*1' für größere Stellenzahl auswendig
gelernt hat.

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
> Nur jetzt sagen ich soll in der
> Grundschule anfangen finde ich schon ziemlich krass.

Du magst das nicht hören wollen, aber es ist tatsächlich so:
Du hast das 'Prinzip' tatsächlich in der Grundschule gelernt,
nur hat man dir das damals nicht so verkauft.

> Habt ihr damit eigentlich beruflich zu tun oder macht ihr das nur
> hobbymäßig? Studiert in diesem Bereich?

Was ich von den regelmäßigen Forenteilnehmern so mitgekriegt
habe: Teils, teils.

von Gast (Gast)


Lesenswert?

> Das Multiplizieren von Zahlen in anderen Zahlenformaten als dem
> Zehnersystem ist Hochschulstoff der ersten Semester. Ist der
> Unterschied Hoch und Grundschule klar?

Das hat meine Tochter bereits in der 9./10. Klasse (auf dem Gymnasium im 
sprachbetonten Zweig) im Informatikunterricht gelernt ... das ist 
niemals Hochschulstoff. In der Hochschule/Universität wird erwartet, daß 
solche Elementarkenntnisse bereits vorliegen.

von jochen (Gast)


Lesenswert?

Das ist leider falsch



http://www.mmi.rwth-aachen.de/fileadmin/ggi1/u2.pdf

Aufgabe 14-16 , zum Beispiel

von Gast (Gast)


Lesenswert?

Das ist ein Übungsblatt mit Aufgaben zur selbständigen Übung ... keine 
Darstellung zum Lehrstoff. Daß man es nochmal üben läßt, um dieses 
Wissen z. B. wieder anwendungsbereit bzw. sicher zu machen, heißt noch 
lange nicht, daß es nicht vorausgesetzt wird.

von jochen (Gast)


Lesenswert?

Dann schau doch mal weiter oben. Da sind es keine Aufgaben zum üben.

von jochen (Gast)


Lesenswert?

Wenn du sagst "das ist niemals Stoff an eienr Universität" meinst du 
damit wohl, dass es dort nicht behandelt wird. Sonst wäre es ja Stoff. 
Es wird aber sehr wohl behandelt, "Zahlendarstellung und Codierung" ist 
ein Oberthema. Somit ist es Hochschulstoff und kein Grundschulniveau.

von Thilo M. (Gast)


Lesenswert?

Hochschulstoff würde ich nicht sagen, Hauptschule auch nicht, aber in 
der Realschule wird das Thema schon behandelt.

von jochen (Gast)


Lesenswert?

... Je nachdem auf welcher Schule man ist. Für Otto - Normal-Student 
wohl eher nicht, Informatik ist zumindest hier bei den Schulen bei uns 
eher nicht Schulfach.
Deswegen ist es auch gut, dass es im ersten Semester nochmal als 
seperates Thema auftaucht, da so jeder die Chance hat, klarzukommen und 
nicht die Leute die von irgendeiner teschnischen Schule kommen absolut 
im Vorteil sind.

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
> Das ist leider falsch
>

Das ändert aber nichts an der Tatsache, daß das Prinzip
von Addition, Subtraktion, Multiplikation etc. identisch
ist zu dem in der Grundschule gelernten und unabhängig vom
benutzten Zahlensystem ist.
Ist schon klar, dass man 7-jährige nicht mit binärer Arithmetik
quält, die haben andere Sorgen.

von jochen (Gast)


Lesenswert?

Ich habe jetzt angefangen, die Multiplikation in Assembler umzusetzen. 
Dabei bin ich gleich vom allgemeinen Fall ausgegangen, wenn in den AD 
Wandler eingelesen wird. Könntet ihr Euch das mal ansehen und mir dann 
sagen ob das so effektiv ist und überhaupt stimmt? Das hat leider 
ziemlich viele Register beansprucht:

in adlow, ADCL
in adhigh, ADCH

//Multiplikation.

// Anfangswert H Byte: adhigh
// Anfangswert L Byte: adlow
// Multiplikator: 5

ldi r19, 5

//Multiplikation L Byte
MUL adhigh, r19

//Sichere die Register r0 und r1. Das Ergebnis der Multiplikation vom L 
Byte ist dann r21 und direkt daran r20 angehängt. Ich schreibe das für 
die weiteren Erklärungen dann immer r21#r20

mov r20,r0
mov r21r1

//Genauso Multiplikation H Byte. Ergebnis der Multiplikation vom H Byte 
ist dann r23#r22

mul adlow, r19
mov r22,r0
mov r23,r1

//Man hat also
// Ergebnis L Byte: r21#r20 [16bit]
// Ergebnis H Byte: r23#r22 [16bit]

//Multiplikation Ergebis H Byte * 256
// Das Ergebnis dieser Multiplikation ist dann [24bit] und r27#r26#r25
ldi r24,256
mul r20,r24
mov r25,r0
mov r26,r1

mul r21,r24


mov r27,r0


von Johannes M. (johnny-m)


Lesenswert?

> //Multiplikation Ergebis H Byte * 256
> // Das Ergebnis dieser Multiplikation ist dann [24bit] und r27#r26#r25
> ldi r24,256
Erstens passt "256" nicht in ein Register und zweitens hatte ich weiter 
oben schon mal geschrieben, wie eine Multiplikation mit Zweierpotenzen 
durchgeführt werden kann. 256 ist 2^8, also muss einfach nur der Wert um 
8 Bits nach links geschoben werden. Und das wiederum bedeutet, dass es 
um ein komplettes Byte (also ein Register) verschoben wird (was man 
wiederum einfach erreicht, indem man ein weiteres Register mit dem 
Inhalt "0" hinten dran hängt).

von Hannes L. (hannes)


Lesenswert?

Johannes M. wrote:
>> //Multiplikation Ergebis H Byte * 256
>> // Das Ergebnis dieser Multiplikation ist dann [24bit] und r27#r26#r25
>> ldi r24,256
> Erstens passt "256" nicht in ein Register und zweitens hatte ich weiter
> oben schon mal geschrieben, wie eine Multiplikation mit Zweierpotenzen
> durchgeführt werden kann. 256 ist 2^8, also muss einfach nur der Wert um
> 8 Bits nach links geschoben werden. Und das wiederum bedeutet, dass es
> um ein komplettes Byte (also ein Register) verschoben wird (was man
> wiederum einfach erreicht, indem man ein weiteres Register mit dem
> Inhalt "0" hinten dran hängt).

Also exakt genauso wie im Dezimalsystem, mit dem einzigen Unterschied, 
dass eine "Stelle" eben einen Wertevorrat von 256 (0..255) statt 10 
(0..9) hat. Grundschul-Niveau eben...

...

von jochen (Gast)


Lesenswert?

Johannes, ich danke Dir.

Ich hab noch eine Sache, die mir im moment nicht einleuchtend ist. 
Wiesoist das Ergebnis dieser Multiplikation dann genau 24 Bit groß?

von Johannes M. (johnny-m)


Lesenswert?

Schau Dir das mal genau an:
...und jetzt überleg mal, was wohl passiert, wenn man die 16-Bit-Zahl 
(XXXX...) um 8 Bit nach links schiebt (was, wie oben schon gesagt, einer 
Multiplikation mit 256 entspricht).

von Michael U. (Gast)


Lesenswert?

Hallo,

Faustregel: ;)
Stellenzahl bei Multiplikation (gilt auch für alle Zahlensysteme).
Die Anzahl Stellen des Produkts ist maximal gleich der Summe der Anzahl 
Stellen der Faktoren.

Dezimal: 9 (eine Stelle) * 9 = 81 -> mehr geht nicht.
99 * 999 = 98901 -> 2 Stellen + 3 Stellen -> maximal 5 Stellen.

Binär 16 Stellen * 8 Stellen -> maximal 24 Stellen
16Bit * 16Bit -> 32 Bit

Gruß aus Berlin
Michael

von jochen (Gast)


Lesenswert?

Ok, verstanden. Danke.

Nochmal zu der Rechnung von Johannes:

Ausgangswert, High-Byte      0000 0011 (3)
Ausgangswert, Low-Byte       1111 1111 (255)
Multiplikator                0000 0101 (5)

Ergebnis Multipl. High-Byte  0000 0000 0000 1111 (15) [16 Bit!]
Ergebnis Multipl. Low-Byte   0000 0100 1111 1011 (1275) [16 Bit!]

Ergebnis High-Byte * 256     0000 0000 0000 1111 0000 0000 (3840) [24 
Bit!]

-> Summe High + Low (in 24 Bit):
                             0000 0000 0000 1111 0000 0000 (3840)
                          +  0000 0000 0000 0100 1111 1011 (1275)
                          ---------------------------------------
                             0000 0000 0001 0011 1111 1011 (5115)





Jetzt kommt die Division durch 1024.
Das heißt doch, ich schiebe das ganze Ergebnis um 8 Stellen nach rechts.
Übrig bleibt:

0000 0000 0001 0011 , 1111 1011

inwiefern ist das die Zahl 4,9?

von jochen (Gast)


Lesenswert?

moment ich habe mich vertan ich korrigiere

von jochen (Gast)


Lesenswert?

0000 0000 0001 00, 11  1111 1011

die vier, 00000100, vor dem Komma erkenne ich. Das könnte ich ja dann 
auch direkt an einen Treiber und so an eine Segmentanzeige schicken.
Wie mache ich die 9 erkenntlich? Könnte man daraus gar die Zahl 5 
erstellen?

von jochen (Gast)


Lesenswert?

Ich habe herausgefunden, dass man 2^-1 + 2^-2 + 2^-3 + 2^-4 + 2^-5  + 
2^-6 + 2^-7 für die ersten 8 Bit nach dem Komma rechnen muss.

Gibt es dafür für den Assembler eine Möglichkeit um am Ende dann 
wirklich eine 9 an die Anzeige zu senden?

von Simon K. (simon) Benutzerseite


Lesenswert?

In dem Register wird kein "4,9" stehen. Sondern (wenn du alles richtig 
gemacht hast, wird durch die ganzen Divisionen (Bzw nach 
rechts-schiebungen) nur noch "4" in deinem Register stehen.

von jochen (Gast)


Lesenswert?

also am Ende, nach den Verschiebungen habe ich

0000 0000 0001 00, 11  1111 1011

die 4 ist dann ja noch  0001 00 (s.o) oder?
müsste dann nicht 11  1111 1011 mit der 9 was zu tun haben?
Ist das die Idee?

von Johannes M. (johnny-m)


Lesenswert?

Noch mal: Mit den Standard-Operationen kannst Du NUR ganzzahlige 
Rechnungen machen! Eine 4,9 gibt es so nicht. Die musst Du Dir selber 
erzeugen, indem Du z.B. den Nachkommateil aus dem Rest der Division 
selber errechnest. Und das geht tatsächlich genau so, wie beim 
schriftlichen Dividieren bzw. Multiplizieren. Und den Rest der Division 
durch 1024 bekommst Du, indem Du oder während der eigentlichen Division 
die letzten 10 Bit des Ausgangswertes (das ist nämlich genau das, was 
bei der Schieberei hinten rausplumpst und was bei Dir hinter dem Komma 
steht) sicherst. Das geht z.B., indem Du das Schieben mit ror machst 
(was für die höherwertigen Bytes sowieso gemacht werden muss) und das 
Carry-Flag wiederum in ein Registerpaar hineinschiebst. Die Rechnung 
lautet dann
5115 / 1024 = 4 Rest 1019
Für die Weiterverarbeitung des Restes musst Du dann halt noch ein 
bisschen rechnen.

Ach ja, noch was: So falsch ist Deine Vermutung natürlich nicht:
1019 / 1024 = 0,995...
Du musst eben noch den Rest verarbeiten und v.a. korrekt runden! 0,995 
ist nicht 0,9...

von jochen (Gast)


Lesenswert?

Für die Weiterverarbeitung des Restes musst Du dann halt noch ein
bisschen rechnen.

Das ist mein Problem, wie ich das anstelle. Ich habe 2 Ideen:

Die erste ist (s.o) ich rechne:

2^-1 + 2^-2 + 2^-3 + 2^-4 + 2^-5  +
2^-6 + 2^-7


die zweite ist wie du schreibst

1019 / 1024 = 0,995.


ich weiß jedoch nicht, wie ich das mit den Standart sachen hinbekomme, 
ich kann bis jetzt nur die Sachen die wir besprochen haben. Dividieren 
durch 1024 (zweite Mmöglichkeit) könnte ich zwar, jedoch bewege ich mich 
dann im Kreis, weil ich dann ja nur die 0 vor dem Komma richtig auslesen 
kann.

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Jochen, Deine Binärschreibweise verkompliziert die Betrachtung 
erheblich. Betrachte die Bytes als "Ziffern" (mit dem Wertevorrat 
0..255), das wird übersichtlicher. Und wenn es gar nicht geht, dann nimm 
die "komprimierte Binärschreibweise", schreib' also hexadezimal, dann 
repräsentiert jede Ziffer 4 Bit, also ein halbes Byte, auch Nibble 
genannt...

Zu den (getürkten) Kommazahlen (Festkomma oder Fixpoint):
Man errechnet sich einfach einen Wert, der dem zehnfachen, hundertfachen 
oder tausendfachen des anzuzeigenden Wertes entspricht und füge bei der 
Ausgabeformatierung an der entsprechenden Stelle (1, 2 oder 3 Stellen 
vor Ende der Zahl) ein Komma oder Dezimalpunkt ein.

Schau Dir mal meine Ausgabeformatierungsroutine für 16-Bit-Integerzahlen 
an (Anhang), der kann man mitteilen, ob, und an welcher Stelle sie ein 
Komma einfügen soll.

In Deinem Fall, wenn Du also bis zu 5 Volt messen willst, bietet sich 
an, den 10-Bit-Messwert mit 125 zu multiplizieren, das Low-Byte (der 
24-Bit-Zahl) zur Rundung heranzuziehen (wie im ADC-Tutorial) und dann 
wegzuwerfen, und nur die beiden oberen Bytes mit 2 Stellen hinter dem 
Komma auszugeben. Du erhältst also eine Zahl bis 500, die dann als 5,00 
ausgegeben wird. Das geht natürlich auch dreistellig, aber dann passt 
der Skalierungsfaktor von 1250 nicht mehr in ein Byte, was die 
Multiplikation verkompliziert, ohne wirklich mehr Genauigkeit zu bieten.

...

von Hannes L. (hannes)


Lesenswert?

Nachtrag:
Mein Vorschlag der Skalierung beruht darauf, Divisionen durch "krumme" 
Werte zu vermeiden. Es wird nur durch 256 dividiert, was durch Wegwerfen 
des niederwertigen Bytes erfolgt. Zuvor wird dieses Wegwerfbyte 
allerdings darauf überprüft, ob es größer als 127 (die Hälfte) ist, um 
eine Rundung durchführen zu können, da sonst der Wert von 5,00 Volt nie 
angezeigt werden könnte.

...

von jochen (Gast)


Lesenswert?

Hannes, deine Lösungsidee gefällt mir sehr gut, aber den Code im Anhang 
versteh ich mal überhaupt garnicht. Dennoch würde ich jetzt gerne eine 
Möglichkeit haben den angefangenen Weg zum Ende zu bringen, bevor ich 
mit einem neuen beginne.

 "Für die Weiterverarbeitung des Restes musst Du dann halt noch ein
bisschen rechnen."


In Assembler umsetzen?

von jochen (Gast)


Lesenswert?

also

5115 / 1024 = 4 Rest 1019

die 4 hab ich und den Rest hab ich auch. Aber jetzt müsste ich den Rest 
noch so verarbeiten, dass ich eine 9 auf die Anzeige bekomme.
Das bekomm ich leider nicht gelöst. Wie macht man es?

von Karl H. (kbuchegg)


Lesenswert?

    1024   ....   1.0
    1019   ....   x

        1019
    x = -----
        1024

Da hier jetzt aber eine Zahl zwischen 0 und 1 rauskommt,
wird es wohl sinnvoll sein, da erst mal mit 10 zu multiplizieren.


     1019 * 10
     ---------
       1024

von Karl H. (kbuchegg)


Lesenswert?

Hinweis um mit 10 zu multiplizieren braucht man keine
allgmeine Multiplikation


  Zahl * 2                   ; * 2
  nochmal * 2                ; * 4
  original Zahl addieren     ; * 5
  nochmal * 2                ; * 10

Du ahnst es schon: * 2 ist trivial zu rechnen, einfach alle
Bits um eine Stelle nach links schieben.

von Falk (Gast)


Lesenswert?

@ jochen (Gast)

>5115 / 1024 = 4 Rest 1019

>die 4 hab ich und den Rest hab ich auch. Aber jetzt müsste ich den Rest
>noch so verarbeiten, dass ich eine 9 auf die Anzeige bekomme.
>Das bekomm ich leider nicht gelöst. Wie macht man es?

Nun, dein Rest sind die Nachkommastellen im Festkommaformat. Die 
Auflösung ist 1/1024 tel.
Du brauchst aber nur 1/10 tel. Ohne Division kann man einfach 
vergleichen

9/10 ~ 922/1024
8/10 ~ 819/1024
...
1/10 ~ 102/1024

Num musst du nur noch vergleichen, ob dein Rest grösser gleich der 
jeweiligen Zahl ist und schon hast du deine Nachkommastelle.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:

> Das bekomm ich leider nicht gelöst. Wie macht man es?

Wenn in eine Apfelsinenkiste 1024 Apfelsinen passen und
du 5115 Apfelsinen hast, wiviele Kisten kannst du voll
machen, und wieviele Apfelsinen bleiben übrig?

   5115 / 1024               = 4      -> Anzahl voller Kisten
   Rest( 5115 / 124 )        = 1019   -> soviele Apfelsinen sind
                                         in der letzten nicht vollen
                                         Kiste

Wenn in der nicht vollen Kiste 1019 Apfelsinen sind, zu wieviel
Prozent ist die letzte Kiste voll. (Drücke das Ergebnis als
Zahl zwischen 0 und 1 aus. 1 entspricht 100%)

Besonders bei der letzten Aufgabe werden dir ein paar
Zahlenwerte sehr bekannt vorkommen.

von Hannes L. (hannes)


Lesenswert?

jochen wrote:
> also
>
> 5115 / 1024 = 4 Rest 1019
>
> die 4 hab ich und den Rest hab ich auch. Aber jetzt müsste ich den Rest
> noch so verarbeiten, dass ich eine 9 auf die Anzeige bekomme.
> Das bekomm ich leider nicht gelöst. Wie macht man es?

Wie macht man das dezimal und schriftlich (ohne Taschenrechner)?

Man setzt in Ergebnis ein Komme, holt sich eine Null hinter dem 
(fiktiven) Komma des Dividenden herunter und rechnet wie gehabt weiter.

Die bessere Lösung ist allerdings, Divisionen auf dem AVR zu vermeiden 
(geht aber nicht immer).

> Hannes, deine Lösungsidee gefällt mir sehr gut, aber den Code im Anhang
> versteh ich mal überhaupt garnicht.

Das ist eine Routine zur Umwandlung eines 16-Bit Zahlenwertes (also den 
Inhalt zweier Register) in ASCII-Ziffern. Dies geschieht durch 
(getürkte) Division durch 10000, 1000, 100 und 10, der Rest ergibt die 
Einer. Getürkt deshalb, weil eine Division ja eigentlich nur eine 
fortgesetzte Subtraktion ist. Statt

"wieviel ist 90 durch 10?"

kann man ja auch formulieren

"wie oft kann ich von 90 10 subtrahieren, ohne einen Unterlauf zu 
erreichen?"

Diese Routine arbeitet allerdings vorwärts und rückwärts, das ich mir 
mal bei PeDa abgeschaut habe. Um sie zu verstehen, solltest Du sie in 
ein Programm einbinden und im Simulator des AVR-Studios durchspielen.

Beim Skalieren von Werten zur Ausgabe gehe ich meist so vor:

- Ermitteln, welche Werte anfallen können (beim ADC 0..255 oder 0..1023)

- Festlegen, was angezeigt werden soll (bei Dir 0,00..9,99, wobei 9,99
  ja nie erreicht wird)

- Festlegen, was bei maximalem Eingangswert angezeigt werden soll
  (Skalierung)

Bei Dir würde 1023 am Eingang knapp 5,00 (also 500) an der Anzeige 
erzeugen müssen. Du musst also 1024 auf 500 skalieren. Divisionen durch 
"krumme Zahlen" sollen dabei vermieden werden, es sollte möglichst nur 
durch 256 (1 Byte) oder 65536 (2 Bytes) dividiert werden.
Zum Skalieren muss der Eingangswert mit einem Bruch multipliziert 
werden, bei dem der Nenner (wegen der leichteren Division) 256 oder 
65536 beträgt.
Nehmen wir erstmal 256 als Nenner an. Dann muss unsere als Ergebnis 
gewünschte Zahl bei der Betrachtung erstmal mit 256 multipliziert werden 
(500 x 256 = 128000), denn wir wollen sie ja im AVR durch 256 teilen.
Und nun soll 1023 am Eingang 128000 ergeben. Dazu muss der Eingangswert 
mit 125 multipliziert werden, denn 128000 durch 1023 ergibt 125,122, 
also 125. Unser Bruch zur Skalierung heißt also 125/256. Also 
multiplizieren wir den Messwert mit 125 und teilen ihn durch 256 (indem 
wir das untere Byte wegwerfen). Vor dem Teilen sollten wir aber runden.

Wie rundet man dezimal und schriftlich?

Man überprüft den Rest und entscheidet danach, ob man das Ergebnis um 1 
erhöht. Mann kann aber auch vor dem Dividieren die Hälfte des Divisors 
zum Dividenden addieren, das rundet genauso.

Die einfachste Möglichkeit zum Runden ist also das Addieren von 128 zum 
24-Bit-Zwischenergebnis. Bei guter Vorbereitung (das Vorhandensein eines 
unteren Registers namens null mit dem Inhalt 0 und eines verwendbaren 
oberen Registers) ist das ganz simpel und kostet ganze 4 Takte:

 ldi tmp,128
 add byte0,tmp
 adc byte1,null
 adc byte2,null

Fertig... - Byte1 und Byte2 werden dann der Integer-zu-ASCII-Routine zum 
Fraß vorgeworfen, die daraus Ziffern mit eingeschobenem Komma macht, 
Byte0 wird weggeworfen.

...

von Hannes L. (hannes)


Lesenswert?

Apfelsine ist gut, ich gehe erstmal in den Keller und hole mir eine. 
Habe jetzt richtig Appetit drauf bekommen...

Gruß,
Hannes, der Obertroll...

von jochen (Gast)


Lesenswert?

Hannes, ich hoffe du hast nichts dagegen wenn ich mir deinen Weg nochmal 
durch den Kopf gehen alsse und bei Fragen einen neuen Beitrag eröffne. 
Dieser hier wird was unübersichtlich.
Auf fertige Routinen zurückgreifen möchte ich nicht, ich möchte es 
verstehen.

Ich habe jetzt aber noch eine Frage zu dem alten Weg.

Wie oben geschrieben wurde, rechne ich nun (1019 / 1024) * 10, dann hab 
ich vor dem Komma endlich die 9 stehen.

1019 war 1111111011 wenn man das jetzt durch 1024 teilt, verschiebt man 
diese Zahl um 10 Stellen (vom Komma) nach rechts. Man erhält also wieder 
1111111011 wobei man sich davor ein 0, denkt.
Die Multiplikation mit der 10 habe ich hinbekommen. Dabei habe ich das 
0, vernachlässigt und nur den Ausdruck 1111111011 mit 10 multipliziert.
Ich habe das mal schriftlich auf dem Papier gemacht und erhalte als 
Ergebnis
10011111001110. Das komma war nach der 8. Stelle von rechts man hat also
1001,1111001110 und vor dem Komma die Zahl 9.

In Assembler sieht es bei mir nun so aus, dass ich die Zahl
1001,1111001110 ohne das Komma in verschiedenen Registern als

r21= 10011111 und r22=00111000 habe.  r22 brauche ich nicht mehr und r21 
schiebe ich um 4 Stellen nach rechts.

Ok so?

Ich komme aber leider nicht auf die Zahl 1019. Sie entsteht ja als Rest 
beid er Division von 5115 durch 1024. Wie aber mache ich das:

000000000001001111111011 ist die Zahl 5115.  Wie gesagt wurde, dividiert 
man durch 1024, indem man sich ein Komma nach der 10. Stelle von rechts 
denkt. Das wäre also

00000000000100, 1111111011

und das Ziel ist es 3 Register zu haben:

erste Register: hier ist die vier vor dem Komma drin:  00000100

zweite Register: hier ist der erste Teil nach dem Komma drin:  11111110
dritte Register: hier sind die letzten beiden Stellen nach dem Komma 
drin: 11000000

Wie mache ich diese Aufteilung? Ist der Rest von Weg so okay?

von jochen (Gast)


Lesenswert?

Ich habe es mit dem lsr und dem ror Befehl hinbekommen.
Puhh jetzt denke ich kann ich meine 4,9 auf die Segmentanzeige bringen 
morgen versuche ich es. Ich bedanke mich bei allen, die mir geholfen 
haben!

von jochen (Gast)


Lesenswert?

Alles klar, das funktioniert einwandfrei, danke nochmal :-)

Es bleibt allerdings das Problem,d ass der AD Wandler an sich manchmal 
einfach nicht einliest, wenn ich PC0 auf 5 V lege.

Woran kann so etwas liegen?

GND und AVCC hab ich en die Stromversorgung angeschlossen und zwischen 
den beiden einen 100N kondensator. A Ref habe ich nicht beschaltet, wozu 
ist das da?

Also er liest nur sehr unzuverlässig ein.

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
>  A Ref habe ich nicht beschaltet, wozu
> ist das da?

Dort schiebt der Chip die benutzte Referenzspannung raus, damit
der geneigte Elektroniker Massnahmen ergreifen kann, um die
Referenzspannung seinen Anforderungen gemäss zu stabilisieren.

Du solltest ARef als Minimumbeschaltung mit 100nF nach GND
abblocken.

Steht aber auch alles im Datenblatt oder alternativ auch
im AVR-Tutorial

von jochen (Gast)


Lesenswert?

Hab ich jetzt gemacht, das Problem sit aber immer noch nicht so recht 
behoben. Wenn es dann nicht geht und  ich PC0 dann mit 9V verbinde geht 
es kurz danach auch mit 5 V. Das scheint also das Problem kurzzeitig zu 
beheben aber das ist ja keine Lösung.

von Karl H. (kbuchegg)


Lesenswert?

> Wenn es dann nicht geht und  ich PC0 dann mit 9V

9V ?!?
Laut Datenblatt darfst du maximal 5.5V draufgeben.
Hast du noch einen zweiten Mega8? Wenn ja: probier den
mal aus.

von Michael U. (Gast)


Lesenswert?

Hallo,

Du solltest vielleicht mal ins Datenblatt des AVR schauen. Die maximal 
zulässige Spannung an allen Eingängen eines AVR liegt nur knapp über 
seiner Betriebsspannung. Darüber wird die interne Schutzdiode leitend, 
die darf maximal mit 1mA belastet werden.

Dein Verfahren hat also große Chancen, den armen AVR in den 
Halbleiterhimmel zu befördern...

Gruß aus Berlin
Michael

von Karl H. (kbuchegg)


Lesenswert?

> Es bleibt allerdings das Problem,d ass der AD Wandler an sich manchmal
> einfach nicht einliest, wenn ich PC0 auf 5 V lege.

Welchen Wert kriegst du den, wenn du dir mal die Werte direkt
vom ADC ausgeben lässt.


von jochen (Gast)


Lesenswert?

ich habe im Moment nur eine Segmentanzeige an high angeschlossen und die 
zeigt dann keine Veränderung, also 0 an.

von jochen (Gast)


Lesenswert?

wie gesagt, manchmal zeigt sie auch den korrekten Wert 3 an aber da muss 
ich schon was an der Sache wackeln und vorher mal auf 9 V legen.
Evtl. ist er dadurch beschädigt worden?

von Karl H. (kbuchegg)


Lesenswert?

Entweder du hast einen Wackelkontakt oder du hast den
Mega8 geschossen.

(Reden wir eh vom selben: der Wert wird ausgegeben so wie
er vom ADC kommt, ohne Umrechnung oder Sonstiges was zusätzlich
fehlerhaft sein könnte. Die Ausgaberoutine steht ausserhalb
jeglichen Zweifels?)

von jochen (Gast)


Lesenswert?

Ja, die habe ich testweise mal weggelassen und nur das folgende Programm 
ganz vom Anfang drauf gespielt. Das haben wir oben ja erarbeitet und 
sollte die minimale Funktionsweise sein:

.include "m8def.inc"

.def temp = r16

.def temp1=r17
.def adlow =r20
.def adhigh=r21

.org 0x0000
  rjmp main

  ldi temp1,(1<<REFS0)
  out ADMUX, temp1
  ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0)
  out ADCSRA, temp1

main:

  ldi temp, LOW(RAMEND) ;Stackpointer initalisieren
  out SPL, temp
  ldi temp, HIGH(RAMEnD)
  out SPH, temp

  sbi DDRB,0
  sbi ddrB,1
  sbi ddrB,2
  sbi ddrB,3
  ldi r22, 9

  sample_adc:
  sbi ADCSRA, ADSC

  wait_adc:
  sbic ADCSRA, ADSC
  rjmp wait_adc

  in adlow,ADCL
  in adhigh, ADCH

loop:

out PORTB, adhigh

rjmp sample_adc

von Karl H. (kbuchegg)


Lesenswert?

Das Programm sieht an und für sich gut aus.
Da wirst du wohl den µc gegrillt haben.

von jochen (Gast)


Lesenswert?

Nicht so schlimm ich hab 10 Stück :-)

Ich teste es mit einem neuen danke!

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger wrote:
> Das Programm sieht an und für sich gut aus.

Das sehe ich anders, sorry...
1
.org 0x0000
2
  rjmp main
3
4
  ldi temp1,(1<<REFS0)
5
  out ADMUX, temp1
6
  ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0)
7
  out ADCSRA, temp1
8
9
main:

Wann wird der ADC denn nun initialisiert???

> Da wirst du wohl den µc gegrillt haben.

Das kommt mit hoher Wahrscheinlichkeit dazu. 9V am EDC-Eingang, der 
Gedanke ist schon sehr schmerzhaft, nicht nur für den AVR... ;-)

Gruß von der Elbe...
Hannes

von Karl H. (kbuchegg)


Lesenswert?

Hannes Lux wrote:
> Karl heinz Buchegger wrote:
>> Das Programm sieht an und für sich gut aus.
>
> Das sehe ich anders, sorry...
>
> Wann wird der ADC denn nun initialisiert???

Ooops. Das hab ich ja völlig übersehen.
Ich hab mich nur auf die Werte in den Registern
konzentriert.

Ist schon gut wenn mehr Augenpaare ein Programm absuchen.

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger wrote:
> Ist schon gut wenn mehr Augenpaare ein Programm absuchen.

Nunja, mit ist halt aufgefallen, dass das recht "komische 
Interrupt-Vektoren" sind, darauf habe ich den Rest gar nicht mehr 
angesehen und entschieden, erstmal nicht darauf zu antworten. Aber Dein 
versehentliches "Absegnen" wollte und konnte ich so leider nicht stehen 
lassen.

Übrigens: Ein Programm, das 7-Segment-Anzeigen multiplext, ADC-Eingänge 
abfragt und vermutlich später mal noch andere Dinge tun soll, kann ich 
mir ohne Timer-Interrupt gar nicht mehr vorstellen.

...

von jochen (Gast)


Lesenswert?

also es klappt auch mit einem neuen AVR nicht. Den Rest habe ich sicher 
richtig angeschlossen. Muss ein Widerstand vom AD Eingang auf Masswe? 
ich habe 1 kohm, 10 kohm und 100 ohm mal versucht, das ändert alles aber 
nicht viel.
Kann es vielleicht daran liegen, dass es nur auf dem Steckbrett 
aufgebaut ist?

von jochen (Gast)


Lesenswert?

was muss ich im Programm denn noch ergänzen, das hab ich jetzt übersehen 
.

von jochen (Gast)


Lesenswert?

ich habe das aus dem Tutorial übernommen und wollte das erstmal als 
gegeben hinnehmen.

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
> ich habe das aus dem Tutorial übernommen und wollte das erstmal als
> gegeben hinnehmen.

Tortzdem hast du einen Fehler eingebaut.
Hannes hat ihn gesehen.

Wann wird eigentlich der Programmteil
1
  ldi temp1,(1<<REFS0)
2
  out ADMUX, temp1
3
  ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0)
4
  out ADCSRA, temp1

jemals ausgeführt?

davor steht ein
   rjmp main
und das Label main ist direkt hinter diesem Programmteil.


Ergo -> der ADC ist nie richtig initialisiert worden.

von jochen (Gast)


Lesenswert?

Ja, jetzt, wenn ich das rjmp main entferne funktioniert es wie 
gewünscht. Herzlichen Dank!

von Karl H. (kbuchegg)


Lesenswert?

jochen wrote:
> Ja, jetzt, wenn ich das rjmp main entferne funktioniert es wie
> gewünscht. Herzlichen Dank!

Das war die falsche Problemlösung :-)
Denk darüber nach, warum ich wohl zu dieser
Aussage komme.

von jochen (Gast)


Lesenswert?

Ja ich hätte vorher einmal im Schritt für Schritt simulieren können und 
hätte spätestens dann gesehen, dass direkt zu main gesprungen wird.
Ich werde das nächste mal bevor ich poste auch soetwas machen.

von Karl H. (kbuchegg)


Lesenswert?

Das meine ich nicht.

Was ich meine ist:
Jedes (!) Assembler Programm beginnt immer mit
einem Sprung zu main.
Ausser die ganze einfachen ersten beiden für die Anfänger.

Nach main erfolgt als aller erstes immer die Initialisierung
des Stack Pointers. Dadurch stehen ab da dann Unterprogramm
Aufrufe und Interrupt Aufrufe zur Verfügung, ohne das etwas
Schlimmes passiert.

Danach erfolgt die Initialisierung des Rests.
Das können CPU Register sein, das kann Hardware sein,
das können SRAM Zellen sein. Was auch immer.

Halte dich an dieses Schema, und du hast weniger Probleme.
Und jetzt schau mal ob das Ergebnis deiner Problemlösung
in dieses Raster passt.

von jochen (Gast)


Lesenswert?

Danke  Karl Heinz.

Dann lasse ich rjmp main stehen und schreibe


ldi temp1,(1<<REFS0)
  out ADMUX, temp1
  ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0)
  out ADCSRA, temp1


nachdem der Stackpointer eingestellt wurde.

Als nächstes schau ich mir die Routine von hannes mal an, die scheint 
noch besser zu sein als

z.B.

(1019 / 1024) * 10 zu rechnen und so die Zahl vor dem Komma als die 
Nachkommatelle der Gesamtzahl zu sehen.
Dann hab ich nämlich nur 4,9 stehen und das ist ja nicht 5, der 
eigentlich richtige Wert.
Ich melde mich,falls es Frageb geben sollte, dann  aber in einem neuen 
Beitrag.

EInen schönen Tag noch

von Hannes L. (hannes)


Lesenswert?

jochen wrote:
> Ja, jetzt, wenn ich das rjmp main entferne funktioniert es wie
> gewünscht. Herzlichen Dank!

Fazit:
"RJMP" ist schuld, man sollte RJMP meide wie die Pest...

Hmmm, ääähhh, oder vielleicht doch nicht?

Jochen, es bringt nix, mit Copy und Paste programmieren zu wollen. Da 
kommt nur Mist raus. Du musst Dir angewöhnen, den Programmcode auch zu 
verstehen. Dazu gehört, dass Du zu jeder Programmzeile ganz genau weißt, 
was sie bewirkt, warum Du das so und nicht anders machst und warum sie 
an genau dieser Stelle in der Reihenfolge der Anweisungen steht. Das 
gilt für selbsterdachten Code genauso wie für "gefundenen" Code.

Ich nutze auch diesen oder jenen Algorithmus, den ich nicht selbst 
erdacht habe, sondern den ich irgendwo "gefunden" habe. Aber ich 
verwende ihn erst, wenn ich ihn genau verstanden habe.

Auch ich mache Fehler beim Programmieren, mehr als Du vielleicht 
glaubst. Aber ich versuche systematisch die Ursache des Fehlverhaltens 
des Programms aufzuspüren, wobei ich auch mal ins Datenblatt oder in 
andere Quellen schaue, um mich zu informieren. Es gibt viele Dinge beim 
AVR, über die ich nicht detailliert bescheid weiß, damit belaste ich 
mich momentan auch gar nicht, ich informiere mich aber dann umfassend, 
wenn ich Neuland betrete, also wenn ich ein Feature (oder 
Peripheriebaustein) erstmalig benutze. Das ist zwar etwas mühsamer und 
auch langwieriger als das unverstandene Bebutzen fremder Routinen oder 
das unüberlegte Befragen eines Forums, aber es ist ehrlicher und fördert 
das Verständnis für das was man tut.

...

von jochen (Gast)


Lesenswert?

Danke für die Tipps.
Also ich greife nicht gerne auf fertige Sachen zurück und möchte auch 
alles selber verstehen. Aber so Sachen wie die Initalisierung des Stack 
Pointers oder auch des AD Wandlers ist mir momentan egal. Also jetzt 
reinweg die Initalisierung betrachtet. Ich würde es zwar gerne 
verstehen, ich habe jedoch keinerlei Bezugsquellen und im Internet finde 
ich auch nichts. Deswegen belasse ich es jetzt erstmal dabei und mache 
lieber was produktives, anstatt mich mit einer Initalisierung zu 
befassen.  Für das was ich machen will reicht es mir ja erst einmal, 
wenn der AD Wandler zur Verfügung steht, wie kann ich aus Zeitgründen 
erstmal nicht erarbeiten.  Und wenn ich was wie die Pest hasse, sind das 
Datenblätter bzw. die Art und Weise, wie dort etwas beschrieben wird.
Ich finde auch keinerlei gute Literatur. Deswegen habe ich mir das my 
Avr Starterset für satte 200 Euro gekauft. Das hat mir zwar was die 
allerersten Schritte angeht viel geholfen, stößt aber meiner Meinung 
nach auch schnell an seine Grenzen, zumal das Programm Sisy, was dort 
verwendet wird, nicht so weit verbreitet scheint.
Deswegen würde  mich es sehr interessieren, wie ihr angefangen habt, 
euch damit zu befassen und woher ihr Eure Informationen erhalten habt. 
Ich finde die Sachen an sich sind garnicht schwer, das schwere ist es 
einmal eine fundierte Beschreibung zu erhalten. Wenn man die dann 
durcharbeitet ist es klar und man wundert sich, wie einfach es doch ist. 
So ging es mir jedenfalls bisher bei dem, was ich gelernt habe. Und 
klar, man denkt dann als "Insider": "was stellt der denn für blöde 
Fragen". Aber wie beschrieben ich habe halt keine gerechten Quellen und 
irgendwoher muss man seine Informationen ja bekmmen
Könntet ihr mir Bücher empfehlen?

von jochen (Gast)


Lesenswert?

P.S. Das Tutorial in allen Ehren es hat mir eucht bei vielen Sachen 
geholfen.
Aber was den AD Wandler angeht konnte ich es fast nicht brauchen, dort 
wurde verwirrenderweise nicht reinweg der AD Wandler beschrieben sondern 
noch viel mehr gleich mit und der nur auf den AD Wandler beziehende CODE 
(wie "Gast" auch kanz zu Anfang hier in diesem Beitrag meinte) wird 
nicht offen sichtlich.
Aber evtl ist das Tutorial ja auch nicht für absolute Neulinge gedacht 
und die Kritik ist nicht berechtigt.

von Hannes L. (hannes)


Lesenswert?

jochen wrote:
> Danke für die Tipps.
> Also ich greife nicht gerne auf fertige Sachen zurück und möchte auch
> alles selber verstehen. Aber so Sachen wie die Initalisierung des Stack
> Pointers

Wieso? - Wo ist das Problem? Du musst erstmal verstehen, was Stack ist 
und wozu man ihn braucht. Es ist ein als "Stapelspeicher" genutzter Teil 
des RAMs, in dem Rücksprungadressen bei Aufruf von Unterprogrammen und 
Interrupts gesichert werden und den man auch benutzen kann, um mal 
schnell den Inhalt eines Registers zu "parken" (push/pop), damit man das 
Register temporär für andere Zwecke frei hat. Vergleiche den Stack mit 
einer Art Ablage für Zettel, die so gebaut ist, dass Du immer nur den 
zuletzt reingelegten Zettel rausnehmen kannst. Der Stackpointer ist der 
Zeiger auf die gerade aktuelle Stack-Adresse im RAM. Er muss zu Beginn 
des Programms auf das RAM-Ende gesetzt werden, da der Stack "nach unten 
wächst".

> oder auch des AD Wandlers ist mir momentan egal.

Der AD-Wandler ist ansich extrem primitiv. Er arbeitet nach dem Prinzip 
der schrittweisen Annäherung. Dabei wird die außen anliegende Spannung 
per Sample&hold-Stufe vor Veränderung während der Messung geschützt und 
dann schrittweise mit der Spannung einres internen DAC 
(Digital-Analog-Converters) verglichen, der die Referenzspannung in 1024 
Stufen zerhacken kann. Dabei wird im ersten Schritt geprüft, ob die 
externe Spannung größer oder kleiner als die Hälfte der Referenzspannung 
ist. Anhand des Ergebnisses wird entschieden, ob im nächsten Schritt auf 
die Hälfte des oberen oder unteren Teils geprüft wird. Und so hangelt 
sich dieser Klapperatismus vom höchsten bis zum niedrigsten Bit durch. 
Dazu braucht er natürlich einen Takt, den man (als Initialisierung) per 
Vorteiler einstellen muss. Und damit man diesen ADC effizient nutzen 
kann, gibt es einige Schalter für bestimmte Betriebsarten, einen 
Multiplexer zur Auswahl der Referenzquelle und Messquelle und eine 
Zustands-Anzeige, die in der Lage ist, einen Interrupt auszulösen. Im 
einfachsten Fall schaltet man den ADC im Free-Run-Mode ein (aden, 
adfr/adate, adpsx) lässt ihn klappern (adsc) und liest gelegentlich 
(dann wenn man es braucht) mal den zuletzt ermittelten Wert aus adch und 
adcl aus. Man muss nur sicherstellen, dass man erst dann ausliest, wenn 
er genug Zeit hatte, eine Wandlung zu schaffen.

> Also jetzt
> reinweg die Initalisierung betrachtet. Ich würde es zwar gerne
> verstehen, ich habe jedoch keinerlei Bezugsquellen und im Internet finde
> ich auch nichts.

Die QAuelle heißt Datenblatt.

> Deswegen belasse ich es jetzt erstmal dabei und mache
> lieber was produktives, anstatt mich mit einer Initalisierung zu
> befassen.

Das ist keine gute Idee, dabei lernst Du nichts. Du kannst keinen Roman 
schreiben wenn Du das Alphabet nicht kennst.

> Für das was ich machen will reicht es mir ja erst einmal,
> wenn der AD Wandler zur Verfügung steht, wie kann ich aus Zeitgründen
> erstmal nicht erarbeiten.  Und wenn ich was wie die Pest hasse, sind das
> Datenblätter bzw. die Art und Weise, wie dort etwas beschrieben wird.

Das musst Du umgehend ändern. Datenblätter sind die wichtigste Quelle 
für Informationen. Als nächstes kommen die AppNotes 
(Anwendungsbeispiele).

> Ich finde auch keinerlei gute Literatur. Deswegen habe ich mir das my
> Avr Starterset für satte 200 Euro gekauft.

Gut gemacht, diese Firma will auch leben. Trotzdem ziehe ich das 
Original (AVR-Studio und ATMEL-Datenblätter) vor.

> Das hat mir zwar was die
> allerersten Schritte angeht viel geholfen, stößt aber meiner Meinung
> nach auch schnell an seine Grenzen, zumal das Programm Sisy, was dort
> verwendet wird, nicht so weit verbreitet scheint.

Das Programm braucht eigentlich niemand. Im AVR-Studio ist alles drin, 
was man für Assembler braucht. Und statt des modifizierten 
AN910-Programmers von Sisy (mySmartUSB) sollte man lieber den AVR-ISP 
(MKII) benutzen, da kann man wenigstens sicher sein, dass es dafür ein 
Firmwareupdate gibt, wenn neue AVR-Typen auf den Markt kommen.

> Deswegen würde  mich es sehr interessieren, wie ihr angefangen habt,
> euch damit zu befassen und woher ihr Eure Informationen erhalten habt.

Man hat mich vor ein paar Jahren gebeten, eine Schaltung zu bauen, die 
durch den Einsatz eines AVRs bedeutend einfacher wird (Platine, 
Logikbausteine). Also habe ich mir ein paar AT90S1200 gekauft, mir eine 
ATMEL-AVR-CD besorgt und mich mühsam eingelesen. Internet-Zugang und 
Forum kam erst später. Einige meiner (anfangs recht primitiven) Projekte 
kannst Du Dir hier gern ansehen: http://www.hanneslux.de/avr/index.html

> Ich finde die Sachen an sich sind garnicht schwer, das schwere ist es
> einmal eine fundierte Beschreibung zu erhalten.

Nein, diese (mundgerechte) Beschreibung wirst Du nicht finden. Das 
Wissen (die Informationen) sind wie Puzzleteile verstreut. Du musst sie 
schon selbst zusammenfinden (ich habe bewusst das Wort "suchen" 
vermieden) und zusammenfügen. Das ist zwar mühsam und dauert seine Zeit, 
aber "ohne Fleiß kein Preis". Dazu muss das neu gefundene immer mit dem 
bereits Gelernten verglichen und verknüpft werden. Daher auch meine 
Hinweise auf "Grundschulwissen". Du hast fast alles schonmasl in anderem 
Zusammenhang gelernt, mehr oder weniger motiviert, mehr oder weniger 
fleißig, mehr oder weniger ehrlich. Und diese Schummeleien (gute Noten 
für unverstandenen Lernstoff) rächen sich jetzt.

> Wenn man die dann
> durcharbeitet ist es klar und man wundert sich, wie einfach es doch ist.

Du kannst doch aber nicht erwarten, dass Dir Andere alles mundgerecht 
zusammentragen. Wissen muss man erarbeiten, der "Nürnberger Trichter" 
funktioniert nunmal nicht. Ich habe auch die Erfahrung gemacht, dass man 
einer einzigen Wissensquelle nicht trauen kann. Der Autor ist auch nur 
ein Mensch und Menschen irren sich gelegentlich. Man muss also immer 
mehrere Wissensquellen gegeneinander überprüfen und sich seine eigene 
Meinung bilden.

> So ging es mir jedenfalls bisher bei dem, was ich gelernt habe. Und
> klar, man denkt dann als "Insider": "was stellt der denn für blöde
> Fragen".

Neenee, das ist meist anders. Oft stellt man beim Lesen der fragen fest 
dass der Hilfesuchende das Problem falsch einschätzt. Dabei ist bei 
Anfängern oft Selbstüberschätzung im Spiel. Die reale Welt ist nunmal 
erheblich komplexer als sie in Lehrbüchern dargestellt ist. Es fehlen 
also meist elementare Grundlagen.

> Aber wie beschrieben ich habe halt keine gerechten Quellen und
> irgendwoher muss man seine Informationen ja bekmmen

Du wirst keine (mund-)gerechten Quellen finden. Denn jeder Lernende 
braucht das etwas anders, der Eine "kopiert" das Wissen (das 
Geschriebene), der Andere versteht es und macht es sich zu Eigen, 
verknüpft es also mit dem zuvor erworbenen Wissen und kommt zu 
Erkenntnissen, die in keiner dieser gelesenen Quellen beschrieben 
wurden.

> Könntet ihr mir Bücher empfehlen?

Eigentlich nicht. Ich könnte Dir für ein/zwei Monate das Elektor-Buch 
"AVR-Mikrocontroller-Praxis" von S&F Volpe leihen, das beschreibt den 
AVR-ASM-Befehlssatz auf Deutschnd enthält ein paar Programmbeispiele mit 
Erklärungen. Aber der echte Bringer ist das auch nicht...

> P.S. Das Tutorial in allen Ehren es hat mir eucht bei vielen Sachen
> geholfen.

Ein Tutorial kann nur die ersten Schritte begleiten und vor den ersten 
Fallstricken bzw. Fußangeln warnen. Unter diesem Aspekt ist das Tutorial 
sehr gut gemacht. Man sollte aber in der Lage sein, das Wissen 
verschiedener Quellen zu verknüpfen, wer das Tut nur "nachäfft", der 
lernt daraus auch nichts.

> Aber was den AD Wandler angeht konnte ich es fast nicht brauchen, dort
> wurde verwirrenderweise nicht reinweg der AD Wandler beschrieben sondern
> noch viel mehr gleich mit und der nur auf den AD Wandler beziehende CODE
> (wie "Gast" auch kanz zu Anfang hier in diesem Beitrag meinte) wird
> nicht offen sichtlich.

Das ist jetzt aber unfair. Der Umgang mit dem ADC ist doch kein 
Selbstzweck. 99% der ADC-Arbeit besteht aus Warten, die reinen 
ADC-Zugriffe sind die Initialisierung und das Auslesen von ADCL und 
ADCH. Der Rest des Tut-Programms zeigt die Verarbeitung des eingelesenen 
ADC-Wertes. Gut, zugegeben, ich würde das etwas anders organisieren, 
aber das Programm ist korrekt und zeigt, wie es funktioniert.

> Aber evtl ist das Tutorial ja auch nicht für absolute Neulinge gedacht
> und die Kritik ist nicht berechtigt.

Doch, das Tutorial ist für Einsteiger gedacht. Allerdings setzt man beim 
Mikrocontroller-Einsteiger voraus, dass er bereits Ahnung von 
allgemeiner Elektronik hat, speziell von Digitaltechnik (TTL- oder 
CMOS-Logikschaltungen), dass er weiß was AND, OR, EXOR ist und dass er 
mit Bits, Bytes und deren Verknüpfereien Bescheid weiß. Die 
Mikrocontroller-Technik ist also nicht der Anfang der 
Elektronikbastelei, sondern eher die fortgeschrittene Abteilung. Und man 
sollte einen Weg mit dem ersten Schritt beginnen und nicht mit dem 
letzten.

...

von Gast (Gast)


Lesenswert?

> Doch, das Tutorial ist für Einsteiger gedacht.
> Allerdings setzt man beim
> Mikrocontroller-Einsteiger voraus,
> dass er bereits Ahnung von
> allgemeiner Elektronik hat

Und vor allem wird vorausgesetzt, daß man das Tutorial Schritt für 
Schritt durcharbeitet und nicht mittendrin anfängt.

von Simon K. (simon) Benutzerseite


Lesenswert?

Hannes Lux wrote:
> Man hat mich vor ein paar Jahren gebeten, eine Schaltung zu bauen, die
> durch den Einsatz eines AVRs bedeutend einfacher wird (Platine,
> Logikbausteine). Also habe ich mir ein paar AT90S1200 gekauft, mir eine
> ATMEL-AVR-CD besorgt und mich mühsam eingelesen. Internet-Zugang und
> Forum kam erst später. Einige meiner (anfangs recht primitiven) Projekte
> kannst Du Dir hier gern ansehen: http://www.hanneslux.de/avr/index.html

echt? Woher hast du denn den AT90S1200 und die CD gekauft, wenn nicht 
übers Internet?

WAS? Ihr habt einen lokalen Elektronik Händler?! Unfassbar ;)

Der letzte der hier in der Umgebung war, kam mit seinem Lämpchen, 
Schalterchen und kilometerweise Kupferlackdraht nicht so weit. Wenn man 
schon (halbwegs) komplexe ICs haben wollte.. No chance. Tja das war wohl 
sein Verderben.
Aber Widerstände und Elkos bekam man dort trotzdem.

von Thilo M. (Gast)


Lesenswert?

>WAS? Ihr habt einen lokalen Elektronik Händler?! Unfassbar ;)

Wir haben auch einen freu!

Der (und seine Mitarbeiter) haben echt Ahnung und bestellen auf wunsch 
alles machbare! Der hält sich auch schon seit 30 Jahren! Nicht ohne 
Grund... :)

von jochen (Gast)


Lesenswert?

Es hat mir Spaß gemacht, deine Homepage anzusehen hannes.
Danke für die Anregungen.

von Michael U. (Gast)


Lesenswert?

Hallo,

@Simon Küppers: Brief, Zeitschriften und Telefon gab es schon vor dem 
Internet und CD-Rom...

Inserate bestanden da oft noch aus ziemlich langen Bauteillisten mit 
Preisen, nicht nur einer unsinnig bunten Seite, die ein schnelleres 
Internet mit einem Pentiom-III versprach.

Da konnte man anrufen und bestellen oder hinschreiben (ja, das ging 
wirklich!).

Lokale kleine Elektronik-Händler waren da auch merklich weiter 
verbreitet. :)

Allerdings sehe ich im Internet manchmal auch einen Nachteil: man findet 
manchmal zu schnell jemanden, der ein Problem schon gelöst, eine 
Schaltung schon entwickelt oder ein Programm schon geschrieben hat.

So wird sicher mehr relativ gedankelos nachgebaut ohne am Verständnis 
der Zusammenhänge sonderlich interessiert zu sein.

Empfinde ich selbst nicht unbedingt als großen Vorteil.

Gruß aus Berlin
Michael


von Spess53 (Gast)


Lesenswert?

Hi

>echt? Woher hast du denn den AT90S1200 und die CD gekauft, wenn nicht
übers Internet?

Zum Informieren gibt es Bücher , Zeitschriften und Kataloge (die sollen 
sogar Offline funktionieren). Zum Bestellen gibt so ein altmodisches 
Teil mit etwas,das man an Ohr und Mund hält und einenem anderen Etwas 
mit dem man eine Nummer wählen kann. Wenn man dann noch einer Sprache 
mächtig ist, die der oder die am anderen Ende versteht, geht das auch 
ohne Internet.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

@Simon Küppers:

Ich bin seit 1990 (oder 91?) Kunde bei Reichelt. Anfangs wurde per Brief 
bestellt, gelegentlich per Fax, seit etwa 1995 per CB-Funk. Ja, richtig 
gelesen, per CB-Funk in der Betriebsart Packet-Radio (1200 Baud) auf 
Kanal 24 oder 25. Dazu wurde einfach eine PR-Mail (Textdatei, ASCII) in 
die lokale Box geschrieben, an einen Internet-Gateway (dbo812, 
München-Pasing) gesendet, die dann von diesem als E-Mail weitergesendet 
wurde. Das funktionierte auch rückwärts. Dieses gut funktionierende 
anarchistische Netz wurde leider etwa 2002 von einigen 
besserwisserischen Möchtegern-Administratoren durch den Machtkampf 
konkurrierender (sich bekämpfender) Vereine zerschlagen. Die Zunahme der 
Sonnenfleckenaktivität (11-Jahres-Zyklus) und die Verbreitung des 
Internets erledigte dann den Rest.

Meine Funktechnik ist inzwischen abgebaut, die PR-Software (Mailbox mit 
S&F, Gateway Kanal 24 <--> 25, Terminalsoft) befindet sich aber noch auf 
meinem Fräsen-Rechner.

Aber zwei Elektronikläden hatten wir in Magdeburg auch, sie sollen sogar 
noch existieren. Ich war da aber schon lange nicht mehr, habe auch gar 
nicht mitbekommen, wohin die umgezogen sind.

...

von Simon K. (simon) Benutzerseite


Lesenswert?

Interessant eure Beiträge. Klar gibt es auch Kataloge wo man 
hinfaxen/anrufen/post hinschicken kann. Aber ich zum Beispiel wäre ohne 
das Internet garnicht erst auf Reichelt, csd und und und gekommen...

Aber ich denke mal, die Adressen von solchen Shops stehen/standen in 
diversen Elektronikmagazinen (die ja damals fast jeder Elektroniker 
hatte, da sie noch was taugten). NichtOder? ;)

von Hannes L. (hannes)


Lesenswert?

Simon Küppers wrote:
> Interessant eure Beiträge. Klar gibt es auch Kataloge wo man
> hinfaxen/anrufen/post hinschicken kann. Aber ich zum Beispiel wäre ohne
> das Internet garnicht erst auf Reichelt, csd und und und gekommen...
>
> Aber ich denke mal, die Adressen von solchen Shops stehen/standen in
> diversen Elektronikmagazinen (die ja damals fast jeder Elektroniker
> hatte, da sie noch was taugten). NichtOder? ;)

Nein, Reichelt war damals ein "Geheimtipp", Völkner (Braunschweig) und 
Conrad machten sich durch aggressive Werbung bekannt, Pollin und CSD kam 
erst später.

Elektronik-Magazine las ich nie wirklich. Den "Funkamateur" bekam ich 
vor der Wende nicht abonniert (da gab es Kontingente), nach der Wende 
wollte ich ihn aus Gnatz nicht mehr. Meine E-Grundlagen habe ich 
allerdings aus der reichlichen Bastler-Literatur des DMV.

...

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.