Notifications
Clear all

Kayak lantern with SOS

23 Posts
5 Users
3 Likes
2,062 Views
Ken56
(@ken56)
Member
Joined: 3 years ago
Posts: 7
Topic starter  

Hi! newbie in Arduino but hope to learn a lot. Now working with a lantern to be used on my kayak. it has 9 bright LEDs´and the with the help of some components and a Nano I would like to change the power and power consumption in three steps. Also included is a SOS alternative. The problem is that when entering the strobe _SOS I get stuck in a endless loop. What is wrong?

int buttonPin = 2;
int lightPin = 3;
static int value = 0;			//Create a changing number
void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(lightPin, OUTPUT);		//Create the pinModes
}
void full_light() {
  digitalWrite(lightPin, HIGH);
  delay(50);
}
void half_light() {
  analogWrite(lightPin, 127);		//Use PWM for brightness level
  delay(50);
}
void fourth_light() {
  analogWrite(lightPin, 64);
  delay(50);
}
void strobe_sos() {
  //  loop() {
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(400);
  digitalWrite(lightPin, HIGH);
  delay(500);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(500);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(500);
  digitalWrite(lightPin, LOW);
  delay(400);
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(200);
  digitalWrite(lightPin, HIGH);
  delay(100);
  digitalWrite(lightPin, LOW);
  delay(2000);
}
void loop() {
  int button_check = digitalRead(buttonPin);
  if (button_check == 1) {			//Check if the button was pressed
    value = value + 1;
    delay(220);
    if (value > 4) {
      value = 0;
      delay(70);
    }
  }
  else {					//Keep the LEDs off if the button was not pressed
    digitalWrite(lightPin, LOW);
  }
  if (value == 1) {			//Output the mode according to the button
    full_light();
  }
  if (value == 2) {
    half_light();
  }
  if (value == 3) {
    fourth_light();
  }
  if (value == 4) {
    strobe_sos();
  }
}

 

Better burn some chips now and then, than never turn on the power supply...


   
Quote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6662
 

Just a quick observation, but I think it is working as coded. If you get to value  equals 4 it will strobe continuously until you press the button.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 

@ken56

There are a few questionable things in your sketch.

1) it's not clear whether you've connected the button to be normally HIGH or normally LOW. Is the button pin connected to GND or +5V and are you using pulp or pulldown resistor. Since you're testing the button pin value against 1, then I'm assuming that it's normally LOW.

2) you haven't allowed for switch bounce. When a switch is closed, there is a short period of time when the contact actually bounces on and off. Normally you'd take a second reading a few milliseconds later and verify that the switch was still closed, indicating that it was a true reading. It's not critical in this case, but you should Google it to see how it may affect further switch usage.

3) Your code does actually work, but you can't tell that because of the difference in timing. If value==1 you turn on the light full strength, wait 1/20th of a second and then motor on. That's nice because the function executes and then returns very quickly to the button test to change values if appropriate.

But, consider that when you hit value==4 you call a routine which takes several seconds to execute and then has a dead 2 second delay before it gets back to the loop to reread the button state wherein it takes  less than a millisecond to do the button test.

What that means is that you pretty much have to hold down the button until the sketch gets to the button test code (which you can't tell because there's no clues built in) and let go if it at precisely the right time to move to the next value (i.e. value==0).

If you press and hold the button, you will be able to advance to the different light displays, but you'll only get them at random because you can't predict when to press and let go.

 

In short, your design is flawed because you have no graceful way to exit the SOS subroutine. You can address this in several ways. One of the easiest would be to simply add a second button whose only job is to STOP the SOS sequence once it starts. 

So you could add another pin sosOffPin =4; wired the same way as the other button (i.e. =1 when pressed) and change your sub to something like ...

void strobe(sos) {

     while ( 0==digitalRead(sosOffPin) ) {

           ... add the existing code here ...

     }

     value = 0;                              // Stop strobing SOS

}

That way, once you enter strobe_sos, you'll stay there until you press the new button which will stop the SOS signalling and change the value to 0 to wait for a new choice.

Anything seems possible when you don't know what you're talking about.


   
Ron reacted
ReplyQuote
Ken56
(@ken56)
Member
Joined: 3 years ago
Posts: 7
Topic starter  

Will!

Thanks a lot for the comprehensive answer!

I would like to enclose the schematics in KiCad format but can´t see the routine for enclosing attachments.

Have to study your ideas carefully and see if I can understand how to do. Would like to test it in the weekend... 🙂  

Better burn some chips now and then, than never turn on the power supply...


   
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 

My recomendation would be to look at the smallest time unit you care about... which seems to be 100ms. And rework the code around only updating every tenth of a second. This does mean that very quick button pushes can be missed, but if this causes issues, reduce the time.

void loop() {
    bool changed = CheckButton();  // returns true if user pushed button
    if (changed) {
        SetLight();
    }
    if (value == 4) {
        UpdateForSOS();
    }
    delay(100);
}

I think the reason for your else clause in the original code is to handle initial setup before the user pushes any button.  A better option is to put

digitalWrite(lightPin, LOW);

at the end of your setup routine.


I don't really understand what the delays in your button processing are doing. Could you elaborate? There is no need to delay after setting a variable in arduino code, it will be set immediately.


SetLight() basically duplicates what you have at the bottom of your current loop. But you can eliminate the various delay calls and make it look like

