It’s not necessary to lose voltage monitoring just because the light is in a blinky mode. In mine, I just light up, wait, turn off, wait, then proceed with the main loop (which allows voltage monitoring to happen), then it happens again next time the loop comes around. Instead of using modes[mode_idx] as a code to enter strobe mode, I use mode_idx itself (with #defines to decide how to map indexes to behaviors). The modes[mode_idx] value represents the strobe speed. This way, you can have strobes of different speeds without using mode space in the ROM.
Here is what I’m using, an off-time firmware with strobe modes:
http://bazaar.launchpad.net/~toykeeper/flashlight-firmware/trunk/files/head:/ToyKeeper/cypreus/
That’s the one which has deviated the furthest from STAR though. Its predecessor, ToyKeeper/s7/s7.c, is closer (but is on-time based). Also, they both use party strobes (freezes motion) instead of tactical strobes (for stunning people), so you’d need to change the duty cycle.
From what I’ve heard/read, the most effective tactical strobe is 10Hz with a 50% duty cycle. So, something like this should work:
#define OWN_DELAY
#define SOLID_MODES 4
#define TACTICAL_STROBE_MODES 2+SOLID_MODES
...
const uint8_t modes[] = {
MODE_LOW, MODE_MED, MODE_HIGH, MODE_TURBO, // solid modes
50, 25, // 10Hz strobe, 20Hz strobe (1000 / 2 / X == strobe speed)
};
...
int main(void)
{
...
while(1) {
if(mode_idx < SOLID_MODES) { // Just stay on at a given brightness
PWM_LVL = modes[mode_idx];
sleep_mode(); // the WDT will wake us up for voltage checks
} else if (mode_idx < TACTICAL_STROBE_MODES) { // strobe mode, fixed-speed
PWM_LVL = 255;
_delay_ms(modes[mode_idx]); // requires OWN_DELAY
PWM_LVL = 0;
_delay_ms(modes[mode_idx]);
}
#ifdef VOLTAGE_MON
if (ADCSRA & (1 << ADIF)) { // if a voltage reading is ready
...
}
#endif
}
}
As for using PWM to do strobes… it should be possible down to 2Hz (I wrote a script to do the math a while back), but it would require setting the CPU to its absolute slowest clock speed. I haven’t looked up if that can be done from inside the program or if it needs fuses set. So, it might interfere with the PWM on regular modes, and the only real benefit is that it would use slightly less power.