Author Topic: Simple Arduino code rookie question  (Read 12289 times)

0 Members and 1 Guest are viewing this topic.

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Simple Arduino code rookie question
« on: May 25, 2015, 01:50:05 pm »
Using ATTiny85,
I am trying to turn ON 3 LEDs in sequence with 1s delay when I press the button. When I press the button again, I want to turn all 3 LEDs OFF simultaneously. And then, the cycle repeats again.
This is what I have: When I press the button for the first time, the initial sequence turning LEDS ON with 1s delay starts OK.  But then, I can not turn LEDs OFF when I press the button again. Any help? I am not sure if I am supposed to write "delay(1000)" in setMode. Thanks.
Code: [Select]
const int LED1 = 0;
const int LED2 = 1;
const int LED3 = 2;
const int button = 3;

boolean lastButton = LOW;
boolean currentButton = LOW;
int ledMode = 0;

void setup ()
{
  pinMode (LED1, OUTPUT);
  pinMode (LED2, OUTPUT);
  pinMode (LED3, OUTPUT);
  pinMode (button, INPUT);
 
}
boolean debounce (boolean last)
{
  boolean current = digitalRead (button);
  if (last != current)
  {
    delay (5);
    current = digitalRead (button);
  }
  return current;
}
void setMode (int mode)
{
  if (mode == 1)
  {
    digitalWrite (LED1, HIGH);
    delay(1000);
    digitalWrite (LED2, HIGH);
    delay(1000);
    digitalWrite (LED3, HIGH);
  }
  else if (mode == 2)
  {
    digitalWrite (LED1, LOW);
   digitalWrite (LED2, LOW);
  digitalWrite (LED3, LOW);
  }
  else
  {
    digitalWrite (LED1, LOW);
   digitalWrite (LED2, LOW);
  digitalWrite (LED3, LOW);
}
}

void loop ()
{
  currentButton = debounce(lastButton);
  if (lastButton == LOW && currentButton == HIGH)
  {
    ledMode++;
  }
  lastButton = currentButton;
  if (ledMode == 2 ) ledMode = 0;
  setMode (ledMode);
}


« Last Edit: May 25, 2015, 01:53:31 pm by IvoS »
 

Offline senso

  • Frequent Contributor
  • **
  • Posts: 951
  • Country: pt
    • My AVR tutorials
Re: Simple Arduino code rookie question
« Reply #1 on: May 25, 2015, 01:57:36 pm »
Switch this two:
if (ledMode == 2 ) ledMode = 0;
  setMode (ledMode);

And them think about what you are doing to that ledMode variable BEFORE it is passed to the setMode function.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #2 on: May 25, 2015, 02:40:42 pm »
I tried that, unfortunately it doesn't work. I am doing something stupid.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #3 on: May 25, 2015, 03:08:33 pm »
Try to add print statements at key points. It will help you to understand what's going on.
 

Offline m98

  • Frequent Contributor
  • **
  • Posts: 615
  • Country: de
Re: Simple Arduino code rookie question
« Reply #4 on: May 25, 2015, 04:52:30 pm »
Well, your Arduino executes the setMode() function in one piece and won't call the loop() function until finished. To respond to the button while the LED blinks, you need to use interrupts.
 

Offline Muxr

  • Super Contributor
  • ***
  • Posts: 1369
  • Country: us
Re: Simple Arduino code rookie question
« Reply #5 on: May 25, 2015, 05:10:22 pm »
I am not convinced that " if (lastButton == LOW && currentButton == HIGH)" is ever satisfied the second time. As I don't see how lastButton gets set to LOW on the 2nd push.

In your loop change your "lastButton = currentButton;" to "lastButton = digitalRead (button);". Just to make sure it's actually being read from the button instead of getting stuck in a logical false state in the debounce function.

Use serial for debugging if you can:

Code: [Select]
Serial.println("sending to serial..");
« Last Edit: May 25, 2015, 05:12:37 pm by Muxr »
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #6 on: May 25, 2015, 05:13:05 pm »
This is a really good learning project... don't rush it for someone else to hand you the answer on a plate.
The ideas you are trying to use are all valid, but there are some fundamental oversights which will help you learn.

As Zapta said - add some debugging print statements to see what your code is actually doing.
it should not take long to figure out.

