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

Question of A/D converter of PIC16F876

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



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

Question of A/D converter of PIC16F876
PostPosted: Sun Nov 16, 2003 11:58 pm     Reply with quote

The A/D converter of the PIC16F876 has 10 bits of resolution. Do you know if there is a way to put it to work with just 8 bits of resolution, instead of 10?
Aztlan
Guest







Re: Question of A/D converter of PIC16F876
PostPosted: Mon Nov 17, 2003 12:02 am     Reply with quote

aroman wrote:
The A/D converter of the PIC16F876 has 10 bits of resolution. Do you know if there is a way to put it to work with just 8 bits of resolution, instead of 10?



Yes use

#device adc=8


Aztlan
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 8:28 am     Reply with quote

Thanks to Aztlan for the suggestion, but unfortunately I tried it and the PIC still uses 10 bits of resolution for the A/D conversion. This is the code that I am using on the PIC:

Code:

#include <16F876.h>
#device adc=8
#use delay(clock=76800)
#fuses LP,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP
#byte adcon1 = 0x9f //Direccion del registro donde se configuran los pines de los puertos del
                    //convertidor A/D
#byte adcon0 = 0x1f //Direccion del registro donde se configuran los pines de los puertos del
                    //convertidor A/D
#byte adresh = 0x1e //Direccion del registro que contiene el resultado de la parte alta de
                    //la conversión A/D
#byte adresl = 0x9e //Direccion del registro que contiene el resultado de la parte alta de
                    //la conversión A/D

void main() { //aquí inicia el programa principal

   int valor_sensor; //es el valor digital del voltaje analógico del sensor
   int direccion; //es la dirección en memoria EEPROM interna del PIC
   valor_sensor = 0;
   direccion = 0;
   disable_interrupts(global); //se deshabilitan las interrupciones pues la recepción se hace
                               //por "polling" y no por interrupción
   setup_adc_ports(RA0_ANALOG); //se pone únicamente el pin RA0 como entrada analógica (todos
                                //los demás pines del puerto A se dejan como entrada/salida
                                //digital) y con voltaje de referencia Vdd
   setup_adc(ADC_CLOCK_INTERNAL); //Aquí utiliza como reloj para el ADC el reloj interno RC
                                  //(el periodo varía entrer 2-6 us y es típicamente 4 us)
   set_adc_channel(0); //Escoge el canal analógico a digital 0 (pin AN0)
   adcon1 = 0x8e; //Pone el resultado de la conversión A/D justificado a la derecha (por
                  //defecto viene justificado a la izquierda)
   setup_spi(FALSE);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   write_eeprom(255, adcon0);
   write_eeprom(254, adcon1);
   while (direccion<100){
      valor_sensor = read_adc();
      write_eeprom(direccion, valor_sensor);
      direccion++;
      write_eeprom(direccion, adresh);//Escribe la parte alta del resultado de la conversión
                                      //A/D en memoria EEPROM interna
      direccion++;
      write_eeprom(direccion, adresl);//Escribe la parte baja del resultado de la
                                            //conversión A/D en memoria EEPROM interna
      direccion++;
      }//del while (direccion<100)
}//fin de main


When I read the adresh register, the result is non-zero, as it should be if the conversion would be with just 8 bits of resolution (instead of 10). When I read the adcon0 register, the result is 0xC1, which means that the A/D clock is set to the internal RC oscillator, the analog channel selected is channel 0, at that time the A/D was not in progress (yet) and that the A/D converter module is operating. When I read the adcon1 register, the result is 0x8E, which means that the A/D result format is right justified (most significant bits of ADRESH are read as 0) and that pin RA0 is configured as analog input with Vref+=Vdd and Vref-=Vss and the rest of the pins of port A are configured as digital I/O.

Does anyone knows if there is a way to tell the PIC16F876 to use 8 bits of resolution instead of 10 for the A/D module?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Nov 18, 2003 8:49 am     Reply with quote

Technically you can't. You can however left or right justify the result. Left justified will place the 8 bit result in adresh. You are using a mixture of the CCS functions and also setting of the registers yourself. The statement
Code:

adcon1 = 0x8e;

is the problem. Bit 7 is set when it should be cleared. You shouldn't need this statement at all. The CCS setup_adc functions will configure this register for you. The 8 bit result will be placed in adresh and can be retreived by accessing that register or by using the read_adc() function.
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 9:51 am     Reply with quote

Thanks to Mark. On the data sheet, I did not find how to change the resolution for the A/D, but I wanted to ask if it was possible.

I want the result of the A/D conversion right-justified, so I can read the low part of the result in register adresl and the 2 higher bits in register adresh. That's why I used the
Code:

adcon1 = 0x8e;

statement, by putting bit 7 of adcon1 register in 1.

I didn't find how to tell the PIC to right-justified the result of the A/D conversion with the CCS setup_adc functions, so I modified the adcon1 register directly. Does anyone knows how to do it with the setup_adc functions?

Another question:
Is the result of the read_adc function an int (8 bits-wide) or a long int (16 bits-wide)? Because it seems like that no matter if I define a variable of either int or long ing to assign the result of the read_adc function, the compiler does not give a "type mismatch" error by using either of those 2 types.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Nov 18, 2003 10:03 am     Reply with quote

If you want 8 bit adc, the result is left justified and the result in placed in adresh

If you want 10 bit adc, the result is right justified and the 2 MSB are placed in adresh and the 8 LSB are placed in adresl

The CCS functions handle the setting up of the adc registers.

ADC=8 causes bit 7 to be cleared. Without the statement, the bit is set.

The size of the return value of the read_adc() function depends on the adc=8 statement. The compiler will cast the 8 bit result and allow it to be placed in a 16 bit variable (or larger).

It sounds like you are a bit confused about wether or not you want 8 bit adc or how it is supposed to function. Why don't you explain a little more as to what you are trying to do with the adc result and how many bits you are trying to use.
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 10:11 am     Reply with quote

I would like to have 8 bits resolution in the A/D conversion (not the 10 bits resolution that is by default), and store the result in an 8 bit-wide variable. What do I need to modify in my code to acheive that?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Nov 18, 2003 10:17 am     Reply with quote

Remove this line:
Code:

   adcon1 = 0x8e;


Also, is you crystal speed really 76.8KHz?
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 10:22 am     Reply with quote

Yes, my crystal is 76.8 kHz (PIC is in low power mode). Is there a problem with this? That's why I used the internal RC for the clock of the A/D converter.
If I only remove the line that you told me, the result of the 8-bit resolution A/D conversion will be stored in the valor_sensor variable?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Nov 18, 2003 10:25 am     Reply with quote

No problem with that. I was just making sure that it was a typo. I like to run them as fast as I can. I haven't used the internal RC for the ADC but I think you have everything set correctly. It should read the adc result properly. Try it and let us know.
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 10:29 am     Reply with quote

OK Mark, thank you very much for your help. I will try it and I will let you know how it goes
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 8:50 pm     Reply with quote

Bad news: I removed the line that Mark recommended me but I am still getting a result of the A/D conversion that is wider than 8 bits-wide (or at least, that is how I am interpreting it).

If I use left-justification of the result (bit 7 of adcon1 register -ADFM- is 0, as the default), and the result is stored in adresh, if I read the value of adresl, it should always be 0x00, right? Am I correct? However, when I read the value of adresl, I get different non-zero values like 80, C0 and 40 (just the 2 MSBs are sometimes changing to 1).

On figure 11-4, on page 116 of the PIC16F876 data sheet, it says that if the result is left-justified the MSB of the A/D conversion is bit 7 of adresh, and the LSB is bit 6 of adresl. If this is correct, if I set the A/D conversion with 8 bits resolution, bits 6 and 7 of adresh should always be 00, right? Am I correct? However, when I read the value of adresh, I get different non-zero values on those bits, because the values of the whole adresh register are 55, 5A, 53..., in general 5X, and since the high nibble of adresh is a 5 (0101 in binary), bit 6 is 1 (and not zero, as it should be)

Please tell me if I am right, or if I am missinterpreting the results. I think that it is not possible to tell the PIC to use 8 bits of resolution in the A/D conversion instead of 10. Or is my problem somewhere else?
astus



Joined: 17 Nov 2003
Posts: 12
Location: Australia

View user's profile Send private message Visit poster's website

PostPosted: Tue Nov 18, 2003 10:07 pm     Reply with quote

Why not try clamping the analog input with a zener diode and a resistor so that only voltages <8-bits are avaliable for digitization?

Adam
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 11:02 pm     Reply with quote

Before you get led totally off the track:

1. The 16F877 hardware always generates a 10-bit result.

2. The #device adc=8 statement tells the compiler to
take the 10-bit result and return the upper 8 bits of it,
when using the read_adc() function.

Quote:
I would like to have 8 bits resolution in the A/D conversion (not the 10 bits resolution that is by default), and store the result in an 8 bit-wide variable. What do I need to modify in my code to acheive that?


The following code should work. But I'm not at the company
right now, so I can't test it. (ie., with respect to using a very
low frequency crystal and LP mode).

#include <16F877.H>
#device adc=8 // Tell compiler to return 8 bits from read_adc()
#use delay(clock=76800)
#fuses LP,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP

main()
{
char result;

setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);

result = read_adc();

while(1);
}
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Nov 18, 2003 11:24 pm     Reply with quote

The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits
The result is always 10 bits

Just use the result in the adresh register. That is effectively your 8 bit adc value. Just ignore the 2 bits in the adresl register. They are the least significant bits. They represent the very small changes in the analog signal which you do not care about since you want only 8 bits.
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