-1

I'm using an Arduino micro with an ic2 module and 1602 LCD. I've written a function to scroll a string on the LCD but I want to listen for a button press at the same time.

Here's my scrolling code:

void ScrollingText(String(StringToScroll), int(LineToScroll))
{
  lcd.setCursor(0, LineToScroll);
  if(StringToScroll.length() <= 16)
  {
    lcd.print(StringToScroll);
  }
  else
  {
    for (int x = 0; x < StringToScroll.length()-15; x++) {
      lcd.clear();
      delay(10);
      for (int i = 0; i < 16; i++) {
        lcd.print(StringToScroll[i+x]);
      }
      if(x == 0 or x == StringToScroll.length()-16)
      {
        delay(1000);
      }
      else
      {
       delay(400); 
      }
      lcd.setCursor(0, LineToScroll);
    }
  }
}

thanks in advance

Danny_ds
  • 11,201
  • 1
  • 24
  • 46
Nathbesspop
  • 5
  • 1
  • 4
  • The function you have now is "blocking". That means that once this function starts it thinks it is the only thing that needs to happen. So while it waits it doesn't just return and let other things run and do it's next thing when it gets called next. Nope, this function calls delay and just blocks everything up while it waits on the only thing it finds important. You'll need to rewrite this function to be non-blocking. Exactly how you do that depends in large part on the rest of your code. But basically you need a function that keeps getting called over and over and checks millis(). – Delta_G Apr 29 '20 at 17:10
  • People are going to throw interrupts at you. This is the noobs answer to blocking code. And it will work to solve your immediate problem. But it comes with some serious caveats and it also means that when you go to add the next thing to this code you may well end up having to undo that and redo it the right way anyway. The interrupt is just a band-aid on the problem of blocking code. – Delta_G Apr 29 '20 at 17:12
  • Never use blocking delays. Use interrupts to set a flag and then return to a fast main loop. – TomServo Apr 29 '20 at 22:26
  • You are correct. There is nothing noob about using interrupts. What I'm calling noob is using interrupts to cover up for blocking code. It's not anyone who uses them is noob. I use interrupts all the time. But noobs tend to want to use them in places where they're not really appropriate like this. – Delta_G Apr 29 '20 at 23:09
  • Please also look below at the comments on the answer about interrupts. I pointed out some good reasons why they are not the best solution here. I can give you more if you'd like. – Delta_G Apr 29 '20 at 23:12
  • Take for instance a button press. Without the interrupt you can count on the button state being the same at the beginning of a function and the end if you don't read the button in between. With the interrupt solution you can't do that. Now you may have a case where something gets corrupted because the button state changes in an unexpected way in the middle of some other function. You lose control over when to get a new state. You lose control over the sequencing of your code. That can be a really big deal. – Delta_G Apr 29 '20 at 23:14
  • And that's not to mention like I noted below, depending on what type of LCD this is, putting this code in an ISR may lock the board up. That certainly wouldn't be a good solution. – Delta_G Apr 29 '20 at 23:28
  • Take this simple line of code: if(buttonState != lastButtonState && buttonState == LOW){ That works perfectly fine if I'm polling my button. But as soon as I decide to use an interrupt to catch button presses because I don't want to write non-blocking code then that line becomes a huge potential bug. You'd have to disable the interrupts or make copies of variables or something to protect that line. Not that it can't be done, it's just an extra burden on the rest of the code. Especially when the non-blocking option is so easy to implement like it is here. – Delta_G Apr 29 '20 at 23:31

1 Answers1

0

You could listen for a button press on an interrupt pin, for example:

const byte interruptPin = 2;
volatile bool buttonState = false;

void setup() {
    pinMode(interruptPin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(interruptPin), ButtonISR, CHANGE);
}

void ButtonISR() {
     // set buttonState
}

and then check or use buttonState in your loop.

Danny_ds
  • 11,201
  • 1
  • 24
  • 46
  • 1
    Humans pressing buttons is a very poor use of interrupt functions. It sounds cool at first. But I've had to fix more code for more noobs after this move gets them into trouble later. The best answer is to rewrite that function so that it doesn't block. – Delta_G Apr 29 '20 at 17:08
  • @Delta_G Are you suggesting polling the button in a 'blocking' `loop()` function? In this case it might be ok, but what if you want to put the mcu to sleep in a battery powered device? Why do you think using an interrupt is so bad? Can you explain a bit more? (of course, in both cases the button will need to be debounced) – Danny_ds Apr 29 '20 at 17:22
  • 1
    Nobody said anything about sleep. If this button it to wake form sleep then yes an interrupt is appropriate. From the context of the question this seems very unlikely to be the case. – Delta_G Apr 29 '20 at 17:28
  • And no, the loop function shouldn't be blocking. Nothing in your code should be blocking. – Delta_G Apr 29 '20 at 17:29
  • @Delta_G And as for the blocking `ScrollingText` function, a timer interrupt could be used instead of delay(), but I wanted to keep the answer simple. – Danny_ds Apr 29 '20 at 17:31
  • Using millis would actually be simpler than the timer interrupt. Maybe not in the immediate, but as you keep trying to work with it. Trust me, I went through the trying to solve blocking code with interrupts phase. One day you'll understand why it isn't the best go to solution. – Delta_G Apr 29 '20 at 17:35
  • With a timer interrupt you start having to worry about things happening concurrent. You lose control over the sequencing. As written, he can change the string and then display it and be absolutely sure of the timing of what happens first and what happens second. If he is using a timer then he would have to either write a critical section or worry that things get corrupted if the interrupt tries to access the string while he is doing something with it. – Delta_G Apr 29 '20 at 17:37
  • Plus he's doing a lot of writing to that lcd in this function. If this was in an interrupt context I would start to worry about the length of that. There are other interrupts that need to be serviced. And if this is a serial LCD or I2C LCD then doing those writes in an interrupt context could easily lock the board up. – Delta_G Apr 29 '20 at 17:39
  • So yeah, you CAN use an interrupt to solve problems with blocking code, but it isn't just as simple as "oh just use an interrupt". You need to know what you're doing with interrupt code or you can get yourself in a heap of trouble. – Delta_G Apr 29 '20 at 17:40