String formatting

I am trying to convert a code written for pic16f886 to Arduino. I am facing issues in string formatting. In PIC the code was

char look(int a){
   switch(a){
       case 0:
              return '0';
       case 1:
              return '1';
       case 2:
              return '2';
       case 3:
              return '3';
       case 4:
              return '4';
       case 5:
              return '5';
       case 6:
              return '6';
       case 7:
              return '7';
       case 8:
              return '8';
       case 9:
              return '9';
       default:
              return '.';
   }
}
unsigned int amps = 1835;
display_va(0, 0, 1835, 'A');

void display_va( char pos_row, char pos_col, unsigned int value, char type){
unsigned char va[] = "00.00 ";
        va[0] = look(value/1000);
        va[1] = look((value/100)%10);
        va[3] = look((value/10)%10);
        va[4] = look((value/1)%10);
        va[5] = type;
        Lcd_out(pos_row, pos_col, va);

this would print 18.35A starting at row 0 column 0. I am trying to achieve this in arduino. I tried

long amps = 00.00;
amps = 1835;
amps = 1835 / 100;
lcd.setCursor(0,0);
lcd.print(String(amps) + "A");

it prints 18.35A which is ok but if amps is 183 it prints 1.83AA. the previous "A" remains. one way would be to use If statement and delete the extra "A" if amps<1000. Is there a better way that the "A" would be fixed in the same column and numbers are displayed close to "A"

which arduino are you using? (sprintf could be an option)

BTW the code from the pic would work and you would just print the va array. because it's fixed size you would not have the issue of length but you might get leading zeros.

1 Like

I am using Arduino nano. I tried using LCD.print(va); I get the error,no matching function for call to 'print(unsigned char[6]'

Omit the 'unsigned' when defining va:

char va[] = "00.00 ";

I don't get any error but nothing prints

No, you must be misremembering. It would only print "18A"

Please show the complete sketch as it is now.

N.b. I think sprintf() as suggested by @J-M-L would be a much more easy solution.

the sketch is work in progress. I had written the whole program for pic and now i am converting little by little to arduino nano. the code so far

#include<LiquidCrystal.h>
#include <avr/interrupt.h>
#include <avr/io.h>
//#include <cstdio.h>
LiquidCrystal lcd (7,8,9,10,11,12); // Define LCD display pins RS, E, D4, D5, D6, D7
const int SpeedoPin = 2;
const int MenuPin = 6;
const int PlusPin = 5;
const int MinusPin = 4;
const int BuzzPin = 3;
volatile unsigned long millis_count = 0;
unsigned int a = 0, volts = 0, vadc, save_maH, batt_cap, amps;
float mAsec;
unsigned char flag_200ms = 0;                                                   // set HIGH once 0.2 second (200ms)
unsigned char charging_flag;                                                    // 1=charging, 0=discharging

void SpeedoIn();
void power_calc();
void display_va( char col, char row, unsigned long value, char type);
void display_percent_watt(char row, char col, unsigned int value, char type);


void setup() {
  // put your setup code here, to run once:
  // Disable Global Interrupts
  //cli();
  noInterrupts();
  // Set Timer1 to Normal Mode
  TCCR1A = 0; // Set Entire TCCR1A register to 0
  TCCR1B = 0; //(1 << WGM12); // Set Entire TCCR1B register to 0
  TCCR1B |= B00000001; // Prescaler = 1
  TCNT1 = 49535;  // Timer Preloading
  TIMSK1 |= B00000001;
  
  
  // Enable Global Interrupts
  //sei();
  interrupts();
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BuzzPin, OUTPUT);
  pinMode(SpeedoPin, INPUT_PULLUP);
  pinMode(MenuPin, INPUT_PULLUP);
  pinMode(PlusPin, INPUT_PULLUP);
  pinMode(MinusPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2),SpeedoIn,CHANGE);
  Serial.begin(9600);
  lcd.begin(20,4);
  //lcd.setCursor(5, 0);
  //lcd.print("V");
  //lcd.setCursor(13, 0);
  //lcd.print("A");
  //lcd.setCursor(19, 0);
  //lcd.print("W");
  lcd.setCursor(6, 1);
  lcd.print("mA");
  lcd.setCursor(0, 2);
  lcd.print("E");
  lcd.setCursor(9, 2);
  lcd.print("F");

}

void loop() {
  // put your main code here, to run repeatedly:
  power_calc();
  delay(200);
}

