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.