Pages: [1] 2   Go Down
Author Topic: replace delay()  (Read 2052 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am new to arduino (and to programming), so I have a very basic question. I have searched the web for solutions, but nothing really answered my question.

I'm working on a light system for an RC drift car. I want to blink 10 different leds, but in more different ways. I'm using a simple button to surf between the different led blinking modes. My problem is, that I'm using the delay() function to delay the blinking time. This stops my code and stops reading the button. I could probably solve it like it is in the "Blink without Delay" example, but I have to toggle 10 different leds in 10 different ways and that would make my code very complicated and very long. I have already written some of it, but I'm stuck now.

Code:
const int buttonPin = 2; //pushbutton
const int L1 = 3; //led 1
const int L2 = 4; //led 2
const int L3 = 5;
const int L4 = 6;
const int L5 = 7;
const int L6 = 8;
const int L7 = 9;
const int L8 = 10;
const int L9 = 11;
const int L10 = 12;

int testL = 13; //only for debugging, will be deleted

int reading;
int state;
int lastButtonState = HIGH;


//for blink mode2
int time = 100;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);  //set button as input

  for (int i=3; i<=12; i++) //set leds as outputs
    pinMode(i, OUTPUT);

  pinMode(Lpin, OUTPUT);  //only for debugging, will be deleted

  Serial.begin(9600);  //only for debugging, will be deleted
}

void loop() {

  reading = digitalRead(buttonPin);

  if (reading == LOW && reading != lastButtonState) {
    state++;
    if (state >= 9)
      state = 0;
    //state changes between 0 and 9 if button is pressed
    //these will be the different blinking modes
  }
  lastButtonState = reading;

  Serial.println(state); //to know which mode is active

    switch (state){  //the different modes:

  case 0: //all leds off
    for (int i=3; i<=12; i++)
      digitalWrite(i, LOW);
    break;

  case 1: //double blink for all leds with 70 millis delay
    for (int i=3; i<=12; i++)
      digitalWrite(i, HIGH);
    delay(70);
    for (int i=3; i<=12; i++)
      digitalWrite(i, LOW);
    delay(70);

    break;

  case 2: //blink mode 2
    digitalWrite(L1, HIGH);
    digitalWrite(L4, HIGH);
    digitalWrite(L7, HIGH);
    digitalWrite(L10, HIGH);
    digitalWrite(L5, HIGH);
    digitalWrite(L6, HIGH);
    delay(time);
    digitalWrite(L1, LOW);
    digitalWrite(L4, LOW);
    digitalWrite(L7, LOW);
    digitalWrite(L10, LOW);
    digitalWrite(L5, LOW);
    digitalWrite(L6, LOW);
    delay(time);
    digitalWrite(L1, HIGH);
    digitalWrite(L4, HIGH);
    digitalWrite(L7, HIGH);
    digitalWrite(L10, HIGH);
    digitalWrite(L5, HIGH);
    digitalWrite(L6, HIGH);
    delay(time);
    digitalWrite(L1, LOW);
    digitalWrite(L4, LOW);
    digitalWrite(L7, LOW);
    digitalWrite(L10, LOW);
    digitalWrite(L5, LOW);
    digitalWrite(L6, LOW);
    delay(time);


    digitalWrite(L2, HIGH);
    digitalWrite(L3, HIGH);
    digitalWrite(L8, HIGH);
    digitalWrite(L9, HIGH);
    delay(time);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    digitalWrite(L8, LOW);
    digitalWrite(L9, LOW);
    delay(time);
    digitalWrite(L2, HIGH);
    digitalWrite(L3, HIGH);
    digitalWrite(L8, HIGH);
    digitalWrite(L9, HIGH);
    delay(time);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    digitalWrite(L8, LOW);
    digitalWrite(L9, LOW);
    delay(time);


    break;
  case 3: //blink mode 3

      break;
  case 4:

    break;
  case 5:

    break;
  case 6:

    break;
  case 7:

    break;
  case 8:

    break;
  case 9:

    break;
  }
}

So my question is: How can I read the button constantly without having to write hundreds of pages of code?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 290
Posts: 25797
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The blink without delay is the way to go. With arrays there's no reason the code should be very long at all.
Logged

