Attiny Treiber/Software mit Seitentaster

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hallo zusammen,

ich suche einen Treiber bzw. Software zum selbst programmieren von nem Tiny der mit einem Taster (nicht clicky) funktioniert. Der Treiber soll also immer an der Batterie hängen und nur auf Druck vom Taster regieren. Es gab mal von TaskLED d2Flex. Genau so was suche ich zum selbstprogrammieren. Der d2Flex hatte zum Schutz vor versehentlichem Einschalten einen Lockout. Man muß drei mal hintereinander den Taster drücken damit die Lampe angeht. Drei mal drücken und sie ist wieder gesperrt. Der Treiber brauchte nur 50µA im gesperrten Modus...

Gruß Markus
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi, die Software würde wohl passen. Sleep mechanismen sind implementiert, aber hier fehlt mir die Sperre der Lampe um versehentliches Einschalten zu vermeiden.

Gruß Markus
 

Wieselflinkpro

Flashaholic***
1 Dezember 2014
5.472
3.090
113
Goslar
Ja, das ist richtig. Eine Sperre gibt es leider nicht.
Hat die Lampe die Möglichkeit eines Lockouts oder dass man einen Clicky einbaut?
 

fritz15

Flashaholic**
8 Mai 2011
1.008
1.626
113
Aalborg, Dänemark
Hallo,

leider auch keine Sperre:
Code:
/*
* moui_v2_menu.c
*
* Created: 21.04.2014 12:42:34
*  Author: fritz
*/

/*
* License: Free for private, non commercial use
*
* use Fuses:
* low  0x75
* high 0xFF
* Compiler optimization set to '-Os' (optimize for size)
* 1016 Bytes used
*
* Some comments:
*
* The UI is similar to the one from NovaTac lights (with some additional features)
*
* click (c): pressing the switch for not more than 'presstime' * 5ms (default 250ms)
* press (p): pressing the switch for more than 'presstime' * ms (default 250ms)
* ('presstime' defined below)
*
* This UI features a BURST mode and the light will dim from 'BURST' to 'mode4' after 'BURSTtime' * 1.28 seconds
* (Only if constant ON BURST, at momentary ON BURST the light will not dim down.)
* If you do not want a BURST mode just set 'BURST' the same as 'mode4'
*
*
* UI description:
* From OFF:
* 'click' switches the light on to 'mode1'
* With a 'press' you get momentary 'mode1'
* With 'click' and 'press' you get momentary 'BURST'
*
* When ON:
* You can toggle between 'mode1' and mode2' with 'click''click'
* With 'click''click''click' you get to 'mode3'
* From 'mode3' you get back to 'mode1' with 'click''click'
*
* From any mode you reach momentary 'BURST' with 'press'. As soon as you release the switch you get back to your last mode.
*
* You reach constand on 'BURST' with 'click''press' from any mode
* You get back to 'mode1' with 'click''click'
*
*
*
* To do:
*
* (0) Bugfixes
*        Done! (more or less...)
*
*        While my usage there did not occour any bugs, so please tell me, if you find some.
*
* (1) Set Attiny to sleep mode, when light was turned of for more than 250ms
*        Done! Consumes when switched OFF from .2 to 6 µA (depends on locator flash ON or OFF)
*
*        I added a locator flash. It flashes every 8 seconds for .01 second at brightness 'locator' (default 5)
*        calculate time until battery is empty (draintime in years):
*        first calculate
*        drain current drc:
*
*        WDTint = Watchdog Interrupt time (8 sec by default)
*        BattAmp = maximal BATTERY Current
*
*        drc = [WDTint * 6 * 10^-6 + 0.01 * BattAmp * locator/255]/8.01
*
*        BattC = Battery Capacity in Ah
*
*        draintime = BattC/(drc * 24 * 365)   
*
*        Example: 2.8A driver, 18650 Battery with 3Ah Capacity, locator = 5
*        drc = 0.000075A
*        draintime > 4 years
*
*        If you do NOT want a locator flash you can disable it in the programming menu
*        See the point "programming menu" below.
*        When the locator flash is disabled an 18650 battery lasts for more than 500 years...
*       
* (2) Implement programming menu
*        Done!
*
*        You can change the brightness of any mode by switching to the mode and then 'click', 'click', 'click' and 'press'.
*        After you release the switch you can ramp up by a single 'click' and save your selected brightness by a single 'press'
*       
*        Example:
*        (c) --> Mode1 (c)(c)(c)(p) --> programming menu for Mode1
*        (c)(c)(c)(c)(c)(c) (6 clicks) --> 7 of 255 selected (p) --> Mode1 is from now on 7 until the next Battery change.
*        Light goes back to Mode1
*
*        By clicking the light 8 or more times you get to the programming menu.
*        Here you can switch the locator flash ON/ OFF, enable or disable mode memory and store your programmed modes in the
*        EEPROM so that they do not get deleted after a battery change.
*
*        Once you entered the programming menu you can select what you want to do by clicking (1) to (3) times and then select the option by a single press.
*        After you pressed the switch the light will flash 1 to 3 times to indicate, which option is/ was selected.
*
*        (1) Toggle locator flash ON or OFF                                                        (the light will flash once)
*        (2) Toggle mode memory ON or OFF                                                        (the light will flash twice)
*        (3) Save your programmed modes so that they are not deleted after a battery change        (the light will flash three times)
*
*        If you click more than three times you leave the programming menu
*
*
*
* The following data has to be stored in the EEPROM:
*
*  reg0:   5 = 0x05                                        <-- brightness for 'mode1'
*  reg1:  20 = 0x14                                        <-- brigthness for 'mode2'
*  reg2:  90 = 0x5A                                        <-- brightness for 'mode3'
*  reg3: 165 = 0xA5                                        <-- brightness for 'mode4'
*  reg4: 255 = 0xFF                                        <-- brightness for 'BURST'
*
*  reg5:   1 = 0x01                                        <-- Locatorflash default ON (0 for default OFF)
*  reg6:   1 = 0x01                                        <-- Memory default OFF (0 for default ON)
*
*  reg7:   1 = 0x01
*  reg8:   2 = 0x02
*  reg9:   3 = 0x03
* reg10:   4 = 0x04
* reg11:   5 = 0x05                                        <-- default 'mode1'
* reg12:   7 = 0x07
* reg13:   9 = 0x09
* reg14:  14 = 0x0E
* reg15:  20 = 0x14                                        <-- default 'mode2'
* reg16:  30 = 0x1E
* reg17:  45 = 0x2D
* reg18:  60 = 0x3C
* reg19:  75 = 0x4B
* reg20:  90 = 0x5A                                        <-- default 'mode3'
* reg21: 105 = 0x69
* reg22: 125 = 0x7D
* reg23: 145 = 0x91
* reg24: 165 = 0xA5                                        <-- default 'mode4'
* reg25: 185 = 0xB9
* reg26: 205 = 0xCD
* reg27: 230 = 0xE6
* reg28: 255 = 0xFF                                       
*               
* you can create a .hex file with the following content:

:10000000051446A5FF0101010203040507090E14AA
:100010001E2D3C4B5A697D91A5B9CDE6FFFFFFFF30
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:00000001FF

*/

#include <avr/interrupt.h>                                    // Include some headers...
#include <avr/sleep.h>
#include <avr/io.h>
#define F_CPU 4800000                                        // Prescaler is set
#include <util/delay.h>   
#include <avr/wdt.h>

#define WDTflag 0                                            // Bit for Watchdog interrupt
#define PCINTflag 1                                            // Bit for Pin Change interrupt

/*
* 'OFFtime * 5ms' is the the time, which the light has to be turned ON or OFF to reset 'clicked'
* If you hold the switch for longer than 'presstime * 5ms' --> 'press', otherwise 'click'
* Both values can be changed (should be in [30, ..., 100])
* Default 250ms for both
*/
#define OFFtime 50
#define presstime 50

/*
* Set 'BURSTtime', here. If you do not want a Burst mode set 'BURST' to the same as 'mode4' (by writing different data in the hex file for the EEPROM or by programming the brightness)
*/
#define BURSTtime 11                                        // (BURSTtime + 1) * 1.28sec (default 15.4 seconds)

/*
* define 'locator' to your preferred brightness in [1, ..., 255]. 4 > is save for 7135 drivers
*/
#define locator 5

/*
* The address for mode1, -2, -3, -4 and BURST in the EEPROM are defined here. Do NOT change.
*/   
#define mode1addr 0
#define mode2addr 1
#define mode3addr 2
#define mode4addr 3
#define BURSTaddr 4

uint8_t lastmode = 0;                                        // Memorize the last mode
volatile uint8_t INTflag = 0;                                // watchdog flag for the locator flash
uint8_t modes[] = {0, 0, 0, 0, 0};                            // Mode Array, do NOT change this

uint8_t click();                                            // Function declaration for click (tests if you click of press the switch)
void momentary();                                            // Function declaration for momentary
void wait_5ms();                                            // Name says it all...
void wait_ms(uint8_t time);                                    // Wait for 'time' * 5ms.
void setmode(uint8_t mode);                                    // Sets OCR0B to 'modes[mode]'
void bedtime();                                                // Sends ATtiny to sleep mode
void ramping(uint8_t mode);                                    // Ramps up and sets new brightness to 'modes[]'
void blink();                                                // Blinks...
uint8_t EEPROM_read(uint8_t EEPROM_address);                // EEPROM read
void EEPROM_write(uint8_t EEPROM_adress);                    // EEPROM write
void programming();                                            // Programming menu
void blinkblinkblink();                                       


ISR(PCINT0_vect)
{
    INTflag = (1 << PCINTflag);                                // Set 'INTflag' to 2 (Important for programming menu)
}   

ISR(WDT_vect)                                                // Watchdog Timer Interrupt (locatorflash)
{
    INTflag = (1 << WDTflag);                                // Set 'INTflag' to 1
}

int main(void)
{
    uint8_t time = 0;                                        // Measure ON/ OFF time and some other things
    uint8_t clicked = 0;                                    // Count how many clicks have been made
    uint8_t memory = 0;                                        // Memorizes last mode for programming
    uint8_t bursttimer = 0;                                    // Used to count time to ramp down
    uint8_t memory_ON_OFF = 0;

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);                    // Use Power Down Sleep mode. Wakes up with Pin Change Interrupt or Watchdog Interrupt

    DDRB = (1 << DDB1);                                        // Define PB1 as output
    PORTB = (1 << PINB3);                                    // Define pull-up switch ON

    GIMSK = (1 << PCIE);                                    // Pin Change Interrupt Enable (switch is pressed --> interrupt)
    PCMSK = (1 << PCINT3);                                    // Enable Pin Change Interrupt at PINB3

    TCCR0A = 0b00100001;
    TCCR0B = 0b00000001;                                    // PWM setup

