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

Hex to float
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
CcsNewbie
Guest







Hex to float
PostPosted: Tue Jan 30, 2007 4:22 am     Reply with quote

I have data in the hex format format 0x0000 to 0x0fff. I wish to get a float value ranging from 0 - 5V and transmit it to through hyperterminal. Is there a function I can use? Thanks!
Ttelmah
Guest







PostPosted: Tue Jan 30, 2007 6:03 am     Reply with quote

First,is '0FFF', 5v, or 4.998v?. If this is the output of a normal 12bit ADC, the behaviour is typically, that the 'reference' voltage (5v), is never actually 'reached', and would correspond to one count more than the full scale of the ADC.
Now, is this really a 'hex' number (ie., held as four ASCII characters), or is this a 16bit binary number that can be represented as the hex values 0000 to 0FFF?. If the latter, then the function, would simply be:

printf("%04.3f",val*1.2207E-3);

where 'val', is the 16bit value, with the output going to stdio. This will send the value, in the form '0.002', with a leading zero, and three dgits after the decimal point.
If instead the value is actually in hex, then a 'hex to bin' conversion will be needed first. The function 'atol', contains the ability to convert such a string to a number (needs '0x' added to the front).

Best Wishes
CcsNewbie
Guest







PostPosted: Wed Jan 31, 2007 5:07 am     Reply with quote

Its e output from a external 12 bit adc connected to my pic. i get a range of 002c to 0fff when i place it to 0 and 5V respectively. I've been tryin to send output to my Visual C# serial port program. Previously i sent it using

printf("%lx\n\r",data)

I've read ure earlier reply to another person and put this in visual C#.

int intValue = (BitConverter.ToInt16(buffer, 0));
//convert value to a range from 0-5V using 12 bit ADC
float voltage = intValue * (5 / 4096);

But I'm sampling @ 250Hz and each time i do a serialport.read(buffer, 0, bytes) I get flooded with around 14-28 bytes in my serial buffer instead of the ideal 2 bytes i tot would be coming in the range 002c to 0fff as seen in hyperterminal. Is there a solution to the problem in the PIC side? Thanks in advance.


Ttelmah wrote:
First,is '0FFF', 5v, or 4.998v?. If this is the output of a normal 12bit ADC, the behaviour is typically, that the 'reference' voltage (5v), is never actually 'reached', and would correspond to one count more than the full scale of the ADC.
Now, is this really a 'hex' number (ie., held as four ASCII characters), or is this a 16bit binary number that can be represented as the hex values 0000 to 0FFF?. If the latter, then the function, would simply be:

printf("%04.3f",val*1.2207E-3);

where 'val', is the 16bit value, with the output going to stdio. This will send the value, in the form '0.002', with a leading zero, and three dgits after the decimal point.
If instead the value is actually in hex, then a 'hex to bin' conversion will be needed first. The function 'atol', contains the ability to convert such a string to a number (needs '0x' added to the front).

Best Wishes
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Wed Jan 31, 2007 10:23 am     Reply with quote

So you have in output in integer A/D counts, and you want it in Volts. I suggest you convert it to integer millivolts (0 to 5000), then just print the thousands, print the decimal point, then print the remaining digits using a putc() for each digit. This avoids floating point and printf() both of which take lots of system resources.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Help needed
Guest







Delay in conversion
PostPosted: Thu Mar 15, 2007 10:29 pm     Reply with quote

Hi,

Can i ask how do i find out the time spent in executing this code?

Code:
printf("%04.3f",val*1.2207E-3);


I'm doing data acq and I suspect this code is taking too much time to execute and I may be having an aliasing problem. Thanks!!
davekelly



Joined: 04 Oct 2006
Posts: 53
Location: Berkshire, England

View user's profile Send private message

Re: Delay in conversion
PostPosted: Fri Mar 16, 2007 4:28 am     Reply with quote

Help needed wrote:
Hi,

