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.

Moving on to C

Status
Not open for further replies.
Usually its easier to use a wrapper function to read the adc....

I use this

C:
int ReadADC(unsigned char ch)
	{
	int ret = 0;
	ADCON0 = 0b10000001 + (ch<<3);	// set channel to read
	delayMs(5);
	GODONE = 1;						// start conversion
   	while(GODONE);					// wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		// get 
   	ret +=	ADRESL;					// result
	return ret;
	}

Then you can pass the channel you want to read and then get the correct reading in return..


Setup the ADC like this
C:
void InitADC()
	{								// Set ADCON0 & 1
	ADCON0 = 0b10000001;			// FOSC/4
	ADCON1 = 0b10000101;			// Right justified
	}
Then just put this in your main

C:
int number;
InitADC();		

while(1)
   {
    number = ReadADC(0);
 
Usually its easier to use a wrapper function to read the adc....

I use this

C:
int ReadADC(unsigned char ch)
	{
	int ret = 0;
	ADCON0 = 0b10000001 + (ch<<3);	// set channel to read
	delayMs(5);
	GODONE = 1;						// start conversion
   	while(GODONE);					// wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		// get 
   	ret +=	ADRESL;					// result
	return ret;
	}

Then you can pass the channel you want to read and then get the correct reading in return..


Setup the ADC like this
C:
void InitADC()
	{								// Set ADCON0 & 1
	ADCON0 = 0b10000001;			// FOSC/4
	ADCON1 = 0b10000101;			// Right justified
	}
Then just put this in your main

C:
int number;
InitADC();		

while(1)
   {
    number = ReadADC(0);

This works but Im still stumped. If it helps Im just using a 2.5k Pot on both AN0 and AN1 to vary the voltage, so impedance shouldnt be a issue. What happens if this: The PIC only sees one voltage, it will turn on one LED and then shortly after, the other one if I keep increasing the voltage. Its strange. Its like the Registers arent being cleared. Ive increased the delays (unless, ofc the delays arent actually working..)

Also changing the channel seems to make no difference.
Code:
/*
 * File:   ADC_Ver1
 * Author: chris
 * This is Basic ADC Code for the PIC12F1840 Series. Should be portable to others
 * Created on August 19, 2013, 6:11 PM
 */

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>




#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5) //Charge LED
#define RA4 (PORTAbits.RA4) // PFET
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON


void SetupClock (void) //set up clock
{
    OSCCON = 0b01110010;

}
void IntADC (void) //setup ADC
 {
         //** Initalise Ports FOR ADC **//
         //PORTA = 0x00;
         TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1 Inputs
         //** Set Up ADC Parameters **//
         ANSELA = 0b00000111; //RA4 Output, RA5 Output, all others input
         ADCON1 = 0b10010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
         ADCON0bits.ADON = 1;
}    // void InitADC(void)

int ReadADC(unsigned char ch)
{
	int ret = 0;
        ADRESH = 0;
        ADRESL = 0;
	ADCON0 = 0b10000001 + (ch<<3);	// set channel to read
	__delay_ms (25);
	ADCON0bits.GO = 1;						// start conversion
   	while(ADCON0bits.GO_nDONE);					// wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		// get 
   	ret +=	ADRESL;					// result
	return ret;
}


void main (){
    
    SetupClock();
    IntADC();
    unsigned int Vcharge; 
    unsigned int Vcurrent;
    unsigned int Vbattery;
    Vcharge = 0;
    Vcurrent = 0;
    Vbattery = 0;
    
    while (1){

        Vcharge = ReadADC(0);
        __delay_ms(100);
        Vcurrent = ReadADC(1);

       if (Vcharge >512)

    {
        RA4 = 1;

    }
        else
        RA4 = 0;


    if (Vcurrent > 512 )
    {
        RA5 = 1;
    }
    else
        RA5 = 0;
    
 } 
    }
 
Your symptoms could be caused by excessive loading on the pins, do you have current limiting resistors on the LEDs?

Mike.
 
Your symptoms could be caused by excessive loading on the pins, do you have current limiting resistors on the LEDs?

Mike.

I just tried that. 1k resistors for the LEDs. Im using Red and Green LEDs. Still does the same thing. There has to be something Im overlooking.
 
Just to try!!! Use a manual delay routine....

C:
void DelayUs(int x)
   {
    while(x--)		// these two take 6uS
         NOP();		//
   }

void DelayMs(int x)
   {
   while(x--)
        DelayUs(163);  // adjust this value to get a Milli second
	}
 
I just tried that. 1k resistors for the LEDs. Im using Red and Green LEDs. Still does the same thing. There has to be something Im overlooking.

It would be cool if you posted a schematic of your completed circuit. Of course only if you don't mind other people seeing it.

kv
 
Last edited:
Just to try!!! Use a manual delay routine....

C:
void DelayUs(int x)
   {
    while(x--)		// these two take 6uS
         NOP();		//
   }

void DelayMs(int x)
   {
   while(x--)
        DelayUs(163);  // adjust this value to get a Milli second
	}

still the same operation :/. I even tried another PIC to rule out the possibility the port was bad

I would be cool if you posted a schematic of your completed circuit. Of course only if you don't mind other people seeing it.

kv

I came up with one very quickly using a preexisting PIC in eagle. The pin numbers are correct but I havent edited the names. GP5/4 correspond to Port4/5. I actually didnt use a schematic, as its very simple.

My supplies for this project came in. I bought myself a pretty sweet Microstick II! It came with 4 PIC's (16 and 32 bit) in 28 Pin packages, which is pretty exciting!
 

Attachments

  • PICschematic.png
    PICschematic.png
    7.1 KB · Views: 173
Here.... Try this...

My fault entirely... The ADC routine I gave you was for the older chips... CHS0~CHS4 are shifted 2 not 3....

Also the ADCON tad was a little too fast... I've changed it ...

C:
/*
 * File:   ADC_Ver1
 * Author: chris
 * This is Basic ADC Code for the PIC12F1840 Series. Should be portable to others
 * Created on August 19, 2013, 6:11 PM
 */
 
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
 
 
 
 
#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5) //Charge LED
#define RA4 (PORTAbits.RA4) // PFET

 
#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON
 
 
void SetupClock (void) //set up clock
{
    OSCCON = 0b01110010;
 
}
void IntADC (void) //setup ADC
 {
         //** Initalise Ports FOR ADC **//
         //PORTA = 0x00;
         TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1 Inputs
         //** Set Up ADC Parameters **//
         ANSELA = 0b00000111; //RA4 Output, RA5 Output, all others input
         ADCON1 = 0b11010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
         ADCON0bits.ADON = 1;
}    // void InitADC(void)
 
int ReadADC(unsigned char ch)
{
	int ret = 0;
        ADRESH = 0;
        ADRESL = 0;
	ADCON0 = 0b10000001 + (ch<<2);	// set channel to read
	__delay_ms (25);
	ADCON0bits.GO = 1;						// start conversion
   	while(ADCON0bits.GO_nDONE);					// wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		// get 
   	ret +=	ADRESL;					// result
	return ret;
}
 
 
void main (){
 
    SetupClock();
    IntADC();
    unsigned int Vcharge; 
    unsigned int Vcurrent;
    unsigned int Vbattery;
    Vcharge = 0;
    Vcurrent = 0;
    Vbattery = 0;
 
    while (1){
 
        Vcharge = ReadADC(0);
        __delay_ms(100);
        Vcurrent = ReadADC(1);
 
       if (Vcharge >512)
 
    {
        RA4 = 1;
 
    }
        else
        RA4 = 0;
 
 
    if (Vcurrent > 512 )
    {
        RA5 = 1;
    }
    else
        RA5 = 0;
 
 } 
    }

It works in simulation...
 
Here.... Try this...

My fault entirely... The ADC routine I gave you was for the older chips... CHS0~CHS4 are shifted 2 not 3....

Also the ADCON tad was a little too fast... I've changed it ...

It works in simulation...

This works ! Im so happy! Thanks a lot for the help. I should have seen the Shifting issue myself, and I didnt even think of increasing TAD.

The rest of my code should work as well, since it requires just 2 analog inputs. The rest is just math. I feel proud now for being able to program in C. Its not that difficult of a language. I resisted "cheating" by not going to mikroC (because of the libraries and predefined functions)
 
This works ! Im so happy! Thanks a lot for the help. I should have seen the Shifting issue myself, and I didnt even think of increasing TAD.

The rest of my code should work as well, since it requires just 2 analog inputs. The rest is just math. I feel proud now for being able to program in C. Its not that difficult of a language. I resisted "cheating" by not going to mikroC (because of the libraries and predefined functions)

If possible push the final draft with (Comments) for us beginners please:)

Good job.

kv
 
If possible push the final draft with (Comments) for us beginners please:)

