/******************************************/ /* ハンダゴテ制御用トライアックのテスト */ /******************************************/ //===== ポートの使用状況 ===== // PB0 out loopでトグル // PB1 OC1A out A/D入力タイミング // PB2 OC1B out // PB3 OC2A out // PB4 out // PB5 (LED) out 1msでトグル // PD2 INT0 in AC100V↑↓ゼロクロス入力, H/Lチェック // PD3 INT1 out // PD4 out ゼロクロス入力確認出力 // PD5 out // PD6 out // PD7 out トリガ出力 H/L // PC0 ADC0 in VR1 A/D ch0入力 // PC1 ADC1 in VR2 A/D ch1入力 // PC2 ADC2 in VR3 A/D ch2入力 // PC3 ADC3 in VR4 A/D ch3入力 // PC4 in - // PC5 in - /***** マクロ *****/ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) // 配列のデータ数を返す // ポートH/L制御出力 #define LED_ON (PORTB |= (1 << PB5)) // PB5:LEDポート #define LED_OFF (PORTB &= ~(1 << PB5)) #define LED_TGL (PINB |= (1 << PB5)) // (トグル) // トリガ出力 #define TRG_H (PORTD |= (1 << PD7)) // PD7 トリガ出力 #define TRG_L (PORTD &= ~(1 << PD7)) #define CHG_TRG (PORTD & (1 << PD7)) // H/Lチェック #define TRG_OUT (DDRD |= (1 << PD7)) // 出力に #define TRG_INP (DDRD &= ~(1 << PD7)) // 入力にしてHi-impに // INT0パルス入力 #define CHK_PLS0 (EIFR & (1 << INTF0)) // INT0↓↑パルスチェック #define CLR_PLS0 (EIFR |= (1 << INTF0)) // 入力クリア #define INP_PLS0 ((PIND) & (1 << PD2)) // PD2 INT0入力 H/L // 1msタイマーチェック (OCR0A) #define CHK_TM0 (TIFR0 & (1 << OCF0A)) // OCR0Aチェック #define CLR_TM0 (TIFR0 |= (1 << OCF0A)) // OCR0Aクリア // A/D処理 #define CHK_ADIF (ADCSRA & (1 << ADIF)) // ADIFチェック #define CLR_ADIF (ADCSRA |= (1 << ADIF)) // ADIFクリア #define START_AD (ADCSRA |= (1 << ADSC)) // A/Dスタート // テストパルス #define PD4_H (PORTD |= (1 << PD4)) // PD4 AC100V H/L確認 #define PD4_L (PORTD &= ~(1 << PD4)) #define PB0_H (PORTB |= (1 << PB0)) // PB0 #define PB0_L (PORTB &= ~(1 << PB0)) #define PB0_X (PINB |= (1 << PB0)) // (トグル) #define PB1_L (PORTB &= ~(1 << PB1)) // PB1 #define PB1_H (PORTB |= (1 << PB1)) #define PB2_H (PORTB |= (1 << PB2)) // PB2 #define PB2_L (PORTB &= ~(1 << PB2)) #define PB3_H (PORTB |= (1 << PB3)) // PB3 #define PB3_L (PORTB &= ~(1 << PB3)) #define PB4_H (PORTB |= (1 << PB4)) // PB4 #define PB4_L (PORTB &= ~(1 << PB4)) /***** シリアル出力データ *****/ char tx_bff[64]; // sprintf用バッファ /***** タイマー1制御 *****/ #define CHK_OVF1 (TIFR1 & (1 << TOV1)) // TM1オーバーフローチェック #define CLR_OVF1 (TIFR1 |= (1 << TOV1)) // TM1オーバーフロークリア #define STOP_TM1 (TCCR1B = 0b00000000) // TM1停止 #define RUN_TM1 (TCCR1B = 0b00000010) // TM1カウント開始(2MHz) // +++--- CS2,1,0 : 1/8 0.5us /***** 1usタイマーセット *****/ // 1us単位でタイマーをセット max 32767us // 0.5usクロックなのでtを2倍してセット // タイムアップはOVF1をチェック // setupで標準モードにWGMを初期化 void settm1(word us) { long d; STOP_TM1; // タイマー1停止 CLR_OVF1; // オーバーフローフラグをクリア if(us < 2) us = 2; // 最小が2usに if(us >= 32768){ // 32768usがmax d = 0; // 0で65536カウント } else{ // 0~32767 d = 65536L - (2 * (long)us); } TCNT1 = (word)d; // 0.5us単位 RUN_TM1; // タイマー計時開始 } /*****************************/ /* A/D入力処理 */ /*****************************/ /***** A/Dデータ *****/ // A/D ch0~3:VR1~VR4 volatile word ad_avr[4]; // AD0~3 VR1~VR4がつながる // 平均値 0~1023 // 平均計算 volatile word ad_add[4]; // 平均用加算値 (wordに入る) // 64回加算 1023*64 = 65472 volatile byte ad_ch; // A/D変換チャンネル 0,1,2,3 volatile byte ad_cnt; // A/D変換平均回数 (64回) volatile byte f_adok; // 平均値確定フラグ // 256msごとに確定 // マルチプレックスデータ const byte PROGMEM ad_mpx[] = { // MPX指定 0b01000000, // 0 A/D ch0 0b01000001, // 1 ch1 0b01000010, // 2 ch2 0b01000011, // 3 ch3 // ||| ++++------- ADC MPX // ||+------------ ADLAR // ++------------- AVCC接続 }; /***** A/D入力処理 *****/ // タイマーでA/D変換開始 // 64回平均*4chで256msでデータが確定 // 1023*64=65472で16bitに入る // ADIFをチェックして読み出し処理 void adread(void) { word d; ad_add[ad_ch] += ADC; // 平均用に加算 // 平均処理 1chごとに処理 if(ad_cnt == 63){ // 63回目? d = ad_add[ad_ch] / 64; // 平均値 10bit ad_avr[ad_ch] = d; ad_add[ad_ch] = 0; // 次加算データクリア } // 次ch ad_ch++; // 次ch if(ad_ch >= 4){ // 4ch終了 ad_ch = 0; // ch0に戻す ad_cnt++; // 平均加算回数 if(ad_cnt >= 64){ // 64回? ad_cnt = 0; f_adok = 1; // A/Dデータ確定 } } ADMUX = pgm_read_byte(&ad_mpx[ad_ch]); // MPX ch } /***** SETUP *****/ void setup() { cli(); // 割込禁止 // I/Oイニシャル PORTB = 0b00100000; // data/pull up DDRB = 0b00111111; // port指定 // |||||+---- PB0 IO8 out // ||||+----- PB1 IO9 out // |||+------ PB2 IO10 out // ||+------- PB3 IO11 out // |+-------- PB4 IO12 out // +--------- PB5 IO13 out LED(Hでon) PORTC = 0b00110000; // data/pull up DDRC = 0b00000000; // port指定 // |||||+---- PC0 AD0 in A/D入力 // ||||+----- PC1 AD1 in A/D入力 // |||+------ PC2 AD2 in A/D入力 // ||+------- PC3 AD3 in A/D入力 // |+-------- PC4 AD4 in (pull up) // +--------- PC5 AD5 in (pull up) PORTD = 0b00000011; // data/pull up DDRD = 0b11111010; // port指定 // |||||||+---- PD0 IO0 in RXD // ||||||+----- PD1 IO1 out TXD // |||||+------ PD2 IO2 in INT0 ACゼロクロス入力 // ||||+------- PD3 IO3 out // |||+-------- PD4 IO4 out INT0確認 // ||+--------- PD5 IO5 out // |+---------- PD6 IO6 out // +----------- PD7 IO7 out トリガ出力(Hi-imp) // A/D入力 DIDR0 = 0b00001111; // AD デジタル入力禁止 ADMUX = 0b11000000; // 内蔵A/D // ||| ++++----- ADC0 MPX ch0 入力 // ||+---------- ADLAR 右詰めで // ++----------- REFS 内蔵1.1Vで (外部出力) ADCSRA = 0b10000111; // |||||+++---- プリスケーラ 1/128 125kHz // ||||+------- ADIE 割込なし // |||+-------- ADIF // ||+--------- ADATE // |+---------- ADSC // +----------- ADEN A/D変換有効に // タイマー0オーバーフロー割り込み停止(システムのタイマーは使わない) // OCR0Aで1msタイマー計時 TCCR0B = 0b00000000; // タイマー0停止 TIMSK0 = 0b00000000; // 割り込み無しに // ||+---- TOIE0 オーバーフロー割り込みなし // |+----- OCIE0A OCR0A割り込みなし // +------ OCIE0B OCR0B割り込みなし TCCR0A = 0b00000010; // |||| ++---- WGM1,0 CTC // ||++-------- COM0B // ++---------- COM0B TCCR0B = 0b00000011; // || |+++---- CS 1/64 250kHzクロック // || +------- WGM2 CTC // ++---------- FOC2 OCR0A = 250 - 1; // 1kHz // タイマー1 標準動作に TCCR1A = 0b00000000; // WGM = 0 TCCR1B = 0b00000000; // CS=0 TM1停止 // INT0パルス入力 EICRA = 0b00001001; // 外部割り込み // ||++---- ISC0 INT0 ↑↓両エッジ // ++------ ISC1 INT1 ↓エッジ EIMSK = 0b00000000; // |+---- INT0 割り込み未使用 // +----- INT1 割り込み未使用 sei(); // 割込許可 // シリアル Serial.begin(9600); // 9600BPSで } /***** 実行 *****/ byte f_trig; // トリガフラグ // ゼロクロス点でオン byte f_trgon; // トリガフラグonフラグ byte trg_cnt; // トリガー回数カウンタ byte ad_stbl; // A/D安定待ちカウンタ // 実行区分 volatile byte exc_j; // 実行区分 // 「void (*exc_tbl[])(void)」で実行 // ※volatileを付けておかないと最適化で // 処理が飛ばされることがあった // タイマーデータ volatile word tm_1ms; // 1msダウンカウントタイマー // 割り込みでの処理じゃないので // いつでも読み書きOK /***** A/D安定待ち *****/ void jadstbl(void) { ad_stbl = 4; // 4回平均待ち f_adok = 0; exc_j++; // next exc } /***** A/D安定待ち #1 *****/ void jadstbl1(void) { if(f_adok){ // A/D変換完了 f_adok = 0; ad_stbl--; // 安定回数 if(ad_stbl == 0){ exc_j++; // next exc } } } /***** ゼロクロスチェック *****/ // f_trigをクリアして次入力を待つ void jzerox(void) { f_trig = 0; trg_cnt = 0; // トリガ回数VR3 1~4 exc_j++; } /***** ゼロクロスチェック *****/ // 正弦波 プラス側を確認 // トリガ出力待ちタイマー(VR1)をセット void jzerox1(void) { if(f_trig){ // ゼロクロス f_trig = 0; if(INP_PLS0){ // AC100V プラス側の確認 settm1(6 * ad_avr[0]); // タイマーVR1セット max 6ms exc_j++; // next exc } } } /***** トリガ出力 *****/ // タイムアアップで出力on void jtrig(void) { if(CHK_OVF1){ // タイムアップ? TRG_H; // トリガー出力on exc_j++; // next exc } } /***** トリガ出力 *****/ // 次のゼロクロス点(AC100Vマイナス側)でタイマーセット void jtrig1(void) { if(f_trig){ // ゼロクロス f_trig = 0; settm1(6 * ad_avr[0]); // タイマーVR1セット max 6ms exc_j++; // next exc } } /***** トリガ出力 *****/ // タイムアアップで出力off // 回数チェック(1~8)して繰り返す void jtrig2(void) { if(CHK_OVF1){ // タイムアップ? TRG_L; // トリガー出力off trg_cnt++; // 回数(VR3) +1 if(trg_cnt > ad_avr[2] / 128){ // トリガ回数VR3(0~7) if((ad_avr[3] / 32) == 0){ // 休止設定(VR4)ゼロ? exc_j -= 4; // jzeroxへ } else{ trg_cnt = 0; exc_j++; // next exc } } else{ exc_j -= 3; // jzerox1へ } } } /***** オフ時間 *****/ // ゼロクロス点回数待ち void joffcnt(void) { if(f_trig){ // ゼロクロス f_trig = 0; trg_cnt++; // 休止回数(VR4) +1 if(trg_cnt > ad_avr[3] / 32){ // 休止回数VR4(0~31) exc_j -= 5; // 次トリガ jzeroexへ } } } /***** 実行テーブル *****/ void (*exc_tbl[])(void)={ jadstbl, // 0 jadstbl1, // 1 jzerox, // 2 jzerox1, // 3 jtrig, // 4 jtrig1, // 5 jtrig2, // 6 joffcnt, // 7 }; /*******************************/ /* ループ */ /*******************************/ /***** LOOP *****/ void loop() { Serial.println("Test TRIAC 2024-01-05"); tm_1ms = 1000; // 1秒セット while(1){ PB0_X; // (!!!) // 1msチェック if(CHK_TM0){ // 1ms経過 CLR_TM0; // TIFR0フラグをクリア START_AD; // A/D変換開始 LED_TGL; // LEDポートをトグル if(tm_1ms) tm_1ms--; // 1msダウンカウントタイマー } // AC100V ゼロクロス入力をチェック if(CHK_PLS0){ CLR_PLS0; if(INP_PLS0) PD4_H; // AC100V H/Lをチェック else PD4_L; f_trig = 1; // トリガフラグをon } // A/D入力 if(CHK_ADIF){ CLR_ADIF; PB1_H; // (!!!) adread(); // A/D値読み出し PB1_L; // (!!!) } // 処理実行 exc_tbl[exc_j](); // テーブルで実行 // A/D値確認 if(tm_1ms == 0){ tm_1ms = 1000; // 1秒セット sprintf(tx_bff, "VR1:%uus", 6 * ad_avr[0]); // トリガディレーVR1 max 6ms Serial.println(tx_bff); } #if 0 if(f_adok){ f_adok = 0; sprintf(tx_bff, "%5d%5d%5d%5d", ad_avr[0], ad_avr[1], ad_avr[2], ad_avr[3]); Serial.println(tx_bff); } #endif } }