Page 1 of 2

PIC12F1501, ADC not converting

PostPosted: Fri Jul 04, 2014 6:41 pm
by ksmes
Hello,
I'm having difficulty with an ADC segment working on a PIC12F1501. Using a PIC12F1501, programmed with a PICkit3, using MPLAB X ver 2.0 and XC8.
After reviewing the data sheet for ADC configuration for the past two days, and changing things around, I have not been able to get past this road bump.

The program is meant to monitor door switches being NC, when one opens, the PIC would check the light level outside, if it is bright, no need to turn the lights on. If it is dark, the lights would be turned on via the PWM code segment. I do not seem to be resolving the light change value in the ADC sequence.

I have a variable resistor(simulates a solar cell) connected between the VSS and VDD, wiper going to a 1K resistor into Pin 7 of the PIC. this is meant to simulate a difference in light level being encountered.

Have I not turned one of the other peripherals off or have I missed a step in this ADC code segment?

I Did read about alternate pin functions in the data sheet but do not see a correlation to this directly?

Thanks,
Ken


Code: Select all
/*
 * File:   GarageDoorLights.c
 * Author: Ken
 *
 * Created on June 28, 2014, 3:59 PM
 */

// PIC12F1501 Configuration Bit Settings

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = HI        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), high trip point selected.)
#pragma config LPBOR = ON       // Low-Power Brown Out Reset (Low-Power BOR is enabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

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

#define _XTAL_FREQ 16000000


char   LightOut     = 0;        // Sample of light from outside, used to decide if light out
char   LightTrip    = 0x7F;     // Trip point 50. If the Light out is less than X value. Trip
char   Counter      = 0;        // used to adjust the PWM output.

void Dev_Init();
void MonitorSwitch();
void TestLight();
void RunLights();
void HoldTillClosed();


void LightRampUp();         //  may not be needed ?
void LightRampDown();       // ISR is turned on
void HasDoorClosed();


void main()                 //   The start of the entire functional program.
{
    Dev_Init();

    OSCCON=0x7A;            // 16 MHz
    T2CON=0x07;             // was 04,
    while(TMR2IF==0);
    TMR2IF=0;
    PR2=0x7C;               // 0x50=50us ,c7 = 60 us, D7 = 84 us,F7 = 92us,
    PWM1CON=0xE0;           // was F0
    PWM1DCH = 0x00;         // Start with cycle at 0 %
    PWM1DCL = 0x00;         // Start with cycle at 0 %
    while(1)
    {
        MonitorSwitch();
        TestLight();
        RunLights();
        HoldTillClosed();
    }
 }

void Dev_Init() // setup the OPTION_REG , Load with 0xD4
    {
       OPTION_REG = 0x08;           //
       INTCON     = 0;              // Interups Off till needed.
       OSCCON     = 0x7A;           // Int RC Osc at 16 MHz, Int Osc is system CLK
       //  PORTA SETUP
       PORTA = 0x00;                //  Clear PORTA
       LATA =  0x00;
       ANSELA = 0x00;               // Analog OFF
       TRISA = 0b101001;
       TRISA0 = 1;                  // Photo Cell input
       TRISA1 = 0;                  // Not Used, was TS output led
       TRISA2 = 0;                  // PWM output.
       TRISA3 = 1;                  // Not Used, MCLR
       TRISA4 = 0;                  // Not used
       TRISA5 = 1;                  // Switch input active High

       LATAbits.LATA1  = 0;            // turn off ts LED
   }

void MonitorSwitch()
{
    while(PORTAbits.RA5==0)         // Test the door switches.
    {
      //  NormISRSetSleep();        // Doors are closed, start Power save
    }
}

void TestLight()
    {
        ADCON1  =   0x60;           // ADRESH is Result, FOSC/64, Vref = VDD
        TRISAbits.TRISA0 = 1;
        ANSELAbits.ANSA0 = 1;
        ADCON0  = 0x01;             // Chan AN0 selected, Not in Progress, ADC Enabled
        __delay_ms(50);             // Cap Charge time, may be a bit much
        ADCON0bits.GO = 1;          // Start the conversion

        while(ADCON0bits.GO == 1)   // Wait for the conversion to finish
        {
            LATAbits.LATA1  = 1;  // turn on trouble shoot LED ****
          ;                         // ***  it gets to hear.
        }

           LightOut = ADRESH;       //
           ADCON0 = 0x00;           // ADC turned off, save power

           if(LightOut > LightTrip)     // is it dark out
           {
               MonitorSwitch();         // still light out, monitor the switch state.
           }
               // If Light out is greater, continue on to RunLights
    }

void RunLights()
{
    while(PWM1DCH < 0x7C)      // Max value is 0x7C 100% Duty Cycle.
     {
         PWM1DCH = PWM1DCH++;   // Increase the duty cycle +1
         PWM1DCL=0x00;          //
         __delay_ms(10);        // Incriment Step, Time interval
     }

                                // Duration of the Max PWM Duty Cycle next.
     __delay_ms(1000);          // Time of 5 seconds, to be 120 seconds in production.

     while (PWM1DCH > 0x00)
     {
         PWM1DCH = PWM1DCH--;   // Decrease the Duty cycle
         PWM1DCL = 0x00;
         __delay_ms(10);        // Decriment Step time interval
     }
}

void HoldTillClosed()               // may need to be refined.
{
    while(PORTAbits.RA5==1)         // Door is open, Start PWM Output low to
    {                               // high duty cycle. Once at high rate,
        // Stay and Wait            // hold for a set time, then ramp down.
        __delay_ms(2000);
        LATAbits.LATA1  = 0;            // turn off trouble shoot LED
    }
}

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 04, 2014 8:11 pm
by jtemples
Are you saying GO never returns to 0?

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 04, 2014 8:54 pm
by ksmes
Hi, and thanks for replying.

No, it is getting through the GO loop, I have placed a troubleshoot LED on PORTA1, and turned it on in the "void Dev_Init() //" and used "LATAbits.LATA1 = 0;" in the while loop for testing GO to be cleared and after the loop, individually of course, not at the same time. And the code will run up to and through this area.
It seems that the result is always less than the "LightTrip = 0x7F" value, even when the input level being supplied should make a ADC result of 0xAA to 0xFF. This would cause the PWM to not run, but it is running every time that a switch change is received on "PORTAbits.RA5".

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 04, 2014 9:52 pm
by jtemples
Have you looked at the ADC result in the debugger? Does it vary as you vary the light?

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 04, 2014 10:06 pm
by ksmes
I have not learned the Debugger operation using MPLAB X yet.

Your first reply above made me think about if the ADC is already working. From what I tried above it should be resolving a value. Maybe I have botched comparing the LightOut.

Re: PIC12F1501, ADC not converting

PostPosted: Sat Jul 05, 2014 9:22 pm
by ksmes
jtemples,

The ADC is working to resolve the temporary variable resistor voltage used to simulate the LightOut level. This was proven out over the evening by adding temporary functions and testing for just the ADC code. All along I have been experiencing spurious operation that seemed to lead to the ADC being at fault. The temporary door switch being used on the bread board was found to be a major contributor to my problem. It is a 8 position rocker type (side by side) used normally for address setting on boards. I was able to detect switch bound well into 20 msec consistently and the contact could glitch even if an adjacent rocker was thrown by accident. With even slight pressure being placed on the rocker the contacts would also glitch momentarily open. I had insufficient and nonexistent bounce delays throughout the code. I will clean the code up some more and continue on with a better switch for testing. Still a bit apprehensive on its functioning.

Thanks,
Ken

Re: PIC12F1501, ADC not converting

PostPosted: Tue Jul 08, 2014 9:34 pm
by Olin Lathrop
ksmes wrote:I had insufficient and nonexistent bounce delays throughout the code. I will clean the code up some more and continue on with a better switch for testing.


In general a good way to do debouncing is to wait for the new state to be seen 50 consecutive times in a 1 ms interrupt. Very often you need something for timing anyway, so the same interrupt that produces the 1 ms and other derived clock ticks also does the debouncing. All it takes is a single counter per input to debounce, and a global flag that the interrupt routine sets to the official debounced state. The rest of the firmware then only looks at the flag to determine the switch state, not the actual switch line.

I have done this many times, and it has always worked well. 50 ms is short enough so that a human won't notice the delay, but long enough for any reasonable switch to be done bouncing. For example, here is one such snippet from a 1 ms interrupt routine:

Code: Select all
;
;   Update the debounced button state.
;
         btfss   butt_reg, butt_bit ;the button is currently up ?
         jump    butt_down   ;the button is currently down
         ;
         ;   The instantaneous state of the button is UP.
         ;
         skip_flag butt      ;debounced state is opposite ?
         jump    butt_dbres  ;instantaneous and debounced states are the same
         decfsz  bvalidms    ;count one less tick until new state is valid
         jump    butt_done   ;new state is not valid yet
         clrflag butt        ;debounced state is now UP
         jump    butt_dbres
         ;
         ;   The instantaneous state of the button is DOWN.
         ;
butt_down
         skip_nflag butt     ;debounced state is opposite ?
         jump    butt_dbres  ;instantaneous and debounced states are the same
         decfsz  bvalidms    ;count one less tick until new state is valid
         jump    butt_done   ;new state is not valid yet
         setflag butt        ;debounced state is now DOWN

butt_dbres                   ;reset to maximum dbounce interval
         loadk8  bvalidms, dbms
butt_done                    ;done processing button state

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 11, 2014 5:18 pm
by Joe14228
Debouncing and slowing the code down to human speed is a major part of embedded programming. I always start a new program now by defining timers and the sequencing control structure I want to use. One thing to consider also is creating shadow variables that old input status bits for use in the program. I recently got tripped up when the code was awakened by a pushbutton closure, then later in the main loop it saw that the button input was off and the program went back to sleep! This was due to the bouncing of the switch. I got by that with the statement copySwitch = Switch;. Since Switch is only read once and saved, ALL statements in that loop will then see the same value.

Another suggestion is in your original program listing you have a variable defined as char LightTrip = 0x7F, which in this program is really a constant used for trip point comparison. For readability, it would be better to use the statement #define LIGHT_TRIP 0x7F. This prevents that value from being changed anywhere in the program, and will alert you that it is really a fixed constant. You COULD use the keyword const, as in const char LightTrip = 0x7F, but that - I think - still uses data memory, and with a smaller PIC you might not want to do that. The #define statement just tells the compiler to equate the name with a value and doesn't reserve memory space.

Re: PIC12F1501, ADC not converting

PostPosted: Fri Jul 11, 2014 10:28 pm
by ric
Joe14228 wrote:...
You COULD use the keyword const, as in const char LightTrip = 0x7F, but that - I think - still uses data memory, and with a smaller PIC you might not want to do that.
...

Hitech and XC8 really do put const variables into ROM.

Re: PIC12F1501, ADC not converting

PostPosted: Tue Jul 15, 2014 1:46 am
by ksmes
Olin, Joe,

On Sunday the 6th I had added some De-bounce to the original program posted. Still it was failing to work the way I thought it should, in this case, properly return to the beginning after the PWM function was finished and the switch was closed. Luckily I had signed out a digital scope from work and put it to use hear. I added an troubleshoot LED on one of the outputs and at the beginning and end of each section I added an incremented time delays to have the LED on and then off. I started with 25 ms and worked up to 200 ms by 25 ms increments. I could monitor this activity on the scope and trace where the program was at most times. This was able to show me I was not getting back to the original "MonitorSwitch()" function. In trying to figure this out, I made a change that caused the compiler to error on a Recursive Function Call. Could it get any worse? I got past this recursive error by placing the Monitor Switch back in the main for the time being.
Please keep in mind; I taught my self to program PIC MCUs in assembly language through a book, this took 2+ years. Earlier this year I asked a software Engineer a few questions on some program functions in assembly, he was limited in assistance and recommended for me to learning C. It has been a few months now sense starting to program in 'C'. I'm getting to understand it more all the time.
The software engineer spent some time with me at lunch Thursday. He imparted a recommendation to use the '# define' for assigning some of the PORTA pins, this does make the code very readable. By the middle of this week I should have the code fully together and debugged for the next go-around.

Thank you for the input.
Ken