2

I'm trying to make a embedded c project where i will input 7 chars and make some calculations with them - now i got problem getting my conversion to work - I'm working with a ATMEGA 2560, where I output the chars on uart.

Here's the code:

volatile char daata[8] = "123:456\0";
volatile char recdata[8];
volatile char data = 0;
volatile char byte;
volatile int minimum;
volatile int maximum;
volatile char mx;
volatile char mi;

and my function uses:

void putsUSART0(char *ptr)
{
    while(*ptr)
    {
        putchUSART0(*ptr);
        ptr++;
    }
}

and

void putchUSART0(char tx)
{
    while(!(UCSR0A & (1 << UDRE0)));   // wait for empty transmit buffer

    UDR0 = tx;
}

where the code im working on is:

minimum = (100 * (daata[0] - 0x30) + 10 * (daata[1] - 0x30) + daata[2] - 0x30);
maximum = daata[6] - 0x30 + 10 * (daata[5] - 0x30) + 100 * (daata[4]);

mi = minimum + 0x30;
putsUSART0("mimimum is:");
//putchUSART0(minimum );
putsUSART0(mi);
putsUSART0("maximum is:");
putchUSART0(maximum);
_delay_ms(5000);
status = requestsample;

The problem is that my output is

mimimum is:maximum is:ˆ

Can anyone explain the strange behavior.

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
Martin
  • 59
  • 1
  • 6
  • 1
    You don't say what output you want. I guess you want to format the numeric values as decimal; you might do that using the inverse of the operations you used to read the decimal values. – Mike Seymour May 05 '15 at 13:07

2 Answers2

4
char buf[15];
...
mi = minimum + 0x30;
sprintf(buf, "%d", mi);
putsUSART0("mimimum is:");
//putchUSART0(minimum );
putsUSART0(buf);

Do similar for maximum also

You are sending the value of ASCII character (and trying to convert it to character by adding 0x30 which is not the right way, you need to convert all digits) and possibly printing it without conversion at the other end.


From kind comment of Lundin

sprintf() is probably not an option, as this is an embedded project, where that function usually is far too slow and memory-consuming.

You can also write your own function that can convert a number to string:

const char *numToStr(int n) {
  /* Non-reentrant, returned buffer will be invalidated on subsequent call */
#define BUF_SIZE 15
  static char buf[BUF_SIZE] = {0};
  int pos = BUF_SIZE - 1;
  int neg = 0;
  if(n < 0) {
    neg = 1;
    n *= -1;
  }
  do {
    buf[--pos] = (n % 10) + '0';
    n /= 10;
  } while(n);
  if(neg) buf[--pos] = '-';
  return &buf[pos];
}

And use this to convert number to string.


From kind comment of Chux

Fails for numToStr(INT_MIN) Suggest if(n < 0) { neg = 1; } else { n = -n; } do { buf[--pos] = '0' - (n % 10); n /= 10; } while(n);

A version to handle INT_MIN can be written as:

const char *numToStr(int n) {
  /* Non-reentrant, returned buffer will be invalidated on subsequent call */
#define BUF_SIZE 15
  static char buf[BUF_SIZE] = {0};
  int pos = BUF_SIZE - 1;
  int neg = 0;
  if(n < 0) {
    neg = 1;
  } else {
    n = -n;
  }
  do {
    buf[--pos] = '0' - (n % 10);
    n /= 10;
  } while(n);
  if(neg) buf[--pos] = '-';
  return &buf[pos];
}
Community
  • 1
  • 1
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • 1
    sprintf() is probably not an option, as this is an embedded project, where that function usually is far too slow and memory-consuming. – Lundin May 05 '15 at 13:11
  • @Lundin Hmmm, then possibly some function that does the reverse. i.e. set buf[14] to `'\0'` and buf[13...] with successive digits and return the pointer to the most significant digit. I will try to add one such example. – Mohit Jain May 05 '15 at 13:14
  • Perfect - worked like a charm :) but had to remove 0x30 from mi = minimum + 0x30; – Martin May 05 '15 at 13:16
  • 1
    @Martin And you just blew up 25% or so of the total RAM memory available of your ATmega 2560... Check you map file, then go back to your original code. – Lundin May 05 '15 at 13:21
  • Or indeed roll out your own conversion routine, feel free to use [this one](http://stackoverflow.com/questions/9994742/want-to-convert-integer-to-string-without-itoa-function/10011878#10011878). – Lundin May 05 '15 at 13:24
  • Fails for `numToStr(INT_MIN)` Suggest `if(n < 0) { neg = 1; } else { n = -n; } do { buf[--pos] = '0' - (n % 10); n /= 10; } while(n);` – chux - Reinstate Monica May 05 '15 at 17:14
0

daata[4] should be daata[4] - 0x30. This causes you to get 100*52 instead of 100*4 as intended.

The way to avoid simple bugs like this is some coding discipline: don't put everything on the same line, be consistent and avoid "magic numbers".

minimum =   (100 * (data[0] - '0') 
          + ( 10 * (data[1] - '0') 
          + (  1 * (data[2] - '0');

maximum =   (100 * (data[4] - '0'))
          + ( 10 * (data[5] - '0'))
          + (  1 * (data[6] - '0'));
Lundin
  • 195,001
  • 40
  • 254
  • 396