/*****************************************/ /* ワンショットパルス出力のテスト */ /*****************************************/ // 16bitのタイマー1を使って // PB1 15pin OC1A 出力で // タイマー1 フラグ処理 #define CLR_OCF1A (TIFR1 = (1 << OCF1A)) // OCF1Aクリア #define SET_FOC1A (TCCR1C = (1 << FOC1A)) // FOC1Aフラグをセット // OC1Aを直接H/L制御 #define CLR_PSR (GTCCR = (1 << PSRSYNC)) // プリスケーラをリセット // タイマー0のもリセットされる // ポート出力 H/L #define PB0_H (PORTB |= (1 << PB0)) // 14pin #define PB0_L (PORTB &= ~(1 << PB0)) #define PB1_H (PORTB |= (1 << PB1)) // 15pin OC1A #define PB1_L (PORTB &= ~(1 << PB1)) #define PB2_H (PORTB |= (1 << PB2)) // 16pin OC1B #define PB2_L (PORTB &= ~(1 << PB2)) #define PB3_H (PORTB |= (1 << PB3)) // 17pin #define PB3_L (PORTB &= ~(1 << PB3)) /***** タイトルと日付 *****/ const char prg_titl[] PROGMEM = "# 1shot pulse test (2021-12-02)"; // タイトル /******************************/ /* 書式付シリアル出力 */ /******************************/ // クラスPrintへのポインタ Print *Cp; // クラスPrintへの関数ポインタ // Cp = &Serial; や &LCDなど /***** Printクラスへの書式付シリアル出力 *****/ // PSTR("")で書式を指定 void CpPrintf_P(const char *s, ...) { va_list vp; char bff[64]; // バッファを確保 va_start(vp, s); vsnprintf_P(bff, sizeof(bff), s, vp); // PSTRで書式を指定 Cp->print(bff); // cpへ出力 va_end(vp); } /***** 文字出力 *****/ void CpPuts_P(const char *s) { char c; while(1){ c = pgm_read_byte(s); if(c == '\x0') break; Cp->write(c); s++; } } /******************************/ /* シリアル入力 */ /******************************/ /***** シリアル1行入力 *****/ #define RXBF_SIZ 20 // 文字バッファ文字数 char rx_bff[RXBF_SIZ+1]; // 受信文字バッファ (+null) byte f_rxok; // 受信データありフラグ /***** シリアル1行受信 *****/ // CRでターミネート f_rxokを1に void rxbff(void) { static byte cnt = 0; // 受信文字数 char c; if(Serial.available()){ // 受信データあり if(f_rxok == 0){ // 前データ受信処理した c = Serial.read(); // 1文字読み出し if(c == '\r'){ // CR? rx_bff[cnt] = '\0'; // nullを最後に // Serial.println(); // 改行 f_rxok = 1; // 受信成功 cnt = 0; // 最初から } else if(c == '\x08'){ // BS? if(cnt > 0){ cnt--; // 1文字戻す Serial.print("\b \b"); // BS,space,BS } } else{ // 文字 if((cnt < RXBF_SIZ) && // バッファサイズ内 (isprint(c))){ // 表示可能文字0x20~0x7E // Serial.write(c); // エコーバック rx_bff[cnt] = c; // バッファに入れる cnt++; // 1文字進める } } } } } /***************************/ /* ワンショット */ /***************************/ // ワンショット実行中 volatile byte f_oneshot; // 実行中1に // 完了(ICF1割り込み)で0に /***** ワンショット出力 *****/ // OC1AにHパルスを出力 // in us単位のパルス幅  max4.096秒 // 4000us   0.0625usクロック *16 // 32ms   0.5usクロック *2 // 256ms   4usクロック 1/4 // 1024ms  16usクロック 1/16 // 4096ms 64usクロック 1/64 void oneshot(uint32_t d) { word a; // OCR1A設定値 byte b; // TCCR1B設定値 TIMSK1 = 0b00000000; // タイマー1割り込みなしに TCCR1B = 0b00000000; // プリスケーラ停止 // ||+++----- CS プリスケーラ // ++-------- WGM 標準動作 TCCR1A = 0b10000000; // OC1A L出力 // |||| ++---- WGM // ||++-------- COM1B // ++---------- COM1A L出力 SET_FOC1A; // FOC1Aフラグをセットして直出力 // 0なら即停止 if(d == 0){ f_oneshot = 0; // ワンショット終了 return; } // max規制 if(d > 4096000) d = 4096000; // max 4.096sec // パルス幅でOCR1Aへの設定を変える if(d <= 4000){ // ~4000us a = 16 * d; // 16~64000に a -= 5; // 遅れ補正 b = 0b00000001; // カウンタ制御設定 // ||+++---- CS プリスケーラ 1/1 16MHz 62.5ns // ++------- WGM 標準動作 } else if(d <= 32000){ // ~32ms a = 2 * d; b = 0b00000010; // 1/8 2MHz 0.5us } else if(d <= 256000){ // ~256ms a = d / 4; b = 0b00000011; // 1/64 250kHz 4us } else if(d <= 1024000){ // ~1.024s a = d / 16; b = 0b00000100; // 1/256 62.5kHz 16us } else{ // ~4.096s a = d / 64; b = 0b00000101; // 1/1024 15.625kHz 64us } f_oneshot = 1; // ワンショット実行フラグ cli(); // 割込禁止 CLR_OCF1A; // OCF1Aクリア TIMSK1 = 0b00000010; // タイマー1割り込み // | ||+---- TOIE1 // | |+----- OCIE1A COMP-A有効 // | +------ OCIE1B // +--------- ICIE1 if(a < 2) a = 2; // 0と1は2に 1の出力は出せない OCR1A = a - 1; // パルス幅設定 (-1して1~65534) TCNT1 = 0; // ゼロスタート TCCR1A = 0b11000000; // OC1A H出力 SET_FOC1A; // FOC1Aフラグをセットして直出力 TCCR1A = 0b10000000; // コンペアマッチでOC1A L出力 CLR_PSR; // プリスケーラをリセット TCCR1B = b; // プリスケーラ+WGM設定でカウント開始 sei(); // 割込許可 } /***** タイマー1 OCF1A 割り込み *****/ // 出力を止めるためカウントを停止 ISR(TIMER1_COMPA_vect) { PB2_H; // (!!!) TCCR1B = 0b00000000; // || ||+++---- CS プリスケーラ停止 // || ++------- WGM // |+---------- ICES1 // +----------- ICNC1 TIMSK1 = 0b00000000; // タイマー1割り込みなしに // | ||+---- TOIE1 // | |+----- OCIE1A // | +------ OCIE1B // +--------- ICIE1 TCCR1A = 0b10000000; // OC1A L出力 // |||| ++---- WGM // ||++-------- COM1B // ++---------- COM1A L出力 SET_FOC1A; // FOC1Aフラグをセットして直出力 f_oneshot = 0; // ワンショット終了 PB2_L; // (!!!) } /***************************/ /* SETUP */ /***************************/ /***** SET UP *****/ void setup() { cli(); // 割込禁止 // I/Oイニシャル PORTB = 0b00000000; // data/pull up DDRB = 0b00111111; // port指定 // |||||+---- PB0 IO8 out 確認用パルス出力 // ||||+----- PB1 IO9 out OC1A // |||+------ PB2 IO10 out OC1B // ||+------- PB3 IO11 out // |+-------- PB4 IO12 out // +--------- PB5 IO13 out (LED) 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 = 0b00000010; // port指定 // |||||||+---- PD0 IO0 in RXD // ||||||+----- PD1 IO1 out TXD // |||||+------ PD2 IO2 out // ||||+------- PD3 IO3 out // |||+-------- PD4 IO4 out // ||+--------- PD5 IO5 out // |+---------- PD6 IO6 out // +----------- PD7 IO7 out sei(); // 割込許可 // シリアル,I2C Serial.begin(9600); // 9600BPSで } /**********************************/ /* LOOP */ /**********************************/ /***** LOOP *****/ void loop() { uint32_t a; // 入力long値 byte f_prnpt = 1; // プロンプト出力フラグ Cp = &Serial; // シリアル出力に CpPuts_P(prg_titl); // タイトル Cp->println(); // 改行 delay(100); // 100ms // 繰り返し while(1){ if(f_prnpt){ // プロンプト出力 Cp->print(F("us>")); f_prnpt = 0; } rxbff(); // 1行受信処理 if(f_rxok){ // CR入力あり f_rxok = 0; a = atol(rx_bff); // 文字変換 CpPrintf_P(PSTR("%lu us\r\n"), a); PB0_H; // (!!!)トリガー確認用 oneshot(a); // ワンショット出力 PB0_L; // (!!!) f_prnpt = 1; // 次入力待ち } // if(f_oneshot) PB3_H; // else PB3_L; // while(f_oneshot); // 出力待ち // delay(10); // 10ms } }