Go Down

### Topic: Displaying 2 decimal places on an LCD (Read 5064 times)previous topic - next topic

#### g4edg

##### Feb 03, 2011, 09:43 pm
I have modified some code posted by DeFex (thank you!) about a year ago, to produce 3 bargraphs on a 4x20 LCD......I'm pleased with the results.

I am using the 4th line of the display to show 3 numerical values calculated from 2 of the values that the bargraphs are monitoring.

The first numerical value I calulated was RF power which involves squaring the value of V2, this displayed as a large interger......I then needed to multiply this by a factor to display the actual RF power.....the factor in this case is 0.00153836. I was amazed to see the value expected displayed to two decimal places!

Previous reading led me to think i would need to apply "floating point" or "double" to produce this result.......

Even multiplying by 1.0 causes the result to be displayed to 2 decimal places. Excellent!! what sets the number of decimal places? Can i change this? Is this something new? See also SWR and V calculations, last 3 "paragraphs" of code.
Code: [Select]
`// include the library code:#include <LiquidCrystal.h>// these constants won't change.  But you can change the size of// your LCD using them:const int numRows = 4;const int numCols = 20;const int V1pin=0;const int V2pin=1;const int V3pin=2;const int V4pin=3;int V1;int V2;int V3;int V4;int val1;int val2;int val3;int val4;//CUSTOM LCD CHARACTERSuint8_t custom_0[8] = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //blankuint8_t custom_1[8] = {   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00}; //1lineuint8_t custom_2[8] = {   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00}; //2lineuint8_t custom_3[8] = {   0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00}; //3lineuint8_t custom_4[8] = {   0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00}; //4lineuint8_t custom_5[8] = {   0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00}; //5lineuint8_t custom_6[8] = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //6line redundant.// initialize the library with the numbers of the interface pinsLiquidCrystal lcd(7, 8, 9, 10, 11, 12); //LCD pins on arduino please see liquidcrystal.h and arduino LCD wiring examples// LiquidCrystal lcd(RS, E, D4, D5, D6, D7)void setup() {  lcd.begin(numRows, numCols);  lcd.createChar(0, custom_0); //send the custom characters to the LCD  lcd.createChar(1, custom_1);  lcd.createChar(2, custom_2);  lcd.createChar(3, custom_3);  lcd.createChar(4, custom_4);  lcd.createChar(5, custom_5);  lcd.createChar(6, custom_6);}void loop() {  val1 = analogRead(V1pin);//read analog inputs (S)  val2 = analogRead(V2pin);//                   (Fwd)  val3 = analogRead(V3pin);//                   (Ref)  val4 = analogRead(V4pin);//                   (V)  V1 = (val1/10.5); //change divider depending on how many segments in a meter  V2 = (val2/6); // changes sensitivity, lower number more sensitive  V3 = (val3/6);  V4 = (val4/10.5);  int vom1 = (V1 / 6);  //divide reading for solid blocks  int rem1 =  (V1 % 6 ); //get modulo for remainder  int vom2 = (V2 / 6);   //6 represents no. of horizontal pixels inc the space  int rem2 =  (V2 % 6 ); //between characters  int vom3 = (V3 / 6);  int rem3 =  (V3 % 6 );  int vom4 = (V4 / 6);  int rem4 =  (V4 % 6 );  //static numbers on LCD changes if you change your meter.  lcd.setCursor(0,0);  //  lcd.print ("S   ");  // Print title for S meter  lcd.setCursor(0,1) ; //  lcd.print ("Fwd ");  // Print title for Forward Power meter  lcd.setCursor(0,2);  //  lcd.print ("Ref ");  // Print title for Reflected Power meter  lcd.setCursor(4,0);       //move cursor to first meter (S)  for (int i=0; i<vom1;i++) {    lcd.print(5,BYTE);  //print 3 vertical lines  }  lcd.print(rem1,BYTE); //print the remainder which is meter segments within character  for (int i=(vom1 + 1); i<16; i ++) { // i<17 segments to be written as blank    lcd.print(" "); //blank spaces after so there is no leftover mess after fast moving meter  }    lcd.setCursor(4,1);       //move cursor to second meter (Fwd)  for (int i=0; i<vom2;i++) {    lcd.print(5,BYTE);  }  lcd.print(rem2,BYTE);  for (int i=(vom2 + 1); i<16; i ++) {    lcd.print(" ");  }    lcd.setCursor(4,2);       //move cursor to 3rd meter (Ref)  for (int i=0; i<vom3;i++) {    lcd.print(5,BYTE);  }  lcd.print(rem3,BYTE);  for (int i=(vom3 + 1); i<16; i ++) {    lcd.print(" ");  }    lcd.setCursor(4,3);  lcd.print((1+((V3*1.0)/(V2*1.0)))/(1-((V3*1.0)/(V2*1.0))));//calculate SWR and print numerical value  lcd.setCursor(0,3);    lcd.print("SWR ");  lcd.setCursor(7,3);  lcd.print(":1");  lcd.setCursor(10,3);  lcd.print(V4/4.4361);//calculate supply voltage from voltage divider V4 and print numerical value  lcd.setCursor(14,3);// Calibration factor = 4.4361  lcd.print("V");  lcd.setCursor(16,3);  lcd.print((V2*V2)*0.00153836);//calculate Forward Power and print numerical value  lcd.setCursor(19,3);// Calibration factor = 0.00153836  lcd.print ("W");  delay(0);  //delay changed to suit your taste, if using rapid interrupt, then delete.}`

#### egdinger

#1
##### Feb 04, 2011, 12:31 am

Previous reading led me to think i would need to apply "floating point" or "double" to produce this result.......

Your not wrong here, you do need to use floating point to get decimals.

Code: [Select]
`lcd.print((V2*V2)*0.00153836);//calculate Forward Power and print numerical value`

Whats happening here is that the compiler is seeing a floating point number, it knows this because of the . point in the number, it then does floating point math and passes the floating point result to lcd.print(). 2 decimal precision I think is the default precision.

You said it works if you use 1.0, again this is because the . lets the compiler know it's floating point value. Try it again with 1, and it won't work.

If you want to find out more, look up type conversion, specifically implicit type conversion in c.

#### pocketscience

#2
##### Feb 04, 2011, 05:47 am
Implicit type conversions are the devils work - well actually I mean to say relying on them is the devils work. The hours spent tracking down weird little bugs because the compiler has done a conversion on your behalf are too numerous. I always try to use explicit conversions, especially with portable code, as rules may change in the future or on another platform - also it's just better practice.

Multiplying a value by 1.0 to force the compiler to give a float result is bad form. Other programmers may look at down the track and ask "wtf?". It's much cleaner if you explicitly cast the values:

lcd.print((1+((float)V3/(float)V2))/(1-((float)V3/(float)V2)));//calculate SWR and print numerical value

Cheers,
G.

#### edarmstrong

#3
##### Feb 04, 2011, 06:00 amLast Edit: Feb 04, 2011, 06:01 am by Ed Armstrong Reason: 1
Yes, 2 decimal places is default. use a comma and a number after your floating point to change it.
example: If you want to set 3 decimal places you would write:
float PinVoltage = 1.234;
lcd.print(PinVoltage,3); // displays voltage value for 3 digits after decimal place command

#### g4edg

#4
##### Feb 04, 2011, 10:02 pm
Hi guys

Thanks very much for the replies..........all very useful, and added to my knowledge bank!

Yes, I did some pretty crude things in this sketch...........like overwriting the second decimal place with the measurement unit i.e. V so that it would look like it was displaying just one decimal place!!

Have modified my code, and although the results look the same as before...........I'm now safe in the knowledge that it is now done properly and will be future proof.

Thanks again

Steve

Go Up