/** AssHeat.c
*
* Created: 25.12.2013 2:29:55
*  Author: Alex
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <avr/eeprom.h>
#define CHAN1_INC 0
#define CHAN1_DEC 1
#define CHAN2_INC 2
#define CHAN2_DEC 3
#define MAX_STAGE 3
volatile unsigned char chan1Stage = 0;
volatile unsigned char chan2Stage = 0;
volatile uint32_t channel1StartCount = 0;
volatile uint32_t channel2StartCount = 0;
volatile int chan1HeatMode = 0;
volatile int chan2HeatMode = 0;
volatile int indicatorFlashCounter = 0;
volatile int indicatorFlashState = 0;
volatile int buttonPressTime[4];
volatile char buttonStates[] = {0,0,0,0};
char buttonPins[] = {PB0, PB1, PB6, PB7};
//volatile char btn1State = 0;
//volatile char btn2State = 0;
//volatile char btn3State = 0;
//volatile char btn4State = 0;
volatile char learnMode = 0;
uint32_t heatingTime_ee EEMEM;
volatile uint32_t heatingTime = 0;
char chan1LastStage_ee EEMEM;
char chan2LastStage_ee EEMEM;
char chan1LastStage = 0;
char chan2LastStage = 0;
void startHeat(unsigned char chan)
{
    if (1==chan)    
    {
        channel1StartCount = 0;
        chan1HeatMode = 1;
    }
    else if (2==chan)
    {
        channel2StartCount = 0;        
        chan2HeatMode = 1;
    }
}
void updateStatusLeds()
{
    if (chan1HeatMode==0)
    {
        switch (chan1Stage)
        {
            case 0:
            PORTD &= ~(1 << PD0);
            PORTD &= ~(1 << PD1);
            break;
            case 1:
            PORTD &= ~(1 << PD0);
            PORTD |= (1 << PD1);
            break;
            case 2:
            PORTD |= (1 << PD0);
            PORTD |= (1 << PD1);
            break;
            case 3:
            PORTD |= (1 << PD0);
            PORTD &= ~(1 << PD1);
            break;
        }
    }    
    
    if (chan2HeatMode==0)
    {
        switch (chan2Stage)
        {
            case 0:
            PORTD &= ~(1 << PD2);
            PORTD &= ~(1 << PD3);
            break;
            case 1:
            PORTD &= ~(1 << PD2);
            PORTD |= (1 << PD3);
            break;
            case 2:
            PORTD |= (1 << PD2);
            PORTD |= (1 << PD3);
            break;
            case 3:
            PORTD |= (1 << PD2);
            PORTD &= ~(1 << PD3);
            break;
        }
    }
}
void strartLearn()
{
    learnMode = 1;
}
void stopLearn()
{
    heatingTime = channel1StartCount;
    eeprom_write_dword(&heatingTime_ee, heatingTime);
    learnMode = 0;
    chan1HeatMode = 0;
    channel1StartCount = 0;
    
}
void buttonDown(int btn)
{
    
}
void updateState()
{
    updateStatusLeds();        
    updatePWM();    
}
void buttonUp(int btn, int pressTime)
{
        _delay_ms(20);
        
        //PORTB |= (1 << PB4);
        switch (btn)
        {
            case CHAN1_INC:
            
            if (pressTime<35)
            {
                if (0==chan1Stage)
                {
                    startHeat(1);
                    if (chan1LastStage>0 && chan1LastStage <= MAX_STAGE)
                        chan1Stage = chan1LastStage;
                    else
                        chan1Stage = 1;
                } 
                else if (chan1Stage<MAX_STAGE && chan1HeatMode==0)
                {
                    chan1Stage++;
                    chan1LastStage = chan1Stage;
                    eeprom_write_byte(&chan1LastStage_ee, chan1LastStage);
                }
            }                                
            break;
            
            case CHAN1_DEC:
            if (1==learnMode)
            {
                stopLearn();
                if (chan1LastStage>0 && chan1LastStage <= MAX_STAGE)
                    chan1Stage = chan1LastStage;
                else
                    chan1Stage = 1;
            }
            else if (pressTime<35)
            {
                if (chan1Stage>0  && chan1HeatMode==0)
                {
                    chan1Stage--;
                    if (chan1Stage==0)
                        chan1HeatMode = 0;
                    else 
                    {
                        chan1LastStage = chan1Stage;
                        eeprom_write_byte(&chan1LastStage_ee, chan1LastStage);                        
                    }
                }
                else if (chan1HeatMode==1)
                {
                    chan1HeatMode = 0;
                }
            }                
            break;
            
            case CHAN2_INC:
            if (0==chan2Stage)
            {
                startHeat(2);
                if (chan2LastStage > 0 && chan2LastStage <= MAX_STAGE)
                    chan2Stage = chan2LastStage;
                else
                    chan2Stage = 1;                    
            }
            else if (chan2Stage<MAX_STAGE  && chan1HeatMode==0)
            {
                chan2Stage++;
                chan2LastStage = chan2Stage;
                eeprom_write_byte(&chan2LastStage_ee, chan2Stage);
            }                
            break;
            
            case CHAN2_DEC:
            if (pressTime < 35)
            {
                if (chan2Stage>0  && chan2HeatMode==0)
                {
                    chan2Stage--;
                    if (chan2Stage==0)
                        chan2HeatMode = 0;
                    else
                    {
                        chan2LastStage = chan2Stage;
                        eeprom_write_byte(&chan2LastStage_ee, chan2LastStage);
                    }                        
                }
                else if (chan2HeatMode==1)
                {
                    chan2HeatMode=0;
                }
            }                
            break;
        }
        
        updateState();        
}
//#define Prescaler 0x01 //0x00 - для кварца 4MHz, 0x01 - для кварца 8MHz...
void updatePWM()
{
    // fast PWM mode
    TCCR0A = (1 << WGM01) | (1 << WGM00);
    if (chan1Stage>0 || chan1HeatMode)
    {
        TCCR0A |= (1 << COM0A1);
    }
    if (chan2Stage>0 || chan2HeatMode)
    {
        TCCR0A |= (1 << COM0B1);
    }
}
void loadEepromValues()
{
    heatingTime = eeprom_read_dword(&heatingTime_ee);
    if (0==heatingTime)
        heatingTime = 1000;
        
    chan1LastStage = eeprom_read_byte(&chan1LastStage_ee);
    chan2LastStage = eeprom_read_byte(&chan2LastStage_ee);
}
int main(void)
{
    
    unsigned char stateValues[] = {255,64,128,254};
    DDRB = 0;
    DDRD = 0;
    DDRB   |= (1 << PB2) | (1 << PB4);      // PWM output on PB2 - OC0A
    DDRD   |= (1 << PD5) | (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3); // PWM output on PD5 - OC0B
    TCCR0A = (1 << WGM01) | (1 << WGM00);
    TCCR0B = (1 << CS02);   // clock source = CLK/8, start PWM
    TCCR1A = 0;
    TCCR1B = (0 << CS12)|(1 << CS11)| (0 << CS10);//|(1 << WGM12); //предделитель clk/1024, режим таймера СТС;
    OCR1AH=0x0F; OCR1AL=0x42; // Число N=15625=0x3D09.
    TCNT1 = 0;
    
    //OCR1A = 0;//62500/1;     // compare match register.
    
    //TCCR1B |= (1 << WGM12);   // CTC mode
    //TCCR1B |= (1 << CS12);    // 256 prescaler
    TIMSK  |= (1 << OCIE1A);  // enable timer compare interrupt
    //TIMSK = (TOIE1<<1);
    //TCNT1 = 7;
    chan1Stage = 0;
    chan2Stage = 0;
    PORTB &= ~(1 << PB4);
    PORTB |= (1 << PB0);
    PORTB |= (1 << PB1);
    PORTB |= (1 << PB6);
    PORTB |= (1 << PB7);
    
    loadEepromValues();
    sei();
while(1)
{    
    OCR0A  = chan1HeatMode==0 ? stateValues[chan1Stage] : 254;// PWM_val1;       // write new PWM value
    OCR0B  = chan2HeatMode==0 ? stateValues[chan2Stage] : 254;
    
    for (char btn=0;btn<4;++btn)
    {
        if ((PINB & (1 << buttonPins[btn]))==0)
        {
            if (0==buttonStates[btn])
            {
                buttonDown(btn);
                buttonPressTime[btn] = 0;
            }
            buttonStates[btn] = 1;
        
        }
        else
        {
            if (1==buttonStates[btn])
            {
                    
                buttonUp(btn, buttonPressTime[btn]);
            }                
            buttonStates[btn] = 0;                
        }        
    }
    
    if (buttonStates[CHAN1_DEC]==1 && buttonPressTime[CHAN1_DEC]>35)
    {
        chan1Stage = 0;
        chan1HeatMode = 0;
        updateState();
    }
    
    if (buttonStates[CHAN2_DEC]==1 && buttonPressTime[CHAN2_DEC]>35)
    {
        chan2Stage = 0;
        chan2HeatMode = 0;
        updateState();
    }
    
    if (buttonStates[CHAN1_INC]==1 && 0==chan1Stage && buttonPressTime[CHAN1_INC] > 35)
    {
        startHeat(1);
        strartLearn();
        updateState();
    }
}
}
int state = 0;
ISR (TIMER1_COMPA_vect)
{
    TCNT1H=0; TCNT1L=0; // Сброс таймера.
    
    for (char btn=0;btn<4;++btn)
    {
        if (buttonStates[btn]!=0)
            buttonPressTime[btn]++;
    }
    
    indicatorFlashCounter++;
    if (indicatorFlashCounter > 4)
    {
        indicatorFlashCounter = 0;
        indicatorFlashState = ~ indicatorFlashState;
    }
    if (chan1HeatMode == 1)
    {
        channel1StartCount ++;
        if (channel1StartCount > heatingTime && learnMode == 0)
        {        
            chan1HeatMode = 0;
            updateStatusLeds();
        }
        else
        {
            int port = learnMode==0 ? PD0 : PD1;
            if (indicatorFlashState==0)
                PORTD &= ~ (1 << port);
            else
                PORTD |= (1 << port);
        }
    }
    
    if (chan2HeatMode == 1)
    {
        channel2StartCount ++;
        if (channel2StartCount > heatingTime)
        {        
            chan2HeatMode = 0;
            updateStatusLeds();
        }            
        else
        {
            if (indicatorFlashState==0)
                PORTD &= ~ (1 << PD2);
            else
                PORTD |= (1 << PD2);
        }
    }
    
    
}
[свернуть]