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

Activate RA0/RA5 as inputs to use ADC and read 2 sensors

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



Joined: 07 Nov 2021
Posts: 2

View user's profile Send private message

Activate RA0/RA5 as inputs to use ADC and read 2 sensors
PostPosted: Sun Nov 07, 2021 9:56 pm     Reply with quote

I would like to know how I can activate the pins of a 16f877 such as RA0 to RA5 to function as inputs that allow me to capture the value of 2 respective sensors to store them in separate variables that later will be evaluated or used in relevant conditionals.

I have tried with the following code, but I only get reading through RA0.
Code:

#include<16f877a.h>
#device *=16
#device adc=10
#include <lcd.c>
#use delay(clock=4M)

#use fast_io(a)
#use fast_io(b)

float TempAmbiente, SRefe;


void main(){

//transform temperature and separate data receiving channels

set_tris_b(0b00000000); // I configure the pins for input or output, being 1 input and 0 output.
setup_adc_ports(RA0_ANALOG); // I allow the input of the data provided by the TempAmbiente sensor.
setup_adc_ports(RA1_ANALOG); // I try to read the reference signal
setup_adc(ADC_CLOCK_INTERNAL);
setup_COUNTERS(RTCC_internal.rtcc_div_1); // voltage division

// Turn on the LCD

lcd_init();
lcd_gotoxy(5,1); //posiciono
printf(lcd_putc, "Temperatura");
delay_ms(350);
lcd_init(); //Delete the display leaving it clean or initialized again.

while (true){

  TempAmbiente=(float) read_adc()/2; // here I read the PIN2.AN0 where is the ambient sensor
  lcd_gotoxy(5,1);
  printf(lcd_putc,"%f" , TempAmbiente); // I show the ambient temperature
  lcd_gotoxy(14,1);
  printf(lcd_putc,"Grados");
  delay_ms(200);

// I set the conditions for closing the loop

  if(TempAmbiente>=SRefe&& TempAmbiente<=SRefe){
    output_high(pin_b1); // Command a 1 to turn on the Red Led
    output_high(pin_b2); // Command a 1 to turn on the FanMotor V1
    output_low(pin_b4); // Command a 0 to turn off the Green Led

    // I print a message to let people know what is happening.
    lcd_gotoxy(5,2);
    printf(lcd_putc, "Disipando calor");
    delay_ms(200);
    }
  else{
    output_low(pin_b1); // Command a 0 to turn off the Red Led
    output_low(pin_b2);// I turn off the V1 Fan
    output_high(pin_b4);// I turn on the Green led
    //I am sending again a message to let you know what is going on.
    lcd_gotoxy(5,2);
    printf(lcd_putc, "Disipando Frio");
    delay_ms(200);
   }

  }
}

I'm really new to this and little by little is that with the manual and other information I try to get the project forward, since the assembly for the simulation is there but I lack that detail in the code, I would appreciate all the help possible.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 1:54 am     Reply with quote

The first critical thing is to read the processor .h file.
Look at the values allowed for particular statements.
so for 'setup_adc_pports', the #defines are:
Code:

// Constants used in SETUP_ADC_PORTS() are:
#define NO_ANALOGS                           7    // None
#define ALL_ANALOG                           0    // A0 A1 A2 A3 A5 E0 E1 E2
#define AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF 1    // A0 A1 A2 A5 E0 E1 E2 VRefh=A3     
#define AN0_AN1_AN2_AN3_AN4                  2    // A0 A1 A2 A3 A5         
#define AN0_AN1_AN2_AN4_VSS_VREF             3    // A0 A1 A2 A4 VRefh=A3             
#define AN0_AN1_AN3                          4    // A0 A1 A3
#define AN0_AN1_VSS_VREF                     5    // A0 A1 VRefh=A3
#define AN0_AN1_AN4_AN5_AN6_AN7_VREF_VREF 0x08    // A0 A1 A5 E0 E1 E2 VRefh=A3 VRefl=A2     
#define AN0_AN1_AN2_AN3_AN4_AN5           0x09    // A0 A1 A2 A3 A5 E0       
#define AN0_AN1_AN2_AN4_AN5_VSS_VREF      0x0A    // A0 A1 A2 A5 E0 VRefh=A3           
#define AN0_AN1_AN4_AN5_VREF_VREF         0x0B    // A0 A1 A5 E0 VRefh=A3 VRefl=A2           
#define AN0_AN1_AN4_VREF_VREF             0x0C    // A0 A1 A4 VRefh=A3 VRefl=A2             
#define AN0_AN1_VREF_VREF                 0x0D    // A0 A1 VRefh=A3 VRefl=A2
#define AN0                               0x0E    // A0
#define AN0_VREF_VREF                     0x0F    // A0 VRefh=A3 VRefl=A2
#define ANALOG_RA3_REF                    0x1     //!old only provided for compatibility
#define A_ANALOG                          0x2     //!old only provided for compatibility 
#define A_ANALOG_RA3_REF                  0x3     //!old only provided for compatibility 
#define RA0_RA1_RA3_ANALOG                0x4     //!old only provided for compatibility
#define RA0_RA1_ANALOG_RA3_REF            0x5     //!old only provided for compatibility
#define ANALOG_RA3_RA2_REF                0x8     //!old only provided for compatibility
#define ANALOG_NOT_RE1_RE2                0x9     //!old only provided for compatibility 
#define ANALOG_NOT_RE1_RE2_REF_RA3        0xA     //!old only provided for compatibility 
#define ANALOG_NOT_RE1_RE2_REF_RA3_RA2    0xB     //!old only provided for compatibility 
#define A_ANALOG_RA3_RA2_REF              0xC     //!old only provided for compatibility 
#define RA0_RA1_ANALOG_RA3_RA2_REF        0xD     //!old only provided for compatibility
#define RA0_ANALOG                        0xE     //!old only provided for compatibility
#define RA0_ANALOG_RA3_RA2_REF            0xF     //!old only provided for compatibility


Now not that there is not a RA1_ANALOG. The reason is down to the
chip. It does not allow individual pins to be set as analog. Only particular
combinations of pins.
It supports
RA0
RA0, 1 & 3
RA0, 1, 2, 3 & 4
and then a number with more pins as analog.

Now you talk about wanting to read two pins. First thing, do not set more
pins as analog, than you actually intend to use. Every extra pin potentially
introduces noise. So for two pins. you would actually have to select 3
0,1, & 3, then make sure that pin RA3 is connected to the ground, or
with a capacitor, to keep it from picking up noise. This is a limitation of
this old chip - most modern chips do allow you to or together patterns
of individual pins to enable. This one doesn't.
So you will have to use AN0_AN1_AN3 as your setting.

Now understand that for the port setup, the last one used is what applies.
So in your code, if 'RA1_ANALOG', was allowed, this would override the
RA0_ANALOG setting.

Then look at the data sheet. In the section 'Selecting the A/D conversion
clock', you will find the note:
"When the device frequencies are greater than 1 MHz, the RC A/D
conversion clock source is only recommended for Sleep operation."

This is generic to 90% of the mid range PIC's. Basically, though the
internal RC clock is available, it leads to noisy results when used with
a chip running about 1MHz. So for your device frequency you should
instead select the /8 clock operation:

setup_adc(ADC_CLOCK_DIV_8);
Generally do not use the RC clock.

Now you need to understand the ADC a bit more. The ADC has an 'input
multiplexer', which connects external channels to the ADC 'block'. Once
this is done, you can then connect the actual ADC to a channel from this
multiplexe. This is done by the set_adc_channel command. You are
not doing this.
Once this connection is made, you have to wait for a minimum of Tacq
before performing a conversion. You can then change the channel selected
wait Tacq again, and then read the new channel.

Now before going on, get rid of the fast_io commands. Generally for
99.99% of code, use standard_io, and let the compiler handle the tris
for you. fast_io, is only very rarely used, and is likely to cause problems.
You are setting fast_io for A, but not then setting the TRIS. Sad

So:
Code:

void main(){

//transform temperature and separate data receiving channels
setup_adc_ports(AN0_AN1_AN3); // Select 3 analog channels
setup_adc(ADC_CLOCK_DIV_8);
setup_COUNTERS(RTCC_internal.rtcc_div_1); // voltage division

// Turn on the LCD
delay_ms(100); //Many LCD's need 90+mSec to wake.
lcd_init();
lcd_gotoxy(5,1); //posiciono
printf(lcd_putc, "Temperatura");
delay_ms(350);
lcd_init(); //Delete the display leaving it clean or initialized again.

while (true){
  set_adc_channel(0); //select AN0
  delay_us(20); //Tad for this chip is just under 20uSec
  TempAmbiente=(float) read_adc()/2; // here I read the PIN2.AN0 where is the ambient sensor
  lcd_gotoxy(5,1);
  printf(lcd_putc,"%f" , TempAmbiente); // I show the ambient temperature
  lcd_gotoxy(14,1);
  printf(lcd_putc,"Grados");
  delay_ms(200);

// I set the conditions for closing the loop

  if(TempAmbiente>=SRefe&& TempAmbiente<=SRefe){
    output_high(pin_b1); // Command a 1 to turn on the Red Led
    output_high(pin_b2); // Command a 1 to turn on the FanMotor V1
    output_low(pin_b4); // Command a 0 to turn off the Green Led

    // I print a message to let people know what is happening.
    lcd_gotoxy(5,2);
    printf(lcd_putc, "Disipando calor");
    delay_ms(200);
    }
  else{
    output_low(pin_b1); // Command a 0 to turn off the Red Led
    output_low(pin_b2);// I turn off the V1 Fan
    output_high(pin_b4);// I turn on the Green led
    //I am sending again a message to let you know what is going on.
    lcd_gotoxy(5,2);
    printf(lcd_putc, "Disipando Frio");
    delay_ms(200);
   }

  }
}


Now two more comments at this point. You do understand that the value
from the ADC, will be an integer from 0 to 1023. Just a count. Not a
floating point value. Generally as a 'remark', avoid floating point numbers.
They are pretty much never needed, and cost huge amounts of time and
space. You could get exactly the same value as your /2, but keeping the
ADC value as an int16, multiplying this by 5, and printing with
"%5.1lw". This would be much faster and smaller.
I have though a nasty suspicion that you are expecting the ADC to
return a 'voltage'. It doesn't, it just returns a count.

Now, you don't show us what you want to do with your other analog
channel but assuming this is on AN1, then you simply need:
Code:

    set_adc_channel(1);
    delay_us(20);
    val=read_adc(); //now reads the count from AN1
temtronic



Joined: 01 Jul 2010
Posts: 9247
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 5:47 am     Reply with quote

Mr. T's reply should be a 'sticky' with a title of 'how to use the ADC..." !!
Iagree with everything he says, except the comment about that PIC being 'old'. Sigh, I remember when it was NEW ! still have a tube of them in the drawer here... great ,now I feel old........ Sad
Jay
SMF7



Joined: 07 Nov 2021
Posts: 2

View user's profile Send private message

For TTelmah How use ADC PORTS
PostPosted: Mon Nov 08, 2021 6:54 am     Reply with quote

First of all grateful for the incredible explanation you are giving me. Glad to be corrected to kill my ignorance.

Now, the RA1 intends to use it to be able to read the 2nd sensor and save this value in the SRefe variable to be able to generate the IF conditionals.

In such a way, would you keep the explanation and commands that you just explained to me dear?

Code:


#include <16f877a.h>
#device *=16
#device adc=10
#use delay(clock=4M)
#include <lcd.c>
#use standard_io(a)


int16 TempAmbiente, SRefe;


void main () {

// transforma la temperatura y los canales de recepción de datos separados
setup_adc_ports (AN0_AN1_AN3); // Seleccione 3 canales analógicos
setup_adc (ADC_CLOCK_DIV_8);
setup_COUNTERS (RTCC_internal.rtcc_div_1); // división de voltaje

// Enciende la pantalla LCD
delay_ms (100); // Muchas pantallas LCD necesitan más de 90 mseg para activarse.
lcd_init ();
lcd_gotoxy (5,1); // posiciono
printf (lcd_putc, "Temperatura");
delay_ms (350);
lcd_init (); // Elimina la pantalla dejándola limpia o inicializada de nuevo.

while (true) {
  set_adc_channel (0); // seleccione AN0
  delay_us (20); // Tad para este chip es un poco menos de 20uSec
  TempAmbiente = (int16) read_adc () ; // aquí leo el PIN2.AN0 donde está el sensor de ambiente
   set_adc_channel (1);
    delay_us (20);
    SRefe =(int16) read_adc (); // ahora lee el recuento de AN1-RA1
  lcd_gotoxy (5,1);
  printf (lcd_putc, "% f", TempAmbiente); //Muestro la temperatura ambiente
 lcd_gotoxy (14,1);
  printf (lcd_putc, "Grados");
  delay_ms (200);

// Establezco las condiciones para cerrar el ciclo
if (TempAmbiente> = SRefe && TempAmbiente <= SRefe) {
    output_high (pin_b1); // Comando a 1 para encender el Led rojo
    output_high (pin_b2); // Comando a 1 para encender el FanMotor V1
    output_low (pin_b4); // Comando un 0 para apagar el LED verde

    // Imprimo un mensaje para que la gente sepa lo que está sucediendo.
    lcd_gotoxy (5,2);
    printf (lcd_putc, "Disipando calor");
    delay_ms (200);
    }
  else {
    output_low (pin_b1); // Mando a 0 para apagar el Led rojo
    output_low (pin_b2); // Apago el ventilador V1
    output_high (pin_b4); // Enciendo el led Verde
    // Te estoy enviando de nuevo un mensaje para avisarte qué está pasando.
    lcd_gotoxy (5,2);
    printf (lcd_putc, "Disipando Frio");
    delay_ms (200);
   }

  }
}






If you wish, I can contact you by mail to provide you with the Proteus file and thus continue giving us feedback.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 8:26 am     Reply with quote

Tell us what the two sensors actually 'are'. Part number and/or datasheet.
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