sprintf formatting

The following snippet was distributed as part of the tuning test program for the ByVac BV-4242 display and while it compiles without error when it runs no values are displayed on the serial monitor. I assume there must be an issue with the sprintf syntax but haven't been able to find it yet. Suggestions appreciated!

Bob

// Prints a string of 8 average values
void printAvg()
{
uint16_t v[9];
char b[24];
ui.avg(v); // get 8 values
Serial.print("\nAvg: ");
for(char j=0;j<8;j++) {
sprintf(b," %4d",v[j]);
Serial.print(b);
}
}

It's depending on the avg method of the "ui" object to fill the array v[] with values. So my guess is that you haven't called other methods of whatever class "ui" is an instantiation of, that are a necessary precursor.

The full explanation lies in the nature of the class that constructed "ui".

If it's as poorly documented as this function is, good luck.

Try adding this statement after the for loop:

  Serial.println();

Pete

Thanks - yes, there is a function called void avg(uint16_t *b) that fills an 8 integer buffer with the 8 average values of each channel on the board. The loop that calls this function runs, but all I see in the serial monitor is an empty square box each loop without any values. The box character repeats across the screen as long as the program runs. That's why I suspected something was wrong with the sprintf format such as trying to print a non ASCII value that the monitor just shows as a blank space.

Hopefully the manufacturer will respond to my questions as this is supposed to work.

Bob

Is the baud rate on your serial monitor set to the same baud rate as the Arduino sketch does?

Yes, 9600 baud both. First thing I thought of, but... Nor does changing the line ending option.

Port is set for 9600/N/8/1 and other prints to the serial monitor show up fine.

Bob

Does it print, "\nAvg: " ?

w9ran:
Yes, 9600 baud both. First thing I thought of, but... Nor does changing the line ending option.

Port is set for 9600/N/8/1 and other prints to the serial monitor show up fine.

Bob

I'm curious... why are you making the array 9 elements long and only using the 8?

uint16_t v[9];
char b[24];
  ui.avg(v); // get 8 values

not that it's your issue...

The bug is somewhere else in your code. Post all of it.

Pete

el_supremo:
The bug is somewhere else in your code. Post all of it.

Pete

It's not the OP's code. I think an answer to reply #6 might avoid some wasted time.

I'm not clairvoyant so I would like to see the code. An answer to #6 would also be helpful.

Pete

W9RAN, it's a library, so how about saving us a trip to Google, and posting a link.

To #6 - no it does not print "Avg". Here is a screen cap that shows what I see in the serial monitor:


(the empty box symbols continue across the screen horizontally as long as the program runs)

As can be seen from the screen cap, "something" is getting printed in the "Avg" loop - which appear as blank spaces - causing the cursor box to move to the right (it continues do do so in the endless loop).

This is a touch-sensitive keypad and display device which stores the sensitivity of the touch pads in EEPROM and then uses these values to transmit key codes via I2C. I can read most of the key codes from the device in my own code so I think it is mostly functioning correctly, but one key is non-responsive, and this sketch was provided by the manufacturer for users to see and adjust the touch and threshold values (e.g. "tuning"). Either it never gets to the part where ui.scan is supposed to display raw key values or they are also invisible because pressing known working keys produces no change in this display.

Below is the entire sketch as distributed by the manufacturer. It and other data on the device can be found here: http://www.pichips.co.uk/index.php/BV4242#arduino

I am sure the manufacturer will eventually respond but since I am still learning the Arduino language I thought that if there is an obvious problem it might be obvious to a more experienced person. Thanks for the comments.

Bob

#include <bv4242.h>
#include <Wire.h>
// Use this sketch to tune the touch pads, see the data
// sheet for more details

// 7 bit adddress is used
BV4242 ui(0x3d);

void setup()
{
Serial.begin(9600);
}

// Prints a string of 8 average values
void printAvg()
{
uint16_t v[9];
char b[24];
ui.avg(v); // get 8 values
Serial.print("\nAvg: ");
for(char j=0;j<8;j++) {
sprintf(b," %4d",v[j]);
Serial.print(b);
}
}

// Prints a string of 8 delta values
void printDelta()
{
uint16_t v[9];
char b[24];
ui.delta(v); // get 8 values
Serial.print("\nDlt: ");
for(char j=0;j<8;j++) {
sprintf(b," %4d",v[j]);
Serial.print(b);
}
}

void loop()
{
uint8_t k;
char b[24];
Serial.print("\nTuning\n");
while(1) {
Serial.print("\n");
printAvg();
printDelta();
k = ui.scan();
if(k) {
sprintf(b,"\nScan Code: 0x%x",k);
Serial.print(b);
}
delay(500);
}
}

The BV4242 class probably has a fatal bug that is causing a complete crash.

I'm not sure about that. I've since discovered that the problem is related to the baud rate, somehow. The example sketch opens the serial port at 9600 baud which does not work. But if I change that and the serial monitor to 115200 baud, it displays the values as it should with proper formatting (no change to the code other than the baud rate). The sketch doesn't seem to be working quite right but I'll play with it now that it's partially working. I need the exercise :wink:

The hardware I'm using is a Sparkfun RedBoard and it's going thru a USB 3.0 hub to an i7 machine. I would think any timing errors would be more severe at high baud rates than at low ones, but that's not the case.

It's become a moot point since the manufacturer says that tuning is not really required and I subsequently found an error in my code that was causing one key not to work. So with my appreciation for the help, I'll call this case closed.

Regards,

Bob

w9ran:
uint16_t v[9];
...
ui.avg(v); // get 8 values

void BV4242::avg(uint16_t *b)
{
uint16_t v;
    sendKeyCmd(10); // command
    Wire.requestFrom(_PADi2adr, 16); // returns 16 bytes
    for(uint8_t j=0;j < 16; j++) {
        v=Wire.read()*256; // high byte
        v+=Wire.read(); // low byte
        *(b++)=v;
    }
}

First one to spot the nasty bug gets a cookie. Or a smiley. Or karma. I'll decide later.

passes through 16 times:

for(uint8_t j=0;j < 16; j++) {
        v=Wire.read()*256; // high byte
        v+=Wire.read(); // low byte
        *(b++)=v;
    }

reading 32 bytes...

but requested only 16...

Wire.requestFrom(_PADi2adr, 16); // returns 16 bytes

EDITED to add...

(b++)

the pointer b gets moved 16 times over an array of length of 9...

BulldogLowell:
the pointer b gets moved 16 times over an array of length of 9...

Yup. Corrupt stack. Definitely qualifies as "nasty".

(I went with karma.)

w9ran:
I've since discovered that the problem is related to the baud rate, somehow.

Specious reasoning. Lisa has a rock to sell you.

aarg:
The BV4242 class probably has a fatal bug that is causing a complete crash.

w9ran:
I'm not sure about that.

I am. And so is @BulldogLowell.

Not just a bug, but really crap programming...

the function takes a pointer to an int16_t array:

void BV4242::avg(uint16_t *b)

that's really leaving it outside your zipper flapping in the breeze...

A better way would have been to force the programmer to pass of the number of elements of the array:

void BV4242::avg(uint16_t *b, size_t bSize)

and iterate in the function over the size of the array passed, but some dope could still screw that up by entering some incorrect value as the 2nd parameter.

another (perhaps even better) way is to just create a type for the data to be passed:

typedef struct EightIntArray_t{
  uint16_t value[8];
};

class Example{
  public:
    void fillAndPrintMyArray(EightIntArray_t arry);
};

void Example::fillAndPrintMyArray(EightIntArray_t arry)
{
  int x = 0;
  for (auto& i : arry.value)
  {
    i = (++x);  // just fill array with arbitrary values
  }
  for (auto i : arry.value)
  {
    Serial.println(i);
  }
}

Example example;

void setup() 
{
  Serial.begin(9600);
  
  EightIntArray_t myArray;
  example.fillAndPrintMyArray(myArray);
//  int array[8];
//  example.fillAndPrintMyArray(array);  // no good but gives a great compiler error
}

void loop() {}

which is type safe and...

it generates a nice (pointing you in the right direction) compiler error if you pass the wrong type:

/Users/bulldoglowell/Documents/Arduino/sketch_jul03a/sketch_jul03a.ino:10:6: note:   no known conversion for argument 1 from 'int [8]' to 'EightIntArray_t'
exit status 1
no matching function for call to 'Example::fillAndPrintMyArray(int [8])'

I was hoping for a smiley, so here's to you for spotty the nasty bug:

:slight_smile: