/***** ATtiny1614で2相パルス発生 *****/ // "quad_pls01.ino" 2026-06-03 // クロック 8MHz // PA0 10pin in UPDI // PA1 11pin in DIP-SW8 // PA2 12pin out // PA3 13pin in EXTCLK TCDのクロック入力 // PA4 2pin out TCD WOA B相出力 // PA5 3pin out TCD WOB A相出力(周期決定) // PA6 4pin in SW1 RUN/STOP L:RUN // PA7 5pin in SW2 REV/FWD L:REV // PB0 9pin out TCA WO0 →EXTCLKへ // PB1 8pin in DIP-SW1 // PB2 7pin in DIP-SW2 // PB3 6pin in DIP-SW4 // /***** マクロ *****/ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) // 配列のデータ数を返す // SW入力 on,offチェック (L=onで1) #define INP_SW1 (~PORTA.IN & (1 << 6)) // PA6 RUN/STOP #define INP_SW2 (~PORTA.IN & (1 << 7)) // PA7 REV/FWD /***** TCA分周データテーブル *****/ // 周波数発生モードなので8MHzを1/2した // 4MHzを原発振周波数と考える // 2相パルスを出すTCDでさらに1/4される const struct{ const word cmp0; // TCA0 CMP0データ 1/(n-1) const byte clksel; // プリスケーラ設定値 + ENABLE(b0) // 1/1,2,4,8,16,64,256,1024 }frq_tbl[] = { { 15625, 0b00001010 }, // 0 1Hz 1/64 { 31250, 0b00001000 }, // 1 2Hz 1/16 { 12500, 0b00001000 }, // 2 5Hz 1/16 { 6250, 0b00001000 }, // 3 10Hz 1/16 { 3125, 0b00001000 }, // 4 20Hz 1/16 { 2500, 0b00000110 }, // 5 50Hz 1/8 { 1250, 0b00000110 }, // 6 100Hz 1/8 { 625, 0b00000110 }, // 7 200Hz 1/8 { 1000, 0b00000010 }, // 8 500Hz 1/2 { 500, 0b00000010 }, // 9 1kHz 1/2 { 250, 0b00000010 }, // A 2kHz 1/2 { 100, 0b00000010 }, // B 5kHz 1/2 { 100, 0b00000000 }, // C 10kHz 1/1 { 50, 0b00000000 }, // D 20kHz 1/1 { 10, 0b00000000 }, // E 100kHz 1/1 { 1, 0b00000000 }, // F 1MHz 1/1 }; // |||+--- ENABLE // +++---- プリスケーラ /***** スイッチデータ *****/ // SW1 RUN/STOP SW2 回転方向 REV/FWD byte f_sw1x; // SW1 変化フラグ byte f_sw1on; // SW1 on/offフラグ byte f_sw1in; // SW1 入力状態 byte f_sw2x; // SW2 変化フラグ byte f_sw2on; // SW2 on/offフラグ byte f_sw2in; // SW2 入力状態 /***** スイッチ入力 *****/ void inpsw1(void){ if(INP_SW1) f_sw1in = 1; else f_sw1in = 0; } void inpsw2(void){ if(INP_SW2) f_sw2in = 1; else f_sw2in = 0; } // スイッチ入力実行データ const struct{ byte *chg; // 変化フラグ byte *on; // on/offデータ byte *inp; // 入力状態 void (* inpsw)(void); // SW入力 }sw_tbl[] = { { &f_sw1x, &f_sw1on, &f_sw1in, inpsw1 }, // SW1 { &f_sw2x, &f_sw2on, &f_sw2in, inpsw2 }, // SW2 }; /***** スイッチ入力チェック *****/ void chksw(void) { byte i; // loopカウンタ static byte exc[DIMSIZ(sw_tbl)]; // 実行区分 static byte tm[DIMSIZ(sw_tbl)]; // 1msタイマ static byte chk[DIMSIZ(sw_tbl)]; // チェックデータ for(i = 0; i < DIMSIZ(sw_tbl); i++){ // loop sw_tbl[i].inpsw(); // スイッチ入力 if(tm[i]) tm[i]--; // タイマ-1 switch(exc[i]){ // 実行区分 case 0: // 変化チェック if(*sw_tbl[i].on != *sw_tbl[i].inp){ chk[i] = *sw_tbl[i].inp; // 変化した tm[i] = 10; // 10ms exc[i] = 1; // 安定チェックへ } break; case 1: // 安定チェック if(chk[i] != *sw_tbl[i].inp){ // 変化したら chk[i] = *sw_tbl[i].inp; // 新状態セット tm[i] = 10; // 10ms } else{ // 安定している if(tm[i] ==0 ){ // タイムアップで *sw_tbl[i].on = chk[i]; // on/off確定 *sw_tbl[i].chg = 1; // 新状態に変化あり exc[i] = 0; // 次の変化をチェック } } break; } } } /***** スイッチ入力で設定 *****/ // SW1 RUN/STOP STOPならTCA0クロック出力を停止 // SW2 回転方向 REV/FWD ポート反転で処理 void setsw(void) { if(f_sw1x){ // SW1:RUN/STOP変化? f_sw1x = 0; if(f_sw1on){ // on:RUN TCA0.SINGLE.CTRLA |= 0x01; // TCA0 ENABLE } else{ // off:STOP TCA0.SINGLE.CTRLA &= 0xFE; // TCA0 DISABLE } } if(f_sw2x){ // SW2:REV/FWD変化? f_sw2x = 0; if(f_sw2on){ // on:REV (PA4を反転) PORTA.PIN4CTRL = 0b10000000; // PA4 2pin 反転 } else{ // off:FWD PORTA.PIN4CTRL = 0b00000000; // PA4 2pin 通常出力に } } } /***** DSW読み込み *****/ // 0~Fを返す pull up // PORT offで1 onで0 // PB1:DSW-1 PB2:DSW-2 PB3:DSW-4 PA1:DSW-8 byte inpdsw(void) { byte n; byte d = 0; // リターンデータ n = ~PORTB.IN; // ポートB反転して入力 if(n & 0b00000010) d |= 1; // DSW-1 if(n & 0b00000100) d |= 2; // DSW-2 if(n & 0b00001000) d |= 4; // DSW-4 if(~PORTA.IN & 0b00000010) d |= 8; // DSW-8 return d; } /***** DSWデータ *****/ byte dsw_now; // 安定した現在値(0~F) byte f_dswok; // 変化確定フラグ dsw_nowに安定値 /***** DSW変化チェック *****/ // 確定したらf_dswokを1に dsw_nowが確定値 // PITの1024Hz周期で実行 void chkdsw(void) { static byte exc; // 実行区分 static byte tm; // 1msタイマ // PITの1024Hz周期でダウンカウント static byte chk; // DSW入力安定チェックデータ byte d; d = inpdsw(); // DSWデータ入力 if(tm) tm--; // DSWチェックタイマダウンカウント switch(exc){ case 0: // 変化チェック if(dsw_now != d){ // DSW変化あり chk = d; // チェックデータ tm = 20; // 20ms exc = 1; } break; case 1: if(chk != d){ // 変化続く? chk = d; // チェックデータ再セット tm = 20; // タイマも再セット 20ms } else{ // 安定 if(tm == 0){ // タイムアップ dsw_now = d; // 新DSW値 f_dswok = 1; // 確定フラグをon exc = 0; // 次の変化待ちに } } break; } } /***** 周波数設定 *****/ // d:DSW設定値 0~F // 分周値を-1してからCMP0にセット // SW1のonならENABLEに(クロック出力) void setfrq(byte d) { byte n; TCA0.SINGLE.CTRLA = 0; // TCA0 タイマー停止 TCA0.SINGLE.CMP0 = frq_tbl[d].cmp0 - 1; // 分周値(n-1) TCA0.SINGLE.CNT = 0; // カウント 0から n = frq_tbl[d].clksel; // プリスケーラ if(f_sw1on) n |= 0b00000001; // RUN/STOPでENABLE on TCA0.SINGLE.CTRLA = n; // プリスケーラ+ENABLE } /***** SETUP *****/ void setup() { cli(); // 割込禁止 // ポート PORTA.OUT = 0b00000000; PORTA.DIR = 0b00110100; // |||||||+---- PA0 10pin in UPDI // ||||||+----- PA1 11pin in DIP-SW8 // |||||+------ PA2 12pin out // ||||+------- PA3 13pin in EXTCLK // |||+-------- PA4 2pin out TCD WOA // ||+--------- PA5 3pin out TCD WOB // |+---------- PA6 4pin in SW1 RUN/STOP // +----------- PA7 5pin in SW2 REV/FWD PORTB.OUT = 0b00000000; PORTB.DIR = 0b00000001; // |||+---- PB0 9pin out TCA WO0 // ||+----- PB1 8pin in DIP-SW1 // |+------ PB2 7pin in DIP-SW2 // +------- PB3 6pin in DIP-SW4 // ポート機能 pull up,デジタル入力 PORTA.PIN1CTRL = 0b00001000; // PA1 11pin in DIP-SW8 PORTA.PIN3CTRL = 0b00001000; // PA3 13pin in EXTCLK PORTA.PIN6CTRL = 0b00001000; // PA6 4pin in SW1 RUN/STOP PORTA.PIN7CTRL = 0b00001000; // PA7 5pin in SW2 REV/FWD PORTB.PIN1CTRL = 0b00001000; // PB1 8pin in DIP-SW1 PORTB.PIN2CTRL = 0b00001000; // PB2 7pin in DIP-SW2 PORTB.PIN3CTRL = 0b00001000; // PB3 6pin in DIP-SW4 // | |+++-- デジタル入力有効,割り込みなし // | +----- pullupあり // +--------- 反転I/Oなし // タイマーTCA0, 分割モードで初期化されるので16bitモードに TCA0.SPLIT.CTRLA = 0; // タイマー停止 TCA0.SPLIT.CTRLESET = 0x0F; // 強制リセット PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに TCA0.SINGLE.CTRLB = 0b00010001; // ||||+++----- WGM 波形生成FRQ(周波数) // |||+-------- ALUPD // ||+--------- CMP0EN PB0 9pin WO0 出力 // |+---------- CMP1EN PB1 8pin WO1 出力 // +----------- CMP2EN PB2 7pin WO3 出力 // タイマーTCD 2相パルスを出力 // 周期はCMPBCLRで決まる TCD0.CTRLB = 0b00000000; // 波形制御 // ++--- WGMODE 1ランプモード TCD0.CMPBCLR = 4 - 1; // WOB L カウント最大値 TCD0.CMPBSET = 2 - 1; // WOB H カウント値 TCD0.CMPASET = 1 - 1; // WOA H カウント値 TCD0.CMPACLR = 3 - 1; // WOA L カウント値 _PROTECTED_WRITE(TCD0.FAULTCTRL, 0b00110000); // |+----- CMPAEN WOA出力 // +------ CMPBEN WOB出力 while(!(TCD0.STATUS & 1)); // ENRDY イネーブルレディを待つ TCD0.CTRLA = 0b01000001; // 制御開始 // ||||||+-- ENABLE // ||||++--- SYNC分周比 1/1 // ||++----- プリスケーラ 1/1 // ++------- EXTCLK入力(PA3) // RTC,PIT 有効に while((RTC.STATUS & 0x0F) || // RTC busy ? (RTC.PITSTATUS & 1)); // PIT busy ? RTC.PITCTRLA = 0b00100001; // PIT分周操作 // |||| +-- PITEN PIT有効 // ++++----- PERIOD 1/32 →1024Hz // RUN/STOP FWD/REV f_sw1x = 1; // SW1:RUN/STOP f_sw1on = INP_SW1; f_sw2x = 1; // SW2:FWD/REV f_sw2on = INP_SW2; // DSW(0~F)で周波数を設定 dsw_now = inpdsw(); // DSW値(0~F) setfrq(dsw_now); // 16選択で4Hz~4MHzセット sei(); // 割込有効 } /***** LOOP *****/ // 割込は未使用 // PIT(1024Hz)のタイミングでDSW,SW入力処理 void loop() { while(1){ if(RTC.PITINTFLAGS & 1){ // 1024Hz(約1ms)周期 VPORTA.IN |= (1 << 2); // PA2 12pin トグル RTC.PITINTFLAGS = 1; chkdsw(); // DSW変化チェック if(f_dswok){ // DSW変化あり f_dswok = 0; setfrq(dsw_now); // 1Hz~1MHz周波数セット } chksw(); // SW1,SW2変化チェック setsw(); // RUN/STOP, REV/FWD } } } // end of "quad_pls01.ino"