/*
* Watchdog Interrupt interval
*
* WDP3 WDP2 WDP1 WDP0 timer   ~seconds
*    0    1    0    1  512 mS       .5
*    0    1    1    0 1024 mS        1
*    0    1    1    1 2048 mS        2
*    1    0    0    0 4096 mS        4
*    1    0    0    1 8192 mS        8
*/   

    WDTCR |= (1 << WDP3) | (1 << WDP0);                        // Set Watchdog prescaler to 8 sec
    if ((EEPROM_read(5) & 1) == 1)
        WDTCR |= (1 << WDTIE);                                // Enable Watchdog Interrupts if Locatorflash enabled...

    modes[mode1addr] = EEPROM_read(mode1addr);                // Mode, when light is switched ON
    modes[mode2addr] = EEPROM_read(mode2addr);                // Mode accessed with two clicks
    modes[mode3addr] = EEPROM_read(mode3addr);                // Mode accessed with three clicks
    modes[mode4addr] = EEPROM_read(mode4addr);                // Mode accessed when switch is hold while the light is ON
    modes[BURSTaddr] = EEPROM_read(BURSTaddr);                // Burst mode. The light will step down from 'BURST' to 'mode4' after 'BURSTtime' * 1.28sec

    OCR0B = 0;                                                // 'Switch on brightness' after getting getting power.
                                                            // Change if you want 'Power ON' (useful for lights with two switches)
    while(1)
    {
        memory_ON_OFF = EEPROM_read(6);
        if ((PINB & 8) == 0)                                // When the button is pressed (PINB3 pulled down)
        {
            if (OCR0B == 0)                                    // When light was switched OFF
            {
                if (memory_ON_OFF == 1)                        // Mode memory switched OFF
                    OCR0B = modes[mode1addr];                // Set brightness to 'mode1', do not use setmode(mode1) otherwise it will not switch to 'mode2' after a 2 clicks
                else
                    OCR0B = modes[memory];
                clicked += click();                            // Test if 'click' or 'press'
                if (clicked == 0)                            // Press                                 
                    momentary();                            // --> momentary ON with 'mode1' (or 'memory' if memory enabled)
                if (clicked == 1)                            // Light was switched OFF and button is pressed
                {
                    if (memory_ON_OFF == 1)                    // Mode memory switched OFF
                        lastmode = mode1addr;                // Set 'lastmode' to mode1 that it will switch to 'mode2' after 2 clicks
                    else
                        lastmode = memory;                    // Set 'lastmode' to 'memory' (so that it will switch to 'mode1' after two clicks)
                    if ((PINB & 8) == 0)                    // If switch is still pressed
                    {
                        setmode(BURSTaddr);                    // Set brightness to 'BURST'
                        momentary();                        // But you have to release the switch sometime, therefore is momentary()
                        OCR0B = modes[BURSTaddr];            // momentary() sets brightness to 0 --> set it back to 'BURST'
                    }   
                }
                if (clicked == 2)                            // Light was switched OFF and ON again
                {
                    if ((PINB & 8) == 0)                    // If switch is still pressed
                    {
                        OCR0B = modes[BURSTaddr];            // Momentary 'BURST'
                        momentary();
                        clicked = 0;
                    }
                    else
                    {
                        if (lastmode == mode1addr)            // Decide which mode and set new mode...
                            setmode(mode2addr);                   
                        else
                            setmode(mode1addr);
                    }
                }               
            }
            else                                            // Light is already switched ON
            {
                clicked +=click();
                if (clicked == 0)                            // Light is ON and switch is pressed
                {
                    OCR0B = modes[BURSTaddr];                // Brightness is set to 'BURST'
                    momentary();                            // While button is pressed...
                    OCR0B = modes[lastmode];                // Brightness is set to 'lastmode' again
                }
                if (clicked == 1)                            // Switch was pressed (and perhaps released)
                {
                    OCR0B = modes[BURSTaddr];                // Momentary 'BURST'
                    momentary();                            // --> switch light OFF   
                }
                if (clicked == 2 || (clicked > 3))
                    OCR0B = 0;                                // --> switch light OFF
                if (clicked == 3)                            // Access 'mode3' or ramping mode
                {
                    setmode(mode3addr);
                    if ((PINB & 8) == 0)                    // If switch is still pressed -> ramping mode is entered
                    {
                        blinkblinkblink();
                        ramping(memory);                    // Set new brightness for the selected mode
                        clicked = 0;                        // Reset clicked
                        momentary();                        // Wait until switch is release
                        OCR0B = modes[memory];                // And set brightness to the new mode
                    }
                }
                if (clicked > 7)                            // Save new modes in EEPROM
                {
                    INTflag = 0;
                    blinkblinkblink();                        // Blink three times to indicate entering the programming menu
                    OCR0B = 0;
                    programming();                            // Enter programming menu
                    clicked = 0;                            // Reset click counter
                }
            }
            time = 0;                                        // Set 'time' to 0 to tell programm the light just was switched ON or OFF
            bursttimer = 0;                                    // Reset 'bursttimer'
        }
        wait_5ms();
        if (time > OFFtime)                                    // More than OFFtime * 5ms without doing anything passed
        {
            memory = lastmode;
            clicked = 0;                                    // Reset 'click' (counter) and
            if (OCR0B == 0)                                    // If light is switched OFF
                bedtime();                                    // --> send ATtiny to sleep mode
            if (time > 254)
                bursttimer++;                                // Increase Burst timer when time is overflowing
        }
        if ((bursttimer > BURSTtime) && (lastmode == BURSTaddr))
            setmode(mode4addr);                                // Ramp down
        if ((INTflag & (1 << WDTflag)) == 1)                // WDT Interrupt occurred
        {
            INTflag = 0;                                    // Set 'INTflag' to 0 again
            OCR0B = locator;                                // Set Brightness to 'locator'
            wait_5ms();
            wait_5ms();
            OCR0B = 0;                                        // After 10ms switch light OFF again
            time = OFFtime;                                    // Set 'time' to OFFtime to enter sleepmode again
        }
        time++;                                                // Reset 'time' not needed, just creates an overflox. Important for BURSTtimer
    }
}

