thoralt.de · projects · elektrohase · source

elektrohase source

//============================================================================
//
// Firmware Elektrohase
//
// Processor:       Atmel ATmega8
// Clock:           8 MHz (internal oscillator)
// Developer:       Thoralt Franz
// Last change:     07.04.2005
//
//============================================================================
//
// Pin allocation:
//
// PB0:    --
// PB1:    --
// PB2:    register clock shift registers
// PB3:    data for shift registers       (MOSI)
// PB4:    --                             (MISO)
// PB5:    data clock for shift registers (SCK)
// PB6:    --
// PB7:    --
//
// PC0:    --
// PC1:    --
// PC2:    --
// PC3:    --
// PC4:    --
// PC5:    --
//
// ADC6:   --
// ADC7:   --
//
// PD0:    --
// PD1:    --
// PD2:    --
// PD3:    --
// PD4:    --
// PD5:    --
// PD6:    --
// PD7:    --
//
//============================================================================

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>

//----------------------------------------------------------------------------
// global #defines
//----------------------------------------------------------------------------
#define TIMER_1_RELOAD -8000
#ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

//----------------------------------------------------------------------------
// global variables
//----------------------------------------------------------------------------
volatile unsigned int g_uTimer = 0;      // global timer
volatile unsigned int g_uTimerRest = 0;  // remaining time of pattern
volatile unsigned char g_ucLED[8];

//----------------------------------------------------------------------------
// overflow timer1
//
// -> --
// <- --
//----------------------------------------------------------------------------
SIGNAL(SIG_OVERFLOW1)
{
    TCNT1 = TIMER_1_RELOAD;     // reload: 1000 µs
    g_uTimer++;
    if(g_uTimerRest) g_uTimerRest--;
}

//----------------------------------------------------------------------------
// Init_IO
//
// -> --
// <- --
//----------------------------------------------------------------------------
void Init_IO(void)
{
    // ports
    DDRB = 0x2C; PORTB = 0x00;
    DDRC = 0x00; PORTC = 0x00;
    DDRD = 0x00; PORTD = 0x00;

    // timer1
    TCCR1B = 0x01;                      // prescaler = 1
    sbi(TIMSK, TOIE1);                  // allow overflow interrupt
    TCNT1 = TIMER_1_RELOAD;             // reload: 1000 µs

    // SPI
    SPCR = (1<<SPE) | (1<<MSTR);        // SPI enable, master
    SPSR = (1<<SPI2X);                  // double speed (4 MHz)

    // allow interrupts globally
    sei();
}

//----------------------------------------------------------------------------
// SetLED
//
// sends the array g_ucLED via SPI to the shift registers
//
// -> --
// <- --
//----------------------------------------------------------------------------
void SetLED(void)
{
    int i;
  
    for(i=0; i<8; i++)
    {
        SPDR = g_ucLED[7-i];
        while(!(SPSR & (1<<SPIF)));
    }
   
    // clock the shift registers contents to their outputs
    sbi(PORTB, 2); cbi(PORTB, 2);
}

//----------------------------------------------------------------------------
// BufRotateLeft
//
// rotates the LED buffer by a given number of bits to the left. left carry
// comes in at the right side.
//
// -> iCount = number of bits to rotate the buffer
// <- --
//----------------------------------------------------------------------------
void BufRotateLeft(int iCount)
{
    int i, j;
    unsigned char u1, u2;
   
    for(j=0; j<iCount; j++)
    {
        // shift buffer by one bit to the left
        u1 = g_ucLED[7] & 128;
        for(i=0; i<8; i++)
        {
            u2 = g_ucLED[i];
            g_ucLED[i] <<= 1;
            if(u1) g_ucLED[i] |= 1;
         
            u1 = u2 & 128;
        }
    }
}

