EmbDev.net

Forum: ARM programming with GCC/GNU tools help with rprintf


Author: Sevc Dominik (sevc)
Posted on:

Rate this post
0 useful
not useful
Hi all.
On example for LPC are used function rprintf to serial port .
But I can't print float value (double).
can some help???
regards

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
I just downloaded the examples and looked at the code and it quite
clearly says in the boiler-plate comment:

------------
// Todo:
// %f, %F for floating point numbers
------------

It is a 'reduced' printf after all and fp handling would increase the
size. Use the  standard printf if you need full functionality.

Clifford

Author: Martin Thomas (mthomas) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Sevc Dominik wrote:
> But I can't print float value (double).

The rprintf in the Michael Wolf's Project in the thread "[ANN]
AT91SAM7S-128 USB MSD Example" includes a rprintf with FP support.
(While most of the projects seems to be under GPL license the lincense
for the rprintf-code seems to be BSD or BSD-compatible and so reather
unrestricted)

Author: Sławomir Wilczewski (wil)
Posted on:

Rate this post
0 useful
not useful
Sevc Dominik wrote:
> Hi all.
> On example for LPC are used function rprintf to serial port .
> But I can't print float value (double).
> can some help???
> regards

You are welcome to use following files:

rprintf.h:
==============
#ifndef __PRINTF_H
#define __PRINTF_H

extern void rputs(char const *txt);
extern void rprintf(char const *fmt0, ...);

#endif


rprintf.c:
===========
//###################################################################### 
########
// (r)printf.c
//
// code based on sprintf() from gcctest9.c by Volker Oth
//
// Changes made by Holger Klabunde:
// Now takes format strings from FLASH (was into RAM ! before)
// Fixed bug for %i, %I. u_val was used before it had the right value
// Added %d, %D (is same as %i, %I)
// Support for long variables %li, %ld, %Lu, %LX ....
// %x, %X now gives upper case hex characters A,B,C,D,E,F
// Output can be redirected in a single function: myputchar()
// Make printf() smaller by commenting out a few #defines
// Added some SPACE and ZERO padding %02x or % 3u up to 9 characters
//
// Changes made by Martin Thomas:
// LPC2000 port using the R O Software UART-Interface (see myputchar)
// ARM7S   port using minimal uart interface
// reverted Klabundes "from flash" since only useful for AVR "Harvard"
//
// Changes made by Sławomir Wilczewski:
//   - added %f, %F for floating point numbers conversion
//  -  accuracy max 1 digit, width max 2 digits in format string (ex: %
10.4f)
//  -  max number of characters (incl. sign): to fit into buffer SCRATCH
size
//  -  floating point conversion code size is 6.5kB in .text area
//
//###################################################################### 
########

#include <stdarg.h>
#include <string.h>
#include "rprintf.h"

#define SCRATCH 12  //32Bits go up to 4GB + 1 Byte for \0

//Spare some program space by making a comment of all not used format
flag lines
#define USE_LONG        // %lx, %Lu and so on, else only 16 bit integer
is allowed
//#define USE_OCTAL      // %o, %O Octal output. Who needs this ?
#define USE_STRING      // %s, %S Strings as parameters
#define USE_CHAR        // %c, %C Chars as parameters
#define USE_INTEGER      // %i, %I Remove this format flag. %d, %D does
the same
#define USE_HEX          // %x, %X Hexadezimal output
#define USE_UPPERHEX    // %x, %X outputs A,B,C... else a,b,c...
#ifndef USE_HEX
 #undef USE_UPPERHEX    // ;)
#endif
#define USE_UPPER        // uncommenting this removes
%C,%D,%I,%O,%S,%U,%X and %L..
                        // only lowercase format flags are used
#define PADDING         //SPACE and ZERO padding

#define USE_FLOAT        // %f %F floating point numbers as parameters.


//float params
#ifdef USE_FLOAT
  #define LEFT_ALIGN      0x01
  #define SHOW_SIGN        0x02
  #define MINUS_ONLY      0x04
  #define SHOW_ALTERNATE  0x08  //always display dot
  #define NEGATIVE        0x10

  //defaults:
  #define DFLT_F_ACCURACY  2
  #define DFLT_F_WIDTH    6
  #define DFLT_F_FILL      ' '

static char * strrev( char * pa );
unsigned char* ftoa( float f, char const *format, unsigned char
*ucaFloat );

#endif



#include "lcd.h"

static void myputchar( unsigned char c ){
    LCDPreter( c );
}



void rprintf( char const *format, ... ){
  unsigned char scratch[SCRATCH];
  unsigned char format_flag;
  unsigned short base;
  unsigned char *ptr;
  unsigned char issigned=0;
  va_list ap;

#ifdef USE_LONG
  unsigned char islong=0;
  unsigned long u_val=0;
  long s_val=0;
#else
  unsigned int u_val=0;
  int s_val=0;
#endif

#ifdef USE_FLOAT
  double f_val = 0;
  char const * pStr;
#endif

  unsigned char fill;
  unsigned char width;

  va_start (ap, format);
  for (;;){
    while ((format_flag = *(format++)) != '%'){      // Until '%' or
'\0'
      if (!format_flag){va_end (ap); return;}
      myputchar(format_flag);
    }

#ifdef USE_FLOAT
    pStr = format;
    fill = 0;

     while( *pStr ){
      if( ( *pStr == 'l' ) || ( *pStr == 'L' ) ) break;
      if( ( *pStr == 'o' ) || ( *pStr == 'O' ) ) break;
      if( ( *pStr == 's' ) || ( *pStr == 'S' ) ) break;
      if( ( *pStr == 'c' ) || ( *pStr == 'C' ) ) break;
      if( ( *pStr == 'i' ) || ( *pStr == 'I' ) ) break;
      if( ( *pStr == 'd' ) || ( *pStr == 'D' ) ) break;
      if( ( *pStr == 'u' ) || ( *pStr == 'U' ) ) break;
      if( ( *pStr == 'x' ) || ( *pStr == 'X' ) ) break;

      if( ( *pStr == 'f' ) || ( *pStr == 'F' ) ){
        fill = 1;
        f_val = va_arg( ap, double );
        ptr = ftoa( (float)f_val, format, scratch );
        format = ++pStr;
        while( *ptr ) { myputchar( *ptr ); ptr++; }
        break;
      }
      pStr++;
    }
    if( fill ) continue;
#endif

    issigned=0; //default unsigned
    base = 10;

    format_flag = *format++; //get char after '%'

#ifdef PADDING
    width=0; //no formatting
    fill=0;  //no formatting
    if(format_flag=='0' || format_flag==' ') //SPACE or ZERO padding  ?
    {
      fill=format_flag;
      format_flag = *format++; //get char after padding char
      if(format_flag>='0' && format_flag<='9')
       {
        width=format_flag-'0';
        format_flag = *format++; //get char after width char
       }
     }
#endif

#ifdef USE_LONG
    islong=0; //default int value
#ifdef USE_UPPER
    if(format_flag=='l' || format_flag=='L') //Long value
#else
    if(format_flag=='l') //Long value
#endif
     {
      islong=1;
      format_flag = *format++; //get char after 'l' or 'L'
     }
#endif

    switch (format_flag)
    {
#ifdef USE_CHAR
    case 'c':
#ifdef USE_UPPER
    case 'C':
#endif
      format_flag = va_arg(ap,int);
      // no break -> run into default
#endif

    default:
      myputchar(format_flag);
      continue;

#ifdef USE_STRING
#ifdef USE_UPPER
    case 'S':
#endif
    case 's':
      ptr = (unsigned char*)va_arg(ap,char *);
      while(*ptr) { myputchar(*ptr); ptr++; }
      continue;
#endif

#ifdef USE_OCTAL
    case 'o':
#ifdef USE_UPPER
    case 'O':
#endif
      base = 8;
      myputchar('0');
      goto CONVERSION_LOOP;
#endif

#ifdef USE_INTEGER //don't use %i, is same as %d
    case 'i':
#ifdef USE_UPPER
    case 'I':
#endif
#endif
    case 'd':
#ifdef USE_UPPER
    case 'D':
#endif
      issigned=1;
      // no break -> run into next case
    case 'u':
#ifdef USE_UPPER
    case 'U':
#endif

//don't insert some case below this if USE_HEX is undefined !
//or put       goto CONVERSION_LOOP;  before next case.
#ifdef USE_HEX
      goto CONVERSION_LOOP;
    case 'x':
#ifdef USE_UPPER
    case 'X':
#endif
      base = 16;
#endif

    CONVERSION_LOOP:

      if(issigned) //Signed types
       {
#ifdef USE_LONG
        if(islong) { s_val = va_arg(ap,long); }
        else { s_val = va_arg(ap,int); }
#else
        s_val = va_arg(ap,int);
#endif

        if(s_val < 0) //Value negativ ?
         {
          s_val = - s_val; //Make it positiv
          myputchar('-');    //Output sign
         }

        u_val = (unsigned long)s_val;
       }
      else //Unsigned types
       {
#ifdef USE_LONG
        if(islong) { u_val = va_arg(ap,unsigned long); }
        else { u_val = va_arg(ap,unsigned int); }
#else
        u_val = va_arg(ap,unsigned int);
#endif
       }

      ptr = scratch + SCRATCH;
      *--ptr = 0;
      do
       {
        char ch = u_val % base + '0';
#ifdef USE_HEX
        if (ch > '9')
         {
          ch += 'a' - '9' - 1;
#ifdef USE_UPPERHEX
          ch-=0x20;
#endif
         }
#endif
        *--ptr = ch;
        u_val /= base;

#ifdef PADDING
        if(width) width--; //calculate number of padding chars
#endif
      } while (u_val);

#ifdef PADDING
     while(width--) *--ptr = fill; //insert padding chars
#endif

      while(*ptr) { myputchar(*ptr); ptr++; }
    }
  }
}