int sosStep = 0;

void SetLight() {
    if (value == 0) digitalWrite(lightPin, LOW);
    if (value == 1) digitalWrite(lightPin, HIGH);
    if (value == 2) analogWrite(lightPin, 127);
    if (value == 3) analogWrite(lightPin, 64);
    if (value == 4)  {
        sosStep = 0;  // in SOS mode, we just need to initialize for the UpdateForSOS function
    }
}

This value for the lightPin is just "left alone" from now on, until the user pushes the button again or value==4.


If we're in mode 4, UpdateForSOS will be called. This function knows from the main loop that this will be called every 100ms. It uses the global variable sosStep to track where it is.

void UpdateForSOS() {
    if (sosStep == 0) digitalWrite(lightPin, HIGH);
    if (sosStep == 1) digitalWrite(lightPin, LOW);
    // if (sosStep == 2)  don't do anything... since we're still in the LOW state from step 1
    if (sosStep == 3) digitalWrite(lightPin, HIGH);
    if (sosStep == 4) digitalWrite....
       .... lots more of these....
       ... a lot more....
    if (sosStep == 41) digitalWrite(lightPin, LOW);
    if (sosStep == 61) {
        digitalWrite(lightPin, HIGH);
        sosStep = 0; // This will be set to 1 in a moment, and that will restart the loop.
    }
    sosStep = sosStep + 1;
}

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
Ron reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2037
 
Posted by: @ken56

I would like to enclose the schematics in KiCad format but can´t see the routine for enclosing attachments.  

Some my not be able to view the KiCad format.  In a reply post you will see on the bottom left buttons in the form of underlined words My Media and Attach Files


   
ReplyQuote
Ken56
(@ken56)
Member
Joined: 3 years ago
Posts: 7
Topic starter  
image

Thanks all!

The schematics of the Kayak lantern. I would like to keep it simple and use only one switch to control the lantern. Still trying to understand and change the coding... The code works except when SOS is entered. Then it is not possible to interrupt the loop  with the push button.

Better burn some chips now and then, than never turn on the power supply...


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6662
 

@ken56 The code is likely working as coded, and @Will and @jker have provided excellent input but I understand if you want to go your own way. I strongly suspect you think the code is working one way and the code thinks a different way. That is why single stepping or at least the time honoured debug print statements will reveal the difference. Good luck.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 
Posted by: @ken56
image

Thanks all!

The schematics of the Kayak lantern. I would like to keep it simple and use only one switch to control the lantern. Still trying to understand and change the coding... The code works except when SOS is entered. Then it is not possible to interrupt the loop  with the push button.

An unusual schematic.

You should normally put capacitors on both the input and output sides of the linear regulator to stabilize the input and output voltages. You can Google L7805 for example circuits and values.

I'm not really sure why you are using a transistor to drive a logic level N-channel MOSFET. The data sheet says that the gate is typically driven by 3V, so the Arduino is quite capable of driving it directly without the extra transistor and its voltage dropping resistor.

If you don't mind changing SW2 wiring a bit, you could probably get rid of the L7805 entirely. You have  pin D2 currently wired as third to ground and connected to 5V when pressed.

You can change D2 to be LOW when pressed and HIGH when open if you change it's definition in the sketch from

pinMode(pinButton, INPUT)            to            pinMode(pinButton, INPUT_PULLUP)

That will cause the Arduino to use an internal pullup resistor to link D2 to 5V all the time. If you then connect D2 to the switch and the other side of the switch to GND, you will find that the digitalRead finds the value HIGH (1) when the switch is open (because the internal resistor keeps it tied high) and LOW when the button is pressed (because then it is connected to GND).

You would then only need to change your sketch to check if digitalRead(pinButton) is LOW (0) for pressed and HIGH (1) for open.

The last change is to move the connection of the SW1 from the Arduino 5V to the Arduino VIN. The Arduino has a built-in regulator that can take a voltage >about 7 volts and create a suitable 5V supply for itself.

As for the MOSFET, you could probably just eliminate the transistor and its supply resistor and connect the pin D3 directly to the current limiting resistor into the MOSFET.

 

I understand that you'd prefer to just use the one switch for light control and that can be easily done if you're willing to add a new function which will debounce SW2.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 
Posted by: @ken56

The problem is that when entering the strobe _SOS I get stuck in a endless loop. What is wrong?

The problem is that as soon as you enter the SOS state, you're only looking at the button pin every ~6 seconds. There's no code to check the buttonPin anywhere inside that function which can be timed from start to end at 6100ms.

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6662
 

@jker A perfect example of where an interrupt would be useful.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
jker reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2037
 

   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2037
 

   
ReplyQuote
Ken56
(@ken56)
Member
Joined: 3 years ago
Posts: 7
Topic starter  

Thanks!

  robotBuilder 

Just tested the code you provided but unfortunatley the SOS does not work. Trying to learn Arduino coding and still at the beginning. However I think the "millis" seems to be more stable than delay function.

Thanks all other as well!

I´ll keep on trying to get this code working. Didn´t think it should be so hard to dim a LED and get a SOS function to run smoothly with just a pushbutton... 

 

Better burn some chips now and then, than never turn on the power supply...


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2037
 

@ken56 

I don't understand why it didn't work?

I tested it myself and it worked for me.

 


   
ReplyQuote
Page 1 / 2