//----------------------------------------------------------------------------
// MovingLightConstant
//
// moving light forward, constant speed, two groups eight leds each
// (red/blue mixed or separated)
//
// -> uTime = duration in ms of the pattern
//    cMode = 0: mixed colors
//            1: red and blue separated
//            2: red only
//            3: blue only
//            4: blue only, gap of 15 LEDs of between each 4 LEDs on
//            5: red only, gap of 15 LEDs of between each 4 LEDs on
//            6: red/blue all on, gap of 8 LEDs moving
//            7: red/blue all on, 8 gaps of one LED moving
//            8: red/blue mixed all on, 8 gaps moving
//    uDelay = time in ms between steps
// <- --
//----------------------------------------------------------------------------
void MovingLightConstant(unsigned int uTime, char cMode,
                         unsigned int uDelay)
{
    int i;

    // init LED buffer
    for(i=0; i<8; i++) g_ucLED[i] = 0x00;

    switch(cMode)
    {
        case 0:
            g_ucLED[0] = 0xFF; g_ucLED[3] = 0xFF;
            break;
        case 1:
            g_ucLED[0] = 0x55; g_ucLED[3] = 0xAA;
            break;
        case 2:
            g_ucLED[0] = 0xAA; g_ucLED[3] = 0xAA;
            break;
        case 3:
            g_ucLED[0] = 0x55; g_ucLED[3] = 0x55;
            break;
        case 4:
            g_ucLED[0] = 0x01;
            g_ucLED[2] = 0x01;
            g_ucLED[4] = 0x01;
            g_ucLED[6] = 0x01;
            break;
        case 5:
            g_ucLED[0] = 0x02;
            g_ucLED[2] = 0x02;
            g_ucLED[4] = 0x02;
            g_ucLED[6] = 0x02;
            break;
        case 6:
            for(i=0; i<8; i++) g_ucLED[i] = 0xFF;
            g_ucLED[0] = 0x00;
            break;
        case 7:
            for(i=0; i<8; i++) g_ucLED[i] = 0xFE;
            break;
        case 8:
        default:
            for(i=0; i<8; i++) g_ucLED[i] = 0x50;
            break;
    }
   
    g_uTimerRest = uTime;
   
    while(g_uTimerRest)
    {
        switch(cMode)
        {
            case 0:
            case 6:
            case 7:
            case 8:
                BufRotateLeft(1);
                break;
          
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            default:
                BufRotateLeft(2);
                break;
        }
       
        SetLED();
       
        // wait until next step
        g_uTimer = 0; while(g_uTimer<uDelay);
    }
}

//----------------------------------------------------------------------------
// SetBit
//
// set one bit in global LED buffer (numbered 0...63)
//
// -> iBit = number of bit to set
// <- --
//----------------------------------------------------------------------------
void SetBit(int iBit)
{
    g_ucLED[iBit>>3] |= (1<<(iBit&0x07));
}

//----------------------------------------------------------------------------
// EyeBlink
//
// blinks with the 'eye'
//
// -> iNum = number of blinks
//    iLength = duration  in ms of one blink
//    iPauseBetween = pause in ms between blinks
//    iPauseAfter = pause in ms after the blinks
//    iPauseBefore = pause in ms before the blinks
// <- --
//----------------------------------------------------------------------------
void EyeBlink(int iNum, int iLength, int iPauseBetween, int iPauseAfter,
                int iPauseBefore)
{
    int i;
  
    // init LED buffer
    for(i=0; i<8; i++) g_ucLED[i] = 0x00;
   
    SetLED();
    g_uTimer = 0; while(g_uTimer<iPauseBefore); 

    for(i=0; i<iNum; i++)
    {
        SetBit(62); SetLED();
        g_uTimer = 0; while(g_uTimer<iLength);
      
        g_ucLED[7] = 0; SetLED();
        g_uTimer = 0; while(g_uTimer<iPauseBetween);
    }
   
    g_uTimer = 0; while(g_uTimer<iPauseAfter);  
}

