|
|
View previous topic :: View next topic |
Author |
Message |
lcs
Joined: 10 Mar 2020 Posts: 6
|
PIC12F683 with VRef in ADC [SOLVED] |
Posted: Tue Mar 10, 2020 8:14 pm |
|
|
Hi!
I'm trying to make a code to use the lm35 with pic12f683, using Vref (AN1) = 1.2V (with potentiometer). For testing, I'm just trying to light a led when the temperature exceeds 27C. What could be wrong?
Code: |
#include <12F683.h>
#device adc=10
#FUSES NOWDT, INTRC_IO, NOCPD, NOPROTECT, NOMCLR, PUT, NOBROWNOUT, NOIESO, NOFCMEN
#use delay(clock=4000000)
#use FIXED_IO( A_outputs=PIN_A5,PIN_A4,PIN_A3,PIN_A2)
void main(void) {
int aMask = 0x00;
int16 r;
int temp;
setup_adc_ports(sAN0|VSS_VREF);
setup_adc(ADC_CLOCK_INTERNAL);
setup_comparator(NC_NC);
setup_vref(TRUE); //I tried VREF_HIGH too
output_A(0);
while(TRUE){
set_adc_channel(0);
delay_us(50);
r = read_adc();
delay_us(50);
temp = ((1,2 * r)/1023)*100;
if (temp > 27){
aMask = aMask | 0b00000100;
output_a(aMask);
}else{
aMask = aMask & 0b11111011;
output_a(aMask);
}
}
}
|
Hardware:
VREF-VSS = 1,2V => AN1
VDD-VSS = 4,77V
Led => AN2
.LM35 => AN0
.AN0-VSS = 0,38V
Thanks for the help!
Last edited by lcs on Thu Mar 12, 2020 6:16 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 10, 2020 11:03 pm |
|
|
1. The Vref module in the 12F683 is for the comparator, not the ADC.
2. The ADC allows you to use an External Vref on a pin. You have to
generate it. If your Vdd is constant, then you could just two resistors or
a trimpot to make a voltage divider and get the external Vref from that
circuit.
3. You can't use a Vref of 1.2v with the ADC. The minimum is 2.2v,
and the preferred minimum is 2.7v. See this section in the data sheet:
Quote: | TABLE 15-9: PIC12F683 A/D CONVERTER (ADC) CHARACTERISTICS
|
12F683 data sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/41211D_.pdf
4. If you decide to use the comparator instead of the ADC, here is
example code showing how to do that:
http://www.ccsinfo.com/forum/viewtopic.php?t=42946 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Wed Mar 11, 2020 1:39 am |
|
|
Start with setup_vref.
This is wrong. This is _not_ for the ADC VREF. This sets up the internal
comparator VREF. This module sets up the comparator Vref as a level
of the supply. If you look in the .h file for the processor, the setup_vref
'mode' settings are VREF_LOW and VREF_HIGH or'ed with a number 0-15.
If you look in the data sheet for the Cvref module. section 8.11, tells you that
the comparator voltage reference has two ranges each with 16 levels. The
VREF_HIGH and VREF_LOW setting gives control of the ranges and the value
0-15 control the levels. However this is completely and totally for the
comparator _not_ the ADC.
So start by getting rid of this setting....
Then the second problem. ADC VREF. If you again check the data sheet
and look in the A/D converter (ADC) Characteristics. you find AD06
'Reference voltage'. This has values of 2.2 and 2.7V 'minimum'.
The value of 2.2v, is the absolute minimum value that the ADC can
use for the Vref. 2.7v is the minimum it can use and retain 1bit
accuracy. So you can not use 1.2v....
I see PCM_programmer has pointed out both problems while I've been
typing.....
As a general 'comment', most of the PIC ADC's require a minimum of
about 2.5v for the Vref. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Wed Mar 11, 2020 4:33 am |
|
|
along with the other comments....
this line...
setup_adc(ADC_CLOCK_INTERNAL);
is incorrect.
Have a look at table 9-1, ADC clock vc clock frequency...
you'll see that 'internal' is wrong for clk>4MHz.... you have 2 choices, /8 or /16.
I'll assume you used a 'Wizard' to come up with 'setup_adc(ADC_CLOCK_INTERNAL); ' ?
PIC rule #2... Never EVER trust Wizards. |
|
|
lcs
Joined: 10 Mar 2020 Posts: 6
|
|
Posted: Wed Mar 11, 2020 6:53 pm |
|
|
Thanks for the answers.
I made some changes to my code, but the led doesn't turn on:
Code: |
#include <12F683.h>
#device adc=10
#FUSES NOWDT, INTRC_IO, NOCPD, NOPROTECT, NOMCLR, PUT, NOBROWNOUT, NOIESO, NOFCMEN
#use delay(clock=4000000)
#use FIXED_IO( A_outputs=PIN_A5,PIN_A4,PIN_A3,PIN_A2,PIN_A1)
void main(void) {
int aMask = 0x00;
int16 r;
int temp;
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_adc_ports(sAN0|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_8);
output_A(0);
while(TRUE){
set_adc_channel(0);
delay_us(50);
r = read_adc();
delay_us(50);
temp = ((3 * r)/1023)*100;
if (temp > 27){
aMask = aMask | 0b00000100;
output_a(aMask);
}else{
aMask = aMask & 0b11111011;
output_a(aMask);
}
}
}
|
VREF-VSS = 3V => AN1
VDD-VSS = 4,5V
Led => AN2
.LM35 => AN0
.AN0-VSS = 0,30V
-------------
Curiosity:
I tried without VREF, configuring 3V in VDD with potentiometer. I used this code, and it didn't work either:
Code: |
#include <12F683.h>
#device adc=10
#FUSES NOWDT, INTRC_IO, NOCPD, NOPROTECT, NOMCLR, PUT, NOBROWNOUT, NOIESO, NOFCMEN
#use delay(clock=4000000)
#use FIXED_IO( A_outputs=PIN_A5,PIN_A4,PIN_A3,PIN_A2,PIN_A1)
void main()
{
int aMask = 0x00;
int16 r;
setup_adc_ports(sAN0|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_16);
while(TRUE)
{
set_adc_channel(0);
delay_us(100);
r=read_adc();
delay_us(500);
if (r > 0){
aMask = aMask | 0b00000100;
output_a(aMask);
}else{
aMask = aMask & 0b11111011;
output_a(aMask);
}
}
}
|
VDD-VSS = 3V
Led => AN2
.LM35 => AN0
.AN0-VSS = 0,31V
Would it be a good option to try to manually configure the registers?
Thanks! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 11, 2020 8:06 pm |
|
|
Quote: | temp = ((3 * r)/1023)*100; |
You're using integer math here. If 'r' is less than 341, you'll get 0 as the result. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Mar 12, 2020 1:02 am |
|
|
A simple set of maths to give a reasonable answer with your Vref would
be:
temp=(r*30)/100;
For 1C, this will give '1'. For 10C, 10 etc..
So at 20C, 0.2v in. ADC should read 0.2/(3/1024)=68. 68*30=2040. 2040/100
= 20.
Understand the ADC reads 1023, just below it's reference voltage, so the
division needed to get the ADC step is /1024, not /1023.
Use a 2.5v Vref. Then the conversion becomes
temp=(r*25)/100
and the actual resolution will be slightly better.
Also if you need to read below about 2 to 3C, you do need the -ve
pull down resistor on the signal. |
|
|
lcs
Joined: 10 Mar 2020 Posts: 6
|
|
Posted: Thu Mar 12, 2020 5:41 am |
|
|
In the last code of my answer, I directly tested the ADC value ... Apparently, read_adc() did not return a value greater than 0. Is the Adc module having problems?
When I get home, I will test the conversion constants that have passed on to me. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Thu Mar 12, 2020 6:51 am |
|
|
That could mean the LM34/35 sensor is defective or a shorted input to ADC pin.
In 3+ decades of using those LMs, I've never had a defective one. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Mar 12, 2020 6:55 am |
|
|
In your original code, there is a major issue, you are setting the Vref pin
as an output. No. It needs to be an input. Input, and 3v.
Honestly get rid of the #use fixed_IO, and just use output_high/ output_low
on PIN_A2 for your test. It should always be high with the code as posted,
since unless the ADC input is totally shorted to 0v, you will always see
a value above 0.
Honestly better to use
#use delay(INTERNAL=4MHz) |
|
|
lcs
Joined: 10 Mar 2020 Posts: 6
|
|
Posted: Thu Mar 12, 2020 6:16 pm |
|
|
The code finally worked! I thank everyone for their help and the time they spent helping me.
The changes:
Code: |
#include <12F683.h>
#device adc=10
#FUSES NOWDT, INTRC_IO, NOCPD, NOPROTECT, NOMCLR, PUT, NOBROWNOUT, NOIESO, NOFCMEN
#use delay(INTERNAL=4MHz)
int16 r;
int temp;
void main()
{
set_tris_a(0b00000011);
setup_adc_ports(sAN0|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_8);
while(TRUE)
{
setup_adc_ports(sAN0|VSS_VREF);
delay_us(100);
r=read_adc();
temp=(r*25)/100;
delay_ms(500);
if (temp > 27){
output_high(pin_A2);
}else{
output_low(pin_A2);
}
}
}
|
Hardware:
VDD-VSS => 4,8V
AN0 => LM35 output
AN1 = 2,5V
AN2 =>Led
This experience added knowledge and now I can continue with the project. Thank you all! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Mar 14, 2020 3:54 am |
|
|
Your code still has several problems:
1. You forgot to set the adc channel. You got away with it because the
channel select register bits default to 0. But it should be set.
2. There should be a 5us delay after setting the channel. This in the
12F683 data sheet in this section:
Quote: | EQUATION 9-1: ACQUISITION TIME EXAMPLE |
3. You don't need to call setup_adc_ports() in the while() loop, because
it only needs to be called once, and you did that above the loop.
4. There is no reason to put a 100us delay after calling setup_adc_ports().
The delay should be done after calling set_channel_adc() as shown below in bold:
lcs wrote: | #include <12F683.h>
#device adc=10
#FUSES NOWDT, INTRC_IO, NOCPD, NOPROTECT, NOMCLR, PUT, NOBROWNOUT, NOIESO, NOFCMEN
#use delay(INTERNAL=4MHz)
int16 r;
int temp;
void main()
{
set_tris_a(0b00000011);
setup_adc_ports(sAN0|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0); // *** Add this line
delay_us(5); // *** Add this line
while(TRUE)
{
setup_adc_ports(sAN0|VSS_VREF); // *** Delete this line
delay_us(100); // *** Delete this line
r=read_adc();
temp=(r*25)/100;
delay_ms(500);
if (temp > 27){
output_high(pin_A2);
}else{
output_low(pin_A2);
}
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Sat Mar 14, 2020 4:27 am |
|
|
I'd also delete this line....
set_tris_a(0b00000011);
and let the compiler handle the I/O configuration.
Unless you NEED very,very fast I/O just use 'standard I/O, the compiler default.
In 3 decades of programming PICs, I've only needed set_tris.. and fast_io... 2 or 3 times. In each case is was early and for a custom interface with propriatory I/O. Once the 20MHz barrier was broken, 'speed' hasn'y been a problem.
Also
try to get into the habit of adding comments at the end of each line. While code looks obvious, now, for you... 3 days,or months from now you or a friend will wonder WHAT is this suppose to do ??
Comments don't take up any codespace and as long as you can type are easy to add. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Mar 14, 2020 9:37 am |
|
|
I agree it's not necessary for his program to work, but one reason for
including that line is if he doesn't want floating inputs on the unused pins.
He is not setting the output level for each pin, but the GPIO register bits
default to 0 at power-up, except pin A3 (input-only) and pin A5. |
|
|
|
|
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
|