Forum Top Banner Ad

Collapse

Ebay Classic organs

Collapse

Announcement

Collapse
No announcement yet.

Read an analog input with my PIC18F66K22 using ADC

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Read an analog input with my PIC18F66K22 using ADC

    I'm trying to read an analog input with my PIC18F66K22(www.kynix.com/Parts/172528/PIC18F66K22-E%2FMR.html) using ADC. But the supposingly 10-bit value often comes to values like 63.241. I found out that a negative value (printing as unsigned) results in the same behaviour.

    I believe there might be something wrong with my ADC settings. My PIC is clocked at default (8Mhz). The range of ADC should be 0v to 2,5v but it doesn't have to be that accurate.

    I can't seem to find the right ADC settings I believe. I'm using XC8 compiler with the adc.h library that was with it in MPLAB X IDE.

    Below is the code (I made a new project tot test, with simplified code.) First the adc.c, I believe the settings are wrong and an error in the reading should be easy to see.
    Code:
    #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();
    }
    also my main.c, the other xport files are not that interesting and seem to work well. I'm not that sure of my conversion from uint to 'c-string' in the function void buttonHandle(void)
    Code:
    #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
    }
    I'm basically receiving uart text in an interrupt. And printing the debug/adc when an button flag has been set (by the button interrupt)

    This is my output after pressing the button some times:



    As you can see, the adc is not very persistent. Though I had it hooked on to the power supply (which shouldn't (and doesn't) drop this much).

  • #2
    I'm not familiar with details of A/D conversion in the PIC line, and so, can't comment on how you're initializing it. I do have a couple of comments.

    First, I wonder if you shouldn't be disabling interrupts during your getADC() routine.

    The other question I have concerns the signal you're attempting to measure in your example. Is the ADC input tied to a fixed DC voltage? Keep in mind that all leads to ADC inputs should be shielded.

    If I were debugging this, I'd simplify the code by eliminating the interrupts and the button push and just run in a loop, polling UART registers as needed, with a constant dc input to the ADC. You should see a nearly constant set of output values on the terminal, although some numerical bobble should be expected.

    Forum member jkinkennon has done a number of PIC based organ projects and probably has some words of wisdom.
    -Admin

    Allen 965
    Zuma Group Midi Keyboard Encoder
    Zuma Group DM Midi Stop Controller
    Hauptwerk 4.2

    Comment


    • #3
      Feel free to download any of my free code at my web site shown below. Look for the downloads under the Projects section. I'm using a PIC32MX on a board that Sparkfun sells. So there will be differences in the chips, but the code you look at is proven to work well -- you might even want to try the PIC32 since you must already have the IDE set up and have a programmer available.
      http://www.nwmidi.com

      Comment


      • #4
        Here are a couple of bits and pieces of my code which may help:


        Code:
        #define M_CTRL_CHANGE	0b10110000  // 0xBn - control change
        #define M_CC_VOLUME     0b00000111  // 0x07 - ch volume
        #define NUM_POTS            8   // Number of potentiometers
        
        uint32_t stalePot[NUM_POTS] = { 0,0,0,0,
                                        0,0,0,0 };  // previous potentiometer values
        uint32_t freshPot[NUM_POTS] = { 0,0,0,0,
                                        0,0,0,0 };  // current potentiometer values
        
        
        void initADC(void) {
            AD1CON1 = 0x00f0;       // auto conversion after sampling, stop after 8 samples
            AD1CON2 = 0x041c;       // use MUXA, AVss/AVdd as Vref
            AD1CON3 = 0x1f3f;       // ??
            AD1CHS = 0;             // ignored for scanning
            AD1CSSL = 0x7f01;       // scan 8 inputs, RB0 and RB8:14
            AD1CON1bits.ADON = 1;   // turn on the ADC
            AD1CON1bits.ASAM = 1;   // start auto sampling
        }
        
        void getPots(int numPots) {
            int i;
            int pot = 0;
            uint32_t diff;
            for (i = 0; i < numPots; i++) {
                freshPot[i] = *adcBufferPtr[i] >> 3;
                freshPot[i] = (freshPot[i] + stalePot[i]) >> 1; // average old and new
                diff = freshPot[i] - stalePot[i]; // find difference
                if (diff > 1) {
                    midiTxMsg[0] = M_CTRL_CHANGE | pot;
                    midiTxMsg[1] = M_CC_VOLUME;
                    midiTxMsg[2] = (uint8_t)freshPot[i];
                    stalePot[i] = freshPot[i]; // save previous value
                    sendMidiMsg();
                }
            }
        }
        Last edited by John Kinkennon; 04-01-2018, 07:09 PM. Reason: Remove irrelevant code lines...
        http://www.nwmidi.com

        Comment

        Working...
        X