//
// フルカラーLED ボリュームコントロール
//  fullcolor_led_090812.c
//  atmega88 Clock 8MHz /8 -> 1MHz Fuses EXT 0xF9 HIGH DF LOW 0x62 Lock 0xFF
//  2009/08/12 5連フルカラーLEDLS1155-525W405(秋月)を3個のボリュームでフルカラー発色
//                           PB0 50% デューティ
//              VR1 AD0ch -> B1 0-99% おおよそ
//              VR2 AD1ch -> B2 0-99%
//              VR3 AD2ch -> B3 0-99%
//-------------------------------------
// ヘッダファイルのインクルード
#define CYCLES_PER_US ((F_CPU)/1000000)     // cpu cycles per microsecond
#define F_CPU 8000000UL                     // 8MHz

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

//-------------------------------------
// データ・タイプの定義
typedef unsigned char BYTE;                 // unsigned 8bit
typedef unsigned int WORD;                  // unsigned 16bit

#define true  1
#define false 0
#define sbi(BYTE,BIT) BYTE |= _BV(BIT)      // BYTEの指定BITに1をセット
#define cbi(BYTE,BIT) BYTE &= ~_BV(BIT)     // BYTEの指定BITをクリア

//-------------------------------------
// 遅延タイマー
void delay_us(uint32_t time_us) 
{
    uint32_t delay_loops;
    register uint32_t i;

    delay_loops = (time_us+3)/5*CYCLES_PER_US;  // +3 for rounding up (dirty) 

    // one loop takes 5 cpu cycles 
    for (i=0; i < delay_loops; i++) {
        asm volatile ("nop\n");
    };
}

//-------------------------------------
// I/O初期化
void port_init(void)
{
    PORTB = 0x00;
    DDRB  = 0xFF;   // FULL COLOR LED PWM出力

    PORTC = 0x7F;
    DDRC  = 0x00;   // VR入力

    PORTD = 0xFF;
    DDRD  = 0x60;   // 未使用
}

//-------------------------------------
// タイマー初期化
void timer_init(void)
{
    TCNT0  = 0x01;  //タイマー設定0
    TCCR0A = 0xF3;  //コンペアマッチセット 高速PWM 8bit
    TCCR0B = 0x03;  //プリスケール clk/64 16mS

    TCNT1  = 0x01;  //タイマー設定1
    TCCR1A = 0xF5;  //コンペアマッチセット 高速PWM 8bit
    TCCR1B = 0x02;  //プリスケール clk/8 4mS

    TCNT2  = 0x01;  //タイマー設定2
//  TCCR2A = 0xA3;  //コンペアマッチクリア 高速PWM 8bit デューティ1-100%
    TCCR2A = 0xF3;  //コンペアマッチセット 高速PWM 8bit デューティ0-99%
//  TCCR2B = 0x02;  //プリスケール clk/8 2mS
    TCCR2B = 0x03;  //プリスケール clk/64 16mS
}

//-------------------------------------
//  タイマー割込み0
ISR(TIMER0_OVF_vect)
{
    PORTB ^=0x01;   // PB0 50% デューティ
}

//-------------------------------------
// 割込み初期化
void init_devices(void)
{
    MCUCR = 0x00;
    EICRA = 0x00;   //extended ext ints
    EIMSK = 0x00;
 
    TIMSK0 = 0x01;  //timer 0 interrupt sources
    TIMSK1 = 0x00;  //timer 1 interrupt sources
    TIMSK2 = 0x00;  //timer 2 interrupt sources
 
    PCMSK0 = 0x00;  //pin change mask 0 
    PCMSK1 = 0x00;  //pin change mask 1 
    PCMSK2 = 0x00;  //pin change mask 2
    PCICR  = 0x00;  //pin change enable 
    PRR    = 0x00;  //power controller
}

//-----------------------------------------------------------------------------
// AD初期化
void adc_init(void){
    ADMUX = (0<<REFS0);                 // 外部基準電圧
    ADCSRA =(1<<ADEN)|(1<<ADSC)|(0<<ADPS0);
    // A/D変換許可、1回目変換開始(調整)、分周率2
}

//-----------------------------------------------------------------------------
// AD変換
int adc_convert(char ch){
int ad;
    ADMUX = ch;                         // 入力ch
    cbi(ADCSRA,ADIF);
    sbi(ADCSRA,ADSC);                   // 変換開始
    loop_until_bit_is_set(ADCSRA,ADIF); // 変換完了まで待つ
    ad = ADCL;                          // 下位8bit
    return ad += (ADCH<<8);             // 上位2bit
}

//-----------------------------------------------------------------------------
// メインプログラム
int main(void)
{
int ad;

    cli();                      // disable all interrupts
    port_init();                // I/O初期化
    timer_init();               // タイマー初期化
    init_devices();             // 割込み初期化
    adc_init();                 // AD初期化
    sei();                      // enable interrupts

    while(1){
        ad = adc_convert(0);    // VR1 AD変換 0ch
        OCR1A = ad>>2;          // Timer1 Aコンペアレジスタ設定 PB1

        ad = adc_convert(1);    // VR2 AD変換 1ch
        OCR1B = ad>>2;          // Timer1 Bコンペアレジスタ設定 PB2

        ad = adc_convert(2);    // VR3 AD変換 2ch
        OCR2A = ad>>2;          // Timer2 Aコンペアレジスタ設定 PB3

//      OCR0A = ad>>2;          // Timer0 Aコンペアレジスタ設定 PD6
//      OCR0B = ad>>2;          // Timero Bコンペアレジスタ設定 PD5
//      OCR2B = ad>>2;          // Timer2 Bコンペアレジスタ設定 PD3

        delay_us(10000);
    }
}