CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem using 12F510 A/D and GP ports

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Jim Oram



Joined: 01 Jan 2010
Posts: 24
Location: Charlotte

View user's profile Send private message

Problem using 12F510 A/D and GP ports
PostPosted: Mon Feb 20, 2012 1:03 am     Reply with quote

12F510:
Concerning a new project design I have to do using the 12F510, I am having a "head banger time" trying to get GP ports to work and the fact that the A/D brings in erratic values from AN0. (0 to 5V from a pot) and
attempts to toggle GP1 pin 6.... but doesn't toggle.

I have read the tables relative to the multi-functionality pins on the 12F510 :
table 3-2, 5-1, 5-5. But to no avail.

The program is really simple: but works erratic... anybody have a clue?
Code:

#include <12F510.h>    // ADC=10
#device adc=8

// CONFIGURATION WORD  (fuses)
#FUSES INTRC, NOWDT, NOPROTECT, MCLR
#use delay(clock=8000000)

void main(void)
{
     #ASM
      MOVLW  0x84   // 1:32
      OPTION   // the T0CS bit in the OPTION register that must be clear,
     #ENDASM

     setup_timer_0(RTCC_DIV_16 | ENABLEPULLUPS);
     
     setup_adc(ADC_CLOCK_INTERNAL);

     set_adc_channel(0);

     setup_comparator(NC_NC); // disable comparator output  0x00FF07

     clrvar();  // a function that just clears ram vars.

     #ASM
      MOVLW  0b000001
      TRIS   GPIO      // reg 6
     
      MOVLW  0b000000
      MOVWF  OSCCAL    // reg 5

      MOVLW  0x42         // disable compare output  WAS 5A
      MOVWF  CM1CON0   // reg 7

      // setup_adc_ports(AN0_AN2);       // AN0 AN2

      MOVLW  0x81      // A/D AN0 Pin 7
      MOVWF  ADCON0    // reg 8
     #ENDASM

     read_adc(ADC_START_AND_READ);         // read and clear

     while(1){

          clock();
          check_float_status();

          if(bit_test(ADCON0, 1) == 0){  // A/D AN0 0x80   0 = COMPLETE
             set_adc_channel(0);
             pot_value = read_adc(ADC_START_AND_READ); 
             //if(pot_value < 2){
             //   pot_value = 2;   // the minimum value
             //}
             
          }

          switch(main_state){        //
          case 0:
                  if(bit_test(flag_reg_1, 0) ){
                     bit_clear(flag_reg_1, 0);

                     OUTPUT_LOW(PIN_B4);  // GP4 pump off. Pin 3
                     OUTPUT_LOW(PIN_B1);  // GP1 pin 6
                     main_state = 1;
                  }
                  break;
          case 1:      // Read Float switch
                  if(bit_test(flag_reg_1, 0) ){
                     bit_clear(flag_reg_1, 0);

                     OUTPUT_HIGH(PIN_B4);  // GP4 pump on. Pin 3
                     OUTPUT_LOW(PIN_B1);   // GP1 pin 6
                     main_state = 0;       
                  }
                  break;
          case 2:      //
             break;
          default:
                main_state = 0;

       }
       
     }
}


// ********************************************************

void clock(void)
{
   
    if(get_timer0() == 0){
       set_timer0(pot_value);

       ms_cntr++;
       if(ms_cntr > 30){            // x counts = 1 sec 2/21/2011
          ms_cntr = 0;
         
          seconds++;
         
          bit_set(flag_reg_1, 0);

          if(tog){
            tog = 0;
            OUTPUT_LOW(PIN_B1);     // bit_clear(GPIO, GP1);  // pin 6
          }
          else{
            tog = 1;
            OUTPUT_LOW(PIN_B1);     // bit_set(GPIO, GP1);    // pin 6
          }


          if(seconds == 60){
             seconds = 0;
             minutes++;
     
             if(minutes == 60){
                minutes = 0;
                hours++;
                if(hours == 24){       //
                   days++;
                   hours = 0;          // bug fix 4/2/2011
     
                   if(days == 7){
                      days = 0;        // reset to 0
                      pump_timer = 5;  // 5 seconds 2/13/2012
                   }
                }
             }
     
          }
       }
    }
}

void check_float_status(void)
{
     //
     if(bit_test(GPIO, 5) == 0){    // GP5 pin 2
        OUTPUT_HIGH(PIN_B4);        // GP4 pump on. Pin 3
        anti_lock_sec = 0; 
        // float_switch_level is an unsigned long 0xF0 is just below 1/2 port value
     }

}

_________________
Jim Oram
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Mon Feb 20, 2012 5:16 am     Reply with quote

Start again.....

Several settings are wrong. For example, you have 'enable_pullups' in the setup for timer0. This is not a legal setting for timer0, so will result in it being setup wrong.
Then, you select an ADC channel, and immediately read it. _Wrong_. You _must_ allow Tacq, after selecting a channel, before reading it.
You are then throwing bits of unnecessary assembler into the code. I can't see one of these that is needed, unless you have a very old and faulty compiler.
You then feed '0' into OSCCAL - why?. The OSCCAL value has been set automatically by the compiler from the value stored in the chip, at boot time. Setting 0, just ensures the calibration will be wrong.
You don't show your variable declarations, so we can't even comment if these may be completely invalid for the operations you then perform on them.
Then there is the problem of the timer. You read it and test 'for' a value. Problem is that it will only read as zero, for 16 instructions. If your loops and branches to get here take longer than this, you _will_ miss the zero state.

Step back, throw away the assembler, and KISS.

I've done a simplified demo, showing how to avoid the timer problems, and how to just toggle two pins, dependant on the value read from a pot on AN2.
It works.

Code:

#include <12F510.h>
#device adc=8
#FUSES NOWDT, INTRC, NOMCLR
#use delay(clock=8000000)
int1 flag=FALSE;

void tick(void) ;

void main() {
   int8 state=0;
   int8 pot_value;

   setup_adc_ports(AN0_AN2);
   setup_adc(ADC_CLOCK_DIV_8);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
   setup_comparator(NC_NC);
   set_adc_channel(0);
   delay_us(10);
   do {
      pot_value=read_adc();
      tick();
   
      //An example of using a flag, rather than using bit_test
      switch (state) {
      case 0:
         if (flag) {
            flag=false;
            output_low(PIN_B4);
            output_low(PIN_B1);
            state=1;
         }
         break;
      case 1:
         if (flag) {
            flag=false;
            output_high(PIN_B4);
            output_high(PIN_B1);
            state=1;
            set_timer0(pot_value/2);
         }
         break;
      }
      delay_us(10); //ensure loop is not too fast for ADC to re-acquire   
   } while (TRUE);
}

void tick(void) {
   int8 timer_val;
   //How to avoid missing the timer - note now /32 not /16
   timer_val=get_timer0();
   if (bit_test(timer_val,7)) {
      set_timer0(timer_val & 0x7F);
      flag^=1;
   }
}


Best Wishes
Jim Oram



Joined: 01 Jan 2010
Posts: 24
Location: Charlotte

View user's profile Send private message

Problem with 12F510 and GP ports
PostPosted: Mon Feb 20, 2012 6:39 am     Reply with quote

Hello Ttelmah, Thank you very kindly for the reply and sample code.
I will try it very soon, ....but first I will give you the variable definitions.... in case I have a problem there:
Code:

//                                       
int8 ms_cntr;                 //         
int8 pump_timer;              //         
int8 anti_lock_sec;           //         
int8 pot_value;               //         
int8 antilock_function_timer; //         
int8 antilock_pump_state;     //         
int8 main_state;              //         
int8 seconds;                 //         
int8 minutes;                 //         
int8 hours;                   //         
int8 days;                    //         
int8 tog;                               
//                                       
// Flags register                       
int8 flag_reg_1;              //         
//  7  6  5  4  3  2  1  0               
//  |  |  |  |  |  |  |  \- sec flag     
//  |  |  |  |  |  |  \ ---             
//  |  |  |  |  |  \-------             
//  |  |  |  |  \---------- OP_TOGGLE;   
//  |  |  |  \-------------             
//  |  |  \---------------- ANTILOCK_FLG1
//  |  \------------------- ANTILOCK_FLG2
//  \----------------------             

Thanks, Jim
_________________
Jim Oram
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Mon Feb 20, 2012 9:05 am     Reply with quote

Realistically, on the flags, looks OK, but much better to just use int1's for the flags with names. So:
Code:

int1 sec_flag = 0;
int1 OP_toggle;
int1 antilock_fllg1;
int1 antilock_flg2;


That way you can initialise them in the declaration (as I show on the first one), and avoid the probability of selecting the wrong bit accidentally!...
Let the compiler do it's job.

You talk about 'float_switch' being an unsigned long, hence I was puzzled about what types you were actually using....

Best Wishes
Jim Oram



Joined: 01 Jan 2010
Posts: 24
Location: Charlotte

View user's profile Send private message

12F510 code corrections:
PostPosted: Mon Feb 20, 2012 10:11 pm     Reply with quote

Ttelmah, Your point of using bit vars is well taken. I will do that.

Your recommended sample code works well. Thank you. However it did not work at first try, the variable state=1; was the same in both cases in your sample code.

I am now proceeding to bring the whole system up and running.

I will study your code recommendations and go over the architecture of the multi-function chip pins. Right now it is confusing to me how to know what to include, exclude, and what effects one function has on another.

The way I see it now is: turn everything off and then enable only what is required for an application.

If you have any insights, examples or tutorials that would make it easier to grasp the multi-layered features of the 12F series of chips would be welcome.

Thank You Very Kindly for your help.

Jim
_________________
Jim Oram
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Tue Feb 21, 2012 2:43 am     Reply with quote

Yes, I Cut&Copied, and didn't change state in the second copy.
Good that you spotted it. Smile
What you want to do, would be _much_ easier on a slightly larger chip. A device like the 12F675 (for example), supports interrupts, and even if you don't use them, this means the hardware will set a flag when the timer wraps. Avoids the problem of missing the '0' on the timer.
Given these slightly more modern chips are often cheaper than the older ones, well worth considering...

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group