PIC - ADC - Negativer Wert? - Falsche Einstellungen?

Ich versuche, einen analogen Eingang mit meinem PIC18F66K22 mit ADC zu lesen. Aber der vermeintliche 10-Bit-Wert kommt oft auf Werte wie 63.241. Ich habe herausgefunden, dass ein negativer Wert (Drucken als unsigned) zum gleichen Verhalten führt.

Ich glaube, dass mit meinen ADC-Einstellungen etwas nicht stimmt. Mein PIC ist standardmäßig getaktet (8 MHz). Der Bereich des ADC sollte 0 V bis 2,5 V betragen, muss aber nicht so genau sein.

Ich kann anscheinend nicht die richtigen ADC-Einstellungen finden, glaube ich. Ich verwende den XC8-Compiler mit der adc.hBibliothek, die in MPLAB X IDE enthalten war.

Unten ist der Code (ich habe ein neues Projekt tot test gemacht, mit vereinfachtem Code.) Zuerst die adc.c, ich glaube, die Einstellungen sind falsch und ein Fehler beim Lesen sollte leicht zu erkennen sein.

#include <adc.h>
#include "adc.h"

void adcSetup()
{
   OpenADC (
           ADC_FOSC_8          &
           ADC_RIGHT_JUST       &
           ADC_20_TAD,
           ADC_CH4              &
           ADC_INT_OFF          &
           ADC_REF_VDD_VDD      &
           ADC_REF_VDD_VSS,
           ADC_CH4
           );
   ENABLE_AN4_ANA();
   SetChanADC(ADC_CH4);
}

//TODO ADC with interrupts

unsigned int adcGet(void)
{
   ConvertADC();
   while(BusyADC()){}
   return ReadADC();
}

auch meine main.c, die anderen xport-Dateien sind nicht so interessant und scheinen gut zu funktionieren. Ich bin mir meiner Konvertierung von uint in 'c-string' in der Funktion nicht so sichervoid buttonHandle(void)

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <p18f66k22.h>
#include <delays.h>
#include <usart.h>

#include "defines.h"
#include "configuration-bits.h"
#include "xport.h"
#include "adc.h"

#define __delay_us(x) _delay((unsigned long)((x)*(8000000/4000000UL)))
#define __delay_ms(x) _delay((unsigned long)((x)*(8000000/4000UL)))

volatile char RxBuf[] = "                                        ";
volatile int RxI = 0;
volatile bool RxMessage = false;
volatile bool ButtonPressed = false;

void SetupRegisters(void);
void SetupInterrupts(void);
void interrupt HighISR(void);
void interrupt low_priority LowISR(void);
void delay_ms(unsigned int x);
void buttonHandle(void);
void messageHandle(void);

void SetupInterrupts(void)
{   
    INTCONbits.GIE  = 1;                //Global interrupt enable
    RCONbits.IPEN   = 1;                //Enable priority interrupts
    INTCONbits.GIEH = 1;                //Global interrupt enable High
    INTCONbits.GIEL = 1;                //Global interrupt enable Low
    INTCONbits.PEIE = 1;                //Peripheral Interrupt Enable bit
    INTCONbits.PEIE_GIEL = 1;           //Peripheral Interrupt Enable?

    INTCON3 =   0b00000000;             //Clear intcon. INT1 and INT2 are now low priority
    INTCON3bits.INT1E = 1;              //Enable int1 (BUTTON)
}

void SetupRegisters(void)
{
            //76543210
    TRISA = 0b10101110;     //7:RFID en2 6:x 5:POWER_LEVEL(analog) 4:PWRKEY 3:SW_CHRG 2:SW_FAULT 1:EXT_INP
    TRISBbits.TRISB1 = 1;   //BUTTON INPUT
    TRISEbits.TRISE3 = 0;   //XPort RESET
    TRISGbits.TRISG3 = 1;   //LDO pwrgd (input)
    TRISGbits.TRISG4 = 0;   //LDO shdn  (ldo to toggle xport)
}

/* Main */
int main() {
    //---Set up Registers/interrupts of PIC---
    //See defines.h for al macros for LED_IN and other pin-renames.
    SetupRegisters();       //Registers...
    SetupInterrupts();      //Interrupts (button/uart)
    adcSetup();             //ADC for power-detection (POWER-LEVEL)

    //---Set up peripherals---
    xportSetup();           //Using xport as debugging help.
    xportEnable();          //Switch ldo to enable it.

   while(true){
        if(RxMessage){
            messageHandle();
        }else if(ButtonPressed){
            buttonHandle();
            ButtonPressed = false;
        }
    }
   return 0;
}


void interrupt high_priority HighIsr(void)    //High priority interrupt
{
    if(PIR3bits.RC2IF){//USART INTERRUPT
        RxBuf[RxI] = RCREG2;
        if(RxBuf[RxI] == ';'){//TODO or full
            RxMessage = true;
        }
        RxI++;
    }else{
        xportSendText("High - unhandled interrupt");
    }
}

