|
|
View previous topic :: View next topic |
Author |
Message |
POPE19
Joined: 27 Jun 2017 Posts: 71
|
ADC does not work with external reference |
Posted: Fri Jul 28, 2017 6:40 am |
|
|
Hello friends,
I am newbie to this field. I want to use PIC16F914 for ADXL335 (Analog accelerometer). I am using 40-pin PDIP microcontroller. I am using external reference volts VREF+ applied to pin 5 (RA3) as per instruction in datasheet. I am using 20 MHz oscillator as external clock. When I put my accelerometer flat on table i get reading 335 with 5v VREF+, however it doesn't change with VREF+ = 3.3 volt. I am giving external reference volts from a 5/3.3V Voltage regulator. Why is the reading same ? I have also tried applying a potentiometer from the output of 5V voltage regulator and applying VREF+ volts from 4.94 to 2 Volts. But the readings are still same without any changes. I am using CCS PCWH 5.074 compiler.
Below is my code:
Code: |
//============================================================================//
// Inclinometer //
// Date: 7-24-2017 //
// //
//============================================================================//
#include <16F914.h>
#device ADC = 10
#fuses HS, MCLR, NOWDT, PUT, NOIESO, BROWNOUT, NOFCMEN
#use delay(clock=20000000)
#define VSS_VREF
//============================================================================================//
//===========================================================================================//
// LCD Configuration //
//==========================================================================================//
// Digit segments A B C D E F G DP
// b7 b6 b5 b4 b3 b2 b1 b0
#define DIGIT5 COM0+17, COM1+17, COM2+17, COM3+17, COM2+18, COM0+18, COM1+18, COM3+18
#define DIGIT4 COM0+3, COM1+3, COM2+3, COM3+3, COM2+2, COM0+2, COM1+2, COM3+2
#define DIGIT3 COM0+1, COM1+1, COM2+1, COM3+1, COM2+0, COM0+0, COM1+0, COM3+0
#define DIGIT2 COM0+19, COM1+19, COM2+19, COM3+19, COM2+20, COM0+20, COM1+20, COM3+20
// ComX+Y is combination of Backplan0-3 and Segment0-SegmentXX
//=======================================================================================//
// character 0 1 2 3 4 5 6 7 8 9 Null
byte const Digit_Map[11] = {0xFD,0x61,0xDB,0xF3,0x67,0xB7,0xBF,0xE1,0xFF,0xF7,0x01}; //Decimal
byte const Digit_Map_1[11] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0x00}; //no Decimal
//=======================================================================================//
// Segments Initialization //
// Seg23 Seg22 ... Seg12 Seg11 Seg10 Seg9 Seg8 Seg7 Seg6 Seg5 Seg4 Seg3 Seg2 Seg1 Seg0 //
// 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 //
// if bit_SegX is 1, SegX is set as Segment Output. Otherwise //
////=====================================================================================//
#define Segments 0x1E000F // Initialize LCD SegmentX
//============================================================================//
#define INTS_PER_SECOND 19 // (20000000/(4*256*256)) (used quarter_seconds)
int int_count=INTS_PER_SECOND;
int count5 = 0;// after decimal
int count_5 = 0;
int count4=0; // 1st digit
int count_4=0; // 1st digit
int count3=0; // 2nd digit
int count_3=0;
int count2=0; // 3rd digit
int count_2=0;
long seconds=0;
long reading;
#int_rtcc //This function is called
//============================================================================//
void clock_isr()
{ //every time the RTCC (timer0)
//overflows (255->0)
//For this program this is apx
//31 times per second.
if(--int_count==0)
{
seconds++;
int_count=INTS_PER_SECOND;
}
}
//============================================================================//
void Disp_num()
{
if(reading < 10)
{
count_5=reading;
count_2=11;
count_3=11;
count_4=11;
}
if(10<= reading < 100)
{
count_5=reading%10;
count_4=reading/10;
count_3=11;
count_2=11;
}
if(100 <= reading <999)
{
count_5=reading%10;
count_4=reading%100/10;
Count_3=reading%1000/100;
count_2=11;
}
if(1000 <= reading < 1024)
{
count_5=reading%10;
count_4=reading%100/10;
Count_3=reading%1000/100;
count_2=reading%10000/1000;
}
if(reading >= 1024)
{
count_5=11;
count_4=11;
count_3=11;
count_2=11;
}
}
//=============================================================================//
void sec_disp()
{
count4=count_4;
count5=count_5;
count2=count_2;
count3=count_3;
}
//============================================================================//
void Display()
{
lcd_symbol (Digit_Map_1[count5], DIGIT5);
lcd_symbol (Digit_Map[count4], DIGIT4);
lcd_symbol (Digit_Map_1[count3], DIGIT3);
lcd_symbol (Digit_Map_1[count2], DIGIT2);
}
//============================================================================//
void Digit()
{
if(seconds>=1)
{
reading = read_adc();
seconds=0;
}
}
//===========================================================================//
void main()
{
set_tris_a (0xdf);
set_tris_b (0xc0);
set_tris_c (0x07);
setup_adc_ports(sAN0);
setup_adc (ADC_CLOCK_INTERNAL);
set_adc_channel (0);
set_rtcc(0);
setup_counters (RTCC_INTERNAL, RTCC_DIV_256);
enable_interrupts (INT_RTCC);
enable_interrupts(GLOBAL);
setup_lcd(LCD_MUX14|LCD_STOP_ON_SLEEP,3, Segments); // set segments
count5 = 8;
count4 = 8;
count3 = 8;
count2 = 8;
Display ();
delay_ms (1000);
while (TRUE) /* Modify on 9/19/2012 */
{
digit();
Disp_num();
sec_disp();
display();
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 28, 2017 7:19 am |
|
|
Code: |
setup_adc_ports(sAN0 | VSS_VREF);
//You are not selecting to use the Vref...
//This is the setting to use Vref+, with Vss for the -
setup_adc (ADC_CLOCK_DIV_32);
//Internal is not recommended above 1MHz, unless you put
//the chip to sleep for the conversion....
set_adc_channel (0);
|
Wrong ADC clock, and you are not selecting to use the Vref |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 28, 2017 7:39 am |
|
|
Quote: | #include <16F914.h>
#device ADC = 10
#fuses HS, MCLR, NOWDT, PUT, NOIESO, BROWNOUT, NOFCMEN
#use delay(clock=20000000)
#define VSS_VREF | Also, remove the line in bold above. That constant is defined in the
16F914.h file. You should not #define it in your own program.
And, since you have defined it to be nothing, you will get this error:
Quote: | *** Error 51 A numeric expression must appear here | Remove that line.
Quote: |
#int_rtcc //This function is called
//==========================================//
void clock_isr()
{ //every time the RTCC (timer0)
//overflows (255->0)
//For this program this is apx
//31 times per second.
if(--int_count==0)
{
seconds++;
int_count=INTS_PER_SECOND;
}
} |
The #int_rtcc line should not be floating around above the isr routine.
It's an integral part of the routine and should be placed above the
isr function declaration, like this:
Code: |
//============================================//
#int_rtcc
void clock_isr()
{ //every time the RTCC (timer0)
//overflows (255->0)
//For this program this is apx
//31 times per second.
if(--int_count==0)
{
seconds++;
int_count=INTS_PER_SECOND;
}
} |
|
|
|
POPE19
Joined: 27 Jun 2017 Posts: 71
|
ADC does not work with external reference |
Posted: Fri Jul 28, 2017 9:22 am |
|
|
thanks Ttelmah & PCM Programmer
I have made recommended correction. Here is what i observed the ADC reading does not change. i.e analog output of ADXL 335 is 1.637 volt. Now if we convert it with 5V ref then we should get 334 ADC value which i am getting 331.
If i select VREF+ = 3.3 volts i should get around 559 ADC value, which i am not.
Also the Datasheet on page 177 says for ADC clock period (TAD) to select ADC Clock Source. I have selected FRC because page 183 says that TACQ (acquisition time) should be greater than 4.67 us. Am i missing something? Please enlighten.
My modified code is as follows
Code: |
//============================================================================//
// Inclinometer //
// Date: 7-24-2017 //
// //
//============================================================================//
#include <16F914.h>
#device ADC = 10
#fuses HS, MCLR, NOWDT, PUT, NOIESO, BROWNOUT, NOFCMEN
#use delay(clock=20000000)
//============================================================================================//
//===========================================================================================//
// LCD Configuration //
//==========================================================================================//
// Digit segments A B C D E F G DP
// b7 b6 b5 b4 b3 b2 b1 b0
#define DIGIT5 COM0+17, COM1+17, COM2+17, COM3+17, COM2+18, COM0+18, COM1+18, COM3+18
#define DIGIT4 COM0+3, COM1+3, COM2+3, COM3+3, COM2+2, COM0+2, COM1+2, COM3+2
#define DIGIT3 COM0+1, COM1+1, COM2+1, COM3+1, COM2+0, COM0+0, COM1+0, COM3+0
#define DIGIT2 COM0+19, COM1+19, COM2+19, COM3+19, COM2+20, COM0+20, COM1+20, COM3+20
// ComX+Y is combination of Backplan0-3 and Segment0-SegmentXX
//=======================================================================================//
// character 0 1 2 3 4 5 6 7 8 9 Null
byte const Digit_Map[11] = {0xFD,0x61,0xDB,0xF3,0x67,0xB7,0xBF,0xE1,0xFF,0xF7,0x01}; //Decimal
byte const Digit_Map_1[11] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0x00}; //no Decimal
//=======================================================================================//
// Segments Initialization //
// Seg23 Seg22 ... Seg12 Seg11 Seg10 Seg9 Seg8 Seg7 Seg6 Seg5 Seg4 Seg3 Seg2 Seg1 Seg0 //
// 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 //
// if bit_SegX is 1, SegX is set as Segment Output. Otherwise //
////=====================================================================================//
#define Segments 0x1E000F // Initialize LCD SegmentX
//============================================================================//
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
int int_count=INTS_PER_SECOND;
int count5 = 0;// after decimal
int count_5 = 0;
int count4=0; // 1st digit
int count_4=0; // 1st digit
int count3=0; // 2nd digit
int count_3=0;
int count2=0; // 3rd digit
int count_2=0;
long seconds=0;
long reading;
//============================================================================//
#int_rtcc //This function is called
void clock_isr()
{ //every time the RTCC (timer0)
//overflows (255->0)
//For this program this is apx
//31 times per second.
if(--int_count==0)
{
seconds++;
int_count=INTS_PER_SECOND;
}
}
//============================================================================//
void Disp_num()
{
if(reading < 10)
{
count_5=reading;
count_2=11;
count_3=11;
count_4=11;
}
if(10<= reading < 100)
{
count_5=reading%10;
count_4=reading/10;
count_3=11;
count_2=11;
}
if(100 <= reading <999)
{
count_5=reading%10;
count_4=reading%100/10;
Count_3=reading%1000/100;
count_2=11;
}
if(1000 <= reading < 1024)
{
count_5=reading%10;
count_4=reading%100/10;
Count_3=reading%1000/100;
count_2=reading%10000/1000;
}
if(reading >= 1024)
{
count_5=11;
count_4=11;
count_3=11;
count_2=11;
}
}
//=============================================================================//
void sec_disp()
{
count4=count_4;
count5=count_5;
count2=count_2;
count3=count_3;
}
//============================================================================//
void Display()
{
lcd_symbol (Digit_Map_1[count5], DIGIT5);
lcd_symbol (Digit_Map[count4], DIGIT4);
lcd_symbol (Digit_Map_1[count3], DIGIT3);
lcd_symbol (Digit_Map_1[count2], DIGIT2);
}
//============================================================================//
void Digit()
{
if(seconds>=1)
{
reading = read_adc();
seconds=0;
}
}
//===========================================================================//
void main()
{
set_tris_a (0xdf);
set_tris_b (0xc0);
set_tris_c (0x07);
setup_adc_ports(sAN0 | VSS_VREF);
setup_adc (ADC_CLOCK_DIV_32);
set_adc_channel (0);
set_rtcc(0);
setup_counters (RTCC_INTERNAL, RTCC_DIV_256);
enable_interrupts (INT_RTCC);
enable_interrupts(GLOBAL);
setup_lcd(LCD_MUX14|LCD_STOP_ON_SLEEP,3, Segments); // set segments
count5 = 8;
count4 = 8;
count3 = 8;
count2 = 8;
Display ();
delay_ms (1000);
while (TRUE) /* Modify on 9/19/2012 */
{
digit();
Disp_num();
sec_disp();
display();
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 28, 2017 11:19 am |
|
|
Tacq, is the period between selecting the channel, and taking a reading, or the time between successive readings. The 'acquisition time'.
It's the time the internal capacitor takes to charge to within 0.5bit of the actual value.
It's not Tad, which is the clock rate of the ADC.
What is your compiler version number?.
Need to check if your version is correctly selecting the Vref option.
334 Vs 331, may well be that the 5v on the chip is not actually 5v, or a little noise. |
|
|
POPE19
Joined: 27 Jun 2017 Posts: 71
|
|
Posted: Fri Jul 28, 2017 11:27 am |
|
|
i am using CCS PCWH Compiler version 5.074 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 28, 2017 12:34 pm |
|
|
Quote: | setup_adc_ports(sAN0 | VSS_VREF); |
According to the 16F914.h file, a comma should be used as the separator
between those two parameters, as shown below:
Code: | setup_adc_ports(sAN0, VSS_VREF); |
However, that didn't fix it for me. I'm testing with a 16F917. I'm getting
334 with a 3.3v Vref+, and a 1.64v input voltage on AN0. That's incorrect.
I then stuck in a 16F1937 and it worked. I got 501 with 1.64v input
with a 3.3v Vref+.
I'm still working on it. Not sure what to try next. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 28, 2017 12:56 pm |
|
|
Yes, but it doesn't make any difference.
The | syntax was the old syntax (before the days of CCS supporting overloaded functions). For many dozens of compiler versions now, they have supported the use instead of an optional second parameter (as you show). However for 'reverse compatibility', they still support the | syntax as well.
I looked into this a while ago, and keep trying to remember to switch to the new syntax, but still tend to type the older form...
Have you tried going back to an older compiler?. If not, I'll try this later. Have used this chip, and am sure it was working, but it was a while ago. Have a nasty feeling that something has got missed in an upgrade. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 28, 2017 2:00 pm |
|
|
OK.
It's incorrectly setting the VCFG bits....
With VSS_VREF selected it should give 10 in these bits. Instead it gives 01...
The two defines are reversed in the .h file.
Code: |
#include <16F914.h>
#device ADC = 10
#fuses HS, MCLR, NOWDT, PUT, NOIESO, BROWNOUT, NOFCMEN
#use delay(clock=20000000)
#use RS232 (UART1, baud=9600, ERRORS)
#undef VSS_VREF
#undef VREF_VDD
#define VSS_VREF 0x4000 //| Range 0-VrefH
#define VREF_VDD 0x2000 //| Range VrefL-Vdd
//===========================================================================//
void main()
{
setup_adc_ports(sAN0 ,VSS_VREF);
setup_adc (ADC_CLOCK_DIV_32);
set_adc_channel (0);
while (TRUE) /* Modify on 9/19/2012 */
{
delay_us(500);
printf("ADC=%ld\r\n", read_adc());
}
}
|
Set up to do a simple serial test, this gives the correct readings. |
|
|
POPE19
Joined: 27 Jun 2017 Posts: 71
|
|
Posted: Fri Jul 28, 2017 2:29 pm |
|
|
Ok I will give a try and will let you know once I test it. Thanks again Ttelmah. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 28, 2017 3:15 pm |
|
|
What is amusing, is that nobody has spotted this before!...
I went back about 10 versions and it is still wrong. :( |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Fri Jul 28, 2017 4:35 pm |
|
|
too many PICs,
too many pins,
too many peripherals.....
I can understnad why it hasn't been caught until now....
sigh, life is too short to try everything on every PIC !!
|
|
|
POPE19
Joined: 27 Jun 2017 Posts: 71
|
|
Posted: Fri Jul 28, 2017 4:46 pm |
|
|
Quick question .
I think the header file is right because according to data sheet if you look to page 180 it says that VCFG1 is (1 for VREF+ and 0 for Vss ) & VCFG0 is ( 1- for VREF- & 0 for VSS ).
In my case I am choosing VREF+ as positive peak and VSS as ground reference. In that case won't the bit B5 is 1 (VCFG0) & bit B6 is 0 (VCFG1) make it 0x2000 ?
Please suggest |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sat Jul 29, 2017 1:12 am |
|
|
You want VCFG1 to be for Vref+. So '1'. VCFG0 to be for Vss, so '0'.
10 in the two bits.
I tested with the change, and the voltage read correctly. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 29, 2017 5:01 am |
|
|
I tested it on a 16F917 and it didn't work for me.
The 16F917 data sheet shows that VCFG1 is for the Vref- pin.
PIC16F913/914/916/917/946
DS41250F-page 180
http://ww1.microchip.com/downloads/en/DeviceDoc/41250F.pdf
From page 180 (page 182 in the Adobe reader):
Code: |
REGISTER 12-1: ADCON0: A/D CONTROL REGISTER 0
bit 6 VCFG1: Voltage Reference bit
1 = VREF- pin
0 = VSS
bit 5 VCFG0: Voltage Reference bit
1 = VREF+ pin
0 = VSS
|
|
|
|
|
|
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
|