MiniMo - simple firmware for momentary (electronic) switches (source code)

Lights with electronic switches are becoming quite popular, I also like them, because they give more flexibility regarding the UI. Similar to MiniDrv, a small firmware for clickies, I made a minimalistic firmware for momentary buttons, named it MiniMo (MINImalistic driver for MOmentary switches) and decided (not lightly; I hope people still buy some drivers from me so I can buy some flashlights...) to share it.

The UI is simple but consistent: A long press (>0.4s, so it's not that long) switches the light on and off (with memory), a short press switches to the next mode (circular) when on.

To configure, just add/delete/edit the values in the modes[]={...} line.

//MiniMo -- minimalistic driver firmware for momentary buttons (no blinkies)  --  DrJones 2014
#define F_CPU 4800000                    //use fuses  low:0x75  high:0xff
#include <avr/io.h>
#include <util/delay.h>
//change modes here; just change/add/delete values. The "0" is 'off' 
uint8_t modes[]={0,  8,90,255};          //PWM values, 5..255 - LEAVE THE "0" THERE
int main() {
  DDRB=2; PORTB=8;                       //define PB1 as output and pull-up switch on PB3
  TCCR0A=0b00100001; TCCR0B=0b00000001;  //PWM setup, 9kHz
  uint8_t count=0,mode=0,lastmode=1,waspressed=0; //define some variables used below

while(1) { //endless loop

if ((PINB&amp;8)==0) {                   //when the button is pressed (PB3 pulled down)
  count++;                           //count length of button press
  if (count==16) {                    //pressed long (8*50ms)
    if (mode&gt;0) {lastmode=mode; mode=0;}  //was on?  -&gt; off, but remember the mode
    else mode=lastmode;                   //was off? -&gt; on, with previous mode.
  }
  waspressed=1;                      //remember that the button was pressed, see below
}
else {                               //button not pressed
  if (waspressed) {                    //but it was pressed, so it has just been released!
    waspressed=0;                      //reset that
    if (count&lt;16 &amp;&amp; mode&gt;0) {           //really was a short press AND the light is on
      mode++; if (mode&gt;=sizeof(modes)) mode=1; //next mode
    }
    count=0;                           //reset counter
  }
}    

OCR0B=modes[mode]; //set PWM level (0 is off)
_delay_ms(25); //wait a bit before checking again, important for counting
}
}

I think this may help a couple of projects here.

License: CC

EDIT Since people seem to like Werner's UI (short press for next mode, long press for previous mode, like in mobydrv; but OFF is just one of these modes) and since it is already implemented elsewhere, i thought I'd just show how easily it can be implemented in MiniMo, too. Only 4 lines had to be edited, marked with **, and the lastmode variable declaration was omitted.

I also changed the timing a bit (25ms delay in the main loop) to make it respond a bit quicker.

//MiniMo -- minimalistic driver firmware for momentary buttons (no blinkies)  --  DrJones 2014
//Up&Down variant ("Werner's UI")
#define F_CPU 4800000                    //use fuses  low:0x75  high:0xff
#include <avr/io.h>
#include <util/delay.h>
//change modes here; just change/add/delete values. The "0" is 'off' 
uint8_t modes[]={0,  8,90,255};          //PWM values, 5..255 - LEAVE THE "0" THERE
int main() {
  DDRB=2; PORTB=8;                       //define PB1 as output and pull-up switch on PB3
  TCCR0A=0b00100001; TCCR0B=0b00000001;  //PWM setup, 9kHz
  uint8_t count=0,mode=0,waspressed=0;   //define some variables used below

while(1) { //endless loop

if ((PINB&amp;8)==0) {                   //when the button is pressed (PB3 pulled down)
  count++;                           //count length of button press
  if (count==16) {                   //pressed long (16*25ms=0.4s)
    if (mode&gt;0)  mode--;             // ** decrease mode
    else mode=sizeof(modes)-1;       // ** wraparound
  }
  waspressed=1;                      //remember that the button was pressed, see below
}
else {                               //button not pressed
  if (waspressed) {                    //but it was pressed, so it has just been released!
    waspressed=0;                      //reset that
    if (count&lt;16) {                  // ** really was a short press
      mode++; if (mode&gt;=sizeof(modes)) mode=0; // ** next mode
    }
    count=0;                           //reset counter
  }
}    

OCR0B=modes[mode]; //set PWM level (0 is off)
_delay_ms(25); //wait a bit before checking again, important for counting
}
}

Thanks Dr Jones for your great contribution to the flashlight world!! Highly appreciated.

I'm not going to use it, because I have no side clickers that need a special code, but I guess this could be a replacement for some lights. (Even branded)

Bravo! :beer:

Thank you :beer:

Cheers David

Nice work : -) thanks