Good luck.   a great next step after the blinking LED "
Don't ask a question if you aren't willing to listen to the answer.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #7 on: May 25, 2015, 06:16:30 pm »
Thank you. It kind of works, but I have to hold the button down for 2 sec to turn those LEDs OFF. Sometime 2 seconds, sometimes it turns OFF instantly. I think it gets stuck for 2x delay(1000); to wait for the "setMode" to finish? I thought the "void setMode" is set up only once when ATTiny is powerd up whereas void loop () runs over and over again.....  :(
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #8 on: May 25, 2015, 06:20:44 pm »
ok, so what happens if you press the button while in, or just about to enter one of the the delay() calls?
What if it just happens elsewhere?
Don't ask a question if you aren't willing to listen to the answer.
 

Offline hneve

  • Regular Contributor
  • *
  • Posts: 61
  • Country: no
    • http://www.neve.nu/
Re: Simple Arduino code rookie question
« Reply #9 on: May 25, 2015, 06:52:31 pm »
I love pseudokode.

I would think like this:

? Is button pressed
      ? Is timestamp set.
      If set then clear and turn leds off.
      Else set timestamp from millis.

? Is time since timestamp 1 sec.
Then led 1 on.
........
? Is time 3 sec.
Then led 3 on.



This is just a Idea.... I might have thought wrong...
73 de LB4NH
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #10 on: May 25, 2015, 07:03:08 pm »
OP once you have this working as you want it to...
Rewrite it without delay() -- that will teach you a lot about realtime, async event programming (the button).

That will give you a whole new insight to 'better' code development. and structure.   This should be the mandatory second lesson after the blinking LED ,

delay() - in most incarnations - is a 'blocking' function - which inhibits anything else happening for the duration of the delay.
« Last Edit: May 25, 2015, 07:04:57 pm by SL4P »
Don't ask a question if you aren't willing to listen to the answer.
 

Offline m98

  • Frequent Contributor
  • **
  • Posts: 615
  • Country: de
Re: Simple Arduino code rookie question
« Reply #11 on: May 25, 2015, 08:23:21 pm »
Thank you. It kind of works, but I have to hold the button down for 2 sec to turn those LEDs OFF. Sometime 2 seconds, sometimes it turns OFF instantly. I think it gets stuck for 2x delay(1000); to wait for the "setMode" to finish? I thought the "void setMode" is set up only once when ATTiny is powerd up whereas void loop () runs over and over again.....  :(
As you call setMode() in loop(), it gets called in a ...loop. And because the uC waits for setMode() to complete before doing something else, it can't check the state of the button before the blink sequence is finished. So you could use interrupts or non-blocking code. First ones interrupt the uC from whatever is happening and call a handler, where you could for e.g. change the mode and call your setMode() function again. Non-blocking code would be the more elegant solution, where @hneve posted a good example.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #12 on: May 25, 2015, 08:25:34 pm »
OP once you have this working as you want it to...
Rewrite it without delay() -- that will teach you a lot about realtime, async event programming (the button).

That will give you a whole new insight to 'better' code development. and structure.   This should be the mandatory second lesson after the blinking LED ,


+1

Delay is good for initial blinky but is a dead end otherwise.

After you get this reasonably working start to learn how to program with state machines (a fancy word) and polling instead of blocking delay. You can easily model it as an arbitrary number of arduinos running on the same MCU, one to track the button events, one to control the overall state, one to blink Leeds, etc. All without having to use  interrupts.

Delay is not your friend.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #13 on: May 25, 2015, 09:06:51 pm »
Thank you. It kind of works, but I have to hold the button down for 2 sec to turn those LEDs OFF. Sometime 2 seconds, sometimes it turns OFF instantly. I think it gets stuck for 2x delay(1000); to wait for the "setMode" to finish? I thought the "void setMode" is set up only once when ATTiny is powerd up whereas void loop () runs over and over again.....  :(
As you call setMode() in loop(), it gets called in a ...loop. And because the uC waits for setMode() to complete before doing something else, it can't check the state of the button before the blink sequence is finished. So you could use interrupts or non-blocking code. First ones interrupt the uC from whatever is happening and call a handler, where you could for e.g. change the mode and call your setMode() function again. Non-blocking code would be the more elegant solution, where @hneve posted a good example.
I don't need to use the button in the middle when LEDs are sequencing. So I kind of understand what you wrote about it can't check the button before sequence is finished. The problem alone is to turn OFF all 3 LEDs after they been turned ON.
But you are right. I tried to shorten the delay to delay(200) between digitalWrite (LED1, HIGH) etc., and the button responded much quickly to turn LEDs OFF. It must be pressed and held down until it turns OFF.

If I write the code without delays for lets say 8 modes, every button press = next mode, then, there is no problem. So the code structure written like this is no good for this task.
I have a book "Exploring Arduino" from Jeremy Blum, but there are no good examples on this kind of thing. Just a simple examples on digital read write, sensors etc. but very basics on each topic. So, I don't know where to look, tried google, no luck.
 

Offline hneve

  • Regular Contributor
  • *
  • Posts: 61
  • Country: no
    • http://www.neve.nu/
Re: Simple Arduino code rookie question
« Reply #14 on: May 25, 2015, 09:11:18 pm »
73 de LB4NH
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #15 on: May 25, 2015, 09:32:19 pm »
last hint:
write button code that does what you want, then wrap the LEDs around that.

We're not trying to be mean, and you are obviously getting the idea from your most recent attempts.  The essence is that the LEDs are a consequence of the button press, so the button is more important than the LEDs.

Imagine you are developing a bomb detonator... press to 'arm' then press again to stop the countdown... It won't work so well if the bpmb goes off while you're waiting!

The state-machine sounds complicated, and often the explanation makes it sound that way too...  Just think of a counter that increments at each state of operation... idle, press, LED1, LED2, LED3... etc.

In this simple example, one state will be unique (idle)... waiting for something to start the ball rolling, and then to sequence through the remaining 'states'.  Your second button press will clear the runtime conditions, and revert to that first idle condition.

Even with this minimal example, there are a number of options you can consider... eg whether to stop the sequence immediately 'mid-LED' or wait for the current state to complete.   This would mean 'catching' the second press, but holding the event as 'pending' until other condition are met...

This discussion can go on forever. The methodology,  you *must* master timing and asynchronous events before your code is worth talking about!
« Last Edit: May 25, 2015, 10:18:12 pm by SL4P »
Don't ask a question if you aren't willing to listen to the answer.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #16 on: May 25, 2015, 10:14:38 pm »
 

Offline Dragon88

  • Regular Contributor
  • *
  • Posts: 88
Re: Simple Arduino code rookie question
« Reply #17 on: May 26, 2015, 03:02:32 am »
Here's some code I wrote that does what you want (I think). I tested it on an Uno and it works fine:

Code: [Select]
#define redLED 2             //define IO
#define greenLED 3
#define blueLED 4
#define button 5

boolean lightsOn = false;    // state variables
int whichLED = 2;

int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(button, INPUT);
}

void loop()
{
  if (digitalRead(button) == LOW)    // The button is pressed, handle it
  {
    delay(200);                      // debounce and delay
    lightsOn = !lightsOn;            // toggle state
   
   
    if (lightsOn == false)          // turn LED off and clean up
    {
      counter = 0;
      digitalWrite(whichLED, LOW);
      whichLED = 2;
    } else {                         // Or if we are activating LEDs
      digitalWrite(whichLED, HIGH);  // Turn first LED on to start
    }
  }
 
  if (lightsOn == true)              // Manage LED state
  {
    counter++;                      // Increment counter
 
    if (counter >= 1000)            // ~ 1 second has passed
    {                               // So increment LED state
      counter = 0;                 
      digitalWrite(whichLED, LOW);  // Don't forget to turn old LED off
      whichLED++;
     
      if (whichLED >= 5)            // Don't let whichLED go to invalid state
        whichLED = 2;
       
      digitalWrite(whichLED, HIGH); // Turn new LED on
    }
  }
 
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second
}


I do believe in figuring it out yourself, but I also know from teaching people that an example is worth a thousand words. Now this is very quick, inefficient code. There are a thousand ways to do things and this is just one. The timing is only approximately 1 second per LED (do you see why?) and it ties up the entire microcontroller from doing other things. But you can modify and grow this code into something much better.

Notice the structure of the main loop. The LED doesn't really get turned on until the end. The entire first part of the loop is figuring out what state we are in, handling the button if it's pressed, and cleaning up as necessary. Once we know what state we should be in, acting on the state is too easy. Also notice that by using a counter and avoiding excessive delays, we can make the button far more responsive. Debouncing (really just delaying while the user removes their finger) becomes very important though with it being checked so frequently. There are far better ways to debounce. But this type of debounce also adds a "feature" or alternate mode of sorts, test it and see how.

Good luck. Make sure you understand this code fully, modify it, and make it your own.
« Last Edit: May 26, 2015, 03:05:01 am by Dragon88 »
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #18 on: May 26, 2015, 03:18:04 am »
Dragon88 is right, in giving some basic ideas to push you along...

Another 'feature' you can might become aware of in this type of operation is a 'long press'... e.g hold for 3-secs to clear and reset some other output - buzzer, a cycle counter or whatever...

keep us posted!
Don't ask a question if you aren't willing to listen to the answer.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #19 on: May 26, 2015, 01:20:54 pm »
You can imagine how readable your code gets if you would add a couple of more buttons and a couple of more functions to perform.

That would be a good next step to solve. How to manage you code readability/maintainability with increased complexity...?

For instance think of how a robot main loop would look. How would all the sensor information interleave with all the processing?

Don't feel bad if you don't know, not a lot of people do it right in my view (no using a real-time os with multi threading is not the way to go on a tiny mcu).
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline hneve

  • Regular Contributor
  • *
  • Posts: 61
  • Country: no
    • http://www.neve.nu/
Re: Simple Arduino code rookie question
« Reply #20 on: May 26, 2015, 01:24:11 pm »
I remember once I used the watchdog timer to poll the buttons. A fun experiment, worked fine thou.
73 de LB4NH
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #21 on: May 26, 2015, 01:39:53 pm »
I remember once I used the watchdog timer to poll the buttons. A fun experiment, worked fine thou.

You have a good point though. I think that interrupts are the secret to making your code 'multi-threading' on MCUs. Think about it, it is hardware supported and has minimal overhead (check the compiled assembler code to make sure).
You have to change how you think about your code - which is hard for most.

There is also another (software) option that is not known to many. It has to do with a strange construction you can do with a switch statement... (see Task.h in my library)
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: Simple Arduino code rookie question
« Reply #22 on: May 26, 2015, 08:44:03 pm »
It's essential when programming microcontrollers to understand the difference between 'blocking' functions and 'non-blocking' functions and how they can or might effect your application coding. A simple blocking function like delay() can be used in many cases without side effects but other times it can be a deadly bug. There can be many ways to structure your code to avoid such problems but does take understanding of the problem and how best to deal with it.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #23 on: May 26, 2015, 09:43:55 pm »
Thank you "Dragon88 " :-+ so much and all of you guys as well for helping me!
Using "Dragon88" code, I re-arranged few things and I finally have what I wanted! It is a one time sequence:
LED1 ON, delay 1sec, LED2 ON, delay 1 sec, LED3 ON.
I didn't involve all of you into this small project just for fun to blink LEDs!  :) This is a start up (turn ON) sequencer for my audio amplifier. LEDs will get replaced with:
- relay (to release bleeder resistors),
- opto coupler (to turn POWER (triac) ON)
- relay (to bypass inrush current limiting resistor)

I am also planning to use 2 remaining pins on ATTiny85 for LM35 temperature sensor to sense an overheat and another pin for overheat shut down.
So, many thanks again. :-+
I may still do some tweaks on that code later as I would like to have a different (uneven) time values. I know I can just change the counter value to different value but it always gives me the same delay between LEDs.
Here is the final code:
Code: [Select]
#define redLED 0         //define IO
#define greenLED 1
#define blueLED 2
#define button 3

boolean lightsOn = false;    // state variables
int whichLED = 0;

int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(button, INPUT);
}

void loop()
{
  if (digitalRead(button) == LOW)    // The button is pressed, handle it
  {
    delay(200);                      // debounce and delay
    lightsOn = !lightsOn;            // toggle state
   
   
    if (lightsOn == false)          // turn LED off and clean up
    {
      counter = 0;
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, LOW);
      digitalWrite(blueLED, LOW);
      whichLED = 0;
    } else {                         // Or if we are activating LEDs
      digitalWrite(whichLED, HIGH);  // Turn first LED on to start
    }
  }
 
  if (lightsOn == true)              // Manage LED state
  {
    counter++;                      // Increment counter
 
    if (counter >= 1000)            // ~ 1 second has passed
    {                               // So increment LED state
      counter = 0;                 
      digitalWrite(whichLED, HIGH);  // Don't forget to turn old LED off
      whichLED++;
     
      if (whichLED >= 3)            // Don't let whichLED go to invalid state
        whichLED = 3;
       
      digitalWrite(whichLED, HIGH); // Turn new LED on
    }
  }
 
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second
}




 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #24 on: May 27, 2015, 02:23:51 am »
This code is complicated.
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9961
  • Country: nz
Re: Simple Arduino code rookie question
« Reply #25 on: May 27, 2015, 07:12:10 am »
Arduino should rename delay() to. GoAwayCoverYourEyesAndCountTo()

It would make things more obvious to noobs and the length would make people not want to type it out and instead use timers

 :-DD
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline Dragon88

  • Regular Contributor
  • *
  • Posts: 88
Re: Simple Arduino code rookie question
« Reply #26 on: May 27, 2015, 11:02:40 am »
Using "Dragon88" code, I re-arranged few things and I finally have what I wanted! It is a one time sequence:
LED1 ON, delay 1sec, LED2 ON, delay 1 sec, LED3 ON.

If that's all you need to do, you can simplify the code quite a bit. I thought you wanted it to cycle through and repeat while waiting for the button press to turn them off.

i.e.

Code: [Select]
for (int i = 0; i <= 2; i++)    ;For pins 0 through 2
{
  digitalWrite(i, HIGH);
  delay(1000);
}

Run that when the button is pressed, then just wait for another button press and turn everything off.
« Last Edit: May 27, 2015, 11:07:05 am by Dragon88 »
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #27 on: May 27, 2015, 09:31:03 pm »
Thank you Dragon88, I tried that and it also works. But once again, delay is my enemy. If I press and hold the button down, it rolls over the "delay(200)" button debounce function and the loop goes marry go round. I will have to figure out a different debounce function for the button so I can eliminate "delay()" in that loop. :)
 

Offline Dragon88

  • Regular Contributor
  • *
  • Posts: 88
Re: Simple Arduino code rookie question
« Reply #28 on: May 28, 2015, 02:57:41 am »
If you want to be able to hold the button down, there are plenty of ways to do that. You could start a counter, set for 3 seconds equivalent or whatever you want. Then when you check for another button press, also check that counter to see if it has reached zero. You could also flip a boolean and have some future condition that flips it back, i.e. the last LED gets turned on in the sequence. Again, compare against that boolean when checking for a "turn off" button press to see if it should be allowed yet.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #29 on: May 28, 2015, 04:20:37 am »
For several months I am toying with the idea of writing an article about simple multi tasking with Arduino that will target beginners. Something along these lines:

Each task has two core methods, setup() and loop(). There are several options for implementing tasks, e.g.   classes, namespaces, or name prefixes. With the name prefix approach a task may look like

// ----- button task
   ... some button state variables

   // ---- Core functions
   void button_setup() { ... }
   void button_loop() { ... }

   // ---- API functions

   boolean button_isPressed() {}  // post debouncing

   boolean button_consumeClickEvent() {  }
   boolean button_consumeLongPressEvent() {  }

// -----


and then the main will look like

void setup() {
   button_setup();
   task2_setup();
   task3_setup();
}

