This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

AT89C51CC03 : 10-Bit ADC Problems

Hello,

i have problems to get a 10-Bit result from the internal adc of the AT89C51CC03.

I always got only a 8-Bit result, though setting the PSIDLE-Bit.
Also i did not need the adc-eoc-interrupt to continue after the conversion,
as it is explained in the device manual.

So it seems to me, i made something wrong in setting up the adc for 10-Bit resolution.

I include the following code, which should not run with disabled eoc-interrupt.
But it runs !!!

#include "AT89C51CC03.h"
unsigned int i;
void main(void)
{
        ADCF = 0x20;  /* configure channel P1.5(AN5) for ADC */
        ADCLK = 0x00;  /* init prescaler for adc clock */
        ADCON = 0x20;  /* Enable the ADC */

        EA = 0;  /* disable interrupts */
        EADC = 0;

        P31 = 1;   // signal running via txd pin
        for (i=0; i< 20000; i++);

        while(1)
        {
                ADCON &= ~0x07;  /* Clear the channel field ADCON[2:0] */
                ADCON |= 0x05;   /* Select channel 5 */
                ADCON |= 0x40;   /* 10 bit mode */
                ADCON |= 0x08;   /* Start conversion */

                P31 = ~P31;       // signal running via txd pin
                while (!(ADCON & 0x10));
                ADCON &= 0xef;
                for (i=0; i< 20000; i++);

        }
}

So please contact me, if you have any ideas, hints, solutions, etc.

Parents
  • have considered to use a "driver" for the ADC hardware ?
    this works on AT89C51AC3 @29.4912MHz X1 mode.
    also it takes care of the watchdog.
    minor adjustments for the Keil compiler may be needed.

    // ADC 0-3V 8bit Standard or 10bit Best Precision at port P1[7..0]
    __bit adc_eoc = 0;                      // ADC end of conversion
    volatile unsigned char adc_val=0x00;    // ADC value 8bit Standard Precision
    volatile unsigned int  adc_value=0x00;  // ADC value 10bit conversion Best Precision
    
    
    void ADC_ISR(void) __interrupt(ADC_VECTOR) __using (3)
    {
        ADCON &= ~ADEOC;                    // Set by Hardware at end of conversion. Clear by software
        adc_val = ADDH;                     // ADDH contains 8bit standard value of ADC
        adc_value = ADDH << 2;              // ADDH:ADDL contains 10 bit value of ADC
        adc_value |= (ADDL & 0x03);         // mask ADDL[1..0] lower bits best precision
        adc_eoc = 1;                        // Set adc_eoc semaphore to inform end of conversion
    }
    
    
    void initadc(unsigned char ADCFchannels)   // setup P1 pins for ADC. call: initadc(CH6|CH7)  8BITS=8CHANNELS
    {
        ADCON = 0x00;                      // clear
        ADCF  = 0x00;                      // clear all channels
        ADCF |= (ADCFchannels);            // set CH6, CH7 as Analog Inputs
        ADCLK = 0x00;                      // ADCLK[4..0] PRS4..0 = 0 => X1 =Fxtal/128
                                           // F_XTAL = 29.491200 MHz / 128 = 230.400 KHz
        ADCON |= ADEN;                     // ADCON.ADEN = Enable (Disable for low power consumption)
                                           // Tsetup =4usec before the first convertion
        EADC = 1;                          // IEN1.EADC Enable ADC Interrupt
                                           // EA=1 global interrupt enable should handled in main
    }
    
    unsigned char adcreadstd (unsigned char ADCONchannel)   // Standard Precision call by channel to be converted 0..7
    {
        ADCON &= ~(SCH2|SCH1|SCH0);        // clear all SCH clannels   3BITS=8CHANNELS
        ADCON |=  ADCONchannel;            // Select channel ADCON.[SCH2..0]
        ADCON &= ~PSIDLE;                  // Standard converion 8bit clear ADCON.PSIDLE=0
        ADCON |= ADSST;                    // Start conversion. Cleared by hardware after completion.
    
        while (!adc_eoc)
            resetWDT();
    
        return (adc_val);
    }
    
    unsigned int adcreadpre (unsigned char channel)   // Best Precision call by channel to be converted 0..7
    {
        ADCON &= ~(SCH2|SCH1|SCH0);         // clear all SCH clannels
        ADCON  =  channel;                  // Select channel ADCON.[SCH2..0]
        ADCON |= (PSIDLE|ADSST);            // Best Precision convertion 10bit ADCON.PSIDLE=1, ADCON.ADSST=1
                                            // PSIDLE stop MCU but not peripherals. The ADC_ISR wakes system
        while (!adc_eoc)
            resetWDT();
    
        return (adc_value);
    }
    
    

Reply
  • have considered to use a "driver" for the ADC hardware ?
    this works on AT89C51AC3 @29.4912MHz X1 mode.
    also it takes care of the watchdog.
    minor adjustments for the Keil compiler may be needed.

    // ADC 0-3V 8bit Standard or 10bit Best Precision at port P1[7..0]
    __bit adc_eoc = 0;                      // ADC end of conversion
    volatile unsigned char adc_val=0x00;    // ADC value 8bit Standard Precision
    volatile unsigned int  adc_value=0x00;  // ADC value 10bit conversion Best Precision
    
    
    void ADC_ISR(void) __interrupt(ADC_VECTOR) __using (3)
    {
        ADCON &= ~ADEOC;                    // Set by Hardware at end of conversion. Clear by software
        adc_val = ADDH;                     // ADDH contains 8bit standard value of ADC
        adc_value = ADDH << 2;              // ADDH:ADDL contains 10 bit value of ADC
        adc_value |= (ADDL & 0x03);         // mask ADDL[1..0] lower bits best precision
        adc_eoc = 1;                        // Set adc_eoc semaphore to inform end of conversion
    }
    
    
    void initadc(unsigned char ADCFchannels)   // setup P1 pins for ADC. call: initadc(CH6|CH7)  8BITS=8CHANNELS
    {
        ADCON = 0x00;                      // clear
        ADCF  = 0x00;                      // clear all channels
        ADCF |= (ADCFchannels);            // set CH6, CH7 as Analog Inputs
        ADCLK = 0x00;                      // ADCLK[4..0] PRS4..0 = 0 => X1 =Fxtal/128
                                           // F_XTAL = 29.491200 MHz / 128 = 230.400 KHz
        ADCON |= ADEN;                     // ADCON.ADEN = Enable (Disable for low power consumption)
                                           // Tsetup =4usec before the first convertion
        EADC = 1;                          // IEN1.EADC Enable ADC Interrupt
                                           // EA=1 global interrupt enable should handled in main
    }
    
    unsigned char adcreadstd (unsigned char ADCONchannel)   // Standard Precision call by channel to be converted 0..7
    {
        ADCON &= ~(SCH2|SCH1|SCH0);        // clear all SCH clannels   3BITS=8CHANNELS
        ADCON |=  ADCONchannel;            // Select channel ADCON.[SCH2..0]
        ADCON &= ~PSIDLE;                  // Standard converion 8bit clear ADCON.PSIDLE=0
        ADCON |= ADSST;                    // Start conversion. Cleared by hardware after completion.
    
        while (!adc_eoc)
            resetWDT();
    
        return (adc_val);
    }
    
    unsigned int adcreadpre (unsigned char channel)   // Best Precision call by channel to be converted 0..7
    {
        ADCON &= ~(SCH2|SCH1|SCH0);         // clear all SCH clannels
        ADCON  =  channel;                  // Select channel ADCON.[SCH2..0]
        ADCON |= (PSIDLE|ADSST);            // Best Precision convertion 10bit ADCON.PSIDLE=1, ADCON.ADSST=1
                                            // PSIDLE stop MCU but not peripherals. The ADC_ISR wakes system
        while (!adc_eoc)
            resetWDT();
    
        return (adc_value);
    }
    
    

Children
No data