void interrupt low_priority LowIsr(void)    //Low priority interrupt
{
    if(INT1IF){                 //Button interrupt
        ButtonPressed = true;   //Set flag (handled in main)
        INT1IF = false;         //clear interrupt flag afterwards  to avoid hardware bounce re-interrupt
    }else{                      //Warning for unhandled interrupt
        xportSendText("[ERROR] Low - unhandled interrupt!");
    }
}

void delay_ms(unsigned int xc)
{
    do
    {
        xc--;
        __delay_ms(1);
    }
    while(xc  > 0);
}

void buttonHandle(void){
    delay_ms(100);
    if(!BUTTON){
    xportSendText("Button pressed");

    //ADC DEBUG
    char buffer[] = "                   ";
    sprintf (buffer, "ADC: %u", adcGet());
    xportSendText(buffer);

    //RX DEBUG
    xportSendText("RxBuf: ");
    xportSendText(RxBuf);

    //XPORT debug
    xportDebug();
    }
}

void messageHandle(void){
    xportSendText(RxBuf);                                           //Send/Handle the buffer
    strcpy(RxBuf, "                                        ");      //Empty the buffer!
    RxI = 0;                                                        //Start buffer at pos 0 again;
    RxMessage = false;                                              //Reset the flag
}

Ich erhalte im Grunde UART-Text in einem Interrupt. Und Drucken des Debug/Adc, wenn ein Button-Flag gesetzt wurde (durch den Button-Interrupt)

Dies ist meine Ausgabe nach mehrmaligem Drücken der Taste: Geben Sie hier die Bildbeschreibung einWie Sie sehen können, ist der Adc nicht sehr hartnäckig. Obwohl ich es an das Netzteil angeschlossen hatte (das nicht so stark fallen sollte (und nicht fällt).

Zitieren Sie mich nicht (es ist mehrere Jahre her, seit ich das letzte Mal an einem Bild gearbeitet habe), aber ich erinnere mich an etwas darüber, dass der Pin von einem GPIO-Pin in einen ADC-Pin mit einer Art Register geändert werden musste (oder vielleicht war es das umgekehrt). Ich wünschte, ich könnte einen alten ADC-Code ausgraben, um zu helfen, aber ich kann keinen finden. Verzeihung!
Sie haben Recht damit, ENABLE_AN4_ANA();sollten diesen Trick jedoch ausführen. Aber ja, könnte wirklich so eine Kleinigkeit sein.
Mir ist aufgefallen, dass Ihr adc.c #adc.h zweimal enthält. Das ist wahrscheinlich nicht das Problem - Header-Dateien sollten Wächter um sich herum haben, um mehrere #Einschlüsse zu handhaben - aber ich glaube auch nicht, dass es beabsichtigt war.
Nun, es gibt eine <adc.h>-Bibliothek, die mit dem Compiler/Studio geliefert wurde. Aber ich habe auch eine "adc.h" mit "adc.c" gemacht. Ich stimme zu, dass die Namensgebung etwas umständlich ist, aber es sollte trotzdem funktionieren?

Antworten (2)

Ich weiß, dass die Beispiele und Bibliotheken existieren, um Arbeit zu sparen, aber ich finde es oft hilfreich, sie zunächst nicht zu verwenden, während ich verifiziere, dass mein Verständnis und das Datenblatt korrekt sind und dass der Chip nicht kaputt ist. (Normalerweise ist das Problem mein Verständnis.)

Also, ohne die Bibliothek zu benutzen:

  • Stellen Sie alle ADC- und Port-Register so ein, wie sie laut Datenblatt sein sollen, je nachdem, was Sie tun möchten
  • Stellen Sie sicher, dass das funktioniert
  • Debuggen Sie dann die Bibliothek

Sie werden wahrscheinlich feststellen, dass die Bibliothek korrekt ist und Ihnen etwas fehlt, was zu diesem Zeitpunkt offensichtlich wird, aber hin und wieder gibt es eine Bibliothek, die falsch oder zumindest schlecht geschrieben/dokumentiert ist.

AaronD, @FuaZe: Ihr habt Recht, meine Antwort war falsch. Ich sollte sicherstellen, dass ich vollständig wach bin, bevor ich Fragen beantworte :) Ich habe meine Antwort gelöscht.
Kein Punkt! Jede Hilfe ist willkommen!

Ich verstehe immer noch nicht wirklich, warum es überhaupt nicht funktioniert hat ... Könnte so gewesen sein, wie ich es gedruckt habe. Könnte die Bibliothek gewesen sein.

Obwohl ich es getan habe, indem ich die Register manuell eingestellt habe, funktioniert dies (besser) für mich.

static unsigned int result = 0;
ANCON0bits.ANSEL4 = 1;      //AN4 to analog channel.
ADCON2 = 0b10111110;        //Select channel
ADCON1 = 0b00110000;
ADCON0 = 0b00010011;        //Start AN4 conversion

while(ADCON0 & 2){}         //ADC busy

result = ADRESH;
result = result<<8;
result = result | ADRESL;
ADCON0 &= 0b11111110;       // Turn converter off
return (result/85);