Can i ask how do i find out the time spent in executing this code?

Code:
printf("%04.3f",val*1.2207E-3);


I'm doing data acq and I suspect this code is taking too much time to execute and I may be having an aliasing problem. Thanks!!


Simplest way is to use MPLAB, with the simulator as the debugger.

It has a Stopwatch function, which you can reset just before this instruction, then check result after it. Make sure the xtal frequency is set correctly though.
frequentguest
Guest







PostPosted: Fri Mar 16, 2007 6:31 am     Reply with quote

Or, with access to an oscilloscope, set a pin high before the command in question and set it low after. Use the o-scope to measure the elapsed time.
Ttelmah
Guest







PostPosted: Fri Mar 16, 2007 7:52 am     Reply with quote

Seriously, consider using a scaled integer, as as already been mentioned. Floats are _slow_. Remember that to output the digits, involves repeated float divisions by ten. Also, since there are more than two digits, the chip will be waiting for the serial on latter characters (use an interrupt driven serial driver to avoid this).
If you perform:

printf("%04.3w",(INT32)val*1220L);

Then rewrite to use interrupt driven serial transmission through a buffer, the timings will be massively better (orders of magnitude!...).

Best Wishes
Need Help
Guest







PostPosted: Sun Mar 18, 2007 7:28 pm     Reply with quote

Hi, thanks for the input for everyone. May i ask what is an interrupt driven serial driver? Thanks again!
Ttelmah
Guest







PostPosted: Mon Mar 19, 2007 4:26 am     Reply with quote

OK.
The problem with writing directly to the serial port, is that after two characters are sent, you have to start waiting for the hardware buffer to clear, before another character can be sent. This means that a print, that generates (say) ten characters of output, at 9600bps, 8N1 (ten bit times/char), will take 80/9600th second to complete, even if the maths is instantaneous. 8.3mSec. This is an 'age' in computer terms, and can cause problems with timings on other jobs etc..
The 'answer', is to use the same approach as for the serial receive, and perfrom the actual transmission under interrupt control, with a buffer.
Code:

#define TX_BUFFER_SIZE (32)
int8 tx_buffer[TX_BUFFER_SIZE],tx_out=0,tx_in=0;
#define tx_empty (tx_out==tx_in) //test if buffer is empty
#define incbuff(x) ((x+1) & TX_BUFFER_SIZE) //increment buffer pointer
#define tx_full (incbuff(tx_in)==tx_out) //test if buffer is full

void tx_putc(int8 chr) {
   //ensure an interrupt cnnot occur during the buffer update
   disable_interrupts(INT_TBE);
   while (tx_full) {
       //here buffer is full, so wait...
       enable_interrupts(INT_TBE);
       delay_us(10);
       disable_interrupts(INT_TBE)
   }
   //put character in buffer
   tx_buffer[tx_in]=chr;
   //increment input pointer
   tx_in=incbuff(tx_in);
   //and enable interrupt to ensure transmission starts
   enable_interrupts(INT_TBE);
}

#INT_TBE
void serial_tx(void) {
   //Here a serial transmitter buffer empty interrupt has occured
   if (tx_empty) { //if software buffer empty
      disable_interrupts(INT_TBE); //turn off transmission
   }
   else {
      //send character
      putc(tx_buffer[tx_out]);
      //and update pointer
      tx_out=incbuff(tx_out);
   }
}

Now you use this, by sending characters to 'tx_putc', rather than directly to 'putc', and for 'printf' for example, use:

printf(tx_putc,"Test message");

The global interrupt must be enabled, but you don't enable the int_tbe in the main code (this is done automatically, when data is sent).
There are various ways of tweaking this, which may be more efficient but in general an advantage in one area, comes at a cost in another. So (for instance), you can elect to disable the interrupt when the last charater has been sent (cuts the need for one final interrupt call to disable the interrupt, after the data is sent). Or you can elect to send the first character without using the interrupt. However generally, these add complexity, and don't really help overall performance.
As shown, the code will wait if the software buffer is full. Obviously, there are other possible solutions to this (throwing away data for instance). The decision of what is 'best', will depend on the application.

Best Wishes
Need Help
Guest







PostPosted: Tue Mar 20, 2007 8:02 am     Reply with quote

Thanks Ttelmah for your help, may I ask how do i transmit the int32 using the tx_putc?
Ttelmah
Guest







PostPosted: Tue Mar 20, 2007 8:26 am     Reply with quote

Er. Exactly the same way as you'd send it using putc...
Look at the example printf shown.

Best Wishes
Need Help
Guest







PostPosted: Wed Mar 21, 2007 12:45 am     Reply with quote

Hi Ttelmah,

I've tried using the scaled integer but i keep getting 7 digits in hyperterminal although I'm using %04.0w or %04.0lu. How do i truncate the rest when i need only the top 4 digits?

I added the interrupts to my code by my transmit pin keeps outputting a High signal with no output at hyperterminal.

Code:
#include <16F877.h>
#device ADC=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock = 20000000)
#use rs232(baud=9600, xmit = PIN_C6, rcv = PIN_C7)

#define TX_BUFFER_SIZE (32)
int8 tx_buffer[TX_BUFFER_SIZE],tx_out=0,tx_in=0;
#define tx_empty (tx_out==tx_in) //test if buffer is empty
#define incbuff(x) ((x+1) & TX_BUFFER_SIZE) //increment buffer pointer
#define tx_full (incbuff(tx_in)==tx_out) //test if buffer is full

void tx_putc(int8 chr) {

   //ensure an interrupt cnnot occur during the buffer update
   disable_interrupts(INT_TBE);

   while (tx_full) {
       //here buffer is full, so wait...
       enable_interrupts(INT_TBE);
       delay_us(10);
       disable_interrupts(INT_TBE);
   }

   //put character in buffer
   tx_buffer[tx_in]=chr;

   //increment input pointer
   tx_in=incbuff(tx_in);

   //and enable interrupt to ensure transmission starts
   enable_interrupts(INT_TBE);

}

#INT_TBE
void serial_tx(void) {
   //Here a serial transmitter buffer empty interrupt has occured
   if (tx_empty) { //if software buffer empty
   disable_interrupts(INT_TBE); //turn off transmission
   }
   
   else {
      //send character
      putc(tx_buffer[tx_out]);
      //and update pointer
      tx_out=incbuff(tx_out);
   }
}

 void main()
{
   int16 data;     
   setup_adc_ports(ALL_ANALOG); 
   
   setup_adc(ADC_CLOCK_DIV_32);
   set_adc_channel(0);

   enable_interrupts(INT_TBE);
   enable_interrupts(GLOBAL);

   delay_us(20); 

   while(TRUE){

      while(input(PIN_B0))
   {
      data = read_adc();   
      data = (INT32)data*4883L;
      printf(tx_putc,"%04.0w\r",data);
     
      delay_us(40);
   }
   }
}
Need Help
Guest







PostPosted: Wed Mar 21, 2007 7:32 am     Reply with quote

Sorry, posted wrong file, the printf in the main I used was:

Code:

      printf(tx_putc,"%04.0w\r",(INT32)data*4883L);
Ttelmah
Guest







PostPosted: Wed Mar 21, 2007 8:06 am     Reply with quote

You don't...
If you only want the digits in front of the virtaul 'decimal place', then just divide the number by 1000, and print it as a normal decimal. The 'point' about the %w for, is to treat the number as if it has a fixed number of decimal places, so if you use %7.3w, the value will be displayed with three decimal places. To just display the stuff 'in front' of the virtual decimal, just do:

printf(tx_putc,"%04Ld.\r",((INT32)data*4883L)/1000L);

This will add the decimal point.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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