Good job.

kv

The battery controller code or the ADC code? Heres the ADC code.


C:
/*
 * File:   ADC_Ver1
 * Author: chris
 * This is Basic ADC Code for the PIC12F1840 Series. Should be portable to others
 * Created on August 19, 2013, 6:11 PM
 */

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>




#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5) //Charge LED
#define RA4 (PORTAbits.RA4) // PFET

#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON


void SetupClock (void) //set up clock
{
    OSCCON = 0b01110010; //Internal OSC 8Mhz
}


void IntADC (void) //setup ADC
 {
         //** Initalise Ports FOR ADC **//
         
         TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1, RA2 Inputs
         //** Set Up ADC Parameters **//
         ANSELA = 0b00000111; //RA4 Output, RA5 Output
         ADCON1 = 0b11010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
         ADCON0bits.ADON = 1; //ADC on
}    

int ReadADC(unsigned char ch)
{
	int ret = 0;
        ADRESH = 0;
        ADRESL = 0;
	ADCON0 = 0b10000001 + (ch<<2);	// set channel to read
	__delay_ms (25);
	ADCON0bits.GO = 1;				   // start conversion
   	while(ADCON0bits.GO_nDONE);			  // wait for conversion
   	ret =  (ADRESH & 0x3) << 8;		         // get 
   	ret +=	ADRESL;					// result
	return ret;
}


