/******************************************************************************
    パルスモーターを1個のボリュームで正転、停止、逆転、速度制御
    2009/08/16  avr_drv_motor090816.c
    Fuses EXT 0xF9 HIGH 0xDF LOW 0xE2  LOOKBIT 0xFF

    09/08/12    X軸専用にして見る(1軸)
         13    制御方法
                ボリュームの真中で回転停止 励磁OFF
                ボリューム右回転で低速正回転、VR角度によって回転速度上昇
                ボリューム右回転端で最高速正回転
                ボリューム左回転で低速逆回転、VR角度によって回転速度上昇
                ボリューム左回転端で最高速逆回転
          16    速度変換テーブル作成 ボリュームの回転角度に対して速度変化がスムーズに成った。

******************************************************************************/

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

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

#define F_CPU 8000000UL                 // 8MHz
#define CYCLES_PER_US ((F_CPU)/1000000) // cpu cycles per microsecond

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

#define TCNT0_InitVal   (256-80)        // 10ms (128usX80=10.24ms)
#define TCNT1_InitVal   (65536-80)      // 10ms (128usX80=10.24ms)

volatile unsigned char TCNT0_Val;       // 割込みカウンタ0インターバル設定値
volatile unsigned int  count1;          // 割込みカウンタ1

volatile unsigned char  pat[8];

volatile unsigned int   Xpat_no = 0 ;   // X軸パルスモーター励磁位置
volatile unsigned char  Xcw = 0 ;       // X軸パルスモーター回転方向
volatile unsigned int   Xcount;         // X軸パルスモーターパルス

volatile unsigned int   Ypat_no = 0 ;   // Y軸パルスモーター励磁位置
volatile unsigned char  Ycw = 0 ;       // Y軸パルスモーター回転方向
volatile unsigned int   Ycount;         // Y軸パルスモーターパルス

char cnt1_str = 0;
char cnt1_up  = 0;

//-----------------------------------------------------------------------------
// 遅延タイマー
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");
    };
}

//-----------------------------------------------------------------------------
//  Initialize Timer/Counter0 for PWM
void init_PWM_Timer0()
{
    DDRD |= _BV(PD6);           // Set PD6(OC0A) Output
    TCCR0A = 0b10000011;        // Compare Match Low 8 bit High Speed PWM
    TCCR0B = 0b00000101;        // clk/1024 125nsX1024=128us
    OCR0A = 128;                // Set Output Compare Register
}

//-----------------------------------------------------------------------------
//  Initialize Timer/Counter0
void init_Timer0()
{
    TCCR0B = 0x00;              // Stop Timer/Counter0
    TCNT0_Val = TCNT0_InitVal;  // Initial Value of Timer/Counter0
    TCNT0  = TCNT0_Val;         // Set Value of Timer/Counter0
    TIMSK0 = _BV(TOIE0);        // Timer/Counter0 Overflow Interrupt Enable
    TCCR0B = 0x05;              // Start Timer/Counter0 clk/1024 125nsX1024=128us
}

//-----------------------------------------------------------------------------
//  Set Timer/Counter0
void Set_Timer0(unsigned char cnt0)
{
    TCNT0_Val=cnt0;             // Set Value of Timer/Counter0
}

//-----------------------------------------------------------------------------
//  Timer/Counter0 Overflow Handler
ISR(TIMER0_OVF_vect)
{
    TCNT0 = TCNT0_Val;          // Timer/Counter0

      if(Xcount > 0){           // X軸
        if (Xcw == 0){
          if(Xpat_no == 7) Xpat_no = 0; else Xpat_no++;
        }else{
          if(Xpat_no == 0) Xpat_no = 7; else Xpat_no--;
        }
        Xcount--;
        PORTB = pat[Xpat_no];     // 励磁パターンをポートBへ出力
      }    
}

//-----------------------------------------------------------------------------
//  Initialize Timer/Counter1
void init_Timer1()
{
    TCCR1B = 0x00;              // Stop Timer/Counter1
    TCNT1  = TCNT1_InitVal;     // Initial Value of Timer/Counter1
    TIMSK1 = _BV(TOIE1);        // Timer/Counter1 Overflow Interrupt Enable
    TCCR1B = 0x05;              // Start Timer/Counter1 clk/1024 125nsX1024=128us
    count1 = 0;
}

//-----------------------------------------------------------------------------
//  Timer/Counter1 Overflow Handler
ISR(TIMER1_OVF_vect)
{
    TCNT1 = TCNT1_InitVal;
    count1++;
    if(count1>=1000) cnt1_up=1;     //10S
}

//-----------------------------------------------------------------------------
/* PORT設定 */
void port_init(void){
    DDRB = 0x0F;
    PORTB= 0x00;

    DDRD = 0xF2;
    PORTD= 0x00;
}

