VCO recommendation

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
Well, I got as far as attempting to calculate some values for a 555 circuit but felt like I was still fumbling in the dark a bit and probably had about reached the limits of what the venerable 555 could do. So I bit the bullet and bought a Pickit 3 clone, now beginning to regret being a cheapskate and going for the clone rather than the real thing since the clone won't power the chip...

anyway back too it!
 

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
Still stuck with this but getting some input on the Microchip forum however I thought I post it here just in case someone can spot anything

Here is the test code suggested by the_RB
Rich (BB code):
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config FOSC = INTRCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)

#define _XTAL_FREQ 4000000
void delay_ms(unsigned int milliseconds) {
    unsigned int ms = milliseconds;
    while (ms-- > 0) {
        __delay_ms(1);
    }
}


/*
 *
 */
void main(void) {

    unsigned int adcVal;

    TRISIO = 0b00000100; // GP4 = LED, GP2 = ADC
    ANSEL = ADCS2 | ADCS0 | ANS2; //ACD Osc/16; Pin 0
    ADCON0 = 0x00;
    ADCON0 = ADON | ADFM | CHS1; //Start the ADC, right justified, Vdd ref=0
    CMCON = 0x07; //Comparator off
    VRCON = 0x00; //voltage ref off

    while (1)
    {
        GO_nDONE = 1; //Enable
        while (GO_nDONE); //Wait for ADC to complete
        adcVal = ((ADRESH << 8) + ADRESL);

        if(adcVal >= 512) GPIObits.GP4 = 1; // LED on
        else              GPIObits.GP4 = 0; // LED off
    }
}
And here is the full code
Rich (BB code):
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config FOSC = INTRCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)

#define _XTAL_FREQ 4000000
void delay_ms(unsigned int milliseconds) {
    unsigned int ms = milliseconds;
    while (ms-- > 0) {
        __delay_ms(1);
    }
}


/*
 *
 */
void main(void) {

    unsigned int adcVal;

    TRISIO = 0b00000100; // GP4 = LED, GP2 = ADC
    ANSEL = ADCS2 | ADCS0 | ANS2; //ACD Osc/16; Pin 0
    ADCON0 = 0x00;
    ADCON0 = ADON | ADFM | CHS1; //Start the ADC, right justified, Vdd ref=0
    CMCON = 0x07; //Comparator off
    VRCON = 0x00; //voltage ref off

    while (1) {
        GPIObits.GP4 = 1; // LED on
        __delay_ms(100);
        GPIObits.GP4 = 0; // LED off again
        //__delay_ms(500);

        GO_nDONE = 1; //Enable
        while (GO_nDONE); //Wait for ADC to complete

        adcVal = (((unsigned int)ADRESH << 8) + ADRESL);
        if (adcVal > 613) adcVal = 613;
        // this inverts the ADC value so 0.3v = 553 and 3.0v = 0.
        // 0.3v = ADC 61, 3.0v = ADC 614, (range = 553 counts)
        adcVal = (553 - (adcVal - 61));

        delay_ms(adcVal);
    }

}

Neither of these work
 

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
OK, got it going (sort of, the ADC scaling is wrong and I can't immediately see why). BUT ...

This is for a draft detector and one option is to have the detector head on a wand that can be held in gaps and the like to sense very slight drafts. I thought it would be good to have a simple visual indication of the draft strength, hence the LED that flashes faster.

The thing with using a MCU with a delay which might be up to a second is that it is tempting to move the wand on during the delay and so mis a change in draft. I guess the right kind of analog circuit would not suffer from this "problem". That said a bit of patience and understanding how it works is all that is really needed with the PIC approach.

Anyway, and FWIW here is the code as it stands, needs more work but at least it runs.

Rich (BB code):
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config FOSC = INTRCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)

#define _XTAL_FREQ 4000000
void delay_ms(unsigned int milliseconds) {
    unsigned int ms = milliseconds;
    while (ms-- > 0) {
        __delay_ms(1);
    }
}


/*
 *
 */
void main(void) {

    unsigned int adcVal;

    TRISIObits.TRISIO2 = 1; // GP4 = LED, GP2 = ADC
    TRISIObits.TRISIO4 = 0; // GP4 = LED, GP2 = ADC
    //TRISIO = 0b00000100; // GP4 = LED, GP2 = ADC
    ANSELbits.ADCS0 = 1;
    ANSELbits.ADCS2 = 1;   //FOSC/16
    ANSELbits.ANS2 = 1;    //channel 2
    ADCON0bits.VCFG = 0;   //Vdd
    ADCON0bits.CHS1= 1;    //AN1
    ADCON0bits.ADON = 1;   //Turn it on
    CMCON = 0x07; //Comparator off
    VRCON = 0x00; //voltage ref off
    //ANSEL = 0b01010100; //ADCS2 | ADCS0 | ANS2; //ACD Osc/16
    //ADCON0 = 0b00001001; ///ADON | ADFM | CHS1; //Start the ADC, right justified, Vdd ref=0

    while (1) {
        GPIObits.GP4 = 1; // LED on
        __delay_ms(10);
        GPIObits.GP4 = 0; // LED off again
        //__delay_ms(500);

        GO_nDONE = 1; //Enable
        while (GO_nDONE); //Wait for ADC to complete

        adcVal = (((unsigned int)ADRESH << 8) + ADRESL)/20;
        //if (adcVal > 613) adcVal = 613;
        // this inverts the ADC value so 0.3v = 553 and 3.0v = 0.
        // 0.3v = ADC 61, 3.0v = ADC 614, (range = 553 counts)
        adcVal = (1024 - (adcVal));

        if(adcVal>800) adcVal = 800;
        delay_ms(adcVal);
    }

}
 

THE_RB

Joined Feb 11, 2008
5,438
This seems to be a problem?

Rich (BB code):
        adcVal = (((unsigned int)ADRESH << 8) + ADRESL)/20;
Why the /20 at the end? The ADC result will be 0-1023, as unsigned integer.

So if you then divide by 20 the result will be 0-51. You can never get a result > 51. :eek:


Then here;
Rich (BB code):
        adcVal = (1024 - (adcVal));
        if(adcVal>800) adcVal = 800;
The result will be in the range 1024-0 (1024) to 1024-51 (973), so the lowest result you can get is 973 which means something is wrong with the next line. Being always >=973 the next if() will always be true, so the ADC value is always forced to 800.
 

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
Shouldn't really have left that in, just me messing around. However what I see in practice without it is that it does not work as you describe, Without that scale factor I get full scale in the 0 to 30mV range, not the expected 0-5V range. By scaling in that way I get a full scale in the range 0 to hundreds of mV and then it overflows (or something happens because the LED goes from almost fully on to flashing once every second or so).

The upshot is that it is definitely not reading 0-1023 across the full 0-5V range. I know there is the option of using Vdd or a reference voltage for ADC but I think I have set it to use Vdd.
 

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
Looks like I wasn't unsetting the bit to use Vdd for the ADC here is the working code so far.

Rich (BB code):
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config FOSC = INTRCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)

#define _XTAL_FREQ 4000000
void delay_ms(unsigned int milliseconds) {
    unsigned int ms = milliseconds;
    while (ms-- > 0) {
        __delay_ms(1);
    }
}


/*
 *
 */
void main(void) {

    unsigned int adcVal;

    TRISIObits.TRISIO2 = 1; // GP4 = LED, GP2 = ADC
    TRISIObits.TRISIO4 = 0; // GP4 = LED, GP2 = ADC
    //TRISIO = 0b00000100; // GP4 = LED, GP2 = ADC
    //ANSELbits.ADCS0 = 1;
    //ANSELbits.ADCS2 = 1;   //FOSC/16
    //ANSELbits.ANS2 = 1;    //channel 2
    //ADCON0bits.VCFG = 0;   //Vdd
    //ADCON0bits.CHS1= 1;    //AN1
    //ADCON0bits.ADON = 1;   //Turn it on
    CMCON = 0x07; //Comparator off
    VRCON = 0x00; //voltage ref off
    ANSEL = _ANSEL_ADCS2_MASK | _ANSEL_ADCS0_MASK | _ANSEL_ANS2_MASK;
    ADCON0 = _ADCON0_ADFM_MASK | _ADCON0_CHS1_MASK | _ADCON0_ADON_MASK;

    while (1) {
        GPIObits.GP4 = 1; // LED on
        __delay_ms(10);
        GPIObits.GP4 = 0; // LED off again
        //__delay_ms(500);

        GO_nDONE = 1; //Enable
        while (GO_nDONE); //Wait for ADC to complete

        adcVal = (((unsigned int)ADRESH << 8) + ADRESL);
        //if (adcVal > 613) adcVal = 613;
        // this inverts the ADC value so 0.3v = 553 and 3.0v = 0.
        // 0.3v = ADC 61, 3.0v = ADC 614, (range = 553 counts)
        adcVal = (1024 - (adcVal));

        //if(adcVal>800) adcVal = 800;
        delay_ms(adcVal*2);
    }

}
 

THE_RB

Joined Feb 11, 2008
5,438
...
However what I see in practice without it is that it does not work as you describe, Without that scale factor I get full scale in the 0 to 30mV range, not the expected 0-5V range. By scaling in that way I get a full scale in the range 0 to hundreds of mV and then it overflows (or something happens because the LED goes from almost fully on to flashing once every second or so).
...
That sounds like a typical bug of not setting the ADC to "right justified". :)

It needs to be right justified to give you a reading of 0-1023 in acdVal.
 

Thread Starter

sirch2

Joined Jan 21, 2013
1,037
Yes, could have been that, either way using the _MASK approach obviously forces the bits to zero rather than assuming they are unset, even though the datasheet would seem to indicate that they are zero after a power-on reset.
 
Top