[SOLVED] convert uint32_t to asci for LCD doesn't work

Status
Not open for further replies.

arek944

Newbie level 3
Joined
Feb 22, 2011
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Location
Poland, Olsztyn
Activity points
1,314
Hello,
I'm building a peristaltic pump controller on ATmega88 and I'd like to display approximate dose applied on LCD. Calculations are quite simple:
Code:
dose = ((x_speed_val * x_time_meter) / 60);
where:
x_speed_val is pump efficiency in [ml/min] - max value is 170 (170 gives 17.0 ml/min)
x_time_meter is time set in [sec] - max value is 600 (10 minutes)
So solving the equation for max values I should get: dose = 170 x 600 / 60 = 1700 (1700 means that 170.0ml has been pumped).
But my dispay function doesn't work that way. It displays the applied dose value corret until about 109.0ml (1090) afterwards the display function starts counting from 0.
Code for disp function:

Code:
volatile uint8_t x_speed_val = 0;
volatile uint16_t x_time_meter = 0;
volatile uint32_t dose = 0;

Code:
     if (update_lcd5)
        {
          dose = ((x_speed_val * x_time_meter) / 60);
          LCD_XY(1,0);
          LCD_WRITE_DOSE(dose);
          update_lcd5 = F;
        }

version 1:

Code:
void LCD_WRITE_DOSE (uint32_t num_sign)
{
  uint8_t num[4];
  uint32_t Dig_0, Dig_1, Dig_2, Dig_3;

  Dig_3 = num_sign/1000;
  num[3] = Dig_3 + '0';
  num_sign  = num_sign - (Dig_3 * 1000);

  Dig_2 = num_sign/100;
  num[2] = Dig_2 + '0';
  num_sign  = num_sign - (Dig_2 * 100);

  Dig_1 = num_sign/10;
  num[1] = Dig_1 + '0';
  num_sign  = num_sign - (Dig_1 * 10);

  Dig_0 = num_sign;
  num[0] = Dig_0 + '0';

  LCD_WRITE_CHAR(num[3]);
  LCD_WRITE_CHAR(num[2]);
  LCD_WRITE_CHAR(num[1]);
  LCD_WRITE_CHAR('.');
  LCD_WRITE_CHAR(num[0]);
}

version 2:
Code:
void LCD_WRITE_DOSE (uint32_t num_sign)
{
  uint8_t i;
  uint8_t num[4];

  num_sign = (num_sign-20) * 5;
  for (i=0; i<=3; num_sign/=10, i++)
    {
      num[i] = num_sign % 10 +'0';
    }
  LCD_WRITE_CHAR(num[3]);
  LCD_WRITE_CHAR(num[2]);
  LCD_WRITE_CHAR(num[1]);
  LCD_WRITE_CHAR('.');
  LCD_WRITE_CHAR(num[0]);
}

Both versions of the display function work the same way. Can anyone help me out? It seems like ATmega88 can't handle uint32_t variable and all of calculations are cast on uint16_t.
 

Hi,

how did you test it?

You didn´t accidentally change x_speed_val to over 255? (i know you said max = 170).

But this is the only issue I see. It is defined as 8 bit value.
Just for fun: try to define it as unit16.

Klaus
 

Thanks for the quick reply!
No, there is no way the x_speed_val could be any different as displayed. x_speed_val is set from an rotary encoder and its value is directly equaled to OCR0. Layout of information on LCD is following
PIC1:

PIC2:

I calculated some things and here are my thoughts:
In PIC1 dose equal as following:
dose = (170 x 385) / 60 = 65450 / 60 = 1090 (109.0ml) - x_speed_val * x_time_meter is lesser than 16 bit value and everything is displayed correctly.
In PIC2 should be:
dose = (170 x 386) / 60 = 65620 / 60 = 1093 (109.3ml) - here x_speed_val * x_time_meter is greater than 16 bit so something in my code cast the value to 16 bit and we have:
dose = (170 x 386) / 60 = 84 / 60 = 1 (000.1ml)

I have no idea where the error occurs, despite similar functions display time set and reverse angle.
 

Try this modification:
Code:
if (update_lcd5)
        {
          dose = (( [U][B](uint32_t)[/B][/U] x_speed_val * x_time_meter) / 60);
          LCD_XY(1,0);
          LCD_WRITE_DOSE(dose);
          update_lcd5 = F;
        }

For up to 4 digit numbers, the LCD_WRITE_DOSE version 1 works, the second one would work if the following line is removed:
Code:
num_sign = (num_sign-20) * 5;

test example:
Code:
#include <stdio.h>

#define LCD_WRITE_CHAR(x) putchar(x)
typedef long uint32_t;
typedef unsigned char uint8_t;

void LCD_WRITE_DOSE1 (uint32_t num_sign)
{
  uint8_t num[4];
  uint32_t Dig_0, Dig_1, Dig_2, Dig_3;

  Dig_3 = num_sign/1000;
  num[3] = Dig_3 + '0';
  num_sign  = num_sign - (Dig_3 * 1000);

  Dig_2 = num_sign/100;
  num[2] = Dig_2 + '0';
  num_sign  = num_sign - (Dig_2 * 100);

  Dig_1 = num_sign/10;
  num[1] = Dig_1 + '0';
  num_sign  = num_sign - (Dig_1 * 10);

  Dig_0 = num_sign;
  num[0] = Dig_0 + '0';

  LCD_WRITE_CHAR(num[3]);
  LCD_WRITE_CHAR(num[2]);
  LCD_WRITE_CHAR(num[1]);
  LCD_WRITE_CHAR('.');
  LCD_WRITE_CHAR(num[0]);
}
void LCD_WRITE_DOSE2 (uint32_t num_sign)
{
  uint8_t i;
  uint8_t num[4];

//  num_sign = (num_sign-20) * 5;
  for (i=0; i<=3; num_sign/=10, i++)
    {
      num[i] = num_sign % 10 +'0';
    }

  LCD_WRITE_CHAR(num[3]);
  LCD_WRITE_CHAR(num[2]);
  LCD_WRITE_CHAR(num[1]);
  LCD_WRITE_CHAR('.');
  LCD_WRITE_CHAR(num[0]);
}

void main(){
        printf("version 1\n");
	LCD_WRITE_DOSE1 (1234);
        printf("\n\nversion 2\n");
	LCD_WRITE_DOSE2 (1234);
}
and the results:
version 1
123.4

version 2
123.4
 
xenos, You are a genius!
Your modification
Code:
dose = (( (uint32_t) x_speed_val * x_time_meter) / 60);
worked like a charm! So siple yet so helpfull :-D

Regarding this part
Code:
num_sign = (num_sign-20) * 5;
it was my mistake to paste it uncommented. This part of code was added to display pump efficiency in [%] of rotation speed, but found it very inconvenient for practical use, as it din't told anything about real efficiency.

Anyway, thanks a lot guys! :-D
 

Here is an explanation of the rules of multiplication and the type results of that multiplication...

Here is the summary of those rules extracted from that page.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…