Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

12F683 in MPLAB X - Cannot Get ADC Working

Status
Not open for further replies.

MikahB

New Member
I've been struggling with this for hours now and am officially chasing my tail.

Not seeing the expected behavior on my physical circuit, I started playing with the simulator. Every time I set the GO_DONE bit in ADCON0, I get a warning from the simulator that says "ADC-W101: Selected channel is configured as digital IO. The channel selected:X." Where X is whichever channel I've selected (I've tried AN0 and AN2 so far with identical results).

The first goal of this program is just to blink the LED on GPIO4 at a speed that is proportional to the input voltage to the ADC (0-5V).

I'm confident I must be missiong something on my setup, but I've been through the datasheets and countless examples online and have been unable to spot the problem.

Here is the code:
Code:
#include <htc.h>
#include <stdio.h>

#define _XTAL_FREQ 4000000
#define _ADCBITS 10;
#define _ADC_CLOCK3;
#define _ADC_SAMPLEUS 50;

__CONFIG(FCMEN_OFF & WDTE_ON & PWRTE_ON & MCLRE_OFF & IESO_OFF & CP_OFF & BOREN_OFF & FOSC_INTOSCIO);

void config_ADC(void);
int read_ADC(void);

bit on_state;
unsigned char delay;
volatile unsigned int count;

void main()
{
    config_ADC();
    
    while(1)
    {
        on_state = ~on_state;
        GPIObits.GP4 = on_state;

        count = 1000 * read_ADC();
        
        while(count>0)
        {
        count--;
        }

    }
}

void config_ADC(void) {
    /* Turn off all comparators */
    CMCON0 = 7;

    /* Set the ADC Control register per Data sheet */
    ADCON0 = 0;             //initialize to zero
    ADCON0bits.VCFG = 0;     // reference Vdd
    ADCON0bits.CHS = 0b010;  // read AN2
    ADCON0bits.ADON = 1;    // turn ADC on
    ADCON0bits.ADFM = 1;    // right-justify for 10-bit ADC

    /* Set all ports except GP0 to digital (0) */
    ANSEL = 0;
    ANSELbits.ANS = 0b0100;     // set AN2 to analog
    ANSELbits.ADCS = 0b001;     // set freq to fosc/8

    /* Set all pins to output except GP0 (to be used as ADC input)*/
    TRISIO = 0;
    TRISIObits.TRISIO2 = 1;     // set AN2/GPIO2 to input
    TRISIObits.TRISIO3 = 1;     // set MCLR/GPIO3 to input

}

int read_ADC(void)
{ // start an ADC conversion and return the result
	int ret = 0;
	//__delay_ms(5);
	ADCON0bits.GO_DONE = 1;		//start conversion
   	while(ADCON0bits.GO_DONE);		// wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		// get
   	ret += ADRESL;				// result
	return ret;
}

I appreciate any help or guidance!
 
Been reading it - both of those sections and more for a long time. I'm missing or misunderstanding something I'm reading. Can you be any more specific to point me in a direction?

I've disabled the comparators...
I've set my tristates on TRSIO2 and TRISIO3 high...
I've set ANSEL for the clock cycle, justification, and set AN2 as analog...
I've sed ADCON0 with what I believe are the proper settings (error seems to indicate I'm asking for the correct channel)...

When I stop the code right before I try to set ADCON0.GO_DONE high, here are the binary values in key registers:

Code:
TRISIO: 00001100
ANSEL: 00010100
ADCON0: 10001001
CMCON0: 00000111

Those are the values I expect to see based on what I'm reading in the datasheet. Just missing something.
 
Last edited:
4.2.1 ANSEL REGISTER
The ANSEL register is used to configure the Input
mode of an I/O pin to analog. Setting the appropriate
ANSEL bit high will cause all digital reads on the pin to
be read as ‘0’ and allow analog functions on the pin to
operate correctly.

Where did you set ANSEL bit high for this analog input?
What I see is that you keep mentioning two analog ports AN0 and AN2.
Are you using one or two analog ports?