"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.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The first thing you should learn is using array's. Then you can code many things more efficient.
Write a separate functions for the blinking patterns without delays

Here (quite) some code snippets that should get you started, some are not super efficient but I think the application is not time critical smiley
Code:

int leds[10] = {3,4,5,6,7,8,9,10,11,12};  // array of the led numbers used

int state = 0;
int lastState = 0;

setup()
{
  for (int i=0; i<10; i++)
  {
    pinMode(led[i], INPUT_PULLUP);
  }
...
}

void loop()
{
  reading = digitalRead(buttonPin);
  if (reading == LOW && reading != lastButtonState)
  {
    state++;
    if (state >= 9) state = 0;
  }
  lastButtonState = reading;

  switch(state)
  {
    case 0: Pattern0(); break;
    case 1: Pattern1(); break;
    case 2: Pattern2(); break;
    ...
  }
}

////////////////////////////////////////////////////////
//
// PATTERN FUNCTIONS
//
void Pattern0()
{
  for (int i=0; i< 10; i++) digitalWrite(Leds[i], LOW);
}

void Pattern1()
{
  for (int i=0; i< 10; i++) digitalWrite(Leds[i], HIGH);
}

void Pattern2()
{
  static int interval = 100;    // each pattern
  static unsigned long lastTime;
  if (state != lastState) // first call to this pattern?
  {
    lastState = state;
    // setup the initial state of the leds
    for (int i=0; i< 10; i+= 2) // NOTE STEPSIZE 2
    {
     digitalWrite(Leds[i], HIGH);
     digitalWrite(Leds[i+1], LOW);
    }
    lastTime= millis();
  }
  // generic blink if interval has passed since last call
  if (millis() - lastTime >= interval)
  {
    for (int i=0; i< 10; i++) digitalWrite(Leds[i], !digitalRead(Leds[i]);  // blink;
    lastTime= millis();
  }
}

void Pattern3()
{
  static int interval = 50;    // each pattern
  static unsigned long lastTime;
  if (state != lastState) // first call to this pattern?
  {
    lastState = state;
    // setup the initial state of the leds
    for (int i=0; i< 10; i++) digitalWrite(Leds[i+1], LOW);
    digitalWrite(Leds[0], HIGH);
    digitalWrite(Leds[5], HIGH);
    lastTime= millis();
  }
  // generic shift if interval has passed since last call
  if (millis() - lastTime >= interval)
  {
    int temp = digitalRead(0);
    for (int i=0; i< 9; i++) digitalWrite(Leds[i], digitalRead(Leds[ i+1]);
    digitalWrite(leds[9], temp);
 
    lastTime= millis();
  }
}

You see the repeating pattern of patterns?  (code not tested)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1257
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Look at the MultiBlink code in the Playground. It is designed to do what you seem to need.
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your support, especially to robtillaart! I once used arrays, but I found it a bit difficult to understand them. I will work on that.

marco_c: I looked at that code and wit that, I can not make a double blink (or I don't know how). But thanks for the advice.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks guys! Now I understand a lot more from arduino and how to write programs. You just have to think in a logical way smiley-grin.

Now there are 14 different patterns and I'm planning to do 20. Here is a video of the current state: http://youtu.be/c4iR2h2bd0s
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can you post your final code for the future when other people finding this thread?
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can you post your final code for the future when other people finding this thread?

If it's ready I will!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So, it is getting ready, but I have a big problem. I want to flash the program on a Antmega8, but the code is a bit longer, than that the flash memory can hold. By exaclty 252 bytes. smiley-grin
How can I shrink it? smiley-grin

P.S. I had to upload the sketch, because it couldn't fit in a single post. smiley-grin

* RC_Drift_lights.ino (27.94 KB - downloaded 19 times.)
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
How can I shrink it?

you can remove the -   static unsigned long lastmillis = 0; - from the patterns()
and use one global  unsigned long lastmillis = 0;
That will save you 4 bytes per pattern

you might reuse state as a global var instead of local statics. (might introduce some less defined behavior)

static int count = 0;  idem

global vars can be used in all functions but they share state, where a static function has its scope only within the function it is defined in.

int interval = 90;  => uint8_t interval = 90;   use 8 bit variables where possible saves a byte per place
==> also in   for (uint8_t  i=0; i< 10; i++){

should get you started.
« Last Edit: November 05, 2012, 03:04:42 pm by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Now, I deleted all static unsigned long lastmillis = 0; - from the patterns() and declared a global one, but that didn't shrink the size with no bit!

I can't use count, because the blinkings go crazy.

Quote
int interval = 90;  => uint8_t interval = 90;   use 8 bit variables where possible saves a byte per place
==> also in   for (uint8_t  i=0; i< 10; i++){
So uint8_t is the same as byte?

edit:
I replaced all ints to bytes (and uint8_ts), but that only saved me 8 bytes.

I think you misunderstood me. The flash memory is too small not the SRAM. If this isn't the case, my apologies.
« Last Edit: November 05, 2012, 04:19:48 pm by Hasi321 » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, the delights of shrinking programs!

The first question is: why do you need to fit it on an atmega8? Using an atmega16 instead will save you the bother of shrinking the code and leave you room for expansion.

If you really do want to shrink that code, there are plenty of ways you can do it. For example, you can rewrite Pattern13, making use of the similarity between cases:

Code:
void Pattern13()  //leds go around
{
  static int interval = 70;
  static unsigned long lastmillis = 0;
  static int state;
  static boolean onoff;
  static int count = 0;

  if (firstRun){  //initialize leds and states only once
    onoff = LOW;
    for (int i=0; i< 10; i++) digitalWrite(Leds[i], LOW);
    digitalWrite(Leds[4], HIGH);
    digitalWrite(Leds[5], HIGH);
    count = 0;
  }
  else{
    if (millis() - lastmillis >= interval){  //switch case if interval has passed

      switch (state){
      case 0:  //blink first leds twice
      case 1:
      case 2:
      case 3:
        onoff = !onoff;
        digitalWrite(Leds[state], onoff);
        break;
      case 4:  //blink last leds twice
      case 5:
      case 6:
      case 7:
        onoff = !onoff;
        digitalWrite(Leds[13 - state], onoff);
        break;
      }
      count++;
      if (count >= 2){  //if programm has passed 2 times (on, off) go to the sixth part
        state = (state + 1) & 7;
        count = 0;
      }
      lastmillis = millis();
    }
  }
}

PS - if you factor out the lastmillis check/update code you can get it down to 7400 bytes or less.
« Last Edit: November 05, 2012, 05:57:25 pm by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
God Member
*****
Karma: 39
Posts: 988
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's something I'd try.  You use this pattern a lot:

Code:
    digitalWrite(Leds[0], LOW);
I wonder if it generates less code to replace all those calls with calls to a function to do the dereference:
Code:
    // global LED control function
    void setLed(byte led, byte lohi) {
        digitalWrite(Leds[led], lohi);
    }

    // replace all digitalWrite(Leds[0], LOW); with:
    setLed(0, LOW);

It would be easy to try on a few cases to see what the space impact is.

-br
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks guys problem solved. smiley-grin

I wonder if it generates less code to replace all those calls with calls to a function to do the dereference:
Code:
    // global LED control function
    void setLed(byte led, byte lohi) {
        digitalWrite(Leds[led], lohi);
    }

    // replace all digitalWrite(Leds[0], LOW); with:
    setLed(0, LOW);
It would be easy to try on a few cases to see what the space impact is.

I also tried this out, but it only saved me about 20 bytes...
« Last Edit: November 06, 2012, 12:06:12 pm by Hasi321 » Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 988
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Another idea.  There are a lot of patterns like this:

Code:
        digitalWrite(Leds[1], HIGH);
        digitalWrite(Leds[2], HIGH);
        digitalWrite(Leds[7], HIGH);
        digitalWrite(Leds[8], HIGH);

Would it be smaller to do this?

Code:
        setLeds("1278", HIGH);

In other words, would passing a string constant with the LEDs to set to a custom led-setting routine be cheaper than 4 separate calls?

Just a thought. 

-br

Logged

Pages: [1] 2   Go Up
Jump to: