Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[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:
20150924_182140.jpg
PIC2:
20150924_182125.jpg
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.
Section 6.2.1.5 - Usual Arithmetic Conversions of the ANSI C standard states:
"Many binary operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions:
First, if either operand has type long double, the other operand is converted to long double.
Otherwise, if either operand has type double, the other operand is converted to double.
Otherwise, if either operand has type float, the other operand is converted to float.
Otherwise, the integral promotions are performed on both operands. Then the following rules are applied:
If either operand has type unsigned long int, the other operand is converted to unsigned long int.
Otherwise, if one operand has type long int and the other has type unsigned int if a long int can represent all values of an unsigned int the operand of unsigned int is converted to long int; if a long int cannot represent all the values of an unsigned int both operands are converted to unsigned long int.
Otherwise, if either operand has type long int, the other operand is converted to long int.
Otherwise, if either operand has type unsigned int, the other operand is converted to unsigned int.
Otherwise, both operands have type int.
The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby."
So, if both operands have type int, then the result also has type int. If either operand is a long int, then the other operand is converted to a long int and the result is a long int. Our compiler is ANSI C compliant so the following examples produces a long result if a and b are ints:
prodl = (long)a * b;
prodl = a *(long)b;
prodl = (long)a * (long)b;
The following line does not yield the expected 32-bit result either. First a and b are multiplied, but according to the ANSI C Standard, the result is an int. The int is then cast to a long and assigned to prodl:
prodl = (long)(a * b);
Note that on some compilers an int is stored using 32 bits, while on other compilers, an int is stored using 16 bits. The Keil compilers store int types using 16 bits. This explains why some compilers do produce a 32-bit value (they support 32-bit int types).
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top