PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PIC18F442 - ADC Problem



ruNN0r
20.02.2012, 14:52
hi, ich habe einen PIC18F442 (http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME= A300%252FPIC18F242_PIC18F252_PIC18F442%2523MIC.pdf ;SID=12Tx1KXn8AAAIAAE9FsRgb2e4f869f686dc2de53f5202 d8eca285).
Mit dem ADC dort möchte ich nun eine Temperatur messen!
Dazu nutze ich einen KTY 81-220 mit 2000Ohm bei 25°C

Ich habe einiges gelesen aber komm leider nicht weiter...
Ich habe den KTY an AN0 gehängt. Der KTY hängt in reihe mit einem 4,7K Widerstand und das ganze fungiert als Spannungsteiler. Ich Greife nun die Spannung ab und leite diese an den PIC (AN0) zu messung weiter.

Nun ja. Da ich den PIC mit 5V betreibe und der ADC 10Bit hat ist eine Werterhöhung bei 5/1024 = 4,88mV.
Für den KTY habe ich mir eine Wertetabelle in Excel gemacht die ich hier mal anhängen werde!
Laut der Tabelle erhalte ich bei 20°C 1,451V und der ADC Wert müsste 297 Betragen.

Ich komme bei weitem nicht auf diese Werte! 1,434 V habe ich direkt am Spannungsteiler (mit Multimeter gemessen) und ich habe hier ca. 23°C

Das ganze Programm schicke ich nun mal nicht rüber... da die Multiplexingfunktion und die Uhr gut funktionieren. Also nur das nötigste ;)


/*
* I N C L U D E S
*/
#include <p18F442.h>

/*
* C O N F I G U R A T I O N S
*/

#pragma config OSC = XT
#pragma config PWRT = ON //keine ahnung... Memo: noch mal Nachlesen!
#pragma config WDT = OFF //Watchdog off
#pragma config LVP = OFF //Low Voltage ICSP
/*
* D E F I N A T I O N S
*/


/*
* F I X E D V A R I A B L E S
*/
//Global
int i = 0;
int mode = 3; //Anzeigemodus

//Dot Matrix Anzeige
int iCol = 0; //Zähler für die Spalten
int iRow = 0; //Zähler für die Zeilen
int CursorPos = 0; //Aktuelle Position im "Display"
int CursorValue[5] = {0,10,10,10,10}; //Werte an der Position
int SegPos = 0; //Aktuelle Position im Segment
int co = 0; //Anzahl Overflows
int coAnpassen = 0; //Counter um den fehlen viertelTakt nachzuholen.

//Temperatur
int temp1 = 0;
int temp2 = 0;

//Uhr
int Stunden = 0;
int Minuten = 0;
int Sekunden = 0;

//Taster
int TWT = 800; //Entprelltimer
int T1WT = 0;
int T2WT = 0;
int T3WT = 0;


/*
* I N T E R R U P T
*/

#pragma interruptlow InterruptHandler
//Ausgeblendet
/*
* P R O G R A M M
*/
#pragma code
unsigned char ADC_read(void){
ADCON0bits.GO_DONE = 1;
temp2 = 0;
while(ADCON0bits.GO_DONE != 0){}
temp2 = ADRESL;
temp2 += (ADRESH << 6);
}
void main(void) {
TRISD = 0x00;
PORTD = 0x00;
TRISB = 0x07;
TRISAbits.RA0 = 1;

T0CONbits.TMR0ON = 1; //Timer0 an/aus
T0CONbits.PSA = 1; //Den Vorteiler 0 = AN | 1 = OFF
T0CONbits.T0PS = 0b000; //Voteiler einstellen
T0CONbits.T0CS = 0; //Tacktquelle | 1 = vom TOCKI holen | 0 = vom OSC holen
T0CONbits.T08BIT = 1; //Timer Breite einstellen | 1 = 8bit | 0 = 16bit


RCONbits.IPEN = 0; // Priorität aktivieren/deaktivieren
INTCONbits.GIEL = 0; // Low priority
INTCONbits.GIEH = 1; // Interrupting enabled.

INTCONbits.TMR0IE= 1;
INTCONbits.TMR0IF= 1;
INTCON2bits.TMR0IP=0;

ADCON1 = 0b11001110;
ADCON0 = 0b01000000;
ADCON0bits.ADON = 1;

init_4094();

//test();

while(1){
if(mode==0){
test();
}
if(mode==1){
uhr_show();
}
if(mode==2){
uhr_binaer();
}
if(mode==3){
if(Sekunden % 2 == 0 ){
ADC_read();
}
therm();
}
}
}

if(Sekunden % 2 == 0 ){
ADC_read();
}
Soll nur dafür sorgen dass jede sekunde ein mal gemessen wird. Funktioniert gut... da der ADC ja Zeit benötigt zwischen den messungen dachte ich es wäre vorerst die besste Idee.
Ich nutze einen 4MHz Quarz an dem PIC18F442 (http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME= A300%252FPIC18F242_PIC18F252_PIC18F442%2523MIC.pdf ;SID=12Tx1KXn8AAAIAAE9FsRgb2e4f869f686dc2de53f5202 d8eca285).
So, ich glaube ich habe alles wichtige erzählt. Ich hoffe ihr könnt mir helfen... Danke!

