Hi, ich bin gerade dabei beim Keil XC 167 Board den AD Wanlder einzustellen. Allerdings gibt er immer 0 aus!:( Ich schreib euch den Code mal hier rein. Sry das der Code so ausführlich ist, aber ich bin in der Materie MC erst seid 1 Woche! /*/**********************************************************/ /* */ /* AD Wandler */ /* */ /**********************************************************/ #include <reg167.h> #include <stdio.h> #include <math.h> #define VREF 5 /* ADC Voltage Reference */ /*********************************************************************** *******/ /*************************** MAIN PROGRAM ***************************/ /*********************************************************************** *******/ unsigned int adcwert; unsigned int adcberechnet; sfr ALTSEL0P3 = 0xF126; // Umleitung des Seriellen Ports !!! void main (void) { /* Konfiguration der seriellen Schnittstellen */ P3 |= 0x0400; // Port 3.10 = 1 zur Ausgabe benutzen DP3 |= 0x0400; // Port 3.10 für Datenausgabe konfigurieren DP3 &= 0xF7FF; // Port 3.11=0 für Datenausgabe konfigurieren ALTSEL0P3 |= 0x0400; // Umleiten COM auf SubD9 Schnittstelle !!! S0TIC = 0x0080; // Transmit Interruptflag setzen S0RIC = 0x0000; // Recieve Interruptflag löschen S0RBUF = S0CON =0x8011; // Serial Channel 0 Control 0x8011 = 1 0 0 0 0 0 0 0 0 0 0 1 0 001 /* Wird alles in S0CON definiert S0M = 001 ; // asynchron 8-bit Daten S0STP = 0; // Anzahl der Stopbits -> eins S0REN = 1; // Freigabe des Empfängers auf frei setzen S0PEN = 0; // Freigabe der Paritätsprüfung auf freigegeben setzen S0FEN = 0; // Freigabe der Rahmenprüfung auf freigegeben setzen S0OEN = 0; // Freigabe der Überlaufsprüfung auf freigegeben setzen S0PE = 0; // Fehlermarke Paritätsprüfung -> Bit durch Befehl löschen S0FE = 0; // Fehlermarke Rahmenprüfung -> Bit durch Befehl löschen S0OE = 0; // Fehlermarke Überlaufsprüfung -> Bit durch Befehl löschen S0ODD = 0; // Auswahl der Parität -> gerade S0BRS = 0; // Baudratenauswahl -> Teiler durch zwei S0LB = 0; // Freigabe Rückführung auf nein S0R = 1; // Freigabe Baudgenerator -> Takt freigegeben */ S0BG = 0x04; // Baudrate auf 19200 setzen 20MHz S0TBIC =1 ; // Daten nach Schieberegister /* AD Wandler */ ADCON = 0x0111; // A/D Wandler Control 00 00 0 0 1 0 0 01 0001 = 0x0111 /* Wird alles in ADCON definiert ADCH = 0001; // Port 5.1 als Startkanal ADM = 01; // ein Kabal, fortlaufende Messung ADST = 0; // Startet die Wandlung sobalds im Programm auf 1 gesetzt wird ADBSY = 0; // wird während der Wandlung von der Steuerung auf 1 gesetzt ADWR = 1; // wartet bis daten gelesen sind 1 = ja ADCIN = 0; // keine Einzelmessungen einfügen ADCRQ = 0; ADSTC = 00; // Sample Zeit 00= 1 Takt ADCTC = 00; // 00 = 24 Takte */ /* Test ob Serielle Schnittstelle funktioniert while(1) {printf("Hey Test!\n"); } */ while(1) { ADST =1; // startet den wandler while(ADBSY); {} adcwert = (ADDAT & 0x3ff) >>2; adcberechnet = (adcwert*5)/(1024*1000); printf("%i", adcberechnet); printf("Hi"); } }
Mike Müller schrieb: > adcwert = (ADDAT & 0x3ff) >>2; > adcberechnet = (adcwert*5)/(1024*1000); Da bleibt halt nicht viel übrig. Wahrscheinlich soll die Tausend nicht in den Nenner?
Hi, da hast du natürlich recht... da man bei 10Bit ja ca 5mV als Abstufung hat -> ergo muss ich die 1000 nach oben ziehen! Richtig! allerdings spuckt der ADU jezt sehr komische Werte aus Wert=50;Wert=46;Wert=57;Wert=9;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0 ;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=0;Wert=9;W ert=48;Wert=23;Wert=42;Wert=8;Wert=47;Wert=51;Wert=56;Wert=55;Wert=60;We rt=60;Wert=15;Wert=0;Wert=29;Wert=23;Wert=26;Wert=5;Wert=29;Wert=29;Wert =29;Wert=14;Wert=49;Wert=14;Wert=10;Wert=59;Wert=35;Wert=6;Wert=40;Wert= 1;Wert=41;Wert=5 Heißt doch eigentlich, dass meine Eingangsspannung nicht konstant ist oder? Allerdings benutz ich ein Netzteil ... müsst also theoretisch stimmen
Hast du Uref an VCC angeschlossen und entkoppelt? Mir fehlt noch die Umschaltung von P5.1 zum Analogeingang. Diese erfolgt über P5DIDIS (= 1).
Guido B. schrieb: > Hast du Uref an VCC angeschlossen und entkoppelt? Also ich habe ein Netzteil mit 4 Ausgängen, je 2+ und 2- Einmal habe ich + und - als Versorgungsspannung mit 6V eingestellt und die anderen habe ich via Pinstecker zum einen + auf den Pin 5.1 und - auf GND gesteckt. Das müsste doch so passen? > Mir fehlt noch die Umschaltung von P5.1 zum Analogeingang. > Diese erfolgt über P5DIDIS (= 1). Ja das mit P5.1 habe ich noch gemacht einfach P5 = 0x0000 -> Alle als Eingang Also der ADC gibt jezt auch Werte in Abhängigkeit von der SPG aus. Allerdings mit einem Faktor von 4 zu klein -> bei 5V bekomm ich 1,2 als Ausgabe bei 2,5V -> 0,64 ... bei 0,02V (Netzteil lässt sich nicht auf 0V stellen) 0,06 -> Ich habe jezt einfach das Ergebnis mit dem Faktor 4 multipliziert so habe ich eine proportionalität von 5v ausgehend da der Faktor aber nicht 100% konstant ist habe ich wenn ich z.B 0,02V einstelle einen zu großen Wert. Woran könnte die Ungenauigkeit liegen? Zum Anderen möchte ich jezt noch ein digitales FIR Filter -> hat dazu jemand noch etwas das weiterhilft? Wie Programmiert man so einen Filter?
Wundert mich, dass es klappt ohne P5DIDIS zu setzen. Mike Müller schrieb: > adcwert = (ADDAT & 0x3ff) >>2 Da teilst du durch 4, vllt. ist das der Fehler. Du willst den AD-Wert durch 1024 teilen (ich würde ev. vorher 1 addieren) und dann mal 1000 nehmen. Dazu würde ich mal 2000 nehmen und durch 2048 (16 16 8) teilen. Um die Bitverluste zu miniieren wpürde ich das in 3 Schritten machen: Mal 20, durch 16. Nochmal mal 20 und durch 16. Mal 5 und durch 8.
Guido B. schrieb: > Wundert mich, dass es klappt ohne P5DIDIS zu setzen. > Für was wird denn P5DIDIS verwendet? Setzt er P5 als analogen Eingang? > Mike Müller schrieb: >> adcwert = (ADDAT & 0x3ff) >>2 > > Da teilst du durch 4, vllt. ist das der Fehler. Inwiefern teile ih da durch 4? Hier lese ich doch nur die Daten von ADDAT aus und Schiebe 2 Bits raus sodass ich von den 10Bit des ADW auf 8Bit komme Bitte um Erklärung :) > > Du willst den AD-Wert durch 1024 teilen (ich würde ev. > vorher 1 addieren) und dann mal 1000 nehmen. Dazu würde ich > mal 2000 nehmen und durch 2048 (16 16 8) teilen. Um > die Bitverluste zu miniieren wpürde ich das in 3 Schritten > machen: Mal 20, durch 16. Nochmal mal 20 und durch 16. Mal > 5 und durch 8. Also folgendes adcwert = (ADDAT & 0x3ff) >>2;// 1111111111 = 0x3ff -> 10bit von 0-9 adcberechnet = (adcwert*5.0*20.0)/(16.0); adcberechnet = (adcwert*20.0) / (16.0); adcberechnet = (adcwert*5.0) / (8.0); So meinst du das oder?
Mike Müller schrieb: > Für was wird denn P5DIDIS verwendet? Setzt er P5 als analogen Eingang? Siehe User-Manual: "For pins that shall be used as analog inputs it is recommended to disable the digital input stage via register P5DIDIS (see description below). This avoids undesired cross currents and switching noise while the (analog) input signal level is between VIL and VIH." Mike Müller schrieb: > Inwiefern teile ih da durch 4? Hier lese ich doch nur die Daten von > ADDAT aus und Schiebe 2 Bits raus sodass ich von den 10Bit des ADW auf > 8Bit komme > Bitte um Erklärung :) Aus dem Maximalwert von 1023 wird durch das Schieben 255. Du hast also durch 4 dividiert. Außerdem reduziert dieses Schieben die Auflösung auf ca. 20 mV, ich würde es weglassen. Mike Müller schrieb: > So meinst du das oder? Etwa. Bei der Umrechnung musst du darauf achten, dass der Uint nicht überläuft, der Wert also kleiner 65536 bleibt, und dass beim Dividieren keine Stellen durch Divisionsreste verloren gehen. Mike Müller schrieb: > adcberechnet = (adcwert*5.0*20.0)/(16.0); Das kann einen Überlauf ergeben und sollte daher werden zu:
1 | adcberechnet = (adcwert*5*10)/(8); |
Lass die Dezimalpunkte weg, nicht dasss der Compiler sie in den falschen Hals bekommt. Der Rest müsste stimmen, ich würde zu adcwert noch 1 addieren, so dass der Wert zwischen 1 und 1024 liegt.
Hi, achso man schiebt ja um 8bit zu erhalten verringert dadurch aber natürlich auch die max. zahl wegen 2^8 < 2^10 .. :D Variante 1: adcwert =(ADDAT & 0x3ff); adcberechnet = (adcwert*5) / (1024) So klappts -> Wenn ich 2,5V einstelle bekomm ich 2,5-2,64 raus. Variante2: adcwert = (ADDAT & 0x3ff) adcberechnet = (adcwert*5.0*10.0)/(8.0); adcberechnet = (adcwert*20.0) / (16.0); adcberechnet = (adcwert*5.0) / (8.0); Passt nicht ganz ;) Das Komma is um 2 Verschoben -> bei dem Schitt mit *20 wird auch recht schnell ein Überlauf erzeugt.. :) Ich habs gerade mal durchgerehnet und mit Variante 1 & 2 kommt fast das selbe raus. Bei Variante 1 kann man sich halt sicher sein, dass nie ein Überlauft erzeugt wird, da 1023*5 < 65k
Sry für den Doppelpost aber hab noch eine wichtige Frage. Aktuell benutze ich ja ein Netzteil das gibt ja Gleichstrom.. was mach ich denn wenn ich einen Wechselstrom anlege - dann schwankt ja mein Wert andauernd - wie kann ich das realisieren?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.