ISR(TIMER1_OVF_vect){
  TCNT1 = 49535;
  // Increment the millisecond counter
  millis_count++;
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

ISR(TIMER1_COMPA_vect){
  millis_count++;
}


void power_calc(){

  unsigned long int wt = 000;
  //float amps;// = 00.00;
  unsigned int amps;
  float volts = 00.00;
  char va[] = "00.00 ";
   unsigned char sign;
    
    vadc = analogRead(A0);                                                         // Read AN0/RA0 for voltage
    volts = vadc * 4.89;
    volts = volts / 100;
    //volts = (vadc /1023) * 5;
    a = analogRead(A3);                                                            // Read AN2/RA2 for current
    if (a >= 511){
        amps = (float)(((a - 511) * 4.89) / 6.6);                            // ACS712-30A=6.6,20A=10
        sign = "-";                                                             // Battery Discharging
        charging_flag = 0;                                                      // show that battery is discharging
    }
    else if (a < 510){
        amps = (float)(((511 - a) * 4.89) / 6.6);
        sign = "+";                                                             // Battery Charging
        charging_flag = 1;                                                      // show that battery is charging
    }
    
    //amps += current;
    mAsec = (float)(amps / 180);                                             // mA/0.2Sec

     //if(DspUpdInt > 4){                                                         // Display Voltage,Current,Watts every 1 Second
        //////////////////////
        //***LCD Line 1 ***//
        /// Voltage Display ///
        //volts = volts /5 ;                                                      // Voltage to display
        //display_va(0, 0, volts, "V");
        //lcd.setCursor(0, 0);
        //lcd.print(sign);
        lcd.setCursor(0, 0);
        lcd.print(String(volts) + "V");
		
        /// Display  Current ///
        amps = (amps * 10);
        //lcd.setCursor(7, 0);
        //lcd.print("+" + (String(amps)) + "A");
        //display_va(9, 0, amps, "A");
        /// Display Wattage  ///
        

        va[0] = (amps/1000);
        va[1] = ((amps/100)%10);
        //va[2] = ".";
        va[3] = ((amps/10)%10);
        va[4] = ((amps/1)%10);
        va[5] = "A";
        lcd.setCursor(9, 0);
        
        lcd.print(va);
        wt = (volts * amps) * 10;
        
        //lcd.setCursor(15, 0);
        //lcd.print("+");
        lcd.setCursor(15, 0);
        //lcd.print("+" + (String(wt)) + "W");
        lcd.print(amps);
        //display_percent_watt(0, 17, wt, 'W');
      
      }
  //}
  
  void display_va( char col, char row, unsigned long value, char type){
  char va[] = "00.00 ";
//va[6] = '\0';
        va[0] = (value/1000);
        va[1] = ((value/100)%10);
        //va[2] = ".";
        va[3] = ((value/10)%10);
        va[4] = ((value/1)%10);
        va[5] = type;
        lcd.setCursor(col, row);
        //for(int x = 0; x < 7; x++){
        //lcd.setCursor(x, pos_row);
        //va = "123";
        lcd.print(va);
       //}
        
}

void display_percent_watt(char row, char col, unsigned int value, char type){
unsigned char percent[4];// = "000 ";
percent[4] = '\0';
        if (value < 100){
            percent[0] = ' ';
        }
        else{
            percent[0] = (value/100);
        }
        percent[1] = ((value/10)%10);
        percent[2] = ((value/1)%10);
                percent[3] = type;
        lcd.setCursor(col, row);
        for(int x = 0; x < 7; x++){
        lcd.setCursor(x, row);
        lcd.print(percent[x]);
        }
}



  void SpeedoIn(){

}

Sorry my mistake.

float amps = 00.00;
1 Like

after a bit of clean up

#include<LiquidCrystal.h>
LiquidCrystal lcd (7, 8, 9, 10, 11, 12); // Define LCD display pins RS, E, D4, D5, D6, D7

const byte SpeedoPin = 2;
const byte BuzzPin   = 3;
const byte MinusPin  = 4;
const byte PlusPin   = 5;
const byte MenuPin   = 6;


unsigned int a = 0, volts = 0, vadc, save_maH, batt_cap, amps;
float mAsec;
unsigned char flag_200ms = 0;                                                   // set HIGH once 0.2 second (200ms)
unsigned char charging_flag;                                                    // 1=charging, 0=discharging

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BuzzPin, OUTPUT);
  pinMode(SpeedoPin, INPUT_PULLUP);
  pinMode(MenuPin, INPUT_PULLUP);
  pinMode(PlusPin, INPUT_PULLUP);
  pinMode(MinusPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(SpeedoPin), SpeedoIn, CHANGE);

  lcd.begin(20, 4);
  lcd.setCursor(6, 1); lcd.print("mA");
  lcd.setCursor(0, 2); lcd.print("E");
  lcd.setCursor(9, 2); lcd.print("F");
}

void loop() {
  power_calc();
  blinkLed();
}