void main (){
    
    SetupClock();
    IntADC();
    unsigned int Vcharge; 
    unsigned int Vcurrent;
    unsigned int Vbattery;
    Vcharge = 0;
    Vcurrent = 0;
    Vbattery = 0;
    
    while (1){

        Vcharge = ReadADC(0); //Read AN0
        __delay_ms(100);
        Vcurrent = ReadADC(1); //Read AN1

       if (Vcharge >512)

    {
        RA4 = 1;

    }
        else
        RA4 = 0;


    if (Vcurrent > 512 )
    {
        RA5 = 1;
    }
    else
        RA5 = 0;
    
 } 
    }
 
Can I suggest a small change which will make the code more portable?
Code:
//this line,
    ADCON0 = 0b10000001 + (ch<<2);	// set channel to read
//could be written as,
    ADCON0 = 0b10000001 + (ch<<CHS0);	// set channel to read
Writing it this way eliminates the problem of whether it's 2 or 3 shifts and would have prevented the problem that arose earlier.

Mike.
 
Can I suggest a small change which will make the code more portable?
Code:
//this line,
    ADCON0 = 0b10000001 + (ch<<2);	// set channel to read
//could be written as,
    ADCON0 = 0b10000001 + (ch<<CHS0);	// set channel to read
Writing it this way eliminates the problem of whether it's 2 or 3 shifts and would have prevented the problem that arose earlier.

Mike.

Thanks for the suggestion!

Well as I went to test out my firmware on the pic I chose (PIC12F1501), my PK2 didnt recognize that pic. Through a little digging I found that it doesnt support it. Opps. I chose to just go with the PIC I had been testing out (why not, right?). The only reason I didnt was because it was $1.30 (or so) and the PIC12F1501 was below a dollar. But being able to program in C opens up a world of possibilities, I can now use the 12F series to do minor things, and since I just bought a house, I have a whole slew of ideas of where I can use these little IC's.
 
Sorry to see you go from Pic Basic. I find it easy enough for the casual hobbyist even when a serious project does arise Pic Basic can get the job done.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top