void setup() {
   button_loop();
   task2_loop();
   task3_loop();
}

Some useful library tasks will be timers, debouncers, leds (on, off, blink, etc), serial line readers,  and buttons (with debouncers and event detection), and the examples will include a few state machine based apps such as this one.

I think this can be made simple enough for beginners to understand and follow.

Here are a few examples from a previous project

https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/button.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/passive_timer.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/byte_debouncer.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/action_led.h
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #30 on: May 28, 2015, 09:31:40 am »
For more complex tasks, you'll need a statemachine per task to keep track of what you were doing and what the next step (state) will be...
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Simple Arduino code rookie question
« Reply #31 on: May 28, 2015, 08:45:25 pm »
For more complex tasks, you'll need a statemachine per task to keep track of what you were doing and what the next step (state) will be...

Wouldn't you do the FSM inside each task?

One really simple and nifty thing would be able to schedule tasks for later execution. Maybe have the return code from the "loop()" indicate how many milliseconds to wait until it is activated again. Anybody who returns 0 can just fight it out for whatever CPU cycles are left....

Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #32 on: May 29, 2015, 01:09:18 am »
One really simple and nifty thing would be able to schedule tasks for later execution. Maybe have the return code from the "loop()" indicate how many milliseconds to wait until it is activated again. Anybody who returns 0 can just fight it out for whatever CPU cycles are left....

For most beginners programs, a simple timer check in the task's loop () is good enough.

The main point is having those small state machines in the tasks as you pointed out.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #33 on: May 29, 2015, 05:40:58 am »
Wouldn't you do the FSM inside each task?

I thought I said that  :o

I check the time at the start of each loop and use that to determine if specific Tasks waiting for a certain period are up for execution yet when they come to check.

