Jaycar 7 segment display, SPI bus, "stuck" with how to do what I want.

Hi folks.

I have the display working and it is connected to a NodeMCU arduino board.

It connects to my WiFi network and works.

Sorry, but I'm stuck with this little bit I want to add to it: Display the IP address when it connects, then get on with doing what it should do.

I've read the stuff that came with it, but it is still not clear to me how to do this.

I get that I can't send it "192.168.0.x" a text. I need to convert it to actual numbers and set bit 7 for the decimal place. Converting from text to numbers won't be too hard. I'll just get the character and subtract a value to give the number value. Sure there will be a bit of a trick with the decimal place, but......

So, in my effort to get a "working base line" this is sort of what I have:

  char ip[] = "192.168.0.4";  // length = 11

That has all the stuff stored in ip[] I need to loop through the ip[] values and subtract the value from it and send it to the display.

Ok, but it isn't going to be that simple. (When is it ever THAT simple?)

Luckily it is 8 digits. It may grow to 9 depending if it gets an IP address greater than 0.9 at the end.

So that will mean scrolling.

To help "compartmentalise" that, I'm guessing I make an array of 17 characters. All blank at first and the IP address gets put in when it is known.

Then it starts to "scroll" the message across the screen/display. Then when the last part of the IP number is shown, another 8 blanks are scrolled along to "wipe" the display. Starting at position 0 and incrementing along the display to 7 (zero counting)

I haven't done anything like this and would like to ask for a bit of help how to do this.

Oh, and just for reference this is the display: Jaycar 8 digit display

I get that I can't send it "192.168.0.x" a text.

You can't send what "192.168.0.x"? Did you mean "as text"? Why can't you?

I need to convert it to actual numbers

So, do it. What is the problem?

I'm curious, though, how you are going to display up to 12 digits on an 8 digit display.

Paul,

Yeah, that is the question.

In answer to your question asking me about:

You can't send what "192.168.0.x"? Did you mean "as text"? Why can't you?

Because it only displays 0 -> 9 and the letters H E L P -.

So you can't send "Hello world" to the display.

The display wants the actual number value. Range 0 to 15. So the IP address would have to be converted to actual numbers.

And your second question:

I'm curious, though, how you are going to display up to 12 digits on an 8 digit display.

That is why I want to scroll the message on the display.

I sort of worked out a way, but it was more a theoretical way and I don't think it would really work.

I get that it will require two loops to happen.

Loop 1 would count from 1 to the length of the message (plus probably the length of the display) Loop 2 would cycle the length of the display of the data it has. Each time incremented to display another digit. But when it gets to the end of the display and there is still more to display, I'm stuck.

I seem to remember a time when I could work out how to do it in short time. Alas now I can't.

I would like a bit of help to explain how to do it.

Oh, the decimal places are "easy" in that they are on each display and to get it working, you set bit 7 of that value being sent to the display.

So, you have an array of characters, "92.168.0.x". Using a for loop, you deal with each character at a time.

On the first pass through loop, you deal with the '1'. Since that is in the range '0' to '9', you get a numeric value by subtracting '0' from the character.

byte b = c - '0'; // where c is the nth character from the array.

If the character is not in the range '0' to '9', which the '.' isn't, then you have to decide what to do with that, differently. That should not be a problem, as you seem to know what to do with it.

I really don't see the problem, except that I think you are trivializing the handling of the '.'.

No, I am just not getting my head around HOW to do it.

Do I scroll the display along the message, or scroll the message long the display?

I get that I will have to append 8 "blank" characters to the end of the message so when it gets to the end of the message, it scrolls off the left side of the display.

Do I scroll the display along the message, or scroll the message long the display?

Here’s a hint. Suppose you want to display “ABCDEFGHIJ” on a display with 8 letter.

What I would expect to see is
ABCDEFGH
BCDEFGHI
CDEFGHIJ
DEFGHIJA
EFGHIJAB
FGHIJABC
GHIJABCD

So, you can see that you need to display one, or two, subsets of the original string. So, you use one, or two, for loops.

This is what I have so far.

Given all external variables are set.

It scrolls the message 19216811 onto the screen.

I have made it 192168111222 to get all the possible things. Doesn’t really matter as the “clean up” part would handle that, but…

So, now:
When the display is “full” (has 8 digits displayed) the code needs to scroll along the message and start at message[>1] when it calls the routine.

I’m getting there.

But I am still open to help.

void two()
{
  char message[] = "192168111222";
  byte message_length = 8;
  byte x;
  i = 0;    //  position on display
  j = 0;    //  position in message
  while (i < display_size+1)
  {
    Serial.print(" -->  ");
    Serial.println(message[i]);
    fill_in(i, j);
    delay(300);
    i = i + 1;
    j = j + 1;
  }
  //    Now display is full, scroll what is shows.
  //
//  while (j < message_length + 1)
//  {
//    fill_in(j, 8);
//    j = j + 1;
//  }
  delay(4000);
  wipe(15);
  delay(800);
}
//------------------------------------------------------------
void fill_in(byte p, byte m)        // p = position in display   6   = 192168   m = where in message to start
{
  //  set y to m
  char message[] = "192168111222";
  byte message_length = 8;
  byte x = 0;
  byte y = 0;
  Serial.print("-------------");
//  Serial.print(p + '0');
  Serial.println(" ");
  while( p > 0)
  {
    //
    y = y + 1;
    p = p - 1;
    Serial.println(message[p]);
    x = message[p] -'0';
    //  position / data
    MAX7219senddata(y,x);
  }
}

But I am still open to help.

Good, because two() is an absolutely stupid name for a function.

  i = 0;    //  position on display
  j = 0;    //  position in message
  while (i < display_size+1)
  {
    Serial.print(" -->  ");
    Serial.println(message[i]);
    fill_in(i, j);
    delay(300);
    i = i + 1;
    j = j + 1;
  }

Throughout this loop, i and j always have the same values. Why do you need two variables with the same value?

void fill_in(byte p, byte m)        // p = position in display   6   = 192168   m = where in message to start
{
  //  set y to m
  char message[] = "192168111222";

Why does fill_in() use it’s own copy of the message to display? fill_in() should be told what the message is.

In what universe is 6 equal to 192168?

  char message[] = "192168111222";
  byte message_length = 8;

Can’t count, eh?

8 might be the display length, but it is NOT the message length.

x, y, and p are meaningless names. Surely, you can do better than that.

If you have a 12 character message to display in an 8 character display, and you want to scroll the message, the easiest thing to do is to create another array that can hold 8 characters. Call that array portion. At the appropriate time, fill portion with some characters from the 12 character array.

The 8 characters could be 0 to 7, 1 to 8, 2 to 9, etc., so you need one for loop. Or, the 8 characters could be 7 to 11 and 0 to 2, or 8 to 11 and 0 to 3, etc.

The key is determining whether you need to use one for loop to copy the data, or two. And, that isn’t too difficult to determine. The message has some length. The display has some length. When the first character in the portion of the message to display is less than message length minus display length, you need one for loop. Otherwise, you need two.

If you need one, that one is straightforward. Just iterate display length times, copy from message[ i ] to portion[ j ].

for(int i=startingIndex, j = 0; j<displayLength; i++, j++)
{
   portion[j] = message[i];
}

You’ll need appropriate variables named startingIndex and displayLength. The displayLength variable should be global and const, since the display size isn’t variable.

startingIndex should start at 0 and be incremented every time the contents of the display should be scrolled.

If you need two for loops, the first would copy data from startingIndex to messageLength-1 to 0 to something. The second one fills the remaining part of portion with characters from the front of message.

Give this a try, and post what you come up with, and explain what it actually does, and what it doesn’t do right, and I’ll help you get it right.

Hi Paul.

Yeah, you are upset and I can’t blame you, but you are not really getting my confusion.

Here’s a run down of things:

I have written a bare minimum program because I want to get a very simple bit of code working before I try to apply it to my program,

To help me do this, I have tried to make it a “function” rather than a program. That way I just cut/paste the code and all is good.

To help with this two() is my second attempt at writing the function to do what I want.
So really at this point in time it makes no difference what it is called.

But as it is my SECOND ATTEMPT I decided to call it two. Problem?

i = 0;    //  position on display
  j = 0;    //  position in message
  while (i < display_size+1)
  {

Though not obvious: display_size is set outside this bit of code. In case you hadn’t worked it out, it is EIGHT. (See link in first post.)

So when it is called

i = 0

and

display_size = 8

Why does fill_in() use it’s own copy of the message to display? fill_in() should be told what the message is.

Again: true. But as they are written as STAND ALONE things, I was playing with the message to get it working.
Therefore two() needs to know the message, as does fill_in().

Though in the bigger code those lines are not used, they are there to put the value in the code.
Nothing else.

In what universe is 6 equal to 192168?

In the one where I am testing the code. Rather than edit the message length I simple edited the length value.
It achieved the desired result at the time.

This is also because just now I have’t worked out how to get the length of a message.
Though I am sure you are going to flame me for that too.

 char message[] = "192168111222";
  byte message_length = 8;

Yes, I can count.

Again I shall state that I am editing the message_length to allow me to test when the message is: 6, 8 and 12 digits long.
Problem?
And ok, there may be one which I haven’t seem yet. But if there is one either I will find it (after hours of pain) or you could mention to me any problems you see that would help me.

This is where I am at with the code.

void two()
{
  char message[] = "192168111222";
  byte message_length = 8;
  byte _display_size = 8;
  message_pointer = 0;    //  position in message   (  points to message[i]  )
  display_start_pos = 0;    //  starting position on display   (  Work in progress      )
  while (message_pointer < display_size+1)
  {
    Serial.print(" -->  ");
    Serial.println(message[message_pointer]);
    
    //
    fill_in(message_pointer, display_start_pos);
    //
    
    delay(300);
    
    message_pointer = message_pointer + 1;
    display_start_pos = display_start_pos + 1;
  }
  //    Now display is full, scroll what is shows.
  //
//  while (message_pointer < message_length + 1)
//  {
//    fill_in(message_pointer, 7);
//    message_pointer = message_pointer + 1;
//  }
  delay(4000);
  wipe(15);
  delay(800);
}
//------------------------------------------------------------
void fill_in(byte p, byte m)        // p = pointer to message content:  message[p]  ** not used yet.-->    m =  
{
  //
  //    at this stage m = "display_start_pos" which is not really clear what it is doing.
  //
  char message[] = "192168111222";
  byte message_length = 8;
  byte display_size = 8;
  byte x = 0;                       //    Dummy variable to store what is sent to display.
  byte count_up = 0;                //    Count up pointer.   *** NEW ***
  static byte last_position = 0;    //    Last display position used
  byte old = 0;
  Serial.print("-------------");
//  Serial.print(p + '0');
  Serial.println(" ");
}

In the mean time, I see a problem which may or may not be an issue.

I was wanting to display the first/new number on the display at position 1.

What is REALLY happening is the display is a new number is being displayed at position 1.
When a new number is received, it is printed at display position 1.
Then the digit which was at position 1 is printed at position 2.

Likewise if the third digit is received:
It is printed in position 1
The digit which was at position 1 is printed at position 2.
The digit which was at position 2 is printed at position 3.

Though it works, I see it is not the best way of going it.

So here’s how I see what I want to do:
I’ve got a message to display.

print the first digit at position 1 on the display.

if (the message_length > 1)
{
    display_counter ++1
    local_counter = display_counter
    while (local_counter > 0)
    {
        move digit n to digit n+1
        local_counter --1
    }
display new_digit at position 1 of display.
}

This way, all it does is print at position 1.
But before doing that, it checks what position in the message it is.
If it is greater than 1, it shuffles/moves the previous digits 1 position to the left.
Starting with the left most digit. I hope.
The moves right one step each time.
(the names may not be accurate because I am still trying to work it out.)

That way it is “easier” in what it does.

I can’t work out how to get the pointers and do the loop.

I’m trying, but I am just not seeing it.

Once it has displayed 8 digits, all it does it take display position 7 and put it in 8, take position 6 and put it in 7, etc down to 1 to 2.
Then it puts the newest digit in position 1.

I am getting there.

This code nearly works, but there is a problem with the bnumber() routine where it converts from ASCII to real numbers and applies decimal point correction to numbers.

Seems it will only add one decimal point.

I have written another one and which works and displays the IP as required.

(that is the “messing_around” flow.)

I am not getting where the other one is not working.

Display_cycler_3c.ino (5.14 KB)

XC3714_messing_around.ino (2.26 KB)

The Display_cycler_3c.ino file doesn't have a bnumber() function.

Nor does the other ino file.

Quit wasting our time. If you want to know why a function doesn't work, POST THE CODE WITH THE FUNCTION.

INLINE. There is no reason to attach such minuscule amounts of code.

Well, except for being embarrassed about how the code looks. And, that could be corrected

by not using excessive amounts of white space, by not placing useless comments in meaningless places and by properly indenting your code.

Look at EVERY menu item in the IDE, and learn what EVERY one does.