uint8_t click()                                                // Decide if click or press...
{                                                            // if click --> return 1
    uint8_t press_timer = 0;
    while(press_timer < presstime)                            // if press --> return 0 (pressed for more than 50 * 5ms)
    {                                                               
        if ((PINB & 8) == 0)                                // When the button is pressed (PINB3 pulled down)
        {
            press_timer++;                                    // Increase 'time' while switch is pressed
            wait_5ms();                                        // And wait 5ms
        }
        else
            return 1;                                        // Switch was clicked
    }
    return 0;                                                // Switch is pressed
}

void momentary()                                            // Allows momentary function.
{
    while((PINB & 8) == 0)                                    // While switch is pressed wait
        wait_5ms();                                            // Wait 5ms for debouncing
    OCR0B = 0;                                                // When switch is released set brightness to 0
}

void wait_5ms()                                                // Waits for 5ms
{                                                            // This way you use less memory than
    _delay_ms(5);                                            // Always writing _delay_ms(double argument)
}

void setmode(uint8_t mode)                                    // Sets OCR0B to 'modes[mode]'
{                                                            // Also uses less memory than always writing
    OCR0B = modes[mode];                                    // OCR0B = 'modes[mode]';
    lastmode = mode;                                        // lastmode = 'mode';
}

void bedtime()                                                // Send ATtiny to sleep mode
{
    sei();                                                    // Enable global interrupts
    sleep_mode();                                            // Go to sleep and wait for interrupt...
    cli();                                                    // Disable global interrupts
}

void ramping(uint8_t mode)                                    // Ramping mode
{
    uint8_t new_brightness = 0;                                // Define some new variables
    uint8_t click_counter = 0;
    uint8_t dummy = 0;
    momentary();                                            // Wait until the switch is released
    while (1)                                                // Go into a never ending loop except you reach the mode you like and press
    {
        if (new_brightness > 22)                            // 22 brightness settings are stored in the EEPROM
        {
            new_brightness = 0;                                // This avoids getting a wrong adress
            click_counter = 0;
        }
        OCR0B = EEPROM_read(new_brightness + 7);            // OCR0B is set to the current brightness
        if ((PINB & 8) == 0)                                // If switch is pressed
        {
            dummy = click_counter;                       
            click_counter += click();                        // If switch is clicked the light will continue ramping up
            new_brightness = click_counter;
            if (dummy == new_brightness)                    // if dummy == new_brightness then the switch was pressed
            {
                blinkblinkblink();                            // Blink three times to indicate that the new mode is set
                click_counter = EEPROM_read(new_brightness + 7);
                modes[mode] = click_counter;
                return;                                        // Return to main
            }
        }
        wait_5ms();                               
    }
}

void blink()                                                // Blinks with OFFtime 250ms, ontime 250ms and brightness 20
{
    OCR0B = 0;                                                // Set brightness to '0'
    wait_ms(50);
    OCR0B = 20;                                                // Set brightness to 20
    wait_ms(50);
}

uint8_t EEPROM_read(uint8_t EEPROM_address)                    // For more information about this function look in the datasheet
{
    while(EECR & (1 << 1));                                    // Wait for completion of previous write
    EEARL = EEPROM_address;                                    // Set up address register
    EECR |= (1 << EERE);                                    // Start eeprom read by writing EERE
    return EEDR;                                            // Return data from data register
}

void EEPROM_write(uint8_t EEPROM_adress)                    // For more information about this function look in the datasheet
{
    while(EECR & (1 << 1));                                    // Wait for completion of previous write
    EECR = (0 << EEPM1) | (0 >> EEPM0);                        // Set Programming mode
    EEARL = EEPROM_adress;                                    // Set up address and data registers
    if (EEPROM_adress == 5)
        EEDR = EEPROM_read(5) ^ 1;
    if (EEPROM_adress == 6)
        EEDR = EEPROM_read(6) ^ 1;
    if (EEPROM_adress < 5)
        EEDR = modes[EEPROM_adress];
    EECR |= (1 << 2);                                        // Write logical one to EEMPE
    EECR |= (1 << 1);                                        // Start eeprom write by setting EEPE
}

void wait_ms(uint8_t time)                                    // Wait time * 5ms with using wait_5ms()
{
    while ((time > 0) && ((INTflag & (1 << PCINTflag)) == 0))
    {
        wait_5ms();
        time--;
    }
}

void programming()
{
    uint8_t counter = 0;                                    // Define some new variables
    uint8_t click_counter = 0;
    uint8_t dummy = 0;
    while (click_counter < 4)                                // Leave programming menu after 4 clicks       
    {
        INTflag = 0;
        sei();
        wait_ms(50);
        while ((counter > 0) && (INTflag & (1 << PCINTflag)) == 0)
        {
            blink();
            counter--;
        }
        cli();
        OCR0B = 0;
        if ((PINB & 8) == 0)                                // If switch is pressed
        {
            dummy = click_counter;
            click_counter += click();                        // Decide if switch is clicked or pressed
            counter = click_counter;
            if (dummy == counter)                            // Switch was pressed
            {   
                momentary();
                if (dummy == 1)
                {
                    EEPROM_write(5);                        // Toggle Locatorflash ON/ OFF           
                }
                if (dummy == 2)
                {
                    EEPROM_write(6);                        // Toggle mode memory ON/ OFF
                }
                if (dummy == 3)
                {
                    EEPROM_write(mode1addr);                // Update 'mode1'
                    EEPROM_write(mode2addr);                // Update 'mode2'
                    EEPROM_write(mode3addr);                // Update 'mode3'
                    EEPROM_write(mode4addr);                // Update 'mode4'
                    EEPROM_write(BURSTaddr);                // Update 'BURST'
                }
            }
        }
        wait_5ms();
    }
}

void blinkblinkblink()                                        // Blinks three times...
{
    blink();
    blink();
    blink();
}

Das ist eine Firmware, die ich mal geschrieben habe basierend auf dem UI von NovaTac und HDS. Allerdings sollte ich eine Einschaltsperre leicht realisieren lassen. Wollte ich eigentlich auch machen, allerdings hat dann der Platz nicht mehr gereicht. Deshalb müsste man wohl das Programmiermenü raus schmeißen oder ein anderes Feature (oder einen anderen Mikrocontroller verwenden).
In der Zeile in der getestet wird ob die Lampe an war noch eine weitere while Schleife einfügen und danach einen Zähler, der die Anzahl der Clicks zählt und nach einer gewissen Zeit wieder zurück gesetzt wird. Sowas wie
while(clickcounter < 3)
{
Hier die Zeit dann messen und die Anzahl der Clicks zählen. Ansonsten wieder in den Sleep modus gehen.
}

Gruß,
Fritz
 
  • Danke
Reaktionen: mash.m und Nexxos1412

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

danke. Ich habe das Thema erst mal auf Eis gelegt. Aber vergessen ist das nicht. Ich werde das aber mal versuchen selbst zu programmieren.

Gruß Markus