void blinkLed() {
  // blink at 1Hz
  static unsigned long lastBlinkTime;
  if (millis() - lastBlinkTime >= 500) {
    digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW);
    lastBlinkTime = millis();
  }
}

void power_calc() {
  unsigned long int wt = 000;
  //float amps;// = 00.00;
  unsigned int amps;
  float volts = 00.00;
  char va[] = "00.00 ";
  char sign;

  // run only every 200ms
  static unsigned long lastCalcTime;
  if (millis() - lastCalcTime < 200) return;

  lastCalcTime = millis();


  vadc = analogRead(A0);                                                         // Read AN0/RA0 for voltage
  volts = vadc * 4.89;
  volts = volts / 100;

  a = analogRead(A3);                                                            // Read AN2/RA2 for current
  if (a >= 511) {
    amps = (float)(((a - 511) * 4.89) / 6.6);                            // ACS712-30A=6.6,20A=10
    sign = '-';                                                             // Battery Discharging
    charging_flag = 0;                                                      // show that battery is discharging
  }
  else {
    amps = (float)(((511 - a) * 4.89) / 6.6);
    sign = '+';                                                             // Battery Charging
    charging_flag = 1;                                                      // show that battery is charging
  }

  mAsec = amps / 180.0;                                                     // mA/0.2Sec

  lcd.setCursor(0, 0);
  lcd.print(volts);
  lcd.print('V');

  /// Display  Current ///
  amps = (amps * 10);
  va[0] = '0' + (amps / 1000);
  va[1] = '0' + ((amps / 100) % 10);
  va[3] = '0' + ((amps / 10) % 10);
  va[4] = '0' + ((amps / 1) % 10);
  va[5] = 'A';
  lcd.setCursor(9, 0);
  lcd.print(sign);
  lcd.print(va);

  /// Display  Power ///
  wt = (volts * amps) * 10;
  lcd.setCursor(15, 0);
  lcd.print(wt);
}

void display_va( char col, char row, unsigned long value, char type) {
  char va[] = "00.00 ";
  va[0] = '0' + (value / 1000);
  va[1] = '0' + ((value / 100) % 10);
  va[3] = '0' + ((value / 10) % 10);
  va[4] = '0' + ((value / 1) % 10);
  va[5] = type;
  lcd.setCursor(col, row);
  lcd.print(va);
}

void display_percent_watt(char row, char col, unsigned int value, char type) {
  char percent[] = "000%";

  if (value < 100) percent[0] = ' ';
  else percent[0] = '0' + (value / 100);
  percent[1] = '0' + ((value / 10) % 10);
  percent[2] = '0' + ((value / 1) % 10);
  percent[3] = type;
  lcd.setCursor(col, row);
  lcd.print(percent);
}

void SpeedoIn() {}

on your Nano millis() is maintained by the Arduino code, so you don't need to have your own time management

executing something at low frequencies is easily handled using millis()
For extra information and examples look at

Don't use unsigned char for text, char for single characters or a null terminated char array for cStrings is what you want.
Don't use double quotes for single characters (like when you do sign = "-";) use single quotes (sign = '-';). Double quotes are for cStrings.
if you want to convert a single digit (0 to 9) expressed as an integral number into its ASCII representation, you need to add '0' to it
get rid of what is not used

I've not checked what's going on the LCD and got rid of the uncommented lines

hope this gives you some ideas

1 Like

i don't get the point of this single character printing.

when you have your long amps with 2 digits,
just cast calc to a float and let Print.h do it's job.

lcd.println(amps/100.0);

when you want to add a 0 or a blank for lower numbers, print that 0/blank just before you print the value:

if(amps < 1000) lcd.print(' ');

reserve more digits if you need to prepared for negative numbers.

thanks for the help. your code worked. I need 4 functions to be running in a series that would run every 200mSec. the 4 functions may call 3 to 4 sub functions. Can I use millis for it. example as done on pic

void loop(){
do{
        while(!flag_200ms);      // wait until 200mS has passed
        flag_200ms = 0;           // reset the 0.2 Second flag
      
        power_calc();           // Run Voltage, Current and Wattage Calculations

          //***LCD Line 2 ***//
          display_amphour(2, 1, aH);     // Remaining Battery Capacity
          batt_percNbar();                       // Calculate & Display Battery Percentage/Bar
          if(charging_flag){
            display_TimeRemaining();      // Charge-Discharge Time Remaining ///
          }
          else{
             speed_calc();
          }
}while(1);
}

Yes use millis (either only one and you trigger all the functions in a row or if they could have different timings the use multiple variables ).

The loop loops, so no need to add de do {…} while(1); in there. Just let the loop do its thing.

Thanks once again. I was reading the example posted by you, using millis for timing. I hope I don't get stuck again.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.