The state machine in my library is implemented by a switch statement and a private var (hidden behind some macro's). This is one of the nicest ways I was able to discover to do cooperative multi tasking with very low overhead. It allows you to write code like this (template classes):

Code: [Select]
Task_Begin(Execute)
{
while(true)
{
Task_YieldUntil(DelaysT::Wait(BaseT::getId(), Timeout));
BaseT::OnTimeout();
}
}
Task_End

private:
int _task;

This is a part of the TimeoutTask in my library. The Task_ macros implement the switch statement. DelaysT::Wait is a way to have your task wait for a certain period. All you have to do is call the Execute method (of this class) from the loop() repeatedly. No, that while(true) loop will not hang your program - it's magic!  8)
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #34 on: May 29, 2015, 06:02:22 am »
Wouldn't you do the FSM inside each task?

I thought I said that  :o

I check the time at the start of each loop and use that to determine if specific Tasks waiting for a certain period are up for execution yet when they come to check.

The state machine in my library is implemented by a switch statement and a private var (hidden behind some macro's). This is one of the nicest ways I was able to discover to do cooperative multi tasking with very low overhead. It allows you to write code like this (template classes):

Code: [Select]
Task_Begin(Execute)
{
while(true)
{
Task_YieldUntil(DelaysT::Wait(BaseT::getId(), Timeout));
BaseT::OnTimeout();
}
}
Task_End

private:
int _task;

This is a part of the TimeoutTask in my library. The Task_ macros implement the switch statement. DelaysT::Wait is a way to have your task wait for a certain period. All you have to do is call the Execute method (of this class) from the loop() repeatedly. No, that while(true) loop will not hang your program - it's magic!  8)

Can you explain the semantic of this code? (it doesn't matter how it's implemented).

Can the task consider other inputs or events while it is delaying?
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #35 on: May 29, 2015, 06:52:44 am »
DelayT::Wait returns a bool to indicate if the timeout specified has expired. In the main loop DelaysT is fed the current (delta) time. It maintains a list of waiting tasks (by Id) and counts each task down.

The Task_YieldUntil will exit the Execute method if the wait is not over yet. If the wait is over, the Execute method continues and calls the OnTimeout() method implemented by the base class (BaseT is a template parameter used as base class).

Then the while(true) loop takes it all to the top and the wait starts again.

The Execute method is called in the loop() function where other Task-methods can be called in sequence. Each task-method will perform a short/small piece of code and the exit again from its method (using the Task_Yield macros).

You could have multiple Timeout Tasks all doing different Timeout values blinking leds on different pins.

More?
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #36 on: May 30, 2015, 11:01:01 pm »
So, I had more time to play with the code to take the "delay()" completely (except 1ms at the end) out of "debouce" function and replaced it with debounce function I used from Jeremy's book. That works exactly as I want it. The button will execute(change the statement) just one time when pressed and held down. Unlike it was going in circles before.
I might give it more tweaks later, time permitted.
Thank you guys for helping me.
Code: [Select]

#define redLED 0         //define IO
#define greenLED 1
#define blueLED 2
#define BUTTON 3

boolean lightsOn = false;    // state variables

boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.

int whichLED = 0;

int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(BUTTON, INPUT);
}

/* 
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
  currentButton = debounce (lastButton);            // read debounced state
  if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
    lastButton = currentButton;                     // reset button value
    digitalWrite (whichLED, lightsOn);                      // change the LED state


   
   
    if (lightsOn == false)          // turn LED off and clean up
    {
      counter = 0;
      digitalWrite(redLED, LOW);
      digitalWrite(greenLED, LOW);
      digitalWrite(blueLED, LOW);
      whichLED = 0;
     
    } else {                         // Or if we are activating LEDs
      digitalWrite(whichLED, HIGH);  // Turn first LED on to start
    }
 
 
  if (lightsOn == true)              // Manage LED state
  {
    counter++;                      // Increment counter
 
    if (counter >= 1000)            // ~ 1 second has passed
    {                               // So increment LED state
      counter = 0;                 
      digitalWrite(whichLED, HIGH);  // Don't forget to turn old LED off
      whichLED++;
     
      if (whichLED >= 3)            // Don't let whichLED go to invalid state
        whichLED = 3;
       
      digitalWrite(whichLED, HIGH); // Turn new LED on
    }
  }
 
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second
}




 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #37 on: May 30, 2015, 11:33:50 pm »
For several months I am toying with the idea of writing an article about simple multi tasking with Arduino that will target beginners. Something along these lines:

Each task has two core methods, setup() and loop(). There are several options for implementing tasks, e.g.   classes, namespaces, or name prefixes. With the name prefix approach a task may look like

// ----- button task
   ... some button state variables

   // ---- Core functions
   void button_setup() { ... }
   void button_loop() { ... }

   // ---- API functions

   boolean button_isPressed() {}  // post debouncing

   boolean button_consumeClickEvent() {  }
   boolean button_consumeLongPressEvent() {  }

// -----


and then the main will look like

void setup() {
   button_setup();
   task2_setup();
   task3_setup();
}

void setup() {
   button_loop();
   task2_loop();
   task3_loop();
}

Some useful library tasks will be timers, debouncers, leds (on, off, blink, etc), serial line readers,  and buttons (with debouncers and event detection), and the examples will include a few state machine based apps such as this one.

I think this can be made simple enough for beginners to understand and follow.

Here are a few examples from a previous project

https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/button.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/passive_timer.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/byte_debouncer.h
https://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/action_led.h

I think the most difficult part for beginners it to understand the raw basic structure.
When do I use } ? Do I have to use a "{" before "for" or "else" ?......
I can picture the task in my head but even though I write it down on piece of paper in a simple way before I begin to write the actual code, it won't help me much later anyway.  How do I even begin when I don't know things like control structures, data types and further syntax? Some of those I have never seen before and have no clue what they mean.
Now, there are conversions, variable scope & qualifiers.... I don't even want to go further. I couldn't compile the code because of one crazy "}"  >:(   There are so many combinations, it's just not easy for beginner. It took me a while just to wrap my head around the debounce function.....
What works the best for me are examples, so I can see the actual working structure that can be modified.
But that is not programming any more, is it ?  :D


« Last Edit: May 30, 2015, 11:36:09 pm by IvoS »
 

Offline Dragon88

  • Regular Contributor
  • *
  • Posts: 88
Re: Simple Arduino code rookie question
« Reply #38 on: May 31, 2015, 02:49:34 am »
I firmly believe in learning programming with the aid of examples. Imagine trying to learn how to drive without ever having seen a car driven by someone else. It would seem completely strange and perhaps impossible, because you don't know the process AND you don't know what the end result should look like. But with an example, you have a context in your mind for what you need to do. Granted, after a certain point you should crossover and start creating original code on your own, but the first step is learning the building blocks and mastering the basics from good instruction and good examples.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #39 on: May 31, 2015, 05:58:26 am »
But before you can really drive, you have to learn the traffic rules - same with coding: you have to know the syntax of the language of choice. If you still struggle with the '{' and the like, you need to learn that. If that stuff is automatic (enough) than you can focus on the parts that matter (the logic you wrote down on a piece of paper)...
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #40 on: May 31, 2015, 06:03:05 am »
it's that darned single missing semicolon or curly brace...
nested deep inside a hundred lines of new code!

Comment out huge chunks until it jumps out at you as the most obvious error in the world!!
Don't ask a question if you aren't willing to listen to the answer.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #41 on: May 31, 2015, 11:56:16 am »
There are so many combinations, it's just not easy for beginner. It took me a while just to wrap my head around the debounce function.....

There is some kerning that you must go through but if different functionalities are decoupled and separated from each other is easier to understand. This is actually how the pros can handle complex programs, by breaking them to small and simple chunks.

The button read/denounce function is a good example for such separation. BTW,  I wouldn't even require the 'last' argument.

Anyway, good job on being (almost) delay free. Stay clean :)

 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6193
  • Country: us
Re: Simple Arduino code rookie question
« Reply #42 on: May 31, 2015, 12:00:31 pm »
it's that darned single missing semicolon or curly brace...
nested deep inside a hundred lines of new code!

Comment out huge chunks until it jumps out at you as the most obvious error in the world!!

Some tools are better than other providing useful error messages.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #43 on: June 07, 2015, 01:28:04 pm »
Guys, I need your help again, please.
After I successfully implemented LM35 temperature sensors to my code for overheat shut down , I am kind of stuck on one more task I would like to add. When LM35 temp sensor shuts down all LEDs (this works OK), I want to disable the push BUTTON if   (val > LOWER_BOUND).  I tried to add some code at the very bottom but no luck.  As it is right now with "do" and "while",  the button gets disabled but never gets enabled again.   |O

Code: [Select]

#define redLED 0         //define IO
#define greenLED 1
#define blueLED 2
#define BUTTON 4
#define TEMP 3

const int LOWER_BOUND = 53;
const int UPPER_BOUND = 56;
int val = 0;

boolean lightsOn = false;    // state variables
boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.
int whichLED = 0;
int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode (TEMP, INPUT);
}
/*
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
    currentButton = debounce (lastButton);            // read debounced state
    if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
lastButton = currentButton;                     // reset button value
             digitalWrite (whichLED, lightsOn);              // change the LED state

             if (lightsOn == false)            // turn LED off and clean up
{
  counter = 0;
    digitalWrite(redLED, LOW);
    digitalWrite(greenLED, LOW);
    digitalWrite(blueLED, LOW);
    whichLED = 0;
  }
  else
  { // Or if we are activating LEDs
    digitalWrite(whichLED, HIGH);  // Turn first LED on to start
  }

  if (lightsOn == true)              // Manage LED state
{
  counter++;                      // Increment counter
  if (counter >= 1000)            // ~ 1 second has passed
    { // So increment LED state
      counter = 0;
      digitalWrite(whichLED, HIGH);  // Don't forget to turn old LED off
      whichLED++;
      if (whichLED > 2)            // Don't let whichLED go to invalid state
        whichLED = 2;
    }
  }
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second

val=analogRead (TEMP);
    if (val >= UPPER_BOUND)
  {
    if (lightsOn)
    {
      counter = 0;
      digitalWrite (redLED, LOW);
      digitalWrite (greenLED, LOW);
      digitalWrite (blueLED, LOW);
      lightsOn = false;
    }
  }
   
    else
    {
      lightsOn == true;                   // It is good up to here
  }
   
    val=analogRead (TEMP);      //I am trying to disable button through "! lightsOn"
    if (val > UPPER_BOUND)   
    {
      if (! lightsOn)         
      {
        do
        {
     lightsOn = false;                // "lightsOn" goes to false state and it stays false
     }
      while  (val > LOWER_BOUND);
      }
    }
    else                           // When the temperature drops under LOWER_BOUND,
                                  //lightsOn should be true, but it stays false and button
     {                            // is hence disabled
      lightsOn == true;
    }
}

 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #44 on: June 07, 2015, 01:34:18 pm »
You could just stop calling the main-good-loop and call a different main-bad-loop...?
The main-bad-loop would do nothing but check for ok-temps...?
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline kolonelkadat

  • Regular Contributor
  • *
  • Posts: 202
  • Country: us
  • Obviously, windows are central to Windows.
    • Force Project X
Re: Simple Arduino code rookie question
« Reply #45 on: June 07, 2015, 02:00:57 pm »
As it is right now with "do" and "while",  the button gets disabled but never gets enabled again.   |O


you have to read the value again to see if it has gone below the threshold.

I assume this should work. I dont know though, when I copied it to text editor, the curlies wound up all over the place.

Code: [Select]
#define redLED 0         //define IO
#define greenLED 1
#define blueLED 2
#define BUTTON 4
#define TEMP 3

const int LOWER_BOUND = 53;
const int UPPER_BOUND = 56;
int val = 0;

boolean lightsOn = false;    // state variables
boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.
int whichLED = 0;
int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode (TEMP, INPUT);
}
/*
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
    currentButton = debounce (lastButton);            // read debounced state
    if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
lastButton = currentButton;                     // reset button value
             digitalWrite (whichLED, lightsOn);              // change the LED state

             if (lightsOn == false)            // turn LED off and clean up
{
  counter = 0;
    digitalWrite(redLED, LOW);
    digitalWrite(greenLED, LOW);
    digitalWrite(blueLED, LOW);
    whichLED = 0;
  }
  else
  { // Or if we are activating LEDs
    digitalWrite(whichLED, HIGH);  // Turn first LED on to start
  }

  if (lightsOn == true)              // Manage LED state
{
  counter++;                      // Increment counter
  if (counter >= 1000)            // ~ 1 second has passed
    { // So increment LED state
      counter = 0;
      digitalWrite(whichLED, HIGH);  // Don't forget to turn old LED off
      whichLED++;
      if (whichLED > 2)            // Don't let whichLED go to invalid state
        whichLED = 2;
    }
  }
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second

val=analogRead (TEMP);
    if (val >= UPPER_BOUND)
  {
    if (lightsOn)
    {
      counter = 0;
      digitalWrite (redLED, LOW);
      digitalWrite (greenLED, LOW);
      digitalWrite (blueLED, LOW);
      lightsOn = false;
    }
  }
   
    else
    {
      lightsOn == true;                   // It is good up to here
  }
   
    val=analogRead (TEMP);      //I am trying to disable button through "! lightsOn"
    if (val > UPPER_BOUND)   
    {
      if (! lightsOn)         
      {
        do
        {
     lightsOn = false;                // "lightsOn" goes to false state and it stays false
val=analogRead (TEMP);
     }
      while  (val > LOWER_BOUND);
      }
    }
    else                           // When the temperature drops under LOWER_BOUND,
                                  //lightsOn should be true, but it stays false and button
     {                            // is hence disabled
      lightsOn == true;
    }
}
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #46 on: June 07, 2015, 05:06:36 pm »
As it is right now with "do" and "while",  the button gets disabled but never gets enabled again.   |O


you have to read the value again to see if it has gone below the threshold.

I assume this should work. I dont know though, when I copied it to text editor, the curlies wound up all over the place.

Code: [Select]
#define redLED 0         //define IO
#define greenLED 1
#define blueLED 2
#define BUTTON 4
#define TEMP 3

const int LOWER_BOUND = 53;
const int UPPER_BOUND = 56;
int val = 0;

boolean lightsOn = false;    // state variables
boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.
int whichLED = 0;
int counter = 0;            // main counter

void setup()
{
  pinMode(redLED, OUTPUT);      // set up IO
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode (TEMP, INPUT);
}
/*
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
    currentButton = debounce (lastButton);            // read debounced state
    if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
lastButton = currentButton;                     // reset button value
             digitalWrite (whichLED, lightsOn);              // change the LED state

             if (lightsOn == false)            // turn LED off and clean up
{
  counter = 0;
    digitalWrite(redLED, LOW);
    digitalWrite(greenLED, LOW);
    digitalWrite(blueLED, LOW);
    whichLED = 0;
  }
  else
  { // Or if we are activating LEDs
    digitalWrite(whichLED, HIGH);  // Turn first LED on to start
  }

  if (lightsOn == true)              // Manage LED state
{
  counter++;                      // Increment counter
  if (counter >= 1000)            // ~ 1 second has passed
    { // So increment LED state
      counter = 0;
      digitalWrite(whichLED, HIGH);  // Don't forget to turn old LED off
      whichLED++;
      if (whichLED > 2)            // Don't let whichLED go to invalid state
        whichLED = 2;
    }
  }
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second

val=analogRead (TEMP);
    if (val >= UPPER_BOUND)
  {
    if (lightsOn)
    {
      counter = 0;
      digitalWrite (redLED, LOW);
      digitalWrite (greenLED, LOW);
      digitalWrite (blueLED, LOW);
      lightsOn = false;
    }
  }
   
    else
    {
      lightsOn == true;                   // It is good up to here
  }
   
    val=analogRead (TEMP);      //I am trying to disable button through "! lightsOn"
    if (val > UPPER_BOUND)   
    {
      if (! lightsOn)         
      {
        do
        {
     lightsOn = false;                // "lightsOn" goes to false state and it stays false
val=analogRead (TEMP);
     }
      while  (val > LOWER_BOUND);
      }
    }
    else                           // When the temperature drops under LOWER_BOUND,
                                  //lightsOn should be true, but it stays false and button
     {                            // is hence disabled
      lightsOn == true;
    }
}

YES! :-+  It works!
It is good to know that I was in the right ball park with "do" and "while". I know there are many many other ways to do it. I was looking yesterday on Arduino reference page and scratching my head as I had no clue what to use from control structures and further syntax.
Many thanks.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Simple Arduino code rookie question
« Reply #47 on: June 08, 2015, 06:02:57 am »
You try to weave the lightsOn logic through the button and led logic. I don't think you have to do that.

Consider this:

Code: [Select]
void loop()
{
    int temp = readDigital(TEMP);
    if (temp < MAX_THRESHOLD)
    {
        ScanButtonAndDriveLeds();
    }
    else
    {
        DisableOutput();
        WaitForTempToLower();
    }
}

The ScanButtonAndDriveLeds() function is the code you had before you tried to incorporate the temp logic. DisableOutput is the code that switches of the Leds and WaitForTempToLower() performs a loop that reads the temp value and only exists if its below the Max (or any other value).

I think your code will be more readable and maintainable. Remember - it is likely that you will not understand your own code if you revisit it after a couple of months (spending doing something else)...

[2c]
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #48 on: June 08, 2015, 07:14:19 pm »
Thanks, Yes, probably. The code will need revision that is for sure because I will be using ATtiny84 instead of 85, adding another temp sensor and using one more pin for LED status ON/OFF/overheat.
Thank you for your suggestion. :)
 

Offline SL4P

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
  • There's more value if you figure it out yourself!
Re: Simple Arduino code rookie question
« Reply #49 on: June 09, 2015, 04:54:24 am »
Congratulations on getting it working the way you wanted it to!
This was a great example of a 'rookie' asking and receiving - with the appropriate amount of learning on the way through!

Lesson 1: Avoid delay() at all costs, unless you're prepared for the consequences!
Lesson 2: Ask the right questions, don't skimp on detail, or you'll get the wrong answer!

You should now have a lot better understanding of how the code and flow operates  and will be able to make magic with a micro!
Don't ask a question if you aren't willing to listen to the answer.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #50 on: June 16, 2015, 11:30:24 pm »
I have my code refined, I added 2 temperature sensors and I also added "LEDON" as my on/off status LED light.
Everything works but, lower down in the code following
Quote
val=analogRead (TEMP1);
if (val > UPPER_BOUND)
  {
      if (! lightsOn)             
      {
        do
        {
I want to have the LEDON to blink using "counter" while the temperature is still high above the LOWER_BOUND
Quote
while  (val > LOWER_BOUND);
but the LEDON blinks only once at the beginning when the "do" executes and then it's constantly ON during the while condition but it is not flashing. I am trying to figure out how to make it blink, but it looks like I have some conflicts there at the beginning >:( perhaps that prevent the blinking?  |O Any help appreciated.
Code: [Select]

#define BLEEDERS 0         //define IO
#define TRIAC 1
#define BYPASS 2
#define LEDON 3
#define BUTTON 4
#define TEMP1 5
#define TEMP2 6

const int LOWER_BOUND = 87;
const int UPPER_BOUND = 115;
int val = 0;

boolean lightsOn = false;    // state variables
boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.
int whichLED = 0;
int counter = 0;            // main counter

void setup()
{
  pinMode(BLEEDERS, OUTPUT);      // set up IO
  pinMode(TRIAC, OUTPUT);
  pinMode(BYPASS, OUTPUT);
  pinMode(LEDON, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode(TEMP1, INPUT);
  pinMode(TEMP2, INPUT);
}
/*
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
    currentButton = debounce (lastButton);            // read debounced state
    if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
lastButton = currentButton;                         // reset button value
             digitalWrite (whichLED, lightsOn);     // change the LED state
             digitalWrite (LEDON, lightsOn);

             if (lightsOn == false)                 // turn LED off and clean up
  {
  counter = 0;
    digitalWrite(BLEEDERS, LOW);
    digitalWrite(TRIAC, LOW);
    digitalWrite(BYPASS, LOW);
    digitalWrite(LEDON, LOW);
    whichLED = 0;
  }
  else                              // Or if we are activating LEDs
  {                                 
    digitalWrite(whichLED, HIGH);   // Turn first LED on to start
    digitalWrite(LEDON, HIGH);
  }

  if (lightsOn == true)              // Manage LED state
{
  counter++;                      // Increment counter
  if (counter >= 500)            // ~ 1 second has passed
    { // So increment LED state
      counter = 0;
      digitalWrite(whichLED, HIGH);  //
      whichLED++;
      if (whichLED > 2)            // Don't let whichLED go to invalid state
        whichLED = 2;
    }
  }
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second

val=analogRead (TEMP1);                // Read the TEMP1 sensor
    if (val >= UPPER_BOUND)            // If value is higher than upper bound
  {
    if (lightsOn)                      // and OUTPUTs are ON
    {
      counter = 0;                     // shut everything OFF and clear the counter
      digitalWrite (BLEEDERS, LOW);
      digitalWrite (TRIAC, LOW);
      digitalWrite (BYPASS, LOW);
      digitalWrite (LEDON, LOW);
      lightsOn = false;
    }
  }
   
    else
    {
      lightsOn == true;                // Otherwise, toggle button, ON - OFF
  }
   
    val=analogRead (TEMP1);        // Read the TEMP1 sensor
    if (val > UPPER_BOUND)         //If value is higher than upper bound...
    {
      if (! lightsOn)              //...and if outputs were shut OFF by TEMP1 sensor
      {
        do
        {
     lightsOn = false;             // turn all outputs OFF
     val=analogRead (TEMP1);       // and read the TEMP1 sensor again
     digitalWrite(LEDON, HIGH);
     
     counter++;                      //  I WANT THE "LED" TO BLINK
     if (counter >= 500)            //  USING counter INSTEAD OF delay()
    {                               //
      counter = 0;
      digitalWrite(LEDON, LOW);  //
             
    }
    else
    {
      digitalWrite(LEDON, HIGH);
    }
   }
      while  (val > LOWER_BOUND);  // keep all outputs OFF during the time when value is
      }                            // above lower bound, BUTTON is disabled
    }
    else                           
                                 
     {                           
      lightsOn == true;             // Otherwise, toggle button, ON - OFF
    }
   
    val=analogRead (TEMP2);             //Read the TEMP2 sensor
    if (val >= UPPER_BOUND)         //If value is higher than upper bound
  {
    if (lightsOn)                   // and OUTPUTs are ON
    {
      counter = 0;
      digitalWrite (BLEEDERS, LOW);  //shut everything OFF and clear the counter
      digitalWrite (TRIAC, LOW);
      digitalWrite (BYPASS, LOW);
      lightsOn = false;           
    }
  }
   
    else
    {
      lightsOn == true;            // Otherwise, toggle button, ON - OFF
  }
   
    val=analogRead (TEMP2);        // read the TEMP2 sensor
    if (val > UPPER_BOUND)         // if value is higher than upper bound...
    {
      if (! lightsOn)              //...and if outputs were shut OFF by TEMP2 sensor
      {
        do
        {
     lightsOn = false;             // turn all outputs OFF
     val=analogRead (TEMP2);       // and read the TEMP2 sensor again
   }
      while  (val > LOWER_BOUND);  // keep all outputs OFF during the time when value is
      }                            // above lower bound, BUTTON is disabled
    }
    else                           
                                   
     {                             
      lightsOn == true;            // Otherwise, toggle button, ON - OFF
     }
}
« Last Edit: June 16, 2015, 11:44:54 pm by IvoS »
 

Offline kolonelkadat

  • Regular Contributor
  • *
  • Posts: 202
  • Country: us
  • Obviously, windows are central to Windows.
    • Force Project X
Re: Simple Arduino code rookie question
« Reply #51 on: June 17, 2015, 12:04:40 am »
wow what a mess...
anyways what I think i did to your code was move the initial truning on of the led outside of the loop, then set up a led state variable (probably a terrible way to do it ram wise) and then every time counter >= 500 we toggle the ledstate and write the ledstate to ledon

(~ledstate)&HIGH should do the business, bitwise inversion of ledstate, taking only the HIGH bit...

Code: [Select]
#define BLEEDERS 0         //define IO
#define TRIAC 1
#define BYPASS 2
#define LEDON 3
#define BUTTON 4
#define TEMP1 5
#define TEMP2 6

const int LOWER_BOUND = 87;
const int UPPER_BOUND = 115;
int val = 0;

boolean lightsOn = false;    // state variables
boolean lastButton = LOW; // Variable containing the previous button state.
boolean currentButton = LOW;  // Variable containing the current button state.
int whichLED = 0;
int counter = 0;            // main counter

void setup()
{
  pinMode(BLEEDERS, OUTPUT);      // set up IO
  pinMode(TRIAC, OUTPUT);
  pinMode(BYPASS, OUTPUT);
  pinMode(LEDON, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode(TEMP1, INPUT);
  pinMode(TEMP2, INPUT);
}
/*
* Debouncing function
* Pass it to previous button state,
* and get back the current debounced button state.
*/
boolean debounce (boolean last)
{
  boolean current = digitalRead (BUTTON);   // Read the button state
  if (last != current)                      // if it's different...
  {
    delay (10);                              // wait 10ms
    current = digitalRead (BUTTON);         // read it again
    return current;                         // return the current value.
  }
}

void loop ()
{
    currentButton = debounce (lastButton);            // read debounced state
    if (lastButton == LOW && currentButton == HIGH)   // if it was pressed...
  {
    lightsOn = ! lightsOn;
  }                                                 // toggle the LED value
lastButton = currentButton;                         // reset button value
             digitalWrite (whichLED, lightsOn);     // change the LED state
             digitalWrite (LEDON, lightsOn);

             if (lightsOn == false)                 // turn LED off and clean up
  {
  counter = 0;
    digitalWrite(BLEEDERS, LOW);
    digitalWrite(TRIAC, LOW);
    digitalWrite(BYPASS, LOW);
    digitalWrite(LEDON, LOW);
    whichLED = 0;
  }
  else                              // Or if we are activating LEDs
  {                                 
    digitalWrite(whichLED, HIGH);   // Turn first LED on to start
    digitalWrite(LEDON, HIGH);
  }

  if (lightsOn == true)              // Manage LED state
{
  counter++;                      // Increment counter
  if (counter >= 500)            // ~ 1 second has passed
    { // So increment LED state
      counter = 0;
      digitalWrite(whichLED, HIGH);  //
      whichLED++;
      if (whichLED > 2)            // Don't let whichLED go to invalid state
        whichLED = 2;
    }
  }
  delay(1);                          // 1 ms delay for 1000 count = ~ 1 second

val=analogRead (TEMP1);                // Read the TEMP1 sensor
    if (val >= UPPER_BOUND)            // If value is higher than upper bound
  {
    if (lightsOn)                      // and OUTPUTs are ON
    {
      counter = 0;                     // shut everything OFF and clear the counter
      digitalWrite (BLEEDERS, LOW);
      digitalWrite (TRIAC, LOW);
      digitalWrite (BYPASS, LOW);
      digitalWrite (LEDON, LOW);
      lightsOn = false;
    }
  }
   
    else
    {
      lightsOn == true;                // Otherwise, toggle button, ON - OFF
  }
   
    val=analogRead (TEMP1);        // Read the TEMP1 sensor
    if (val > UPPER_BOUND)         //If value is higher than upper bound...
    {
      if (! lightsOn)              //...and if outputs were shut OFF by TEMP1 sensor
      {
  int ledstate= HIGH;
  digitalWrite(LEDON, ledstate);
        do
        {
     lightsOn = false;             // turn all outputs OFF
     val=analogRead (TEMP1);       // and read the TEMP1 sensor again   
     counter++;                      //  I WANT THE "LED" TO BLINK
     if (counter >= 500)            //  USING counter INSTEAD OF delay()
    {                               //
      counter = 0;
  ledstate = (~ledstate)&HIGH; //toggle ledstate
      digitalWrite(LEDON, ledstate);  //
             
    }

   }
      while  (val > LOWER_BOUND);  // keep all outputs OFF during the time when value is
      }                            // above lower bound, BUTTON is disabled
    }
    else                           
                                 
     {                           
      lightsOn == true;             // Otherwise, toggle button, ON - OFF
    }
   
    val=analogRead (TEMP2);             //Read the TEMP2 sensor
    if (val >= UPPER_BOUND)         //If value is higher than upper bound
  {
    if (lightsOn)                   // and OUTPUTs are ON
    {
      counter = 0;
      digitalWrite (BLEEDERS, LOW);  //shut everything OFF and clear the counter
      digitalWrite (TRIAC, LOW);
      digitalWrite (BYPASS, LOW);
      lightsOn = false;           
    }
  }
   
    else
    {
      lightsOn == true;            // Otherwise, toggle button, ON - OFF
  }
   
    val=analogRead (TEMP2);        // read the TEMP2 sensor
    if (val > UPPER_BOUND)         // if value is higher than upper bound...
    {
      if (! lightsOn)              //...and if outputs were shut OFF by TEMP2 sensor
      {
        do
        {
     lightsOn = false;             // turn all outputs OFF
     val=analogRead (TEMP2);       // and read the TEMP2 sensor again
   }
      while  (val > LOWER_BOUND);  // keep all outputs OFF during the time when value is
      }                            // above lower bound, BUTTON is disabled
    }
    else                           
                                   
     {                             
      lightsOn == true;            // Otherwise, toggle button, ON - OFF
     }
}
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #52 on: June 17, 2015, 08:25:22 pm »
Super! Thank you very much.  :-+ I will be honest, I would probably never figure it out like this (lack of experience). I don't have any example in my book similar to this one, or at least something close to it I could use and modify.
I was looking at this line you wrote: "ledstate = (~ledstate)&HIGH;" and I have no clue of its exact function other your note: //toggle ledstate.
Only I know of a state toggling is something like this: LEDON = ! LEDON, for example.
Anyway, it works as I need and I will leave it as it is. Even though it's a mess, it only has 1.5k bytes, so I am not expecting any misbehavior.
Thanks.
 

Offline kolonelkadat

  • Regular Contributor
  • *
  • Posts: 202
  • Country: us
  • Obviously, windows are central to Windows.
    • Force Project X
Re: Simple Arduino code rookie question
« Reply #53 on: June 18, 2015, 06:29:37 am »
I was looking at this line you wrote: "ledstate = (~ledstate)&HIGH;" and I have no clue of its exact function other your note: //toggle ledstate.
Only I know of a state toggling is something like this: LEDON = ! LEDON, for example.

Thanks.

let me break down that line for you.
(~ledstate)
~ means to do a bitwise inversion, meaning to look at the variable and turn every bit that is 0 to 1 and turn every bit that is 1 to 0
so if ledstate were 0b00000011, ~ledstate would be 0b11111100.

&HIGH
& means do a bitwise AND operation. The bitwise AND operator (&) compares each bit of the first operand to the corresponding bit of the second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.

so in the case of &HIGH we limit ourselves to looking only at the bit that HIGH uses.



something like LEDON = !LEDON will do a boolean inversion, which might work fine in this use case, but it technically only swaps between 'true' and 'false'.
 

Offline IvoSTopic starter

  • Frequent Contributor
  • **
  • Posts: 311
  • Country: us
Re: Simple Arduino code rookie question
« Reply #54 on: June 18, 2015, 07:01:53 pm »
Thanks. :-+
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf