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?
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
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.
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 ;)
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.
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.
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'.
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?
Karl Heinz schrieb:> Was genau verstehst du unter 'funktioniert nicht'
Also wenn ich schreibe:
1
intx=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
intx=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?