(Only 4 replies? Seriously guys?!)

  DDRB=2; PORTB=8;                       //define PB1 as output and pull-up switch on PB3

I have one with the switch wired to the third star/PB4 but the wire's hidden under JB Weld (d'oh!), what does that line need to be changed to to switch the input pin from PB3 to PB4? I tried random numbers, but couldn't get it to work. (I temporarily rednecked it by bridging pins 2 & 3 with solder) xD

Received my Minimo today!

Once I’ve done my chores, I will break out the soldering iron and play!

Thank you Dr Jones. :smiley:

nice :slight_smile:

3x XM-L2 T6 3B, 15-amp SRK clone driver, PWM values of 0,1,3,8,20,50,120,255

Gives totally unscientific bathroom ceiling bounce lux numbers of:
0.3
1.8
6.4
17.9
47.6
116.8
241

Comfy is right in Post 5. Thank you very much for the generosity of sharing this code DrJones. I look forward to trying it soon.

have you considered soliciting/accepting ‘donations’ from those who use the code?

I just bought a few drivers and I’m planning to use your firmware. Rather than purchase drivers from you, I’m forcing myself to learn how to flash them, with an eye toward eventually learning to modify the code…….but I have no problem compensating you for your ingenuity.

Another reason for doing it myself - I’m having a little trouble deciding which firmware to use (from just reading the text descriptions), so I want to experiment with each. I might also draw flow diagrams for your UIs at some point.

Oh, and thanks for this new addition :slight_smile:

That's a good idea Dthrckt. I'm sure I will eventually be using this code in some of my lights. I would feel better about it that way.

Anyone know what pins are the momentary switch? I can pull up the Attiny13a data sheet and compare it to the code, but I'm hoping someone already knows.

I presume its star 4, same as for lumodrv or mobydrv:

Thank you DrJones for the code!

Do I understand correctly - If I want to get rid of last mode memory and make the light always start on certain mode, I should change the code something like this:

if (mode>0) mode=0;          //was on?  -> off
else mode=2;                      //was off? -> on, start on Med

(might also skip the “lastmode” variable in the definitions)

Right?

comfychair: For a switch on PB4 use "PORTB=16;" there and "if ((PINB&16)==0)" some lines below.

AlexTG: Yes, exactly.

BTW: The minimum value of 5 in the modes[] is a quite safe value for an AMC7135-based driver; 4 might work, too. For drivers with a FET or a buck driver, even lower values may work.

Thank you Sirius9.

Yep, the low-low values 1 2 & 3 didn't work with 7135s when I tried it, only starts to light up at 4. But on the FET drivers even 1 works fine.

Dear DrJones,
Thanks for your sharing of the code.
If I understand correctly that mode=1 -> 8, mode=2 90, mode=3>255. I mean the position of the PWM levels in the line uint8_t modes={0, 8,90,255}; Am I correct?

Yep. Compare that line in the original to this one: http://75.65.123.78/fw/minimo-7mode-pb4.txt

You can also switch it to descending instead of ascending. {0,8,90,255} vs. {0,255,90,8}.