-         

Ergebnis 1 bis 7 von 7

Thema: PIC18F442 - ADC Problem

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    12.09.2010
    Beiträge
    20

    PIC18F442 - ADC Problem

    Anzeige

    hi, ich habe einen PIC18F442.
    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
    Code:
    /*
     *  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.
    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
    Angehängte Dateien Angehängte Dateien
    Geändert von ruNN0r (22.02.2012 um 02:33 Uhr)

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    06.01.2009
    Alter
    26
    Beiträge
    104
    Was für ein Wert bekommst du? Ist es immer der Gleiche oder schwankt er bei Temperaturänderungen?
    Gruß
    Kevin

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    12.09.2010
    Beiträge
    20
    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 Ich liefer aber noch Werte sobald Debugging usw. wieder funktioniert! Wollte mich nur mal melden

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    523
    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:
    Code:
    
    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
    Geändert von Siro (21.02.2012 um 23:12 Uhr)

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    12.09.2010
    Beiträge
    20
    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 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.

    Code:
    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

    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...

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    523

    Idee

    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

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    12.09.2010
    Beiträge
    20
    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
    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

    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

Ähnliche Themen

  1. ATMega32 UART problem --> Problem gelöst
    Von ChristophB im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 12.03.2010, 19:45
  2. Problem mit Atmega644P Erkennung (Bascom-Versions-Problem)
    Von Rohbotiker im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 11.08.2008, 19:52

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •