Go Down

Topic: Cannot change value in Global Char Array variable (Read 2711 times) previous topic - next topic

martinozanzi

Hi, I am trying to build a led matrix display that rotates text.
Everything is working fine, but I have a problem with global char array variable that contains text to be shown on matrix:
I am unable to change the text in the variable from inside void loop. It continues to revert to original value.

Basically, I am trying to change text contained in the array variable after a button is pressed.
I am able to change variable value, as it seems looking at serial monitor (look for CHECK1: in code).
But as soon as the loop restarts, the variable is reverted to original value (look for CHECK2: in code).

problematic variable is: "char myText[]"

Is there anybody who can help me understanding what is wrong? Thanks in advance!!


HERE IS THE CODE:
Code: [Select]


#include "LedControl.h"
#include <avr/pgmspace.h>
#include "font8x8.h"

LedControl lc=LedControl(8,10,9,3); // Replace with your pin numbers

// User configurable Variables
// ------------------------------------------------------------------------
char myText[] ={"FIRST TEXT TO BE SHOWN"}; // replace with your text
const int animationDelay(80); // Adjusts scrolling speed

//
const int  buttonPin = 2;
//

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
//

// ------------------------------------------------------------------------
byte charBuffer[8]; // Buffer for screen 1
byte charBuffer2[8]; // Buffer for screen 2
byte charBuffer3[8]; // Buffer for screen 3
//byte charBuffer4[8]; // Buffer for screen 3
int charIndex=0; //Remember position in the myText string
int wordLen=sizeof(myText)/sizeof(char)-1; // Determine number of elements (letters) in array


int firstRun=0; // For cosmetical purposes
byte nextChar;

void setup() {
   
  int devices=lc.getDeviceCount(); // Get number of devices
  for(int address=0;address<devices;address++) { // Initialize all devices in the chain
   
     // initialize the button pin as a input:
    pinMode(buttonPin, INPUT);
    //
   
    lc.shutdown(address,false);
    lc.setIntensity(address,2);
    //lc.clearDisplay(address);
     pinMode(buttonPin, INPUT);
     Serial.begin(9600);
  }
}





// ==== Display Buffer on LED matrix ====
void bufDisplay(int LED, byte* buffer) {
for(int i=0;i<8;i++) { // Render Character on Screen 1
     lc.setRow(LED,i,buffer[i]);
     }
     //rotateBuffer(myCount);
}


// ==== Fill Buffer with character data ====
void fillBuffer(){
   for (int i=0;i<8;i++){
    charBuffer[i]=pgm_read_byte(&font8x8[myText[charIndex]-32][i]); //Reference actual char from the font 
  }
  //===============================================================================
  charIndex++; // Increment position in the myWord for next run
     if (charIndex>wordLen-1){ charIndex=0; } // if poistion one less than lengh, reset position to 0
}
// ------------------------------------------------------------------------------

// === Rotate buffer by swapping elements ====
void rotateBuffer(byte* buffer,int nextChar){
 
  for (int i=7;i>-1;i--){ // Rotate array
     if (i>0) { buffer[i]=buffer[i-1]; //  Swap elements 0-6
     }
     else { buffer[i]=nextChar; } // At pos 7 Add element from next character
     
  }
}

// ------------------------------------------------------------------------------

void loop() {
    int wordLen=sizeof(myText)/sizeof(char)-1;
  CHECK2:
  Serial.println(myText);
 

  fillBuffer(); //Let's fill buffer with first/next character in the word
   
   for (int j=7;j>-1;j--){ //Rotate 8 times to create animation of scrolling
     nextChar=pgm_read_byte(&font8x8[myText[charIndex]-32][j]); // Figure out what is the following character after current
     
    // This "First Run" part of the program is optional
    // -------------------------------------------------------------
     if (firstRun!=0) { // Shows character before it rotated.
       bufDisplay(0,charBuffer); // Display 1st buffer
       bufDisplay(1,charBuffer2); //Display Buffer 2
       bufDisplay(2,charBuffer3); //Display Buffer 3
       //bufDisplay(3,charBuffer4); //Display Buffer 4
     } //
     firstRun=1; // Set flag that it's not first run of the program
    // -------------------------------------------------------------
     //rotateBuffer(charBuffer4,charBuffer[23]); // Rotate/fill 4th buffer (for second matrix) first
     rotateBuffer(charBuffer3,charBuffer[15]); // Rotate/fill 3rd buffer (for second matrix) first
     rotateBuffer(charBuffer2,charBuffer[7]); // Rotate/fill 2nd buffer (for second matrix) first
     rotateBuffer(charBuffer,nextChar); // Rotate buffer for first matrix screen
     
     bufDisplay(0,charBuffer); // Show frame on matrix 1
     bufDisplay(1,charBuffer2); // Show frame on matrix 1
     bufDisplay(2,charBuffer3);
     //bufDisplay(3,charBuffer4);
     
     delay (animationDelay); // Delay before showing next frame
     
       //BUTTON
// read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
     
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
     
     
            if (buttonPushCounter==1)
      {
    //--------------------------------------------------------------------------------------------------------------------   
        char myText[] ={"SECOND TEXT TO BE SHOWN REPLACING FIRST"};
        //wordLen=sizeof(myText)/sizeof(char)-1;
        Serial.println (myText);
        Serial.println (wordLen);
        firstRun=0;
        charIndex=0;
        buttonPushCounter=0;
        break;
        //goto inizio;
       
    Serial.println("button=1");
    }
     
      else {}
     
     
     
      if (buttonPushCounter>=4)
      {buttonPushCounter=0;
     
Serial.println("button push counter reset");    }
     
      else {}
     
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
    }
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;
//BUTTON
     
     
   }

CHECK1:
           Serial.println (myText);   
}


Nick Gammon

You have two variables here:

Code: [Select]

char myText[] ={"FIRST TEXT TO BE SHOWN"}; // replace with your text


And another:

Code: [Select]

        char myText[] ={"SECOND TEXT TO BE SHOWN REPLACING FIRST"};


One is global, one is local.

There are a number of issues here, I suggest you look up C string handling.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

PaulS

Quote
Basically, I am trying to change text contained in the array variable after a button is pressed.
I am able to change variable value, as it seems looking at serial monitor (look for CHECK1: in code).
But as soon as the loop restarts, the variable is reverted to original value (look for CHECK2: in code).

No, I won't look for goto labels. There is no reason to be using labels (or goto) in your code.

The real problem is that you never change the text in the myText GLOBAL variable. You introduce a local variable of the same name that hides the global one. Nowhere near the same as changing the global variable.

martinozanzi

Thanks for replying.
I know this code is not perfect, it is my second project after led blink.. I am just trying to learn!
I also know that goto and labels are useless and I should avoid using it, read a couple of things about that.
Anyway I am not asking "please rewrite my code", just need to understand how to solve the global variable issue.

@ PaulS: you highlighted what is the problem, thanks, but how to solve that?
@ Nick: could you suggest a link to read about "C string handling"? Are you able to tell me how to make changes to a global variable? Or do I need to rewrite my code in order to use a local variable that I will then be able to change INSIDE the loop?

PaulS

Quote
you highlighted what is the problem, thanks, but how to solve that?

Don't use goto. Don't use the same name for local variables and global variables.

Do use strcpy() and/or strcat() to change the contents of a char array.

martinozanzi

Great, thanks: strcpy() and strcat() are what I was looking for.
Will test this evening and let you know.
Have a nice day!

Nick Gammon

Er, yes. But if you use strcpy to copy "SECOND TEXT TO BE SHOWN REPLACING FIRST" into the variable:

Code: [Select]

char myText[] ={"FIRST TEXT TO BE SHOWN"};


You will find that the amount of memory allocated will be too small. You need to put more effort into it than that.

As an example:

Code: [Select]

char myText[100];

void setup ()
  {
  Serial.begin (115200);
  strcpy (myText, "FIRST TEXT TO BE SHOWN");
  Serial.println (myText);

  strcpy (myText,  "SECOND TEXT TO BE SHOWN REPLACING FIRST");
  Serial.println (myText);
  }  // end of setup

void loop ()
  {
  }  // end of loop


That works providing you don't try to put more than 100 bytes into myText. And if you think that is possible, look up strncpy.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

aerouta

Hello I am attempting to learn the ins and outs of chars, strncpy, strcat, etc. And I came across this thread. You state that putting more than 100 bytes into myText would results in an error. While I changed myText[100] to myText[50], then 10 and 2, and I didn't get an error?? every worked like expected. Can you please explain?


Er, yes. But if you use strcpy to copy "SECOND TEXT TO BE SHOWN REPLACING FIRST" into the variable:

Code: [Select]

char myText[] ={"FIRST TEXT TO BE SHOWN"};


You will find that the amount of memory allocated will be too small. You need to put more effort into it than that.

As an example:

Code: [Select]

char myText[100];

void setup ()
  {
  Serial.begin (115200);
  strcpy (myText, "FIRST TEXT TO BE SHOWN");
  Serial.println (myText);

  strcpy (myText,  "SECOND TEXT TO BE SHOWN REPLACING FIRST");
  Serial.println (myText);
  }  // end of setup

void loop ()
  {
  }  // end of loop


That works providing you don't try to put more than 100 bytes into myText. And if you think that is possible, look up strncpy.

AWOL

Quote
hile I changed myText[100] to myText[50], then 10 and 2, and I didn't get an error?
You wouldn't get a compilation error, but a run time error, and they're subtle, and don't announce themselves.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

PaulS

Quote
every worked like expected. Can you please explain?
Try this:

Code: [Select]
char one[] = "One";
char two[] = "Two";
char three[] = "Three";

void setup()
{
    Serial.begin(115200);
    Serial.print("one = [");
    Serial.print(one);
    Serial.println("]");

    Serial.print("two = [");
    Serial.print(two);
    Serial.println("]");

    Serial.print("three = [");
    Serial.print(three);
    Serial.println("]");

    strcpy(two, "Eighteen");

    Serial.print("one = [");
    Serial.print(one);
    Serial.println("]");
}

void loop()
{
}


You'll see what happens when you write beyond the end of an array.

Changing the value in three, which has nothing following it in memory, would lead you you believe, incorrectly, that nothing was wrong.

guix

Hello I am attempting to learn the ins and outs of chars, strncpy, strcat, etc. And I came across this thread. You state that putting more than 100 bytes into myText would results in an error. While I changed myText[100] to myText[50], then 10 and 2, and I didn't get an error?? every worked like expected. Can you please explain?
When you write outside of an array bound, you may overwrite other variables.

For example if you create an array A with 3 elements, and then you create 2 variables B and C. In memory it would look like:

Code: [Select]
AAABC

If you write 4 elements in A, instead of 3, then it would look like:
Code: [Select]
AAAAC

You overwrite the value of B, so your program is probably bugged and you may search for hours the cause of that bug.. :)

You may also be lucky and never notice a problem...

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy