How To Build a Flashlight With Perfect Modes (picture heavy)

Microa,

Welcome to BLF! Great looking driver board, did you make it? I appreciate seeing the work of people that decide to "roll their own". I know there are many out there that don't have the resources to do this kind of work. Just as I am frustrated with no access to a lathe or milling machine. We all do what we can with what we have.

I have a comment on your schematic - the battery sense resistors R2 and R3. These allow about 100uA drain on the battery at 6V, not terribly excessive but this is the same problem I've been dealing with in my designs. If you make them larger then you start running into problems with the impedance of the ADC. Perhaps adding a capacitor across R2 would help lower its impedance while allowing a larger resistance value? Of course, using protected cells would eliminate the need for any changes in the circuit.

Keep us posted on how this is working, I'm sure others, besides myself, are eager to learn what you find out.

Crux,

There are a couple of methods you could use to allow higher impedance input to the ADC pin. One, as you say, is to put a 1uF or so cap from the test point to ground. I have had this method allow me around 5Megohms of impedance on a ADC pin and still give accurate results as long as you dont poll it too often. One thing to note, it may be obvious to you but if you try to use a DMM to check the voltage, it may give duff results due to how it constantly samples the voltage.

Another interesting method I have used in the past, though is perhaps a little overkill here is to have the voltage divider switch on only when needed. Either by disconnecting the ADC pin first(!) then the low side of the voltage divider, or have the high side disconnect. Both methods will probably need a couple of transistors.

Good observation, Microa!

#177: From the MCU pin 2 first a diode and a resistor(10MOhm) in parallel, after them a condenser (100nF) to ground (-).

#264: From the MCU pin 2 first the condenser and then the diode and the resistor in parallel, both to ground.

The two circuits are equivalent but #264 is more rugged having two components soldered to the board (ground). I experienced that the condenser could easily break in #177 if I pressed on the diode/resistor pair.