#ifdef USE_FLOAT
static char* strrev( char *pa ){
  char * pStr;
  char c;
  int i, len;


  pStr = pa;
  len = 0;

  while( *pStr++ )  ++len;
  if( len < 2 ) return pa;

  for( i = 0; i < len / 2; ++i ){
    c = *( pa + i );
    *( pa + i ) = *( pa + len - 1 - i );
    *( pa + len - 1 - i ) = c;
  }
  return pa;
}
#endif


#ifdef USE_FLOAT

unsigned char* ftoa( float f, char const *format, unsigned char
*ucaFloat ){
  char  cFlag,
        cWidth = DFLT_F_WIDTH,
        cAccuracy = DFLT_F_ACCURACY,
        * pStr,
//        caTemp[ 82 ],
        caTemp[ 2 * SCRATCH ],
        caFillChar[ 2 ] = " ";  //space or zero

  char const    * pcStr;

  unsigned long  i, j;
  unsigned long long  lNumber;



  //find accuracy or use default
  pcStr = --format;
  while( *pcStr++ ){
    if( ( *pcStr == 'f' ) || ( *pcStr == 'F' ) ) break;
    if( *pcStr == '.' ){  //assume 1 digit for accuracy
      if( ( *( pcStr + 1 ) == 'f' ) || ( *( pcStr + 1 ) == 'F' ) )
cAccuracy = 0;
      else cAccuracy = *( pcStr + 1 ) - '0';
      break;
    }
  }

  //find width or use default. Max 2 digits.
  cFlag = 0;
  pcStr = format;
  while( *pcStr++ ){
    if( ( *pcStr == 'f' ) || ( *pcStr == 'F' ) || ( *pcStr == '.' ) )
break;
    if( ( *pcStr >= '0' ) && ( *pcStr <= '9' ) ){
      if( ( *pcStr == '0' ) && ( cFlag == 0 )){  //leading zero (fill
char)
        *caFillChar = '0';
        *( caFillChar + 1 ) = 0;
        continue;
      }
      *( caTemp + cFlag ) = *pcStr;
      ++cFlag;
    }
  }
  *( caTemp + cFlag ) = 0;
  if( strlen( caTemp ) > 0 ){
    strrev( caTemp );

    cWidth = 0; i = 1;
    pStr = &caTemp[ 0 ];
    while( *pStr ){
      cWidth += ( *pStr - '0' ) * i;
      i *= 10;
      pStr++;
    }
  }

  //special format characters
  cFlag = 0;
  pcStr = format;

  while( *pcStr++ ){
    if( ( *pcStr == 'f' ) || ( *pcStr == 'F' ) || ( *pcStr == '.' ) )
break;
    if( ( *pcStr >= '0' ) && ( *pcStr <= '9' ) ) break;

    if( *pcStr == '-' ) cFlag |= LEFT_ALIGN;
    if( *pcStr == '+' ) cFlag |= SHOW_SIGN;
    if( *pcStr == ' ' ) cFlag |= MINUS_ONLY;
    if( *pcStr == '#' ) cFlag |= SHOW_ALTERNATE;
  }
  //to do: eliminate invalid / useless format combinations

  if( f < 0 ){
    cFlag |= NEGATIVE;
    f = -f;
  }

  if( cAccuracy > 0 )
    for( i = 0; i < cAccuracy; ++i ) f *= 10;

  lNumber = (unsigned long long)( f );
  if( ( ( (unsigned long long)( f * 10 ) ) % 10 ) >= 5 ) lNumber++;