If you are using AN0, as your post suggests, then fix the code so that you are enabling AN0 and not AN2 (and fix the code comments).
If you are using AN2... same story, stick with AN2 - don't mix and match.
 
Last edited:
Look at page 35 you don't set this to 0 ANSEL = 0;

You want ANSEL =0x74;
 
I set the ANSEL bits high in config_ADC():

Code:
    /* Set all ports except GP0 to digital (0) */
    ANSEL = 0;
    ANSELbits.ANS = 0b0100;     // set AN2 to analog
    ANSELbits.ADCS = 0b001;     // set freq to fosc/8

I did it this way because I read somewhere that it's good to explicitly clear the register before I start plugging stuff into it. Plus, being new to this and in a constant troubleshooting mode, it's easier for me to look at it long-hand for now so I know what I'm doing - right or wrong.

@Burt - Tried setting to 0x74 per your suggestion (only clock selection was different from what I had) and identical result.
 
Last edited:
I set the ANSEL bits high in config_ADC():

Code:
    /* Set all ports except GP0 to digital (0) */
    ANSEL = 0;
    ANSELbits.ANS = 0b0100;     // set AN2 to analog <<<<NOTE What is THIS?  Why AN2 when you want to use AN0?
    ANSELbits.ADCS = 0b001;     // set freq to fosc/8
.

NOTE: What is THIS? Why AN2 when you want to use AN0?

for AN0 you should set

Code:
    ...
     ANSELbits.ANS = 0b0001;     // set AN0 to analog
    ...

or configuration byte should be 0x11 (or 0xX1)
 
Last edited:
Switched from AN0 to AN2 during troubleshooting - forgot to change the comment but I"ve changed everything else (and now fixed the comment as well). I made a couple other minor changes to the code while troubleshooting also, here is a "fresh" new version that works equally poorly:

Code:
#include <htc.h>
#include <stdio.h>

#define _XTAL_FREQ 4000000
#define _ADCBITS 10;
#define _ADC_CLOCK3;
#define _ADC_SAMPLEUS 50;

__CONFIG(FCMEN_OFF & WDTE_OFF & PWRTE_OFF & MCLRE_OFF & IESO_OFF & CP_OFF & BOREN_OFF & FOSC_INTOSCIO);

void config_ADC(void);
int read_ADC(void);

bit on_state = 0;
unsigned char delay;
volatile unsigned int count = 0;

void main()
{
    config_ADC();
    
    while(1)
    {
        on_state = ~on_state;
        GPIObits.GP4 = on_state;

        count = read_ADC();
        
        while(count>0)
        {
        __delay_ms(10);
        count--;
        }
    }
}

void config_ADC(void) {
    /* Turn off all comparators */
    CMCON0 = 7;

    /* Set all ports to digital then un-set the ones we need */
    ANSEL = 0;
    ANSELbits.ANS = 0b0100;     // set AN2 to analog
    ANSELbits.ADCS = 0b001;     // set freq to fosc/8

    /* Set the ADC Control register per Data sheet */
    ADCON0 = 0;             //initialize to zero
    ADCON0bits.ADFM = 1;    // right-justify for 10-bit ADC
    ADCON0bits.VCFG = 0;    // reference Vdd
    ADCON0bits.CHS = 0b010; // read AN2
    ADCON0bits.ADON = 1;    // turn ADC on

    /* Set all pins to output except GP0 (to be used as ADC input)*/
    TRISIO = 0;
    TRISIObits.TRISIO2 = 1;     // set AN2/GPIO2 to input
    TRISIObits.TRISIO3 = 1;     // set MCLR/GPIO3 to input

//    __delay_ms(10);

}

int read_ADC(void)
{ // start an ADC conversion and return the 8 most-significant bits of the result
	int ret = 0;
	ADCON0bits.GO_DONE = 1;	//start conversion <<<NOTE: This is the line that produces the error I mentioned in the 1st post
	__delay_ms(5);
        while(ADCON0bits.GO_DONE);		// wait for conversion
   	ret = ADRESL + (ADRESH & 0x3) << 8;		// get result
	return ret;
}
 
Last edited:
fair enough, how about ADCON0? is this used only for AN0? Is there ADCON2?
 
This PIC only has one ADCON register - ADCON0 - that controls all 4 channels (AN0-AN3) so it's common between the two channels I've tried.
 
did you try any settings for CMCON0?
eh, never mind, this is just for analog comparator,
sorry man, unless is something silly like moving those TRIS lines before ADC, i can't see it...
 
Last edited:
Yeah, tried both 000 and 111 in least significant bits on CMCON0 - no difference. I've left it at 111 which I think is right.

I also played around with the order of the TRIS/ANSEL/ADCON assignments thinking that might be the problem, but no dice there either. The current order seems common from a couple of examples (presumably working examples) I've found online.

I really appreciate you taking a look - I'm confident it will be solved, and glad it's not such an obvious problem!
 
3v0 - I started with it on real hardware (not using simulator at all) but was not getting the expected behavior. That led me to try the simulator which helped gain some insight and pointed out some other issues I had. But, I could not get around this problem. And, when I loaded the program back onto the real hardware, I still got odd results.

But, I just realized that I had a misplaced parantheses where I was combining ADRESL and ADRESH, so I fixed that and flashed it again and, VIOLA! It's working like a charm - nice smooth control of the LED flashing frequency with a pot going into AN2. The simulator error is still there - so I guess I have to chock it up to a bug in the simulator or simulator environment. But, I'm so freaking happy that what was supposed to be a very simple second PIC project for me is now working exactly as it's supposed to.

Thanks to those who offered help, questions, suggestions, etc. I have learned a bunch of useful things troubleshooting this and now it's on to phase 3: controlling a RGB LED through 7 "states" based on rising input voltage. Should be a snap.

Finally, as promised, here is working code for future searchers who may have similar problems. I've made a few changes since the last code post, but fundamentally none of them had any impact on what I was chasing.

Code:
#include <htc.h>
#include <stdio.h>

#define _XTAL_FREQ 4000000
#define _ADCBITS 10;
#define _ADC_CLOCK3;
#define _ADC_SAMPLEUS 50;

__CONFIG(FCMEN_OFF & WDTE_ON & PWRTE_ON & MCLRE_ON & IESO_OFF & CP_OFF & BOREN_OFF & FOSC_INTOSCIO);

void config_ADC(void);
int read_ADC(void);

bit on_state = 0;
volatile unsigned int count = 0;

void main()
{
    config_ADC();
    
    while(1)
    {
        on_state = ~on_state;
        GPIObits.GP4 = on_state;

        count = 10 + read_ADC();  // add 10 so there's always a little bit of blinking
        
        while(count>0)
        {
        __delay_us(500);
        count--;
        }
    }
}

void config_ADC(void) {
    /* Turn off all comparators */
    CMCON0 = 7;
    
    /* Set all ports to digital then un-set the ones we need */
    ANSEL = 0;
    ANSELbits.ANS = 0b0100;     // set AN2 to analog
    ANSELbits.ADCS = 0b001;     // set freq to fosc/8

    /* Set the ADC Control register per Data sheet */
    ADCON0 = 0;             //initialize to zero
    ADCON0bits.ADFM = 1;    // right-justify for 10-bit ADC
    ADCON0bits.VCFG = 0;    // reference Vdd
    ADCON0bits.CHS = 0b010; // read AN2
    ADCON0bits.ADON = 1;    // turn ADC on

    /* Set all pins to output except GP0 (to be used as ADC input)*/
    TRISIO = 0;
    TRISIObits.TRISIO2 = 1;     // set AN2/GPIO2 to input
    TRISIObits.TRISIO3 = 1;     // set MCLR/GPIO3 to input

}

int read_ADC(void)
{ // start an ADC conversion and return the 8 most-significant bits of the result
	int ret = 0;
	ADCON0bits.GO_DONE = 1;	//start conversion
	__delay_ms(5);
        while(ADCON0bits.GO_DONE);		// wait for conversion
   	ret = ADRESL + (ADRESH << 8);		// get result
	return ret;
}
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top