Forum: Mikrocontroller und Digitale Elektronik AD-Wandler Verständisfrage


von Björn M (Gast)


Lesenswert?

Hallo,

ich habe ein paar Fragen zum AD-Wandler.
1
/* Configure ADC0_2 */
2
LPC_ADC0->CR = (1 <<  2) |          /* Select ADC0_2 pin for conversion */
3
               (36363 <<  8) |      /* 12MHz / (36363+1) = 330Hz */
4
               (1 << 21);           /* ADC is operational */

Ich habe eine Schaltung mit einem Bessel-Filter. Vom Ausgang des Filters 
gelangt das Signal direkt in den AD-Wandler des Mikrocontrollers. Die 
Grenzfrequenz des Filters liegt bei 15Hz. D.h. dass die maximale 
Frequenz die durchkommt 15Hz betragen kann. Somit bräuchte ich eine 
Abtastfrequenz von mindestens 30Hz (Abtastrate: 30 Samples/s), nach der 
Regel: die Abtastfrequenz muss mindestens doppelt so groß sein wie die 
maximale Signalfrequenz.

Da ich einen 10-bit (11 clock cycles) AD-Wandler habe beträgt die 
Frequenz des AD-Wandlers dann 330Hz (30Hz * 11 clock cycles = 330Hz).

D.h. ich muss die 12MHz durch 330Hz teilen um den Teiler für das Control 
Register zu bekommen (36363). Bis hier hin müsste es korrekt sein denke 
ich?

So nun zu meiner Frage:

Meine OS_Timer_Callback Funktion wird alle 100ms aufgerufen und holt 
sich darin den Wert vom AD-Wandler. Was ich nicht ganz verstehe ist, 
wenn ich eine Abtastrate von 30 Sample/s habe, holt sich meine 
OS_Timer_Callback Funktion in einer Sekunde nur 10 Samples? Oder sollte 
ich besser meinen Timer auf 33.33ms setzen um in einer Sekunde 30 
Sample/s zu bekommen?

Allgemeine Frage:

Das analoge Signal wird ja durch den AD-Wandler digitalisiert. D.h. ich 
bekomme einen Wert geliefert. Wenn ich nun das Signal auf dem Controller 
ausgeben möchte, muss ich davor den Wert den mir der AD-Wandler liefert 
in Volt umrechnen und dann zeichnen lassen oder kann ich das Signal 
direkt mit dem AD-Wert zeichnen?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Björn M schrieb:
> ich habe ein paar Fragen zum AD-Wandler.

Wenn du dazuschreibst, um welchen uC es geht, täten sich einige hier 
leichter deine frage zu beantworten...

Björn M schrieb:
> D.h. dass die maximale
> Frequenz die durchkommt 15Hz betragen kann

Nein, bei der Grenzfrequenz ist dein Signal um 3dB gedämpft, aber noch 
vorhanden, je nach Steilheit = Ordnung des Filters auch noch höhere 
Frequenzen.

Björn M schrieb:
> Da ich einen 10-bit (11 clock cycles) AD-Wandler habe beträgt die
> Frequenz des AD-Wandlers dann 330Hz (30Hz * 11 clock cycles = 330Hz).
Nein, vermutlihc viel höher. Taktfrequenz des ADC und Abtastfrequenz 
haben wneig miteinander zu tun

von Wolfgang (Gast)


Lesenswert?

Björn M schrieb:
> Die Grenzfrequenz des Filters liegt bei 15Hz. D.h. dass die
> maximale Frequenz die durchkommt 15Hz betragen kann.

Nein, es gibt keine Rechteckfilter. Und ein Bessel-Filter gehört schon 
gar nicht dazu.

von Jim M. (turboj)


Lesenswert?

Wenn das für den LPC176x sin soll, dann ist ein Fehler drin:
1
/* Configure ADC0_2 */
2
LPC_ADC0->CR = (1 <<  2) |          /* Select ADC0_2 pin for conversion */
3
               (36363 <<  8) |      /* 12MHz / (36363+1) = 330Hz */
4
               (1 << 21);           /* ADC is operational */

Das CLKDIV Feld hat nur 8 Bits. Da dürfen also nur Werte bis 255 rein.

von Björn M. (Gast)


Lesenswert?

Jim Meba schrieb:
> Wenn das für den LPC176x sin soll, dann ist ein Fehler drin:

Nein, das ist für den MCB4300.

von M. K. (sylaina)


Lesenswert?

Björn M schrieb:
> Die
> Grenzfrequenz des Filters liegt bei 15Hz. D.h. dass die maximale
> Frequenz die durchkommt 15Hz betragen kann.

Nein, Grenzfrequenz ist diejenige Frequenz bei der das Signal um 3 dB 
gedämpft wird, das entspricht einer Signaldämpfung auf ca. 70% des 
Eingangssignals am Filter.

Björn M schrieb:
> Somit bräuchte ich eine
> Abtastfrequenz von mindestens 30Hz

Naja…stimmt schon…aber immer daran denken: Man legt die Abtastrate nicht 
anhand der Filterdaten fest sondern anhand des Signals, das man messen 
möchte. Natürlich legt man den Filter ebenso auf das Signal aus, dass 
man damit filtern will ;)

Björn M schrieb:
> Da ich einen 10-bit (11 clock cycles) AD-Wandler habe beträgt die
> Frequenz des AD-Wandlers dann 330Hz (30Hz * 11 clock cycles = 330Hz).

Ja und nein. Du hast so nur bestimmt, welche Frequenz der AD-Wandler 
mindestens haben muss. Es hindert dich keiner daran ihn schneller zu 
machen ;)

Björn M schrieb:
> D.h. ich muss die 12MHz durch 330Hz teilen um den Teiler für das Control
> Register zu bekommen (36363).

Wenn das dein µC so zulässt kann man das so machen. Ich mach viel mit 
Atmega 328, da liegt die AD-Wandlerfrequenz zwischen 50 und 200 kHz, 330 
Hz  könnte ich da also gar nicht einstellen. Hier würde ich mit Timern 
arbeiten, also z.B. den AD-Wandler-Taktgeber auf 100 kHz einstellen und 
mit einem Timer alle 33 ms eine Messung machen.

Björn M schrieb:
> Oder sollte
> ich besser meinen Timer auf 33.33ms setzen um in einer Sekunde 30
> Sample/s zu bekommen?

Ich kennen deinen Controller nicht aber ich denke du musst es genau so 
machen. Mit einem Atmega8 oder ähnlich müsste man es so machen wenn man 
eine Abtastrate von 30 Hz haben will.

Björn M schrieb:
> Das analoge Signal wird ja durch den AD-Wandler digitalisiert. D.h. ich
> bekomme einen Wert geliefert. Wenn ich nun das Signal auf dem Controller
> ausgeben möchte, muss ich davor den Wert den mir der AD-Wandler liefert
> in Volt umrechnen und dann zeichnen lassen oder kann ich das Signal
> direkt mit dem AD-Wert zeichnen?

Also für das Zeichnen benutze ich immer den AD-Wert, den rechne ich 
nicht in eine Spannung um sondern z.B. in einen Pixelwert meiner 
Anzeige.
Nehmen wir mal an man hätte einen Zeichenbereich von 240*120 Pixel, der 
AD-Wandler liefert 10 bit Werte dann würde ich den AD-Wert auf die 120 
Pixel abbilden (hier also 120/1023*AD-Wert wäre die Höhe (y) die ich 
zeichnen lassen würde).

Mache dir immer Gedanken darüber, was willst du zeigen und was ist dafür 
für den Benutzer von interesse? Muss er einen Spannungswert wirklich auf 
die 3. Nachkommastelle genau wissen oder genügen alle Stellen vor dem 
Komma? Wie genau muss der Benutzer die Frequenz kennen? Vielleicht 
genügt ja auch eine LED zur Anzeige, dass alles "OK" ist. Einfach mal 
drüber Nachdenken ;)

von Jürgen S. (starblue) Benutzerseite


Lesenswert?

Björn M. schrieb:
> Jim Meba schrieb:
>> Wenn das für den LPC176x sein soll, dann ist ein Fehler drin:
>
> Nein, das ist für den MCB4300.

Was nichts am Fehler ändert, CLKDIV hat auch beim LPC43xx nur 8 Bits.
(Sowas solltest du eigentlich vorher selbst nachsehen, oder spätestens 
wenn dich jemand auf den möglichen Fehler hinweist.)

Da du eh jede Wandlung von außen anstoßen musst
(Burst-Modus ist bei dir ausgeschaltet)
kannst du auch einen schnelleren ADC-Takt wählen.

von Björn M. (Gast)


Lesenswert?

Jim Meba schrieb:
> Das CLKDIV Feld hat nur 8 Bits. Da dürfen also nur Werte bis 255 rein.
Jürgen S. schrieb:
> Was nichts am Fehler ändert, CLKDIV hat auch beim LPC43xx nur 8 Bits.

Ja stimmt, das habe ich völlig übersehen. Danke!

Michael Köhler schrieb:
> Hier würde ich mit Timern
> arbeiten, also z.B. den AD-Wandler-Taktgeber auf 100 kHz einstellen und
> mit einem Timer alle 33 ms eine Messung machen.

Aber wie bestimme ich nun die Abtastrate bzw. Abtastfrequenz. Kann man 
dies überhaupt am Mikrocontroller einstellen, oder ist nur die 
Taktfrequenz des AD-Wandlers einstellbar? Reicht es aus, wenn ich jede 
33 ms einen ADC-Wert als Pixel auf dem Display ausgebe ohne die 
Abtastrate zu berücksichtigen. Ich möchte nämlich eine EKG-Kurve 
zeichnen.

Michael Köhler schrieb:
> Also für das Zeichnen benutze ich immer den AD-Wert, den rechne ich
> nicht in eine Spannung um sondern z.B. in einen Pixelwert meiner
> Anzeige.

Das mit der Umrechnung habe ich nun verstanden, danke dafür! Wie ist das 
bei dir, kann man die Pixelwerte miteinander verbinden? Also ich meine, 
ob man die AD-Werte bzw. Pixelpunkte miteinander verbinden kann um ein 
Signal zu sehen und nicht nur die Pixelpunkte. Weil ich möchte ein 
EKG-Signal zeichnen und da ich ja jeden AD-Wert als Pixel auf dem 
Display ausgebe und jedes Pixel auf unterschiedlichen Positionen liegen, 
müsste ich die Pixel verbinden. Aber ich kann nur ein Pixel, eine 
horizontale und vertikale Linie zeichnen.

Sollte man da den Abstand zweier Pixel, mit weiteren Pixel füllen um 
eine Linie zu bekommen?

Michael Köhler schrieb:
> Muss er einen Spannungswert wirklich auf
> die 3. Nachkommastelle genau wissen oder genügen alle Stellen vor dem
> Komma?

Das habe ich schon aufgegeben, irgendwie will der Controller keine 
float-Werte in der Timer_Callback Funktion ausgeben, jedes mal wenn ich 
in der Timer_Callback Funktion den ADC-Wert in Volt umrechne, hört der 
(periodische) Timer nach einem Durchgang auf. Hab schon alles versucht 
und auch recherchiert, aber leider die Ursache des Problems nicht 
gefunden.

von Karl H. (kbuchegg)


Lesenswert?

Björn M. schrieb:

>> Hier würde ich mit Timern
>> arbeiten, also z.B. den AD-Wandler-Taktgeber auf 100 kHz einstellen und
>> mit einem Timer alle 33 ms eine Messung machen.
>
> Aber wie bestimme ich nun die Abtastrate bzw. Abtastfrequenz.

Du musst zwischen 2 Dingen unterscheiden.
Das eine ist die Arbeitsfrequenz des AD-Wandlers. Das ist gewissermassen 
eine interne Frequenz, die der ADC zum arbeien braucht. Die hat nichts 
damit zu tun, wie oft du ihn abtasten lässt. Das ist gewissermassen die 
Drehzahl in deinem Auto, die nichts damit zu tun hat, wie oft du als 
Fahrer am Tacho die Geschwindigkeit abliest.

Und das andere ist die Anzahl der Messungen, die du den ADC pro Sekunde 
machen lässt.

Die beiden Dinge musst du trennen.

Einen sinnvollen Wert für den ersten Parameter kriegst du aus dem 
Datenblatt deines Prozessors. Dort steht drinnen, wie schnell du die ADC 
Maschinerie laufen lassen musst, damit du sinnvolle Werte kriegst. Da 
gibt es eine untere Grenzfrrequenz, unter die du nicht kommen willst, 
damit sich das Signal während dieser Messzeit nicht zuviel ändert. Und 
es gibt eine obere Grenze, über die du nicht kommen willst, weil du dann 
den ADC übertaktest und es dann zu Fehlern im Messvorgang kommt.

Getrennt davon ist die Abtastrate. Die legst du anhand deines Signals 
fest, wie schnell sich das ändert und ja, auch am Abtasttheorem. Wobei 
du nicht an die untere Grenze gehst und nur mit dem doppelten der 
maximalen Signalfrequenz misst, sondern ein ganzes Stück höher. Das 
doppelte der maximalen Signalfrequenz erlaubt dir gerade noch so in 
etwa, das ursprüngliche Signal zu rekonstruieren, aber viel hat das dann 
nicht mehr damit gemein. Zumindest hast du keine groben Frequenzfehler 
aber die Kurvenform ist beim Doppelten unter jeder Sau.

> Kann man
> dies überhaupt am Mikrocontroller einstellen, oder ist nur die
> Taktfrequenz des AD-Wandlers einstellbar?

Das eine ist beim ADC einstellbar (wenn es einstellbar ist), das andere 
bestimmst du dadurch, wie oft du den Messvorgang anstösst. Deine Uhr 
tickt auch mit einer Frequenz von 60Hz, was dich nicht daran hindert nur 
alle 10 Sekunden mal auf die Uhr zu schauen. Die 60Hz sind in der Uhr 
vorgegeben, die 10 mal pro Sekunde machst du als 'Benutzer der Uhr'.

> Reicht es aus, wenn ich jede
> 33 ms einen ADC-Wert als Pixel auf dem Display ausgebe

Tja. Ein wenig musst du auch experimentieren. Das ist ja der meiste 
Spass an der ganzen Sache mit dem programmieren: Das man sich Dinge 
ausdenkt und dann nachsieht, ob und wie gut sie funktionieren.


> Das mit der Umrechnung habe ich nun verstanden, danke dafür! Wie ist das
> bei dir, kann man die Pixelwerte miteinander verbinden?

Sowas nennt man dann im Allgemeinen Fall 'Eine Linie von den Koordinaten 
Xs/Ys zu den Koordinaten Xe/Ye zeichnen.

> ob man die AD-Werte bzw. Pixelpunkte miteinander verbinden kann um ein
> Signal zu sehen und nicht nur die Pixelpunkte.

Wenn du Linien hinmalst, dann malst du Linien hin. Wenn du Punkte 
hinmalst, dann malst du Punkte hin.

> Weil ich möchte ein
> EKG-Signal zeichnen

Schön.
Vor dem 'Ich möchte' kommt aber das 'Ich kann'. Und vor dem 'Ich kann' 
kommt 'Ich lerne'. Schritte auszulassen funktioniert in der 
Programmierung genausowenig, wie es beim Radfahren funktioniert. Vor der 
Tour de France kommt das normale Radfahren. Vor dem Radfahren kommt das 
Radfahren lernen. Teil des Lernens ist es die Balance halten zu lernen 
und auch mal auf die Schnauze zu fallen.
Nur mit dem einen kleinen Unterschied, dass progammieren wesentlich 
komplexer ist als radfahren.
Da hilft auch kein 'mit dem Fuss aufstampfen' und 'Ich will aber' rufen. 
Das funktioniert bei kleinen Mädchen, die ihren Vater rumkriegen wollen, 
aber nicht in der Programmierung. Computer sind da gnadenlos 
unnachgiebig.


> müsste ich die Pixel verbinden. Aber ich kann nur ein Pixel, eine
> horizontale und vertikale Linie zeichnen.

Dann sieh dich mal nach dem sog. 'Bresenham Algorithmus' um.

> Das habe ich schon aufgegeben, irgendwie will der Controller

Der Controller 'will' gar nichts. Der hat keine Persönlichkeit. Der ist 
nur eine Maschine. Wenn die Maschine nicht das tut, was du ihr 
aufträgst, dann sind deine Befehle scheisse und nicht 'der Controller 
will nicht'.