//-----------------------------------------------------------------------------
// 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
}

//-----------------------------------------------------------------------------
// main
int main(void){

unsigned int ad,ad1,ad2,ad3;
unsigned char spd,spdmax;

#define reiji12
#ifdef reiji12
    //1励磁パターン
    pat[0] = 0x08;
    pat[1] = 0x04;
    pat[2] = 0x02;
    pat[3] = 0x01;
    pat[4] = 0x08;
    pat[5] = 0x04;
    pat[6] = 0x02;
    pat[7] = 0x01;
#endif

#ifdef reiji2
    //2相励磁パターン
    pat[0] = 0x03;
    pat[1] = 0x06;
    pat[2] = 0x0c;
    pat[3] = 0x09;
    pat[4] = 0x03;
    pat[5] = 0x06;
    pat[6] = 0x0c;
    pat[7] = 0x09;
#endif

#ifdef reiji12
    //1−2相励磁パターン
    pat[0] = 0x01;
    pat[1] = 0x03;
    pat[2] = 0x02;
    pat[3] = 0x06;
    pat[4] = 0x04;
    pat[5] = 0x0c;
    pat[6] = 0x08;
    pat[7] = 0x09;
#endif

unsigned char tim_tbl[]={100,106,111,116,111,115,118,121,124,127, //10 速度テーブル
                         130,133,136,139,142,144,146,148,150,152, //20
                         154,156,158,160,162,164,166,168,170,172, //30
                         174,176,178,180,182,184,185,186,187,188, //40
                         189,190,191,192,193,194,195,196,197,198, //50
                         199,200,201,202,203,203,204,204,205,205, //60
                         206,206,207,207,208,208,209,209,210,210, //70
                         211,211,211,212,212,212,213,213,214,214, //80
                         215,215,215,216,216,216,217,217,217,217, //90
                         218,218,218,219,219,219,220,220,220,220, //100

                         221,221,221,221,221,222,222,222,222,222, //110
                         223,223,223,223,223,224,224,234,234,234, //120
                         225,225,225,225,225,226,226,226,226,226, //130
                         227,227,227,227,227,228,228,228,228,228, //140
                         229,229,229,229,229,230,230,230,230,230, //150
                         231,231,231,231,231,232,232,232,232,232, //160
                         233,233,233,233,233,234,234,234,234,234, //170
                         235,235,235,235,235,236,236,236,236,236, //180
                         237,237,237,237,237,238,238,238,238,238, //190
                         239,239,239,239,239,239,239,239,239,239, //200

                         240,240,240,240,240,240,240,240,240,240, //210
                         241,241,241,241,241,241,241,241,241,241, //220
                         242,242,242,242,242,242,242,242,242,242, //230
                         243,243,243,243,243,243,243,243,243,243, //240
                         244,244,244,244,244,244,244,244,244,244, //250

                         245,245,245,245,245}; //255
                        

    port_init();                // PORT設定
    init_Timer0();              // Initialize Timer/Counter0
    //init_Timer1();            // Initialize Timer/Counter1
    adc_init();
    sei();                      // 全割り込み許可

    Xcount=0;
    Xcw=0;
    spd=0;
    spdmax=245;

    for(;;){

        ad1 = adc_convert(0);           // AD変換
        delay_us(1000);                 // 遅延タイマー
        ad2 = adc_convert(0);           // AD変換
        delay_us(1000);                 // 遅延タイマー
        ad3 = adc_convert(0);           // AD変換
        ad=(ad1+ad2+ad3)/3;
    
        if((500<=ad)&&(ad<=523)){       //停止
            PORTB=0x00;                 //モーター励磁OFF
            Xcount=0;
            goto LE;
        }

        if(ad<5){                       //逆転高速
            Xcw = 1;                    //回転方向
            Set_Timer0(spdmax);         //速度
            Xcount=400;                 //移動パルス数 ダミー
            goto LE;
        }

        if(1018<ad){                    //正転高速
            Xcw = 0;
            Set_Timer0(spdmax);
            Xcount=400;
            goto LE;
        }

        if(ad<500){                     //逆転可変
            Xcw = 1;                    //回転方向
            spd=tim_tbl[250-ad/2];      //速度AD変換値より計算
            Set_Timer0(spd);            //速度設定
            Xcount=400;                 //移動パルス数 ダミー
            goto LE;
        }

        if(523<ad){                     //正転可変
            Xcw = 0;
            spd=tim_tbl[(ad-523)/2];
            Set_Timer0(spd);
            Xcount=400;
            goto LE;
        }

LE:
        if((Xcount!=0)||(Ycount!=0)){   // Timer0 ON
            sbi(TIMSK0,TOIE0);          // タイマー0割り込み許可
        }
        delay_us(100000);               // 遅延タイマー

    }
}

//end ----------------------------------------------------------------------------