//----------------------------------------------------------------------------
// MovingLightsAntiDirection
//
// moving lights forward and backwards, separated by color
//
// -> uTime = duration in ms of the pattern
//    uDelay = time in ms between the steps
//    iNumRed = number of red LEDs to be on
//    iNumBlue = number of blue LEDs to be on
//    iDistance = distance of both groups (e. g. 31)
// <- --
//----------------------------------------------------------------------------
void MovingLightsAntiDirection(unsigned int uTime, unsigned int uDelay,
                            int iNumRed, int iNumBlue, int iDistance)
{
    int i, iRed = 0, iBlue = iDistance, iRedPos, iBluePos;

    g_uTimerRest = uTime;
   
    while(g_uTimerRest)
    {
        // init LED buffer
        for(i=0; i<8; i++) g_ucLED[i] = 0x00;
       
        iRedPos = iRed;
        iRed += 2; if(iRed>63) iRed -= 64;
        for(i=0; i<iNumRed; i++)
        {
            SetBit(iRedPos);
            iRedPos += 2; if(iRedPos>63) iRedPos -= 64;
        }
       
        iBluePos = iBlue;
        iBlue -= 2; if(iBlue<0) iBlue += 64;
        for(i=0; i<iNumBlue; i++)
        {
            SetBit(iBluePos);
            iBluePos += 2; if(iBluePos>63) iBluePos -= 64;
        }
       
        SetLED();
       
        // wait until next step
        g_uTimer = 0; while(g_uTimer<uDelay);
    }
}

//----------------------------------------------------------------------------
// Fading
//
// soft fading in and out the colors using PWM
//
// -> uTime = duration in ms of that pattern
//    cMode = 0: alternating red and blue
//            1: red only
//            2: blue only
//            3: red and blue at the same time
// <- --
//----------------------------------------------------------------------------
void Fading(unsigned int uTime, char cMode)
{
    int i;
    unsigned char uc, ucPWMCounter = 0, ucPWMValue = 50, ucPWMDir = 0;

    g_uTimerRest = uTime; g_uTimer = 0;
 
    while(g_uTimerRest)
    {
        ucPWMCounter++; if(ucPWMCounter>=100) ucPWMCounter = 0;
     
        // use global timer for brightness depending on current fading
        // direction ucPWMDir 
        if(ucPWMDir==0)
        {
            ucPWMValue = g_uTimer/20;
        }
        else
        {
            ucPWMValue = 100 - g_uTimer/20;
        }
       
        if(g_uTimer>2000)
        {
            g_uTimer = 0;
           
            // invert direction
            ucPWMDir = (ucPWMDir) ? 0 : 1;
        }
       
        switch(cMode)
        {
            case 0:
                uc = (ucPWMCounter<ucPWMValue) ? 0xAA : 0x55;
                break;
          
            case 1:
                uc = (ucPWMCounter<ucPWMValue) ? 0xAA : 0x00;
                break;
              
            case 2:
                uc = (ucPWMCounter<ucPWMValue) ? 0x55 : 0x00;
                break;

            case 3:
            default:
                uc = (ucPWMCounter<ucPWMValue) ? 0xFF : 0x00;
                break;
        }
       
        // fill shift registers
        for(i=0; i<8; i++)
        {
            SPDR = uc;
            while(!(SPSR & (1<<SPIF)));
        }
       
        // clock the shift registers contents to their outputs
        sbi(PORTB, 2); cbi(PORTB, 2);
    }
}

//----------------------------------------------------------------------------
// main function
//----------------------------------------------------------------------------
int main(void)
{
    // do all initializations
    Init_IO();

    // main loop
    while(1)
    {
        EyeBlink(2, 100, 100, 1500, 500);
        EyeBlink(2, 100, 100, 1500, 500);

        MovingLightConstant(5000, 8, 66);
        MovingLightsAntiDirection(8000, 25, 4, 4, 31);
        MovingLightConstant(5000, 7, 100);
        MovingLightConstant(5000, 6, 20);

        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);

        EyeBlink(2, 100, 100, 1500, 500);
        EyeBlink(2, 100, 100, 1500, 500);

        MovingLightConstant(2500, 4, 250);

        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);

        MovingLightConstant(2500, 5, 250);
      
        Fading(4000, 1);
        Fading(4000, 2);
        Fading(4000, 1);
        Fading(4000, 2);
        
        Fading(8000, 0);
        MovingLightConstant(4000, 2, 50);
        Fading(8000, 1);

        EyeBlink(2, 100, 100, 1500, 500);
        EyeBlink(2, 100, 100, 1500, 500);

        MovingLightConstant(6000, 3, 50);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);
        MovingLightConstant(500, 3, 15);
        MovingLightConstant(500, 2, 15);

        Fading(8000, 2);
        MovingLightConstant(4000, 0, 15);
        Fading(8000, 3);
        MovingLightConstant(6000, 1, 50);
    }
}