/***** 赤外線リモコン用LED 周波数スキャンテスト *****/ // 赤外線リモコンで使われている変調周波数を可変して // リモコン受信部の応答を確認する。 // 38KHzが標準。 33kHz~40kHzのものが使われる。 // 22kHz~54kHz(32kHz間)を200Hzステップで0.8秒かけてスキャン // タイマー0 : 1ms割り込み // タイマー1 : 38kHzパルス発生(duty 1/3) // タイマー2 : 周波数スキャンPWM出力 // PB0 in 赤外線センサー入力(H/L入力) // PB1 out OC1A LED駆動出力 // PB2 out センサー入力状態(H/L)を出力 // PB3 out OC2A PWM出力(8bit) /***** タイトル *****/ const char pgm_ttl1[] PROGMEM = "\r\n#IR_FRQ_SCAN1.ino (2022-07-22)\r\n"; // 周波数変化範囲 #define FRQ_LO 220 // 開始周波数 100Hz単位で22.0kHz #define FRQ_HI 540 // スキャン終了周波数 54.0kHz /***** マクロ *****/ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) // 配列のデータ数を返す // 赤外線センサー入力 on,offチェック(Hで1) #define INP_SENS (PINB & (1 << PB0)) // PB0 #define PB2_H (PORTB |= (1 << PB2)) // PB2 #define PB2_L (PORTB &= ~(1 << PB2)) // INP_SENSを反映 // テスト用ポートH/L制御出力 #define PD4_H (PORTD |= (1 << PD4)) // PD4 #define PD4_L (PORTD &= ~(1 << PD4)) #define PD5_H (PORTD |= (1 << PD5)) // PD4 #define PD5_L (PORTD &= ~(1 << PD5)) #define PD7_H (PORTD |= (1 << PD7)) // PD7 #define PD7_L (PORTD &= ~(1 << PD7)) /***** データ *****/ byte f_frqset; // 周波数設定フラグ // 1:タイマー1割り込み内でPWM値をセット // してLEDをオン // 2:8サイクル後にLED出力停止 // 停止の直前にセンサー入力状態を確認 word led_frq; // LED駆動周波数 100Hz単位の値 // 200~500 : 20.0k~50.0kHz word led_div; // LED駆動 分周比 ICR1に設定 word led_duty; // 駆動デューティ PWM設定値 OCR1Aに設定 // センサー状態 byte f_sensok; // センサー状態確定フラグ byte f_senshl; // センサー入力 H/L状態 // LED駆動オフの時に設定 /***************************/ /* タイマー処理 */ /***************************/ // タイマーデータ volatile byte f_5ms; // 5msフラグ 開始タイミング volatile byte tm_10ms; // 10msダウンカウントタイマー /***** タイマー0 : 1ms割り込み *****/ // 5ms,10msを計時 ISR(TIMER0_COMPA_vect) { static byte cnt_5 = 0; // 5msカウント static byte cnt_10 = 0; // 10msカウント PD5_H; // (!!!) cnt_5++; // 5ms if(cnt_5 >= 5){ cnt_5 = 0; f_5ms = 1; // 5ms経過 } cnt_10++; // 10ms if(cnt_10 >= 10){ cnt_10 = 0; if(tm_10ms) tm_10ms--; // ダウンカウント } PD5_L; // (!!!) } /***** 10ms待ち *****/ // n=255で2.55秒 n=100で1秒 void wait10ms(byte n) { tm_10ms = n; // タイマーセット while(tm_10ms); } /***** タイマー1 : LED駆動タイミング *****/ // led_frqにより割り込み周期は変化 // f_frqsetが1なら駆動周波数を設定してLEDをon // 8サイクル出力後にLEDをoff // ICR,OCRは-1した値をセット // offタイミングでセンサー入力をチェック ISR(TIMER1_OVF_vect) { static byte cyc = 0; // LEDonサイクル PD7_H; // (!!!) switch(f_frqset){ // 実行区分 case 1: // PWM 設定指令 ICR1 = led_div - 1; // LED周波数分周比 OCR1A = led_duty - 1; // LED駆動デューティ 1/3 cyc = 8; // 8サイクルだけLEDをon f_frqset = 2; break; case 2: // サイクル数をチェックしてオフに if(cyc) cyc--; if(cyc == 0){ // ダウンカウントしてゼロになった if(INP_SENS){ // センサー入力 H/L ? PB2_H; // PB2で保持 f_senshl = 1; } else{ PB2_L; f_senshl = 0; } OCR1A = 0xFFFF; // LED駆動オフに f_sensok = 1; // センサー状態確定 f_frqset = 0; // 次の起動設定を待つ } break; } PD7_L; // (!!!) } /******************************/ /* シリアル出力 */ /******************************/ char tx_bff[40]; // 40文字のバッファ /***** 書式付液晶表示 *****/ void txprintf(const char *s, ...) { va_list vp; va_start(vp,s); vsnprintf(tx_bff, sizeof tx_bff, s, vp); Serial.print(tx_bff); va_end(vp); } /***** 書式付液晶表示 *****/ // PSTR("%d")で書式指定 void txprintf_P(const char *s, ...) { va_list vp; va_start(vp, s); vsnprintf_P(tx_bff, sizeof tx_bff, s, vp); Serial.print(tx_bff); va_end(vp); } /***** メッセージ出力 *****/ void txputs_P(PGM_P s) { strcpy_P(tx_bff, s); Serial.print(tx_bff); } /***************************/ /* SETUP */ /***************************/ /***** SET UP *****/ void setup() { cli(); // 割込禁止 // I/Oイニシャル PORTB = 0b00000001; // data/pull up DDRB = 0b00111110; // port指定 // |||||+---- PB0 IO8 in 赤外線センサー入力 // ||||+----- PB1 IO9 out OC1A // |||+------ PB2 IO10 out // ||+------- PB3 IO11 out OC2A // |+-------- PB4 IO12 out // +--------- PB5 IO13 out PORTC = 0b00000000; // data/pull up DDRC = 0b00111111; // port指定 // |||||+---- PC0 AD0 out // ||||+----- PC1 AD1 out // |||+------ PC2 AD2 out // ||+------- PC3 AD3 out // |+-------- PC4 AD4 out // +--------- PC5 AD5 out PORTD = 0b00000011; // data/pull up DDRD = 0b11111110; // port指定 // |||||||+---- PD0 IO0 in RXD // ||||||+----- PD1 IO1 out TXD // |||||+------ PD2 IO2 out // ||||+------- PD3 IO3 out // |||+-------- PD4 IO4 out (!!!) // ||+--------- PD5 IO5 out (!!!) // |+---------- PD6 IO6 out OC0A 500Hz出力 // +----------- PD7 IO7 out (!!!) // タイマー0 (システムで使っている) // OC0Aによるコンペアマッチに変更 TIMSK0 = 0b00000000; // 割り込み許可レジスタ // ||+--- TOIE0  全部禁止に // |+---- OCIE0A // +----- OCIE0B TCCR0A = 0b01000010; // |||| ++---- WGM01,00 OCR0A コンペアマッチ // ||++-------- COM0B // ++---------- COM0A PD6トグル出力 TCCR0B = 0b00000011; // |+++--- CLK/64 = 16Hz / 64 = 250kHz 4us // +------ WGM02 OCR0A = 250 - 1; // 1/250 = 1kHz TIMSK0 = 0b00000010; // 割り込み // ||+--- TOIE0 // |+---- OCIE0A 割込on // +----- OCIE0B // タイマー1 PWM出力 (OC1A:PB1) // 38kHz LED駆動出力 TCCR1A = 0b11000010; // |||| ++---- PWM ICR1 モード // ||++-------- COM1B Port PB2 // ++---------- COM1A PWM Negモード PB1 TCCR1B = 0b00011001; // || ||+++---- クロックセレクト 16MHz(分周なし) // || ++------- PWM ICR1 モード // |+---------- ICES1 // +----------- ICNC1 ICR1 = (16000 / 38) - 1; // 仮に38kHz OCR1A = 0xFFFF; // PWM off TIMSK1 = 0b00000001; // 割り込み // | ||+--- TOIE1 割込on // | |+---- OCIE1A // | +----- OCIE1B // +-------- ICIE1 // タイマー2,PWMでD/A出力 (1.95kHz) TCCR2A = 0b11000011; // |||| ++--- WGM1,0 8bit PWM // ||++------- COM2B Port PD3 // ++--------- COM2A 反転PWM出力 PB3 TCCR2B = 0b00000011; // |+++--- CS 2,1,0 16MHz/32 500kHz // +------ WGM2 OCR2A = 0xFF; // 反転出力なのでL連続 sei(); // 割込許可 // シリアル Serial.begin(115200); // 115.2kBPSで } /**********************************/ /*  LOOP */ /**********************************/ /***** LOOP *****/ void loop() { word a, b; char c; txputs_P(pgm_ttl1); // タイトル出力 wait10ms(100); // 1秒待ち f_5ms = 0; // 5msフラグをクリアして次を待つ led_frq = FRQ_LO; // スキャン開始周波数 22.0kHz // 5msサイクルloop while(1){ if(f_5ms){ // 5ms経過 f_5ms = 0; // LED PWM周波数とデューティ PD4_H; // (!!!) a = (word)(160000L / (long)led_frq); // 分周比 b = (2 * a) / 3; // デューティ 1/3で cli(); // いったん割り込み禁止にして led_div = a; // LED駆動周分周比 led_duty = b; // デューティ比 f_frqset = 1; // 設定on タイマー1割り込みで処理 sei(); // 割込再開 // 周波数スキャン D/A PWM出力 220~540を0~320にして1/2 OCR2A = 255 - ((led_frq - FRQ_LO) / 2); // PWM 0~ PD4_L; // (!!!) } // LED駆動終了 周波数とセンサーH/Lを出力 if(f_sensok){ // LED駆動終了 f_sensok = 0; if(f_senshl) c = '1'; // センサー入力 else c = '0'; // H:1 L:0 txprintf_P(PSTR("%2d.%1dkHz %c 1/%-4d\r\n"), // 周波数出力 led_frq / 10, led_frq % 10, c, led_div); // 周波数 +0.2kHz led_frq += 2; // 0.2kHz up if(led_frq > FRQ_HI){ // 54kHzになったら led_frq = FRQ_LO; // 22kHzに戻す Serial.println(); // 2行改行 Serial.println(); } } } } /*===== end of "IR_FRQ_SCAN1.ino" =====*/