(by the way in #177 I switched the big diode with the small diode (S6) on the component side to get a small component, but when I found out that it was a shottky diode with a purpose, I switched back again).

I think I have mounted this circuit on 7-8 drivers now. Memorizes the mode 1/2 sec after switch-off.

Crux,

Thanks for your comment. I shall add a 1uF capacitor to the sensing point which is simple and effective. The famous LFlex driver is also using this method. My driver is powered by 2 pieces of Sanyo 18500. The current of the LED is set at 2A. The IC of the protection circuit is Ricoh R5460N212AF.

Sixty545,

Thanks for your quick reply. I shall try the PINSWITCH with 3 SMD for my driver.

I've added the cap, resistor, diode network to pin 2 of my AK-47A and programmed it with the 8-mode driver files from sixty545. (Thanks for the files!)

It works, but I don't get a reliable tap detect. It seems the tap must be very short to register and advance to the next mode. Is that normal? I've tried using a 1uF cap and that helps a bit but I think that something else is going on here. What am I missing? The diode I'm using is a ZHCS400 schottky, should it be a standard silicon? (cathode to ground, right?) Caps are X7R. Did I miss something in programming? FuseHigh = 0xED FuseLow = 0x79.

I'll try scoping it out, I hope the probe doesn't load the circuit down too much... maybe the resistor could be 1Meg (or less? with a larger cap)

How can something so simple cause so much trouble?

I'm using a 100nF/10mΩ/silicon diode circuit and it works like a charm. When I tried replacing the diode with a schottky type, I had the same problems you are seeing.

Thanks Tido. As that late Jim Williams (of Linear Tech) once said, "Didn't read the datasheet? Then you shall have no pie." The Schottky diode I used has a reverse leakage of about 3-5uA, seems low till you do the math, 4uA at 3Volts = 750kΩ. The 10MΩ in parallel was effectively out of the circuit! I'm now using the venerable 1n914, (reverse leakage = 25nA) and the tap works like a charm.

Oh, by the way I'm having trouble building the code using AVR Studio 5. It creates a .hex file of 4.5kbytes. I'll ask the firmware guys at work for some tips on Monday, have a nice weekend!

hi, i just registered to thanks tido and all here for this great sources and comments.

yesterday i setup my first own driver and it work like sharm. i modify some timings at the beacon mode.

now i wan to take a closer look to the low battery routine. my wish is that a seperate small led will light when 3 volts are detected. and i will flash slow maybe at 2.9 volt, little faster at 2.8 volts...realy fast at 2.5 volts (i am using a imr setup so the 2.5 volts are not realy a problem). i think this is doable, but i am not a programmer. i am a administrator and i had a electronic education several years ago.

thanks again, markus

Take a look at the README to find out how to adjust the low voltage threshold. Controlling a second LED is a bit more tricky. You can either modify every mode function to handle the extra LED or change the watchdog timer ISR to do this.

The second option is the one I would choose. I'd rewrite the voltage monitoring part to toggle an I/O pin after being triggered and every time it's called thereafter. To adjust the blinking frequency, you'd have to change the WDT prescaler, so the ISR gets called with increasing frequency.

hi tido,

that sounds great. i read about to modify the voltage threshold, so today i will start to build the voltage devider and test it, but the extra led will be a nice feature for me (maybe also for other).

thanks, markus

Welcome to BLF Markus! There is a wealth of knowledge here.

Let us know how your program works, you can share your code if you like.

-Crux

I got all the required hardware and was able to upload the Fixed settings without any problems. Now I will try to compile the driver of my dreams, moon-l-m-h, hidden Beacon, Strobe and SOS.

Thanks to everyone involved in this great project, especially Tido!

hi crux,

nothing special at my code. only some changes at the beacon timing. fixed modes with ultra low, low, med, high and beacon.

i am an electronic engineer, not a programmer so i have to wait and hope that tido implement the trigger function for me.

i still need a other change, for a other project i have in my head. i try to illustrate my next idea: i wan to make a little flashlight that have two xp-g (high cri) an one xp-e (red) for night. now when you first power on the light the red schould be glowing. second: the white with low mode, third: white with med and so on. my idea for the shematic is that the first power on triggers any other io pin, for example pb0, from the attiny. idealy it should only go to logic high. with this a can use a 7135 to power the red one. the second power on trigger should be a normal pwm to io pb1. i think this will be no problem for a coder...

markus

That's an interesting idea for a light. The red light works well at preserving night vision. About five years ago, I modified a headlight to use 3 red Leds (instead of 3 white ones) and one Luxeon 1W (instead of a krypton bulb). It had a neat control circuit for selecting either light, so I kept that. I redesigned the driver circuit to accommodate the different Leds. It has only one mode, but will dim when the batteries get low (to extend their life). I'm not tempted to redesign it again, even though today's Leds are brighter.

I hope you have success with your project, I agree that it seems like a SMOP (Simple Matter Of Programming) - but I'm not a coder either...

Hi,

Instead of setting the ADC reference to the internal 1.1v reference and using a voltage divider to determine the voltage it might be possible to set the ADC reference to V_cc and then sample the internal reference to determine the voltage. Then something like

Vbat = 10 * 1.1 * 1024/ADCval + Vdiode

could compute the battery voltage. Not sure if this works with ATtiny13 but I did something similar with the ATtiny85.

doesn´t work with an attiny13 Frown

hi crux,

i got a little help from tido and the first driver is running. first pb0 will be active for the red led. then you can switch the programmed mode output on pb1. now i understand a little more about the µc.

markus

I hesitate to ask for help because C-programing is out of my element (I'm hardware), and I don't want to waste anyone else's time.

I figured that if I could compile the stock driver.c code to a working .hex file then I would try tweaking the code to my needs. But alas,when I build it I got errors saying mode_sos and mode_softbeacon are "undeclared here (not in a function)". So I changed the source to look like this:

//#define NOMEMORY // #define to disable mode memory
#define FUNC_STROBE // #define to compile in strobe mode
#define FUNC_SOS // #define to compile in SOS signal this line was commented out
#define FUNC_SOFTBEACON // #define to compile in softbeacon mode I added this line
//#define FUNC_ALPINE // #define to compile in alpine distress signal

Now it compiles, but it's too big, 1088 bytes (with optimization -Os)!

Device: attiny13a
Program: 1088 bytes (106.2% Full)
(.text + .data + .bootloader)
Data: 36 bytes (56.2% Full)
(.data + .bss + .noinit)
EEPROM: 64 bytes (100.0% Full)
(.eeprom)

I suspect I don't have something configured just right, but what - there so many things to learn (and so little time)...

BTW I'm using AVR Studio 5.

Any or all help is appreciated.

-Crux

There are a few places in the code you will have to change if you are adding a new function. Let's assume that FUNC_FADE did not exist before and we are adding it. First, you will probably want to define a new mode line. This is a handy short cut and makes reading the EEPROM set up easier. It looks like this:

#ifdef FUNC_FADE
#define MODE_FADE   0x04, 0xFF, 0x01, 0x01  // fade in/out. Just a gimmick
#endif

MODE_FADE is the name for the mode, the first number is the offset into the function-array (more on this later) and the three remaining numbers are the three parameters the function may use.

Next you set up the EEPROM. This is where you add the mode line:

const uint8_t EEMEM eeprom[64] =
{   0x00, 0xFF, 0xFF, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00,
    // initial mode programming, indices to mode lines in the following array
    0x03, 0x06, 0x08, 0x00, 0x00,
    // mode configuration starts here. Format is:
    // offset in mode_func_arr, func data1, func data2, func data3
    MODE_LVL001,    // 0x00
    MODE_LVL002,    // 0x01
    MODE_LVL004,    // 0x02
    MODE_LVL008,    // 0x03
    MODE_LVL016,    // 0x04
    MODE_LVL032,    // 0x05
    MODE_LVL064,    // 0x06
    MODE_LVL128,    // 0x07
    MODE_LVL255,    // 0x08
    MODE_STROBE,    // 0x09
    MODE_POLICE,    // 0x0A
    MODE_FADE       // 0x0B <= new mode line replaces another
};

By placing the #define for the mode lines inside the #ifdef FUNC_<name> earlier, this will result in a compile time error if the EEPROM config contains a mode which has not been compiled into the binary. This is a Good Thing™. You got the compiler error because you disabled the code for the SOS-function, but your EEPROM set up still contained MODE_SOS.

Next you will have to give a forward declaration for the new mode function:

#ifdef FUNC_FADE
void fade(uint8_t offset);
#endif

This is necessary to add the function pointer to the function pointer array:

mode_func mode_func_arr[] =
{
        &const_level
#ifdef FUNC_STROBE
        , &strobe
#else
        , &nullmode
#endif
#ifdef FUNC_SOS
        , &sos
#else
        , &nullmode
#endif
#ifdef FUNC_ALPINE
        , &alpine
#else
        , &nullmode
#endif
#ifdef FUNC_FADE
        , &fade
#else
        , &nullmode
#endif
};

Why this #ifdef FUNC_<name>, &func #else , &nullmode #endif construct? This makes sure that the functions keep their place in the array by replacing functions that are not compiled in with a pointer to a dummy function. Remember the bit about the function offset earlier, when defining the mode line? This is where this offset comes from. Count the functions in this array, starting at zero, until you reach your new function. Fade is the fifth function in the array, so its offset is four.

Now all you have to do is write the actual mode function. If you want to know how to get the parameters from the mode line, look at the strobe function, where it reads its parameters from the EEPROM.

I do appreciate the explanation of how the code is structured and how to add a mode, that will come in handy when I get that far...

My immediate problem was just getting the unmodified driver.c to compile, and here I must apologize. The driver.c code I was having trouble building is the code from sixty545, not from Tido. I just realized this during a sanity check, but after I posted above . I have been able to build Tido's driver.c successfully. Output looks like this: (and it flashes too)

Device: attiny13a
Program: 968 bytes (94.5% Full)
(.text + .data + .bootloader)
Data: 26 bytes (40.6% Full)
(.data + .bss + .noinit)
EEPROM: 64 bytes (100.0% Full)
(.eeprom)

(Although I'm not sure how to make the 'simple', 'fixed' and 'programmable' builds. But we'll save that for later...)

Its when I try to build sixty545's driver.c that I get the following warning and errors:

Warning 1 #warning "F_CPU not defined for <util/delay.h>" c:\program files (x86)\atmel\avr studio 5.0\avr toolchain\bin\../lib/gcc/avr/4.5.1/../../../../avr/include/util/delay.h 89 3 8mode
Error 2 'MODE_SOFTBEACON' undeclared here (not in a function) C:\Users\Bob\Documents\AVRStudio\8mode\8mode\8mode.c 299 5 8mode
Error 3 'MODE_SOS' undeclared here (not in a function) C:\Users\Bob\Documents\AVRStudio\8mode\8mode\8mode.c 300 5 8mode

This is how I got to the point where I did the changes shown in post#368 above.

All of the supplied .hex and .eep files from Tido and sixty545 have worked, I'm just having trouble building the one from sixty545.

I'm currently comparing the two side by side to see where a difference may lie. I'm going to take some time and if I'm still can't figure it out then I'll put together a better phrased question.

Thanks for all the help so far!

-Crux