View previous topic :: View next topic |
Author |
Message |
eabir
Joined: 16 Aug 2010 Posts: 19
|
PIC10f220 - calculate result is between 0 to 1, how to ... |
Posted: Wed Aug 25, 2010 2:27 pm |
|
|
Hello,
I'm measuring voltage changes with ADC AN1 channel with delay of two seconds between the two measurements.
The result is given by subtracting two values measurements, and the result is less then 1.
I know the result is less then 1 because the code is triggering an alarm when the result is less then 1. Look from the code:
"if ( (0 < (avalue-value) < 1) )"
But I need to figure out what is my real limit below 1, because I need more resolution from the measurement. When I wrote 0.5 instead of 1 for example it seems nothing happened. Does the CCS not know decimal point?
Please help.
Code: |
#include <10F220.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOMCLR //Master Clear pin: disable
#FUSES NOPROTECT //Code protected from reads
#FUSES NOMCPU //No Watch Dog Timer
#FUSES IOSC4
// #use delay(Clock=4MHZ,OSC)
// #use delay(clock=40) // Only for Debug Mode
#use delay(clock=4000000) // Only for Debug Mode
#bit OSCCAL_0 = 0x05.0 // Disable OSC on GP2, Enable as I/O
// Voltage Table:
// 0.9v=48 ; 0.8v=45 ; 0.7v=38 ; 0.6=32
// 1v=54 ; 1.1v=59 ; 1.2v=66 ; 1.3v=69/70 ; 1.4v=76 ; 1.5v=81 ; 1.6v=85
// 1.7v=90 ; 1.8v=95 ; 1.9v=101 ; 2.0=109 ; //1.85v = 155//
#define DELAY 1
//========================================================================
Alram_on ()
{
int16 step;
for(step = 0;step < 5000 ;step++ ){ // Loop control
// cnt0 = 0;
output_low(PIN_B0); // Sound sequence
restart_wdt();
delay_us(79); // 168 = 5khz for DSP
output_high(PIN_B0);
restart_wdt();
delay_us(79);
// return;
}
}
void main()
{
int flag = 0;
int8 value = 0;
int8 avalue = 0;
int8 step1;
int8 step2;
unsigned char cnt0 = 0; // counter
unsigned char cnt1 = 0; // counter
setup_adc_ports(sAN1);
setup_adc(ADC_CLOCK_DIV_4);
setup_adc( ADC_ON );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_counters(RTCC_INTERNAL,RTCC_DIV_1|DISABLE_PULLUPS); //|DISABLE_PULLUPS
setup_wdt(WDT_2304MS);
set_adc_channel(1);
SET_TRIS_B(0b11111010); //GP0,1,2 as Output; GP3 as Input(default)
for (cnt1 = 0; cnt1 <= 3; ++cnt1){
delay_ms(1000); // 4 Sec
output_low(PIN_B0); // Sound sequence
// flag = 1;
}
while (1) {
// read_adc(ADC_START_ONLY);
//======================//
// ADC Sample #1
//=====================//
value = read_adc();
delay_us( 500);
value=read_adc(ADC_READ_ONLY);
//======================================//
// Delay interval between ADC readings //
//====================================//
// for (cnt0 = 0; cnt0 <= 1; ++cnt0){
delay_ms(2000); // 1 Sec
// flag = 1;
// }
//======================//
// ADC Sample #2
//=====================//
avalue = read_adc();
delay_us( 500);
avalue=read_adc(ADC_READ_ONLY);
//==========================================//
// Check count/voltage between ADC results //
//==========================================//
if ( (0 < (avalue-value) < 1) ) //&& cnt0 == 2)
{
for(step1 = 0;step1 < 3 ;step1++ ){
delay_ms( 700);
Alram_on ();
cnt0 = 0;
}
}
else
{
// Alram_off ();
for(step2 = 0;step2 < 50 ;step2++ ){ // Loop control
output_low(PIN_B0); // Sound sequence
restart_wdt();
delay_us(168); // 0 = 0khz for DSP
}
}
}
} |
|
|
|
vinniewryan
Joined: 29 Jul 2009 Posts: 154 Location: at work
|
|
Posted: Wed Aug 25, 2010 3:44 pm |
|
|
You're using an 8 bit data conversion, CCS doesn't use decimal values in this way. Your ADC result should be reading between -128 to 128, so if your ADC result is below 50% of Vref-VSS, then it will be less than 0. You can always use an alternative method to keep the number above 0, (VAR=adc_read+128) which would give you a value of 0-255.
I'm not sure if I've answered any of your problems, but if you're simply looking to figure out if the values are less than 0, just simplify and make a function such as:
Code: |
X=read_adc();
delay_seconds(2);
Y=read_adc();
var=X-Y;
if(var<0) {do something;}
|
_________________ Vinnie Ryan |
|
|
eabir
Joined: 16 Aug 2010 Posts: 19
|
|
Posted: Wed Aug 25, 2010 4:42 pm |
|
|
Hi Vinnie,
I will try what you recommend : (VAR=adc_read+128) and also the code of the "less then 0".
But if I got an alarm by this condition: 0 < result < 1, then how can the result be negative ?
There is no way to check if my result is between 0 to 1 ?
Thanks for your help. |
|
|
vinniewryan
Joined: 29 Jul 2009 Posts: 154 Location: at work
|
|
Posted: Thu Aug 26, 2010 12:10 am |
|
|
No, there is no way to track if your input value is between 0 and 1, unless you wrote code for a very complex measuring program to moniter the flicker speed of a value shifting between 0 (Vss) and 1 (>Vdd). What is attached to your adc? A switch? A sensor? I think that would help me better understand why you're using the adc to only look for a value below a certain amount. _________________ Vinnie Ryan |
|
|
eabir
Joined: 16 Aug 2010 Posts: 19
|
measuring a bend sensor |
Posted: Tue Aug 31, 2010 7:00 am |
|
|
Hi,
Sorry for my late response.
I'm measuring a bend sensor, the voltage change is from ~1.5v to ~2.2v with error of ~0.2v .
It take a maximum of 1 second for this gap.(min to max value)
So, is this data make sense that my limits are between 0<v<~1 ?
What is the digital data of 1.5v that i should get at the ADC output ? how can i calculate it ?
You wrote:
"unless you wrote code for a very complex measuring program to moniter the flicker speed of a value shifting between 0 (Vss) and 1 (>Vdd)"
Do you think i'm in the "flicker" region ?
Do you have an suggstion how to implement such thing?
Thanks,
Eyall |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Tue Aug 31, 2010 8:35 am |
|
|
Look at your table
Code: |
// Voltage Table:
// 0.9v=48 ; 0.8v=45 ; 0.7v=38 ; 0.6=32
// 1v=54 ; 1.1v=59 ; 1.2v=66 ; 1.3v=69/70 ; 1.4v=76 ; 1.5v=81 ; 1.6v=85
// 1.7v=90 ; 1.8v=95 ; 1.9v=101 ; 2.0=109 ; //1.85v = 155//
|
Your value for 1.5v is 81, this is the reading you get from the ADC,
The value for 2v is 109.
Lets say you had a full swing (2v - 1.5v = .5v) in ADC terms this is (109 - 81 = 28)
You are doing the wrong math. You could convert your ADC values to correct voltages but this is painfull and slow. You are better off sticking with the ADC values and doing integer math.
Please note you will need to do signed math as (1.5v - 2v = -0.5v) or (81 - 109 = -28)
As I am not sure what reading you are looking for I cannot help further without more info. Why does it need to be between 0v and 1v ?
If you are just trying to monitor if the door gets opened or closes then if the result is positive it is going one way and if the result is negative then it is going the other. Becarefull for if the door bounces at the end also you will want to check for a change of x value in either direction. |
|
|
eabir
Joined: 16 Aug 2010 Posts: 19
|
|
Posted: Tue Aug 31, 2010 2:27 pm |
|
|
Hi,
The voltage table is regard working with PIC10F506 emulator, i really don't understand why i get PIC10F222 so tight values.
Thanks,
Eyall |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Wed Sep 01, 2010 2:13 am |
|
|
If you mean more resolution in your ADC readings then this is down to your vref+ and vref- for your ADC.
Assuming you have not got anything connected to the vref+ and vref- pins (if this chip has them) and the fact that your setup_adc does not specify them then you will be using vss and vdd of the chip for your references. This will be 0v and whatever the chip runs at 5v ?
With an 8 bit ADC and a range of 0 to 5v you should get 0.02v approx per bit. So for a 0.1v change you will get approx +- 5 on your ADC.
Now you must also remember that the vref+ may not be exactly 5v and the voltage at the ADC can fluctuate based on hardware so your readings may not be very accurate. The emulator may give precise voltages but your hardware won't so this may be why you are seeing different values.
If you reduce vref+ or (by using a 3v pic) vdd or use a higher vref- you can get more resolution on your ADC but check the spec for your PIC as to what may be possible. |
|
|
eabir
Joined: 16 Aug 2010 Posts: 19
|
ADC Channels |
Posted: Tue Sep 14, 2010 7:24 am |
|
|
Hi,
I have two inputs for each ADC channel.
What is the correct way to declare : "set_adc_channel();
" i.e. to choose which ADC channel to use in each wanted input: 'Temp' and 'Value' ?
As its now only the first setting of "set_adc_channel(0)" is working.
Another question, if I will remove the REM from the TRIS, then PIN_B2 and PIN_B3 will not work, why ?? and how is it working now without TRIS ??
Thanks!
Code: |
#include <10F222.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOMCLR //Master Clear pin: disable
#FUSES NOPROTECT //Code protected from reads
#FUSES NOMCPU //No Watch Dog Timer
#FUSES IOSC4
// #use delay(Clock=4MHZ,OSC)
// #use delay(clock=40) // Only for Debug Mode
#use delay(clock=4000000) // Only for Debug Mode
#bit OSCCAL_0 = 0x05.0 // Disable OSC on GP2, Enable as I/O
// Voltage Table:
// 0.9v=48 ; 0.8v=45 ; 0.7v=38 ; 0.6=32
// 1v=54 ; 1.1v=59 ; 1.2v=66 ; 1.3v=69/70 ; 1.4v=76 ; 1.5v=81 ; 1.6v=85
// 1.7v=90 ; 1.8v=95 ; 1.9v=101 ; 2.0=109 ; //1.85v = 155//
#define DELAY 1
//========================================================================
void Alram_on (void)
{
// two sequences, assume voltage differences //
int16 step = 0;
for(step = 0;step < 5000 ;step++ ){ // Loop control
// cnt0 = 0;
output_low(PIN_B2); // Sound sequence
// restart_wdt(); // 79@5v = ~5khz for DSP
delay_us(40); // 79@3v = 3.3khz for DSP
output_high(PIN_B2); // 40@3v = 5.5khz for DSP
// restart_wdt();
delay_us(40);
// return;
}
int16 step4 = 0;
for(step4 = 0;step4 < 5000 ;step4++ ){ // Loop control
// cnt0 = 0;
output_low(PIN_B2); // Sound sequence
// restart_wdt(); // 79@5v = ~5khz for DSP
delay_us(79); // 79@3v = 3.3khz for DSP
output_high(PIN_B2); // 40@3v = 5.5khz for DSP
// restart_wdt();
delay_us(79);
// return;
}
}
void Bit_on (void)
{
int16 step3 = 0;
for(step3 = 0;step3 < 50 ;step3++ ){ // Loop control
// cnt0 = 0;
output_low(PIN_B2); // Sound sequence
// restart_wdt();
delay_us(400);
output_high(PIN_B2);
// restart_wdt();
delay_us(400);
// return;
}
}
void Temp_on (void)
{
int16 step6 = 0;
for(step6 = 0;step6 < 500 ;step6++ ){ // Loop control
// cnt0 = 0;
output_low(PIN_B2); // Sound sequence
// restart_wdt();
delay_us(50);
output_high(PIN_B2);
// restart_wdt();
delay_us(80);
// return;
}
}
void main()
{
int8 value = 0;
int8 avalue = 0;
int8 Val = 0;
int8 temp = 0;
// int8 Val_res = 0;
int8 step1;
int8 step2;
int8 step5;
unsigned char cnt0 = 0; // counter
unsigned char cnt1 = 0; // counter
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_4);
setup_adc( ADC_ON );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_counters(RTCC_INTERNAL,RTCC_DIV_1|DISABLE_PULLUPS); //|DISABLE_PULLUPS
setup_wdt(WDT_2304MS);
// SET_TRIS_B(0b00000010); //GP0,1,2 as Output; GP3 as Input(default)
// for (cnt1 = 0; cnt1 <= 1; ++cnt1){
// delay_ms(500); // 1 Sec
// output_low(PIN_B0); // Sound OFF
// }
while (1) {
set_adc_channel(0);
// read_adc(ADC_START_ONLY);
//===========================//
// ADC#0 Temperature Sample
//==========================//
temp = read_adc();
delay_us(1000);
if ( temp > 97 )//&& cnt0 == 2)
{
for(step5 = 0;step5 < 1 ;step5++ ){
// delay_ms( 700);
temp_on ();
}
}
}
delay_us(2000);
while (1) {
set_adc_channel(1);
// read_adc(ADC_START_ONLY);
//======================//
// ADC Sample #A1
//=====================//
value = read_adc();
delay_us(1000);
//======================================//
// Delay interval between ADC readings //
//====================================//
// for (cnt0 = 0; cnt0 <= 1; ++cnt0){
delay_ms(3000); // 1 Sec
// }
//======================//
// ADC Sample #A2
//=====================//
avalue = read_adc();
delay_us(1000);
//==========================================//
// Check count/voltage between ADC results //
//==========================================//
Val = value -avalue;
//======================//
// ADC Sample #B1
//=====================//
value = read_adc();
delay_us(1000);
//======================================//
// Delay interval between ADC readings //
//====================================//
// for (cnt0 = 0; cnt0 <= 1; ++cnt0){
delay_ms(3000); // 1 Sec
// }
//======================//
// ADC Sample #B2
//=====================//
avalue = read_adc();
delay_us(1000);
Val = value -avalue;
//============================================//
// Check ADC readings and Calculate Value //
// Set the Alarm if needed //
//=========================================== //
// Val_res = (Val_1 + Val_2 )/2 ;
// if ( ((Val_res ) == 0) || ((Val_res ) <= 2 ) )//&& cnt0 == 2)
if ( Val == 0 )
{
for(step1 = 0;step1 < 1 ;step1++ ){
delay_ms( 500);
Alram_on ();
cnt0 = 0;
}
}
else
if ( Val > 1 )//&& cnt0 == 2)
{
for(step2 = 0;step2 < 1 ;step2++ ){
// delay_ms( 700);
Bit_on ();
cnt0 = 0;
}
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 16, 2010 3:06 pm |
|
|
Quote: |
What is the correct way to declare : "set_adc_channel();
" i.e. to choose which ADC channel to use in each wanted input: 'Temp'
and 'Value' ?
As its now only the first setting of "set_adc_channel(0)" is working. |
Look in this section of the 10F220 data sheet:
Quote: | EQUATION 7-1: ACQUISITION TIME EXAMPLE |
It shows the acquisition time for the A/D is about 6us. You must do this
delay manually with a line of code, every time you set or change the ADC
channel. See the lines shown in bold below. For safety, use a 10us
delay instead of the data sheet value of 6us. Note that the acquisition
time will vary, depending on the PIC. The 16F877 needs a delay of 20us,
for example.
Quote: |
while (1) {
set_adc_channel(0);
delay_us(10);
// read_adc(ADC_START_ONLY);
//===========================//
// ADC#0 Temperature Sample
//==========================//
temp = read_adc();
set_adc_channel(1);
delay_us(10);
// read_adc(ADC_START_ONLY);
//======================//
// ADC Sample #A1
//=====================//
value = read_adc();
|
Quote: |
Another question, if I will remove the REM from the TRIS, then PIN_B2
and PIN_B3 will not work, why ?? and how is it working now without TRIS ?
|
If you use "standard i/o mode", which is the default mode of the compiler,
then CCS will automatically set the correct TRIS for you. When you do
an output_low(), the compiler will put in code to set the TRIS to output
for that pin. You can see the ASM code for this, if you look at the .LST
file. This is one of the things that makes CCS so easy to use compared
to other compilers. You don't have to set the TRIS. (But you must use
CCS functions and library code for pin i/o). |
|
|
eabir
Joined: 16 Aug 2010 Posts: 19
|
Clock settings |
Posted: Sat Sep 25, 2010 1:55 pm |
|
|
Hello again,
There is something I don't understand regard the following:
When I set: #use delay(clock=4000000) then the code (routines) go less faster then if I set: #use delay(clock=1000000).
How the 1Mhz is faster then 4Mhz ?
Thanks |
|
|
|