[SOLVED] Problem Displaying a Signed Value with Decimals in LCD

Status
Not open for further replies.

thir13enth

Member level 1
Joined
Feb 23, 2011
Messages
38
Helped
4
Reputation
8
Reaction score
4
Trophy points
1,288
Location
Quezon City, Philippines
Activity points
1,545
Microcontroller: PIC16F877A
IDE: MikroC Pro
Oscillator: XT 20Mhz

---------------------------

Hi everyone, I am not new to electronic forums but I just registered with recently with this forum hoping that there will be some who will enlighten me regarding my problems which cannot be solved on other forums.

First, to explain my project, I am using a gyroscope and an accelerometer as my inputs and two motors as my outputs. Initially, I tested putting a varying DC input with my PIC16F877A in Proteus. I have generated the program below, the only problem I am having right now is, I want to display the value my PIC calculated from my gyroscope on a 16x2 LCD which I cannot make. Here is the code:

Code:
// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections

signed int gz_adc;
unsigned int gz_deg;
unsigned char value;
unsigned short motor1;

void main()
{
     Lcd_Init();                                   // LCD display initialization
     Lcd_Cmd(_LCD_CURSOR_OFF);        // LCD command (cursor off)
     Lcd_Cmd(_LCD_CLEAR);

     ADCON1 = 0x82;                           
     TRISA = 0x03;                              //RA0 & RA1 as inputs
     TRISC = 0x00;                              //Setting Port C as outputs for PWM
     PORTC = 0x00;
    
     PWM1_Init(5000);
     PWM1_Start();

     while (1) 
     {
          gz_adc=ADC_Read(0);                        //Read gyroscope
          motor1=(gz_adc/4);                           //setting a value in motor1
          gz_deg=(((gz_adc*5/1023)-2.5)/.005); //convert value from gyroscope in deg/s                         
          LCD_Chr(1,1,48+gz_deg);      //put the deg/s value as display on the LCD [I][B]PROBLEM IS HERE[/B][/I]
          PWM1_Set_Duty(motor1);                   //Just runs the motor

          delay_ms(100);
    }
}

On Proteus, the value does not seems to display even just a digit of it. My suspicion is that, the value is not in a proper form in order to be displayed on the LCD. The reason why I am asking for help.

I will give an example of a gyroscope reading in deg/s from starlino webpage:

gz_deg = (323 * 3.3V / 1023 – 1.23V) / ( 0.002V/deg/s) =~ -94 deg/s

For kind people out there, I need a help on how to display the signed value.

Thanks!

PS
If I missed some relevant info that I should included with my post, please tell it.
 

unsigned int gz_deg;

gz_deg=(((gz_adc*5/1023)-2.5)/.005); //convert value from gyroscope in deg/s

I guess problem is here. According to formula above your gz_deg value can be negative. But you have initialized it as unsigned int so it can only save from +0 to +65536.

If you try signed int or just int. It should work.8)

:idea: ALSO...in proteus if you burn abc.cof file. It will allow you to see controller's register and VARIABLES that you have assigned. Right Click on Controller while play mode.>>pic CPU>>variables!

GOOD LUCK
CHULLA
 
Thank you for a fast reply Chullaa.

I have tried your recommendation, I have changed the way I initialize my gz_deg into "signed int" and "int" alone. Yet, still no success.

Additional question is, how to burn .cof files in Proteus?
 

If you need to format an integer or float value to send to a display, you can use the sprintf function that is defined in stdio.h.
Example:

Code:
#include <stdio.h>

void display_value(void)
  {
  unsigned int value = 22;
  char buffer[16];  /* size of line on display */
  
  sprintf(buffer, "Value is %d", value);  /* Same formatting options as printf */
  display_line(buffer);                   /* Your call to display function */
  }
 
Thank you for the info btbass.

I have read somewhere that sprintf is not supported in P12 and P16. In such case, it would not be applicable since I am using P16. Sprinti and Sprintl on the other hand do not support float values... T_T
 

stdio.h is part of the standard library so any reasonable compiler should support it?

If you are using a dodgy compiler, you will have to convert your value into an ascii string that can be displayed.
 

I am using Mikroc. It supports Sprinti and Sprintl only, not Sprintf (P12 and P16). A value I am playing around is a float type which can be remedied by the Sprintf. Yet, it is unavailable, if there are still other methods aside from converting the values into ASCII, please do suggest...
 

It is easy enough to convert a digit to ascii, just add 0x30 to it.
The problem is splitting your value into a string of digits.
I'm sure it's been done. Try googling 'float to ascii' and see if anything comes up.
 

hi thir13enth!

1st of all! ABOUT YOUR QUESTION! :idea:
I am not familiar with MikroC Pro. My compiler produces different files on compilation(e.g. abc.h, abc.hex, abc.cof,abc.c ..etc) When i double click controller in proteus it gives me properties where i can browse for my code file. I usually select the file with .cof extension. Then PLAY.
While playing right click on controller give me a list, at the bottom, you will find pic CPU>>variables! BY THE WAY i use PIC CSS compiler.

ALSO if you want to print a int value to LCD. there is way!

for example:a int value is
myint=345;

a=myint/100; /*saves 3 in a
temp=myint%100 /*saves 45 in temp
b=temp/10; /*saves 4 in b
c=temp%10; /*saves 5 in c

now you get a=3, b=4 and c=5
LCD_print(a+48) ;
where LCD_print will send ascii value of 'a'

THIS IS FOR INT. You can generate it for floats with little changes.

GOOD LUCK
CHULLA
 

Code:
gz_deg=(((gz_adc*5/1023)-2.5)/.005);
Except for becoming negative with some values of gz_adc, there's a more basic problem with this expression considering the C language rules for implicite type conversion.
C expressions are evaluated left to right, if not otherwise commanded by parenthesis, so gz_adc*5/1023 will be calculated first as an integer expression, because all arguments are integer. The result will have 6 possible results: 0,1,2,3,4,5. I guess, that's not what you want. Instead, you would want to multiply gz_adc with a float constant gz_adc*(5.0/1023), or rearrange the expression to save some arithmetic effort:
Code:
gz_deg = (int)(gz_adc*(5.0/1023/.005))-500;
Alternatively, the calculation can be performed with long (don't know, if it's supported by Micro C) - P.S.: Apparently it does.
Code:
gz_deg = (int)((long)gz_adc*1000/1023)-500;

It's always funny to see people creating BCD numbers and strings by % and / operators, but even mikroC has conversion functions for it, consult the compiler manual.
 
Last edited:
I had a whole day this day so I have not checked the forums recently. I am overwhelmed with replies and thanks for the effort everyone. Thanks for the replies btbass, Chullaa, and FvM.

At btbass:
Converting float requires some methods in coding. Honestly I find the process long because my main purpose of having this is actually, just to simulate an analog input reading and get its equivalent in deg/s using the formula I have provided. Perhaps, I will be needing a straightforward direction on my way since this would not be very useful on future steps of my project.

At Chulla:
I am familiar with the code you have provided and I appreciate your efforts, thanks for it. If I use the same coding, the problem will lie when my value becomes a float. I guess that would be a problem if I will retain the steps in coding.

At FvM:
Definitely I was looking for a straightforward coding. Arguments are treated in nature but I am having problems displaying it when it becomes a float. Further explanation with my code:

gz_deg=((((gz_adc*5000)/1023)-2500)/5)

There I have converted some constants to make it easier to our eyes. I need to get first the value of gz_adc, and I will provide the steps I need.

1. gz_adc value from my input, ranges 0-1023.
2. gz_adc*5000 // there is no problem here, the maximum value is 1023*5000=5115000 (that is an unsigned long)
3. (gz_adc*5000)/1023 // my problem lies here, supposed gz_adc=1; (1*5000)/1023=4.88... (it is already a float T_T)
4. ((gz_adc*5000)/1023)-2500 // using the 4.88... value; 4.88...-2500=-2495.11... (the value is still a float)
5. Now, I will be dividing the float value into 500, the result will become -4.99... which is again a float.

Finally, I wanted to display this float (-4.99) on the LCD which I cannot seem to make work. Help please?
 

:smile: Fvm you are may be right! But i am just a beginner. I have just started programming a months back. so i dont know a lot of things.. I found lcd_load() command for my complier.. i will look at it. Tx :razz:
 

I have solved the problem!

Here is the solution I made:

Code:
{
          gz_adc=ADC_Read(0);
          gz_deg=((((float)((long)gz_adc*5)/1023)-2.5)/.005);
          FloatToStr(gz_deg, value);
          LCD_Out(1,1,value);
          delay_ms(100);

    }

gz_adc is an unsigned int
gz_deg is a float


Thanks for all those who replied with my post! (especially with the idea of FvM) xD
 

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…