Achja, weil es nicht funktioniert habe ich sehr viel rumprobiert mit den Registern um mich meinen Werten anzunähern... kann sein dass dies jetzt totaler Bullshit ist aber ich wusste nicht mehr weiter ;)

hagbart06
20.02.2012, 21:48
Was für ein Wert bekommst du? Ist es immer der Gleiche oder schwankt er bei Temperaturänderungen?

ruNN0r
21.02.2012, 20:02
hi, den genauen Wert der ADRESL und ADRESH weiß ich gerade nicht da ich meinen neuen PC nun habe und der ist noch nicht konfiguriert! Aber es sind verschiedene Werte. Meist weichen diese nicht viel ab (1-10 stellen) aber manch mal auch richtig stark!!! Von der Temperatur lässt er sich jedoch kein stück anmerken :D Ich liefer aber noch Werte sobald Debugging usw. wieder funktioniert! Wollte mich nur mal melden ;)

Siro
21.02.2012, 21:49
Hallo ruNN0r

Bei 25 Grad Celsius hat der KTY81-220 einen min und einen max Wert.
1960 bis 2040 Mittig also 2000 Ohm
Wenn wir jetzt mal die worst case Werte berechnen für min und max:
ergeben sich folgende Spannungen bzw. ADU Werte:

bei min 5/(4700+1960)*1960 = 1,4714714714714714714714714714715 Volt ==> 301 ADU steps
bei max 5/(4700+2040)*2040 = 1,5133531157270029673590504451039 Volt ==> 310 ADU steps

Da können also rund 9 counts Differenz sein, das wäre innerhalb der Spezifikation des Datenblattes vom KTY
Wenn es genauer werden soll, müstest DU den KTY81-210 benutzen.


Zu deinem Programmcode:

Deine Funktion ADC_read soll einen "unsigned char" zurück liefern ??? das sind nur Werte von 0..255
Dein ADU hat aber Werte von 0..1023
Aber wie ich deiner Funktion entnehme liefert sie garnichts zurück. oder da fehlt ein Stück Code, kann ja sein.
Oder Du wertest denn temp2 Wert direkt aus, das kann ich deinem Code jetzt nicht entnehmen, aber ich hoffe er ist auch als 16 Bit Wert definiert.

warum schiebst DU den ADRESH 6 mal links ?? Du überschreibst Dir Bit 6 und 7 vom vorher gelesenem ADRESL Ergebnis.
Du hast im ADCON1 RIGHT JUSTIFIED ausgewählt also ADFM = 1
damit müste dein Auslesen meiner Meinung nach so aussehen:


temp2 = ADRESL;
temp2 += (ADRESH << 8);

Ich vermute mal, genau hier liegt das Problem......

ADCON1 = 0b11001110; /* right justified */

Zum timing:
minimun TAD time is 1,6µsec
ADCS2 ADCS1 ADCS0 = 101 ergibt FOSC/16 wären dann bei 4Mhz / 16 = 4 mikro Sekunden.
Das sollte okay sein.

ich hoffe ich konnte Dir weiterhelfen
Siro

ruNN0r
22.02.2012, 01:32
Hallo Siro,
So habe mich mal wieder angeklemmt ^^

Das der Widerstand schwankt war mir klar... jedoch nicht dass der so stark währenddessen schwankt. Ich dachte immer es wäre von Stück zu Stück verschieden... OK Fehlannahme... Danke.


Deine Funktion ADC_read soll einen "unsigned char"
Oh... das ist noch von dem PIC18F45K20 aus dem DemoBoard :D Habe ich total übersehen! Habe nun ein einfaches "void" draus gemacht da es ja keinen return-befehl gibt.


Aber wie ich deiner Funktion entnehme liefert sie garnichts zurück. oder da fehlt ein Stück Code, kann ja sein.
Oder Du wertest denn temp2 Wert direkt aus, das kann ich deinem Code jetzt nicht entnehmen, aber ich hoffe er ist auch als 16 Bit Wert definiert.
Also die temp2 wird ganz vorne unter "* F I X E D V A R I A B L E S" festgelegt (die habe ich rausgelassen... trage ich nach!). Die Funktion soll den Wert nur in die temp2 schreiben und fertig. Einen Rückgabewert gibt es nicht.
Alles weitere wird dann in der Funktion therm() in ein Sichtbares Bildchen umgerechnet und auf die 5 DotMatrix Segmente abgefeuert.


warum schiebst DU den ADRESH 6 mal links ?? Du überschreibst Dir Bit 6 und 7
Das ist eine der von mir beschrieben stellen wo ich einfach mal rumprobiert habe... Ich wollte damit in der Manipulation was testen... evtl. wäre der Fehler wo anders gewesen.

Das mit dem Timing habe ich ehrlich gesagt noch nicht so ganz verstanden!
Dort habe ich zuerst meinen Fehler gesucht. Ich denke du hast mich da ein Stück weiter gebracht... So ganz ist es mir aber noch nicht klar...
Also die FOSC/16 habe ich mit meiner Rechnung nur zufällig erreicht... verstanden aber nicht...


Ist bin nun deine Tips und Ideen durchgegenagen und meinen Code überprüft und geändert.
Ich habe nun mal einige Zeit die Werte beobachtet und aufgeschrieben.



ADRESH | ADRESL | temp2 | meine Anzeige
0x01 0x43 0x0075 117
0x01 0x3c 0x006E 110
0x01 0x40 0x0072 114
0x01 0x42 0x0074 116
0x01 0x3D 0x006F 111

Also wenn ich 0x0075 umrechne komme ich auch auf 117... Also meine Anzeige passt schon mal. Gut, da ist kein rechenfehler!

Wie man sieht schwank dieser zwischen 111 und 117. Also passt es irgendwie... aber sind dies nicht die von mir erhofften Werte :D

Ein weiterer Test der zuvor immer fehl geschlagen ist: Temp fühler stark erwärmen oder abkühlen. Ich habe ihn einfach mal in die Hand genommen und auf 1,520V gebracht (Zuvor 1,458V) dort waren die Werte nun zwischen 120 und 129.

So, Ich danke dir erst mal und hoffe dass du mir noch bei dem letzten Problem helfen kannst, warum meine Werte zu klein sind...

Siro
22.02.2012, 07:12
Guten Morgen,

dein Widerstand bzw. Messwerte schwanken natürlich nicht sooooo. Das hab ich wohl undeutlich umschrieben. Je nach Charge des Bauelemts KTY.. kann der Wert bei 25 Grad an diesen "worst case" Punkten liegen.
Damit ist also nur der Absolutwert gemeint und hat nichts mit den Schwankugen zu tun.

Thema Anzeigewert:
wenn ADRESH auf 0x01 steht, dann sind das schon mal 256 dezimal
dazu kommt ADRESL mit 0x43 also dezimal 67
256 + 67 sind bei mir 323 und der Wert sieht doch garnicht so schlecht aus.
Du must den Wert von ADRESH mit 256 multiplizieren oder 8 mal nach links schieben und dann den Wert von ADRESL dazuaddieren oder aufoderieren.
Irgendwie verschwindet in deiner Berechnung von temp2 der ADRESH Wert.
Weil dein wirklicher ADU Wert ist 0x0143 hex und das sind 323. Wobei die 0x01 das ADRESH und 0x43 dein ADRESL ist. Ist doch okay.

Thema Schwankungen:
Schwankungen hast Du anhand deiner Werte von 7 ADU Counts . Das könnte sicher besser sein.
Die Ursachen sind Vielfältig. Ich würd auf jeden Fall parallel zum KTY noch einen 100nF Kondi spendieren.
Oder Du müstest evtl. das VREF+ vom ADU benutzen und extra mit "sauberer Spannung" versorgen, deinen 4K7 Widerstand natürlich auch dort anknüpfen.
und die Register vom ADU dann entsprechend initialisieren.
Ich denke bis auf 1 bis 2 Counts Schwankungen sollte man es hinbekommen, das ist ja nur ein 10 Bit Wandler.

Viel Spass noch, Du bist fast am Ziel.
Siro

ruNN0r
22.02.2012, 12:29
dein Widerstand bzw. Messwerte schwanken natürlich nicht sooooo. Das hab ich wohl undeutlich umschrieben.
oder ich habe dich misverstanden. Aber nun habe ich es verstanden.

Es funktioniert!!!
Also ADRESH 8 mal nach links schieben funktioniert nicht... habe jetzt mit 256 multipliziert und das klappt.
Dann habe ich das ganz noch eben umgedreht. Also so dass ADRESL zu ADRESH addiert wird und nicht anderes (nur für mich...)
So dann habe ich noch einien fehlerhaften Teil in der Funktion Therm() entdeckt der mir die Anzeige versaut hat... Diese Funktionierte nur bis 300 und ab da wurden 1000 "addiert" also hatte ich immer 1320 :D
Nun liegen meine Werte bei 317-323... Halbwegs OK! das mit dem Kondensator muss ich mal ausprobieren... ich schau mal ob ich noch einen habe und der Platz auf der Platine findet :D

Nun muss ich meinen Wert nur noch mit (5/1024) multiplizieren und dann noch durch den fast liniarisierten Spannungsunterschied des KTY teilen... wenn ich mich da nicht vertue... nun gut.
Muss nun erst mal noch für die Uni lernen. Aber ich danke dir vielmals!!!!! Werde heute abend noch mal nachsehen und probieren. Dann melde ich mich noch mal ;)