文書の表示以前のリビジョンバックリンクPDF の出力全て展開する/折り畳むODT 出力文書の先頭へ この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。 ====== 簡易電源タイマー(切り忘れ防止) ====== ===== 概要 ===== 半田ごてを使用していて、うっかり電源を切り忘れてしまい、翌日にヒヤッとしたときが、過去に幾度かあります。 そこで今回は、電源の切り忘れを防止するための“電源タイマー"を製作しみました。 <仕様> * タイマーの設定値は、1分~999分まで設定出来ます。(EEPROMに記憶) * 商用電源(100V)をSSR(ソリッドステートリレー)を使用してON/OFFさせます。 * スタートスイッチを押下すると、設定した時間だけSSRをONします。 * 動作中に、スタートスイッチを押下すると、再スタートします。 * ストップスイッチを押下するとSSRをOFFします。 * タイムアウト直前の1分間は、1秒周期でブザーを鳴らせます。 <タイミングチャート> {{:imgpaste:202004:htmikan-20200430-144350.png?500}} ===== 動作原理(ハードウェア) ===== ◎タイマー値の表示 3桁の7セグLED(カソードコモン)を簡易接続方式で使用します。 ※通常はトランジスタなどを利用して制御します) ◎商用電源(100V)のON/OFF 秋月電子で販売している、「ソリッド・ステート・リレー(SSR)キット」を使用します。 ===== 動作原理(ソフトウェア) ===== ◎メイン処理(タイマーモード) * スタートスイッチ(SW1)が、押下されると、SSRをONにし、カウント変数(count_msec)に、設定値(set_up_count)をセットします。ドットフラグ(dot_flg)をONにします。 * ストップスイッチ(SW2)が、押下されると、SSRをOFFにします。ドットフラグ(dot_flg)をOFFにします。 * カウント変数(count_msec)が、“0"になると、SSRをOFFにします。ドットフラグ(dot_flg)をOFFにします。 * タイムアウト直前の1分間は、1秒周期でブザーを鳴らせます。 ◎メイン処理(設定値変更モード) * “分"インクリメントスイッチ(SW1)が、押下されると設定値(set_up_count)を“1分"インクリメントします。 * “分"デクリメントスイッチ(SW2)が、押下されると設定値(set_up_count)を“1分"デクリメントします。 ◎メイン処理(その他) * カウント変数(count_msec)から、“分"を求め、表示データ(seg_data)に設定します。 ◎割り込み処理 * TIMER2を使用して、1msecの割り込みを発生させます。 * ダイナミック点灯処理を呼び出します。 * カウント変数(count_msec)をデクリメントします。 * ブザー用のビットをON/OFFします。 ◎ダイナミック点灯処理 * 呼び出される毎に、7セグLEDの桁を順次切り替えて、表示データ(seg_data)の値を点灯させます。 * 1桁目のドットをON/OFFします。 ===== 回路図 ===== {{:imgpaste:202004:htmikan-20200430-144501.png}} {{:imgpaste:202004:htmikan-20200430-144507.png}} ===== ソースコード ===== <code c power_supply_timer.c> //********************************************************************** /* <電源タイマー> */ //********************************************************************** //■■■マクロ定義■■■ //7SEG-SELECT #define SEG_ON 0 #define SEG_OFF 1 sbit SEG1 at PORTA.B6; sbit SEG1_Direction at TRISA.B6; #define SEG1_ON SEG1 = SEG_ON #define SEG1_OFF SEG1 = SEG_OFF sbit SEG2 at PORTA.B7; sbit SEG2_Direction at TRISA.B7; #define SEG2_ON SEG2 = SEG_ON #define SEG2_OFF SEG2 = SEG_OFF sbit SEG3 at PORTA.B0; sbit SEG3_Direction at TRISA.B0; #define SEG3_ON SEG3 = SEG_ON #define SEG3_OFF SEG3 = SEG_OFF //7SEG-DATA #define SEG_DOT_ON 1 #define SEG_DOT_OFF 0 #define SEG_DATA PORTB #define SEG_DATA_DOT PORTB.B7 #define SEG_DATA_Direction TRISB //switch sbit SW_START at PORTA.B3; sbit SW_STOP at PORTA.B4; sbit SW_UP at PORTA.B3; sbit SW_DOWN at PORTA.B4; sbit SW_MODE at PORTA.B5; //SSR #define SSR_ON 1 #define SSR_OFF 0 sbit SSR at PORTA.B2; //BUZZER sbit BUZZER_BIT at PORTA.B1; //other #define INPUT_MODE 1 #define OUTPUT_MODE 0 #define BYTE unsigned short #define WORD unsigned int #define DWORD unsigned long #define UN_LOCK 0 #define LOCK 1 //********************************************************************** //■■■関数&共有データ宣言■■■ extern void main(); extern void init_segment(); extern void init_timer(); extern void segment_disp(); extern void segment_set_data(short seg1, short seg2, short seg3); extern void interrupt(); extern void buzzer(short msec); extern DWORD count_msec; extern short dot_flg; extern BYTE buzzer_flg; //********************************************************************** //■■■メイン関数■■■ void main() { DWORD tmp, set_up_count; WORD minute; BYTE m1, m2, m3, mode, cnt, sec_new, sec_old; union { DWORD _long; BYTE _short[4]; } set_up_count_eeprom; // OSCCON = 0b01110000; //クロックを8MHzに設定します。 ANSEL = 0b00000000; //A/D変換モジュールは使用しません。 TRISA = 0b00111000; // mode = 0; SSR = SSR_OFF; count_msec = 0; dot_flg = SEG_DOT_OFF; // init_segment(); init_timer(); // カウント値を読み込む set_up_count_eeprom._short[0] = Eeprom_Read(0); set_up_count_eeprom._short[1] = Eeprom_Read(1); set_up_count_eeprom._short[2] = Eeprom_Read(2); set_up_count_eeprom._short[3] = Eeprom_Read(3); set_up_count_eeprom._long = ((set_up_count_eeprom._long < 60000) || (set_up_count_eeprom._long > 59940000)) ? 3600000 : set_up_count_eeprom._long; set_up_count = set_up_count_eeprom._long; // 割り込みを許可します。 INTCON.PEIE = 1; INTCON.GIE = 1; // for (cnt = 0; cnt < 5; cnt++) { segment_set_data(10, 10, 10); buzzer(100); segment_set_data(11, 11, 11); Delay_ms(100); } // while (1) { //タイマースタート if ((SW_MODE == 1) && (SW_START == 0)) { mode = 1; SSR = SSR_ON; dot_flg = SEG_DOT_ON; count_msec = set_up_count; sec_old = 60; buzzer(100); } //タイマーストップ if ((SW_MODE == 1) && (mode == 1) && (SW_STOP == 0)) { mode = 0; SSR = SSR_OFF; dot_flg = SEG_DOT_OFF; for (cnt = 0; cnt < 5; cnt++) { segment_set_data(10, 10, 10); buzzer(100); segment_set_data(11, 11, 11); Delay_ms(100); } } //タイムアウト if ((mode == 1) && (count_msec == 0)) { mode = 0; SSR = SSR_OFF; dot_flg = SEG_DOT_OFF; for (cnt = 0; cnt < 5; cnt++) { segment_set_data(10, 10, 10); buzzer(100); segment_set_data(11, 11, 11); Delay_ms(100); } } //設定値(分)のインクリメント if ((SW_MODE == 0) && (mode == 0) && (SW_UP == 0)) { set_up_count += 60000; set_up_count_eeprom._long = set_up_count; Eeprom_Write(0, set_up_count_eeprom._short[0]); Delay_ms(20); Eeprom_Write(1, set_up_count_eeprom._short[1]); Delay_ms(20); Eeprom_Write(2, set_up_count_eeprom._short[2]); Delay_ms(20); Eeprom_Write(3, set_up_count_eeprom._short[3]); Delay_ms(20); } //設定値(分)のデクリメント if ((SW_MODE == 0) && (mode == 0) && (SW_DOWN == 0)) { set_up_count -= 60000; if (set_up_count < 60000) { set_up_count = 60000; } set_up_count_eeprom._long = set_up_count; Eeprom_Write(0, set_up_count_eeprom._short[0]); Delay_ms(20); Eeprom_Write(1, set_up_count_eeprom._short[1]); Delay_ms(20); Eeprom_Write(2, set_up_count_eeprom._short[2]); Delay_ms(20); Eeprom_Write(3, set_up_count_eeprom._short[3]); Delay_ms(20); } //タイムアウト直前の1分間 if (mode == 1) { tmp = count_msec; minute = tmp / 60000; if (minute == 0) { sec_new = tmp / 1000; if (sec_new != sec_old) { buzzer(100); sec_old = sec_new; } } minute++; } else { tmp = set_up_count; minute = tmp / 60000; } //タイマー値の表示 m1 = minute / 100; m2 = (minute % 100) / 10; m3 = minute % 10; if (m1 != 0) { segment_set_data(m1, m2, m3); } if ((m1 == 0) && (m2 != 0)) { segment_set_data(11, m2, m3); } if ((m1 == 0) && (m2 == 0)) { segment_set_data(11, 11, m3); } // Delay_ms(100); } } //********************************************************************** void buzzer(short msec) { buzzer_flg = 1; Vdelay_ms(msec); buzzer_flg = 0; } //********************************************************************** //■■■セグメント初期化関数■■■ void init_segment() { SEG1_Direction = OUTPUT_MODE; SEG1_OFF; SEG2_Direction = OUTPUT_MODE; SEG2_OFF; SEG3_Direction = OUTPUT_MODE; SEG3_OFF; // SEG_DATA_Direction = 0b00000000; SEG_DATA = 0xFF; } //********************************************************************** //■■■タイマー初期化関数■■■ void init_timer() { T2CON.T2CKPS1 = 0; T2CON.T2CKPS0 = 0; T2CON.TOUTPS3 = 1; T2CON.TOUTPS2 = 1; T2CON.TOUTPS1 = 1; T2CON.TOUTPS0 = 1; TMR2 = 0; PIE1.TMR2IE = 1; PIR1.TMR2IF = 0; PR2 = 125; //125=1msec/((1sec/8MHz)*4*16PS) T2CON.TMR2ON = 1; } //********************************************************************** //■■■セグメントデータ設定関数■■■ short seg_dat[3] = {0, 0, 0}; // void segment_set_data(short seg1, short seg2, short seg3) { seg_dat[0] = seg1; seg_dat[1] = seg2; seg_dat[2] = seg3; } //********************************************************************** //■■■割り込み関数■■■ DWORD count_msec = 0; BYTE buzzer_flg = 0; // void interrupt() { if (PIR1.TMR2IF == 1) { PIR1.TMR2IF = 0; // segment_disp(); if (count_msec > 0) { count_msec--; } // if (buzzer_flg == 1) { BUZZER_BIT = ~BUZZER_BIT; } } } //********************************************************************** //■■■セグメントデータ表示関数■■■ short seg_tbl[12] = { 0b00111111, //0 0b00000110, //1 0b01011011, //2 0b01001111, //3 0b01100110, //4 0b01101101, //5 0b01111101, //6 0b00100111, //7 0b01111111, //8 0b01101111, //9 0b01000000, //- 0b00000000 //space }; short seg_cnt = 0; short dot_flg = 0; int dot_cnt = 0; // void segment_disp() { dot_cnt++; if (dot_cnt == 1000) { dot_cnt = 0; } // switch (seg_cnt) { case 0: SEG3_OFF; SEG_DATA = seg_tbl[seg_dat[0]]; SEG1_ON; seg_cnt = 1; break; case 1: SEG1_OFF; SEG_DATA = seg_tbl[seg_dat[1]]; SEG2_ON; seg_cnt = 2; break; case 2: SEG2_OFF; SEG_DATA = seg_tbl[seg_dat[2]]; SEG3_ON; seg_cnt = 0; // if (dot_flg == SEG_DOT_OFF) { return; } // switch (dot_cnt / 500) { case 0: SEG_DATA_DOT = 0; break; case 1: SEG_DATA_DOT = 1; break; } break; } } //********************************************************************** </code> ===== 動作確認 ===== {{:imgpaste:202004:htmikan-20200430-144616.png?500}} SSRには、秋月電子のキットを使用しました。 全体を乾電池(3V)駆動させるため、制御入力側の抵抗を、330Ω→100Ωに変更しました。 {{:imgpaste:202004:htmikan-20200430-144629.png?500}} 左側:設定値を10分にしました。1桁目のドットは消灯したままです。 右側:スタート直後です。1桁目のドットが点滅します。 {{:imgpaste:202004:htmikan-20200430-144638.png}}{{:imgpaste:202004:htmikan-20200430-144647.png}} 左側:SSRに扇風機を接続し、スタートさせました。扇風機が回っています。 右側:タイムアウトして、扇風機が停止します。 {{:imgpaste:202004:htmikan-20200430-144708.png}}{{:imgpaste:202004:htmikan-20200430-144713.png}} <callout type="warning" title="著作権表示 copyright notice"> このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]] This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]] </callout> elechobby/picdic/pic16f88/143.txt 最終更新: 2025/10/17 14:29by 127.0.0.1