This also fixes the justification ooops in your pic above.
void FormatData()
{
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// switch formatting done based on display state
switch (DisplayState)
{
case 1:{
//this is for single A shooter mode
// display number of hits so far
String tmp = "A: # hits = ";
Line1 = tmp + A_count;
// now display the time of last hit in secs out to hundreths of secs
String tmp2 = TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
Line2 = "Hit time= " + tmp2 + " secs";
tmp2 = TimeConvert(A_splits[A_count-1]); // convert split time
Line3 = "Split time= " + tmp2 + " s";
Line4 = " ";
break;}
case 2:{
// this is A review mode hits 1-8
String tmp = TimeConvert(A_Times[0]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[4]); // convert hit time to XX.xx format
Line1 = "A 1:" + tmp + "s 5:" + tmp2 + "s";
tmp = TimeConvert(A_Times[1]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[5]); // convert hit time to XX.xx format
Line2 = "A 2:" + tmp + "s 6:" + tmp2 + "s";
tmp = TimeConvert(A_Times[2]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[6]); // convert hit time to XX.xx format
Line3 = "A 3:" + tmp + "s 7:" + tmp2 + "s";
tmp = TimeConvert(A_Times[3]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[7]); // convert hit time to XX.xx format
Line4 = "A 4:" + tmp + "s 8:" + tmp2 + "s";
break;}
case 3:{
// this is A review mode hits 9-16
String tmp = TimeConvert(A_Times[8]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[12]); // convert hit time to XX.xx format
Line1 = "A 9:" + tmp + "s13:" + tmp2 + "s";
tmp = TimeConvert(A_Times[9]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[13]); // convert hit time to XX.xx format
Line2 = "A 10:" + tmp + "s14:" + tmp2 + "s";
tmp = TimeConvert(A_Times[10]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[14]); // convert hit time to XX.xx format
Line3 = "A 11:" + tmp + "s15:" + tmp2 + "s";
tmp = TimeConvert(A_Times[11]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[15]); // convert hit time to XX.xx format
Line4 = "A 12:" + tmp + "s16:" + tmp2 + "s";
break;}
case 4:{
// this is A review mode hits 17-20
String tmp = TimeConvert(A_Times[16]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[18]); // convert hit time to XX.xx format
Line1 = "A 17:" + tmp + "s19:" + tmp2 + "s";
tmp = TimeConvert(A_Times[17]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[19]); // convert hit time to XX.xx format
Line2 = "A 18:" + tmp + "s20:" + tmp2 + "s";
Line3 = " ";
Line4 = " ";
break;}
default:
// do the default = 0
// 4 string objects
Line1 = " Shot Timer v1 ";
Line2 = " is running ";
Line3 = " Shooter: ";
Line4 = " STANDBY ";
}
}
Yeah, I’m not sure why zeros aren’t getting printed out. The PC output proves the array is being cleared/zero filled. Zeros as part of the hit times get displayed properly. There’s something I’m not seeing properly. Could the LCD firmware be trying to suppress leading zeros and somehow FU’ing things ?
sspbass:
I think something is goofy with your numbers.
You are correct. tmp should be tmp3.
String TimeConvert(long time)
{
// takes the time as argument and returns the time for that hit as a XX.xx string
if (time != 0) // Make sure there's a value...
{
String tmp3 = String(int((time + 5)/10)); // round msecs into csecs
int k = tmp3.length(); // k will be index to last char in padded string
int km1 = k-1; // km1 will be index to next to last char
int km2 = k-2; // km2 will be position of period
tmp3 = tmp3 + '0'; // pad the end of the truncated string with a zero
//now move chars to make space to add a period
tmp3.setCharAt(k, tmp3.charAt(km1)); // move next-2-last to last position in string
tmp3.setCharAt(km1, tmp3.charAt(km2)); // move char to next-2-last position
// now insert period
tmp3.setCharAt(km2, '.');
// add a blank or 2 as needed to get 5 digits with time right justified
if(tmp3.length() < 4)
{
tmp3 = " " + tmp3;
}
if(tmp3.length() < 4)
{
tmp3 = " " + tmp3;
}
// tmp3 now holds rounded time in secs XX.xx format
return tmp3;
}
else
{
String tmp3 = " "; // If the time variable is zero pass 5 blanks back as a string...
return tmp3;
}
}
Lastly … do you think we should get rid of the “s” at the end of the times ? I think it makes the display look busy 'cuz there’s a lot stuffed into the 20 spaces. I think we all know the times are in seconds. In the other display it’s there as much to fill empty space as to be informative. A little more empty space btw the columns might look better.
Still not quite right. There should be 5 places; 1 period plus 4 numbers/blanks. I think I’m seeing 4 places in the <10 sec times above but oddly the zero times do look to be filled with 5 blanks. And I think a single leading 0 for the fractional times would look better, ie - not .59s but 0.59s and perhaps more betterer just 0.59.
I think I know what happened … the code really didn’t “look” at a new tmp3 length after the first blank padding, it just reused the same register value. That’s easily fixable.
So here’s a fix to try tomorrow and see if you like the display.
[EDIT : removed this “beauty” code and implemented the 1/2 of the idea below into the code in post below]
I also think we could include the “s” in the String returned by the convert function and then leave it out … assuming you want to keep the “s” s … where there’s no time to be displayed. For that matter we could pass the hit number to the function as well and have it do pretty much every thing, suppressing the “hit:” as well. It would be hard to suppress the A though …
sspbass:
Is there some “ghost” that causes LCD’s to mess up now and then?
The first trial there was hardly anything readable on the display but after that it looked great.
If that happens again, try scrolling to a different display and then back to the AFU one. See if the ghosting goes away or stays.
I’m still lost as to why some zero filled numbers display properly and others look goofy. Perhaps it’s the same ghosting issue and perhaps that’s related to bad data transfer btw the Arduino and LCD. Or maybe the LCD is occasionally goofy. :?: :?:
OK here’s my final “beautification” build. :mrgreen: It puts the “s” 's into the TimeConvert() function and removes them as predefined in the LineX = “blah blah blah” in the FormatData(). In this way if the hit time = 0 the function returns 6 blanks, no s left hanging out yonder. If the there’s an actual hit time, it returns that with an “s” appended to the end. Subsecond times get a blank and a 0 stuck to the front and an “s” at the tail. Sub10sec times get a blank added up front and an “s” at the tail. This way the function always returns a 6 character string. The only question I have is whether the syntax to append a single character is the same for Strings as it is for char arrays. That is, are multi char appends a + “blah” whereas single char appends are a +‘b’. Note the “” “” vs ’ '. I believe they are but I’m less than 100% sure so trust … but verify. :mrgreen:
void FormatData()
{
// routine to format lines of data to be sent to LCD
// presently assume 4 lines of 20 characters
// switch formatting done based on display state
switch (DisplayState)
{
case 1:{
//this is for single A shooter mode
// display number of hits so far
String tmp = "A: # hits = ";
Line1 = tmp + A_count;
// now display the time of last hit in secs out to hundreths of secs
String tmp2 = TimeConvert(A_Times[A_count-1]); // convert hit time to XX.xx format
Line2 = " Hit time = " + tmp2;
tmp2 = TimeConvert(A_splits[A_count-1]); // convert split time
Line3 = "Split time = " + tmp2;
Line4 = " ";
break;}
case 2:{
// this is A review mode hits 1-8
String tmp = TimeConvert(A_Times[0]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[4]); // convert hit time to XX.xx format
Line1 = "A 1:" + tmp + " 5:" + tmp2;
tmp = TimeConvert(A_Times[1]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[5]); // convert hit time to XX.xx format
Line2 = "A 2:" + tmp + " 6:" + tmp2;
tmp = TimeConvert(A_Times[2]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[6]); // convert hit time to XX.xx format
Line3 = "A 3:" + tmp + " 7:" + tmp2;
tmp = TimeConvert(A_Times[3]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[7]); // convert hit time to XX.xx format
Line4 = "A 4:" + tmp + " 8:" + tmp2;
break;}
case 3:{
// this is A review mode hits 9-16
String tmp = TimeConvert(A_Times[8]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[12]); // convert hit time to XX.xx format
Line1 = "A 9:" + tmp + "13:" + tmp2;
tmp = TimeConvert(A_Times[9]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[13]); // convert hit time to XX.xx format
Line2 = "A 10:" + tmp + "14:" + tmp2;
tmp = TimeConvert(A_Times[10]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[14]); // convert hit time to XX.xx format
Line3 = "A 11:" + tmp + "15:" + tmp2;
tmp = TimeConvert(A_Times[11]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[15]); // convert hit time to XX.xx format
Line4 = "A 12:" + tmp + "16:" + tmp2;
break;}
case 4:{
// this is A review mode hits 17-20
String tmp = TimeConvert(A_Times[16]); // convert hit time to XX.xx format
String tmp2 = TimeConvert(A_Times[18]); // convert hit time to XX.xx format
Line1 = "A 17:" + tmp + "19:" + tmp2;
tmp = TimeConvert(A_Times[17]); // convert hit time to XX.xx format
tmp2 = TimeConvert(A_Times[19]); // convert hit time to XX.xx format
Line2 = "A 18:" + tmp + "20:" + tmp2;
Line3 = " ";
Line4 = " ";
break;}
default:
// do the default = 0
// 4 string objects
Line1 = " Shot Timer v1 ";
Line2 = " is running ";
Line3 = " Shooter: ";
Line4 = " --STANDBY-- ";
}
}
String TimeConvert(long time)
{
// takes the time as argument and returns the time for that hit as a XX.xxs string
if (time != 0) // Make sure there's a value...
{
String tmp3 = String(int((time + 5)/10)); // round msecs into csecs
int k = tmp3.length(); // k will be index to last char in padded string
int km1 = k-1; // km1 will be index to next to last char
int km2 = k-2; // km2 will be position of period
tmp3 = tmp3 + '0'; // pad the end of the truncated string with a zero
//now move chars to make space to add a period
tmp3.setCharAt(k, tmp3.charAt(km1)); // move next-2-last to last position in string
tmp3.setCharAt(km1, tmp3.charAt(km2)); // move char to next-2-last position
// now insert period
tmp3.setCharAt(km2, '.');
// add a blank or 2 as needed to get 5 digits with time right justified
if(tmp3.length() < 3)
{
tmp3 = " 0" + tmp3; // must be a sub 1 sec time so add blank and leading 0
}
else
{
if (tmp3.length() < 4)
{
tmp3 = ' ' + tmp3; // must be a sub 10 sec time so add blank to justify
}
{
// tmp3 now holds rounded time in secs XX.xx format
tmp3 += 's': // add s for seconds
return tmp3;
}
else
{
String tmp3 = " "; // If the time variable is zero pass 6 blanks back as a string...
return tmp3;
}
}
If you decide the display for hits >9 and times >10 sec are too busy and want to get rid of the “s”, then it’s a one line edit.
Assuming the above works and is a “beauty” (I want a vid !), what’s next ? My thinking is it’s time to add modes to the timer as in A vs B mode and then later the “21” and "QD’ modes and … But to add modes means the user must have some way to choose amongst them and I think that means some more input buttons are needed. Short of using a loooong press on the scroll button, I envision another button that brings up a “menu” display. Ideally there would then be 2 scroll buttons, to navigate up or down the displayed items. For the moment you could get away with just one scroll button that wraps around as it’s pressed over and over.
The items on the menu display would be the modes and perhaps a general config item and ??? Selecting the general config item might let the user specifiy random vs fixed countdown delays, max number of hits and run time and auto-start on/off. Selcting a mode, like AvsB would enable that to be the operating mode and present the user with choices of config items particular to that mode.
After all the user choices are made, they are stored in EEPROM and become the defaults used for next run, and thereafter. Somehow the menu stuff is exitted and the timer is ready to run.
I’m not sure what to think. Look at the whole project and make sure you’ve only got 1 function called TimeConvert(). My last snippet had both, a new FormatData() and a new TimeConvert(). You may have copied and pasted the both of them in, w/o realizing the new TimeConvert() was hidden in there. If you have 2 TimeConvert()s, keep the new one. It and the new FormatData() need to be simpatico.
And nope, just stuck working late night + intemittant insomnia. :mrgreen:
Haha, should have known better. A college student would have been too gone at 2 in the morning on a Thursday night/Friday morning to be writing code worth anything!
Have you had a chance to look for 2 instances of TimeConvert() ? If that doesn’t seem to be the case and you’ve still got no answer … I have revised the loop() and added some new variables and altered FormatData() slightly, so as to get ready to add “modes” to the timer. The code I have waiting in the wings doesn’t do anything more than what you (should) have right now but rather than introduce a whole bunch of new stuff all at once, it makes sense to introduce the groundwork, test it and then add the “modes”. So when you want I have new code to test out to verify it still does all the good things it’s supposed to … used to. If you can’t resolve the compiler exception, we can try to leapfrog it with this new code. Let me know.
And then, if it works, we can talk about the user interface (UI) to make “modes” happen. I think it will be interesting to see the A vs B work and what happens if two hits occur simultaneously. I don’t know how the Arduino handles that (interrupt) situation. The good thing is that, I think with your pulse stretcher output, it’ll work no matter what.
It still isn’t displaying as it should. What’s not happening is a blank space in front of the sub 10 sec times. What should happen (for example) is :
A 1: 1.23s 5: 9.99s {this is always 20 columns wide, as it should be}
what I’m seeing is :
A 1:1.23s 5:9.99s {this is only 18 columns wide, an will vary dependant on hit time}
Which will lead to un-lined-up columns when the hit times are 10.95 and such.
What was that first hit time ? In the vid it looked like .00s which shouldn’t happen. All zeros should get suppressed and I see that later with hits >= 14 (and no “s” either !). I hope the vid is just blurry enough that there’s some small sub-1sec time, like .80s, but even then I don’t see my new “fix” working. It should display such a number as blank0.80s. There should always be 6 “digits”, which should be 1 period, 1 s, and some combo of blanks/spaces and numbers, with a leading 0 for sub-1sec times. Can you post the FormatData() and TimeConvert() that you’re presently using ? There’s something, probably stupid and obvious, that’s wrong. And it’ll be wrong in the new code I have as well.