//rounding


  //conversion to ascii
  pStr = &caTemp[ 0 ];
  *pStr = 0;
  do{
    *pStr++ = ( lNumber % 10 ) + '0';
    lNumber /= 10;
  } while( lNumber );
  *pStr = 0;

  //handling small numbers
  if( ( j = strlen( caTemp ) ) <= cAccuracy ){
    for( i = 0; i < cAccuracy - j; ++i ){
      *( caTemp + j + i ) = '0';
    }
    *( caTemp + cAccuracy ) = '0';  //ensure 0 before dot
    *( caTemp + cAccuracy + 1 ) = 0;
  }

  //insert dot
  i = strlen( caTemp );
  *( caTemp + i + 1 ) = 0;

  for( j = 0; j < i - cAccuracy; ++j )
    *( caTemp + i - j ) = *( caTemp + i - j - 1 );

  *( caTemp + cAccuracy ) = '.';


  //check size
  if( ( strlen( caTemp ) > SCRATCH - 2 )  // one char for sign
      || ( cWidth > SCRATCH - 2 ) )
  {
    *ucaFloat = 0;
     *ucaFloat = '?';
    *( ucaFloat + 1 ) = 0;
    return ucaFloat;
  }

  //sign processing
  *ucaFloat = 0;
  //show sign with 0 ??
  if( cFlag & NEGATIVE ){
    *ucaFloat = '-';
    *( ucaFloat + 1 ) = 0;
    if( cWidth > 1 ) --cWidth;  //include sign into string width
  }
  else{
    if( cFlag & SHOW_SIGN ){
      *ucaFloat = '+';
      *( ucaFloat + 1 ) = 0;
      if( cWidth > 1 ) --cWidth;
    }
    if( cFlag & MINUS_ONLY ){  //insert space in this case
      *ucaFloat = ' ';
      *( ucaFloat + 1 ) = 0;
      if( cWidth > 1 ) --cWidth;
    }
  }

  //formating
  if( cFlag & SHOW_ALTERNATE ){};  //dot always inserted

  //fill character.
  if( ( cFlag & LEFT_ALIGN ) == 0 ){  //leading fill chars
    while( strlen( caTemp ) < cWidth )
      strcat( caTemp, caFillChar );
  }
  strrev( caTemp );

  if( cFlag & LEFT_ALIGN ){
    while( strlen( caTemp ) < cWidth )
      strcat( caTemp, caFillChar );
  }
  strcat( (char*)ucaFloat, caTemp );

  return ucaFloat;
}
#endif

Author: ciccio (Guest)
Posted on:

Rate this post
0 useful
not useful
I LOVE YOU!

Ciccio.

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.