: Bearbeitet durch User
von Björn M. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Das eine ist beim ADC einstellbar (wenn es einstellbar ist), das andere
> bestimmst du dadurch, wie oft du den Messvorgang anstösst.

Ah okey, d.h. die Arbeitsfrequenz des AD-Wandlers bestimmt nicht die 
Anzahl der Messungen, sondern nur wie schnell er die Messung umrechnet. 
Falls ich eine hohe Arbeitsfrequenz einstelle, so arbeitet der ADC 
schneller und hat dafür länger Zeit zum ausruhen bis zur nächsten 
Umwandlung und falls man die Arbeitsfrequenz niedriger wählt, so 
bräuchte er etwas länger.

Karl Heinz schrieb:
> Dann sieh dich mal nach dem sog. 'Bresenham Algorithmus' um.

Vielen Dank für den Tipp. Den Algorithmus habe ich noch gar nicht 
gekannt, werde ich mal ausprobieren.

Karl Heinz schrieb:
> Wenn die Maschine nicht das tut, was du ihr
> aufträgst, dann sind deine Befehle scheisse und nicht 'der Controller
> will nicht'.

Ja das ist mir klar ^^! Ich versuche nur seit Wochen dieses Problem zu 
lösen und leider bekomme ich das nicht hin und muss deshalb nur mit 
integern auskommen. Hat eventuell jemand eine Ahnung damit, ob man 
eventuell bei den "Options for Target" etwas einstellen muss? Weil 
normalerweise müsste meine (periodische) Timer_Callback Funktion alle 
100ms neu starten, nur nach einem Durchlauf ist schluss. Ich habe auch 
schon im debugger mode das Programm gestartet und getestet.


Wie ist es den mit dem Code Size Limit. Kann man den ändern? Weil bei 
mir steht im uVision MDK-Lite Version: 5.11.1.0 "Restricted Version with 
32768 Byte Code Size Limit" und nutzen tue ich schon 26228 Bytes. Oder 
ist das nur mit einer anderen Version möglich die mehr "Code Size Limit" 
zur Verfügung stellt?

von Björn M. (Gast)


Lesenswert?

1
x = ((165.0 / 1024.0) * adcValue) - 165;

Funktioniert mit: 200 / 1024
Funktioniert nicht mit: 200.0 / 1024.0

Ich kann mir dafür keine logische Antwort denken???

von Björn M. (Gast)


Lesenswert?

Björn M. schrieb:
> x = ((165.0 / 1024.0) * adcValue) - 165;

Ich meinte natürlich:
1
x_new = ((200.0 / 1024.0) * adcValue) - 200;

von Karl H. (kbuchegg)


Lesenswert?

Was genau verstehst du unter 'funktioniert nicht'

von Björn M. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Was genau verstehst du unter 'funktioniert nicht'

Also wenn ich schreibe:
1
int x = 10;
2
3
y = (200 / 1024) * adcValue - 200;
4
x = x + 1; 
5
GLCD_DrawPixel(x, y);

kann ich den berechneten Wert y mit der aktuellen x-Position als 
Pixelpunkt auf dem Display ausgeben und zwar alle 100ms mit einem neuen 
adcValue. Zwar bekomme ich für jeden adcValue ob 0, 100 oder 1023 immer 
den y-Wert = 200 geliefert aber wenigstens funktioniert die 
Timer_Callback Funktion alle 100ms.

Aber bei:
1
int x = 10;
2
3
y = ((200.0 / 1024.0) * adcValue) - 200;
4
x = x + 1;
5
GLCD_DrawPixel(x, y);

bekomme ich nur den Pixelpunkt mit dem berechneten Wert y und die 
aktuelle x-Position (= 11) auf dem Display ausgegeben und dann müsste es 
normalerweise die Timer_Callback Funtkion wieder aufrufen um dasselbe 
mit einem anderen AD-Wert durchzuführen, was er leider nicht tut. Und 
ich weß der Fehler liegt bei mir ^^, ich weiß nur nicht wo?

von Björn M. (Gast)


Lesenswert?

Also ich habs gelöst. Ein f hinter 200.0f und 1024.0f hat gefehlt. Man 
sind die Controller empfindlich heutzutage ^^.

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.