|
|
View previous topic :: View next topic |
Author |
Message |
marken1
Joined: 26 Feb 2008 Posts: 6
|
round function for a double |
Posted: Tue Mar 18, 2008 1:26 pm |
|
|
Hi there,
I am building a programmable power supply and I use an 8 bit output to drive an R2R ladder circuit, then I use a voltage amplifier to amplify by a factor of 6 because I want a maximum output of 30V.
Then trough a potential divider I read the output voltage and feed it to a 10 bit analogue input on the PIC 18f4550.
Everything works fine except that the display is not very stable.
Every time I increment the 8 bit counter the display increment by 20mV and I get funny output voltages.
I would like to increment the 8 bit counter in step of 100mV and the output voltage to be the some displaying steps of 100mV.
Anything between 100 I want to round to 0 if is less than 50 and round to 1 if it more than 51.
I try to use the round function in CCS C but there is not one.
I only found the floor and ceil function which is not good to me.
I do not understand why CCS does not support round function it is a standard C function
Please have a look at the relevant code:
Any help will be very much appreciated as I am at the desperation point.
At the end I will write my own round function and post it for every one to use it but I am hopping to save a bit of time.
CCS C compiler 4.038 in MPLAB
Code: | #include <18F4550.h>
#device adc=10
//#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NOPBADEN,NOVREGEN
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=20000000)
#use standard_io(A)
#include <lcd(8).c>
#include <kbdd.c>
#include <math.h>
#include <keyboard.c>
#include <check.c>
#include <usb_cdc.h>
//code part of the main.c
#define AN0_TO_AN2 0x0C
set_adc_channel(0);
delay_ms(30);
adc_value = read_adc();
temp = (float)(adc_value * 5)/1023.0;
volts = (float)(temp * 6);
lcd_gotoxy(2,1);
printf(lcd_putc, "%3.2fV ", volts);
|
//code part of the keyboard.c
Code: | float iset;
int8 VCOUNT;
int8 icount;
void voltage(){
//Voltage +
if(!input(PIN_C0) )
{
if(vcount<255) vcount = vcount + 1;
OUTPUT_D(vCOUNT);
}
//Voltage -
if( !input(PIN_C1) )
{
if (vcount>0) vCOUNT = vCOUNT - 1 ;
OUTPUT_D(vCOUNT);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 18, 2008 2:22 pm |
|
|
Your program is missing some of the adc setup functions.
Post a small but complete test program that shows the required functions
and that demonstrates the problem. Example:
http://www.ccsinfo.com/forum/viewtopic.php?t=32168
The program that you post should be small, but also it must be
compilable without errors. Don't put #include files in it that
are not needed to show the problem. |
|
|
Guest
|
round double |
Posted: Tue Mar 18, 2008 3:06 pm |
|
|
Hi PCM Programmer,
You are a much respected member of this forum and I think of you very highly, I do appreciate helping beginners like me.
This is my all main function without the include:
I want to control the PPS through usb using the usb_cdc.h driver.
Code: |
#include <18F4550.h>
#device adc=10
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=20000000)
#include <lcd(8).c>
#include <math.h>
#include <keyboard.c>
#define AN0_TO_AN2 0x0C
void main()
{
int16 adc_value;
float volts;
float temp;
float current;
char string[7];
int1 sby; //true when system is not running
setup_adc(ADC_CLOCK_DIV_8);
lcd_init();
lcd_gotoxy(0,1);
printf(lcd_putc, "\Initializing . ");
delay_ms(1500);
lcd_gotoxy(0,1);
printf(lcd_putc, "\Initializing .. ");
delay_ms(1500);
lcd_gotoxy(0,1);
printf(lcd_putc, "\Initializing ... ");
delay_ms(1500);
lcd_gotoxy(0,1);
printf(lcd_putc, "\fInit...OK");
delay_ms(3000);
printf(lcd_putc, "\f");
delay_ms(1000);
//Initialise
vCOUNT = 76 ; //Initialise vCOUNT
icount = 7 ; //Initialise COUNT
OUTPUT_D(0x00); //Clear Port D
output_bit( PIN_E0, 0);
output_bit( PIN_E1, 1);
sby = 0; //System is normal
while(1)
{
set_adc_channel(0);
delay_ms(30);
adc_value = read_adc();
temp = (float)(adc_value * 5)/1023.0;
volts = (float)(temp * 6);
lcd_gotoxy(2,1);
printf(lcd_putc, "%3.2fV ", volts);
}
delay_ms(250);
set_adc_channel(1);
delay_ms(30);
adc_value = read_adc();
current = (float)(adc_value * 5)/1023.0;
lcd_gotoxy(11,1);
printf(lcd_putc, "%3.2fA", current);
if (usb_cdc_kbhit())
{
}
output_low(pin_E0);
delay_ms(250);
voltage();
}
} |
this is the keyboard.c
Code: |
int8 VCOUNT;
void voltage(){
//Voltage +
if(!input(PIN_C0) )
{
if(vcount<255) vcount = vcount + 1;
OUTPUT_D(vCOUNT);
}
//Voltage -
if( !input(PIN_C1) )
{
if (vcount>0) vCOUNT = vCOUNT - 1 ;
OUTPUT_D(vCOUNT);
}
} |
If you should require the lcd(8).c please let me know
I will post it a.s.a.p
Thanks for you trying to help me.
Best regards
marken |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 18, 2008 3:38 pm |
|
|
Quote: | #use delay(clock=20000000)
setup_adc(ADC_CLOCK_DIV_8);
|
Look at this table in the A/D section of the 18F4550 data sheet. It shows
that you should use a divisor of 16 (not 8) for a 20 MHz oscillator.
Code: |
TABLE 21-1: TAD vs. DEVICE OPERATING FREQUENCIES
Divisor Max Frequency
8 TOSC 11.43 MHz
16 TOSC 22.86 MHz |
Change it to this:
Code: | setup_adc(ADC_CLOCK_DIV_16); |
|
|
|
Guest
|
|
Posted: Tue Mar 18, 2008 4:15 pm |
|
|
Hi there,
I have change the settings to the adc divisor 16.
It makes no difference to my display.
Any other suggestions about the round function ?
Regards
Marken |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 18, 2008 4:22 pm |
|
|
One thing I want to check: What is your crystal frequency ? |
|
|
Guest
|
|
Posted: Tue Mar 18, 2008 4:31 pm |
|
|
Hi PCM,
It is a crystal at 20Mhz.
Regards
Marken |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 18, 2008 5:00 pm |
|
|
Quote: | #include <18F4550.h>
#device adc=10
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=20000000)
It is a crystal at 20Mhz.
|
Your PIC is really running at 48 MHz.
If I take the following test program and use your #fuses settings, and
change the #use delay() statement to 48 MHz, the LED on pin B0 blinks
at a 1 second interval when timed with a stop watch.
Code: | #include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
//===============================
void main()
{
while(1)
{
output_high(PIN_B0);
delay_ms(100);
output_low(PIN_B0);
delay_ms(900);
}
} |
You need to change the A/D divisor to 64 now, so it will work with
a 48 MHz oscillator frequency. This could be the source of most
of your A/D problems. Also change the #use delay() statement
to 48 MHz as shown above. Example:
Code: | #use delay(clock=48000000) |
and
Code: | setup_adc(ADC_CLOCK_DIV_64); |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Mar 18, 2008 5:44 pm |
|
|
Quote: | I do not understand why CCS does not support round function it is a standard C function | Round is a relative new C function, it was not available in the ISO C89 standard. Reason for this might be that round is not so universal as you think it is, for example: how to handle rounding in negative numbers? What to do if the rounded value goes outside the range of the return type? That's why C99 defines multiple new rounding functions besides ceil and floor: trunc, round, nearbyint / rint and lrint.
It would be nice for CCS to add these functions (send them an email) but it's easy enough to roll them yourself.
Quote: | Then trough a potential divider I read the output voltage and feed it to a 10 bit analogue input on the PIC 18f4550. | What are the resistor values in your voltage divider? For a reliable reading the impedance as seen by the PIC must be relative low, check the datasheet. |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 19, 2008 8:55 am |
|
|
Yes.
Ckielstra's comment here, is very much a likely start to the problems. Once the code is working (timing the ADC right, which otherwise could be part of the problem), when dealing with a voltage like this, there are likely to be a number of difficulties. First, the DAC itself, is likely to exhibit some lag, or overshoot (or even both), on the output voltage generated. Then the voltage fed back to the PIC, from the output, will take time to respond (depending on the capacitance, and resistances present in the potential divider). To design a DAC/ADC combination, with gives fast response, without oversoot, is quite a complex task....
Look at the Microchip application notes. Select 'signal conditioning and measurement', then ADC.
Though a lot of the notes are for older chips (like the 16C71), the details a the same for all the Microchip converters. You may find out why you might want to use 1024, rather than 1023 as the divider for Microchip ADC's - the most accurate conversion, is actually:
float_val = ((read_adc()*2)+1)/2048;
Best Wishes |
|
|
|
|
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
|