※※戻る時は、ブラウザの[矢印]で。 ◎Hi_Tech_c のソースです。拡張子を(→ .c)に変更してください。 ◎最後尾にkeydefine.h と doraemon.datを付けてあります。 /* main.c */ /****************************************************************************** 連続間欠タイマー 電池駆動版 Ver5k Pic:16F648A Hitech_c コンパイラ *LCD と 緑4・黄5LEDで10秒~4分50秒を表示 *最後の10秒はLED点滅、最後3秒は「プッ」「プッ」「プッ」 *PORTBはLED表示用B0-B4はカソード、B6,B7はアノード RB5からメロディ、RA0からブザー音を出力 →IC_ampで増幅 →SPへ * RA1:開始/停止 RA2:インターバル時間(5秒ごと)の設定、 RA3:分設定、RA4:秒設定、 RA5:リセット RA6とRA7:I2c_LCDへの接続 *タイマ0:メロディ用、タイマ1:秒カウント用、タイマ2:LED点灯用 *******************************************************************************/ #include #include "keydefine.h" // 周波数と長さのデータ #include "doraemon.dat" #define _XTAL_FREQ 4000000 __CONFIG(CP_OFF & LVP_OFF & BOREN_OFF & MCLRE_ON & PWRTE_ON & WDTE_OFF & FOSC_INTOSCIO); // RA5はリセット #define SDA RA6 #define SCL RA7 #define TRISSDA TRISA6 /******************************** * 調整用定数 *********************************/ //#define CONTRAST 0x18 // for 5.0V #define CONTRAST 0x28 // for 3.3V int const LED_SEG[6] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F}; // 点灯状態 00000 00001 00011 00111 01111 11111 unsigned char Dig, Seg; // 桁(列)と点灯個数 unsigned char vram[2]; // [0]は秒の列、[1]は分の列 #define SdPort RB5 // メロディとブザー音 #define BzPort RA0 // ブザー音 #define Command 255 // keydefine.h参照 unsigned int m_time, s_time, Time, Time2; // 秒数の変数 unsigned int min1, sec1, sec2; unsigned char m_on, s_on; // 表示LEDの個数 unsigned char Mode; // モード: 0~3 unsigned char b_cnt; // 0.5秒のカウンタ(2回で1秒) unsigned int led_cnt; // 電圧低下LED点滅のタイミング用 unsigned char ToneSet; unsigned char TempoCount = 100; //Default TEMPO = 100 unsigned char BF; // 開始ブザーのフラグ unsigned char melody_on; // メロディonのフラグ unsigned char melody_stop; // メロディoffのフラグ unsigned char dummy, hozon; // ダミー用、仮変数 unsigned char ten_cnt; // 10秒未満のフラグ unsigned int BIAS = 3000; // タイマ1の余り分、本来は65536-62500=3036 unsigned char sw; // 押されたキー void melody(void); void wtime(unsigned char t0); void bzr1(void); // ラ void bzr2(void); // シ void bzr3(void); // ド void hyoji1(void); // LED表示サブ void hyoji2(void); // LCD表示サブ void hyoji3(void); // LCD表示サブ(簡易Ver) void delay_5MS(unsigned char t2); // 遅延 void delay_100ms(unsigned char t1); // 遅延 unsigned char keysearch(); unsigned char getkey(); void itostring(char digit, unsigned int data, char *buffer); //   桁数   データ名  書込む場所 void I2CStart(void); void I2CStop(void); unsigned char I2COut(unsigned char data); void lcd_data(unsigned char data); void lcd_cmd(unsigned char cmd); void lcd_init(void); void lcd_str(char* ptr); void lcd_clear(void); unsigned char MsgTime[] = "Rep x:xx"; // 計測時間の残り秒表示 unsigned char IntTime[] = "Int xx"; // インターバル秒の表示 void main(void){ TRISA = 0x3F; // PORTA は、基本入力に(RA6,RA7は出力) TRISB = 0x20; // 基本出力に(RB5は初期設定のみ入力) PCON = 0x08; // 内部発振 4MHz CMCON = 0x07; // コンパレータ不使用 /* タイマー0の設定 メロディおよびブザー用 */ T0CS = 0; // タイマー0使用 PSA = 0; // プリスケーラをタイマ0用に PS2 = 0; PS1 = 1; PS0 =0; // プリスケーラ 8分周 TMR0 = 0x00; T0IF = 0; // タイマ0 初期値 /* タイマー1の設定 秒カウントダウン・タイマー用 */ TMR1IE = 1; TMR1IF = 0; TMR1CS = 0; // タイマ1として使用 T1CKPS0 = 1; T1CKPS1 = 1; // プリスケーラ 8分周 TMR1ON = 0; // タイマ1を停めて置いて TMR1H = BIAS/256; TMR1L = BIAS%256; // タイマ1初期値 /* タイマー2の設定 LEDのダイナミック点灯用 */ T2CON = 0x05; // TMR2プリスケーラ値を4倍、ポストスケーラ値は1:1の設定 PR2 = 124; // タイマーのカウント値を設定 4μs×125=0.5ms TMR2 = 0; // タイマー2の初期化 TMR2IF = 0; // タイマー2割込フラグを0にする TMR2IE = 1; // タイマー2割込みを許可する // タイマー有効 PEIE = 1; // 周辺装置割り込み有効 GIE = 1; // 全割込み処理を許可する /* 変数初期化 */ Mode = 0; m_time = 0; s_time = 0; b_cnt = 0; led_cnt = 0; Time2 = 0; Dig = 0; Seg = 4; dummy = 0x00; hozon = 0x00; /* ポートの初期化 */ PORTA = 0xFF; PORTB = 0x1F; /* 液晶表示器の初期化 */ lcd_init(); while(1){ switch(Mode){ // 0:設定 1:開始 2:動作中 3:インターバル case 0: // 時間設定 sw = getkey(); // どのキーを押した? if(sw == 1){ // スタートボタンON Mode = 1; while(RA1 == 0); // チャタリングの防止 delay_5MS(5); }else if(sw == 2){ // インターバル設定 Time2 = Time2 + 5; // 5秒ずつ if(Time2 > 55)Time2 = 0; // 最長55秒 bzr1(); while(RA2 == 0); // チャタリングの防止 delay_5MS(5); }else if(sw == 3){ // 分のボタンON m_time = m_time + 60; bzr2(); if(m_time > 240){ m_time = 0; // 4分を超えたら0に } while(RA3 == 0); delay_5MS(5); }else if(sw == 4){ // 10秒のボタンON s_time = s_time + 10; bzr2(); if(s_time > 50){ s_time = 0; // 50秒を超えたら0に } while(RA4 == 0); delay_5MS(5); } Time = m_time + s_time; if(Time == 0)Mode = 0; //時間設定しないで開始ボタンを押しても、動作不可 break; case 1: // 開始へ TMR1ON = 1; // タイマ2始動 Mode = 2; vram[1] &= 0x0F;// 設定中表示の赤LEDは消灯 BF = 1; // ブザーフラグ ten_cnt = 0; break; case 2: // 設定時間計測中 if(RA1 == 0){ // 止(始)ボタンONなら while(RA1 == 0); delay_5MS(5); TMR1ON = 0; // タイマ2停止 Time = m_time + s_time; // タイムの再設定 Mode = 0; // 時間設定へ break; } if(BF == 1){ bzr3(); // 開始のブザーを鳴らす delay_5MS(5); // ピッピッ bzr3(); BF = 0; } if(0 < Time && Time < 10){ // 10秒未満点滅 if(hozon != Time){ // 1秒経ったら hozon = Time; ten_cnt = 1; } } if(0 < Time && Time < 4){ // 残り3秒からプッ if(dummy != Time){ bzr2(); dummy = Time; } } if(ten_cnt == 1){ vram[0] = 0x00; // "点滅"のように delay_5MS(40); // 0.2秒間消灯 ten_cnt = 0; } break; case 3: // インターバル中 if(melody_on == 1){ melody_on = 0; // フラグをリセット hyoji2(); // act 0秒に melody(); } break; default: break; } // end_switch hyoji1(); // LED表示 hyoji2(); // LCD表示 } // end_while } // mainの終わり void interrupt warikomi(void){ // メロディ用 if(T0IF){ // タイマ0割込 TMR0 = ToneSet+3; // タイマ0再設定 (+3は微調整) if (ToneSet != 0) { if (SdPort) SdPort = 0 ; else SdPort = 1; //alternate port } T0IF =0; // タイマ0割り込みフラグクリア } // 秒のカウントダウン用 if(TMR1IF){ // タイマ1割込 1μs×8分周×62500=500ms TMR1IF = 0; TMR1ON = 0; // タイマ1を停めて置いて TMR1H = BIAS/256; TMR1L = BIAS%256; // タイマ1初期値 TMR1ON = 1; // タイマ1再始動 b_cnt++; // 0.5秒ずつ if(b_cnt == 2){ // 1秒になったら b_cnt = 0; Time--; // 1秒ずつ減算 if(Mode == 3)hyoji3(); // インターバル中のLCD表示 } if(Mode == 3 && Time == 1)TRISB5 = 1; // メロディ消す if(Time == 0){ if(Mode == 2){ // 通常のタイムアップ? vram[0] = 0x00; // LEDを消して if(Time2 == 0){ Time = m_time + s_time; Mode = 1; }else{ Time = Time2; melody_on = 1; Mode = 3; // インターバル・モードへ } }else if(Mode == 3){ melody_stop = 1; // メロディ中止フラグ Time = m_time + s_time; Mode = 1; } } } // LEDダイナミック点灯用 if(TMR2IF){ // タイマ2割込の場合 4MHz→1MHz→4分周(プリスケーラ) TMR2IF = 0; // PR2=124 → 約0.5ms Seg++; if(Seg > 4){ // アノード共通 Seg = 0; // if(Dig == 0){ Dig = 1; PORTB = 0x9F; // B7 ON,B6 OFF }else { Dig = 0; PORTB = 0x5F; // B6 ON,B7 OFF } } PORTB |= 0x1F; // 一旦消灯 PORTB &= ~(vram[Dig] & (0b00000001 << Seg)); //ビット反転+論理積 //RB6とRB7のビットは値を維持しながら //RB0から順にRB3まで"1"になっているビットのみを"0"にする } } // End-interrupt /***** メロディ *****/ void melody(void){ unsigned int n = 0; // 何時も曲の初めから unsigned char tmp,tmp2; melody_stop = 0; T0IE = 1; // タイマ0開始 TRISB5 = 0; // RB5を出力に TMR2ON = 0; // LED表示 止めて置く while(1){ tmp = songdata[n]; tmp2 = songdata[n+1]; if(RA1 == 0){ // メロディ中:ストップ押 while(RA1 == 0); delay_5MS(5); TMR1ON = 0; // 秒カウント停止 Time = m_time + s_time; // タイムの再設定 Mode = 0; // 時間設定へ break; } if(melody_stop == 1){ // 停止フラグON delay_5MS(40); // 暫時無音に break; } if (tmp == Command) { // CMD だったら if (tmp2 == END){ //Tempo or End of data? n = 0; // 繰り返し 1回で終了時は: break; } else{ TempoCount = tmp2; //New tempo change n += 2; } } else{ ToneSet = tmp; wtime(tmp2); n += 2; } } TRISB5 = 1; // RB5を入力に TMR2ON = 1; T0IE = 0; // タイマ0停止 return; } /***** tempo control *****/ void wtime(unsigned char t0){ unsigned int t1; while(t0--){ t1 = TempoCount * 4; while ( --t1 ){ __delay_us(10); } } } /****** ブザー用ルーチン ********/ void bzr1(void){ TRISA0 = 0; int i; for (i = 0; i < 80 ; i++) { BzPort = 1 ; __delay_us(568) ; BzPort = 0 ; __delay_us(568) ; } TRISA0 = 1; } void bzr2(void){ TRISA0 = 0; int i; for (i = 0; i < 80 ; i++) { BzPort = 1 ; __delay_us(506) ; BzPort = 0 ; __delay_us(506) ; } TRISA0 = 1; } void bzr3(void){ TRISA0 = 0; int i; for (i = 0; i < 70 ; i++) { BzPort = 1 ; __delay_us(476); BzPort = 0 ; __delay_us(476); } TRISA0 = 1; } /***** 表示 ( LEDの点灯数で残り時間を表示 ) *****/ void hyoji1(void){ m_on = (Time + 9) / 60; // 分LEDの個数 s_on = ((Time + 9) % 60)/10; // 10秒LEDの個数 if(Time == 0)s_on = 0; vram[0] = LED_SEG[s_on]; vram[1] = LED_SEG[m_on]; if(Mode == 0)vram[1] |= 0x10; // 設定中は赤LEDずっと点灯 } /***** 表示2( LCDで残り時間やインターバル時間を表示 ) *****/ void hyoji2(void){ if(Mode <= 2){ min1 = Time /60; // 総秒数→x分 sec1 = Time % 60; // 総秒数→xx秒 sec2 = Time2; }else{ min1 = 0; sec1 = 0; sec2 = Time; } itostring(1,min1, MsgTime+4); // MsgTimeの5桁目から itostring(2,sec1, MsgTime+6); // MsgTimeの7桁目から itostring(2,sec2, IntTime+6); lcd_cmd(0x80); // 表示位置を1行目1列[00H]に設定 lcd_str(MsgTime) ; // [00H]から書込まれる(表示する) lcd_cmd(0xC0); // 表示位置を2行目1列[40H]に設定 lcd_str(IntTime) ; // [40H]から書込まれる(表示する) } /***** 表示3( LCDでインターバル時間を表示 ) *****/ void hyoji3(void){ itostring(2,Time, IntTime+6); lcd_cmd(0xC0); lcd_str(IntTime); } /***** 5ms 遅延 multiple x times *****/ void delay_5MS(unsigned char t2){ while(t2--){ __delay_ms(5); } } /**** 100msec遅延関数 ******/ void delay_100ms(unsigned char t1){ t1 *= 4; // 4倍 while(t1){ __delay_ms(25); // 25msec t1--; // 100msec x t1 } } /***** 押されている(=0の)SWを探すSUB *****/ unsigned char keysearch(){ unsigned char tsw; tsw = 0x00; switch (PORTA & 0b00011110){ case 0b00011100: //RA1(int5sec) tsw = 1; break; case 0b00011010: tsw = 2; //RA2(10秒)on break; case 0b00010110: tsw = 3; //RA3(分) on break; case 0b00001110: tsw = 4; //RA4(開始)on break; } return (tsw); } /*** 5回連続で「押」を確認したら、その値を返す ***/ unsigned char getkey(){ unsigned char newval, oldval, cnt; oldval = 0x00; while(1){ for(cnt = 0; cnt < 5; cnt++){ newval = keysearch(); if(newval != oldval){ cnt = 0; oldval = newval; } __delay_us(100); } return(newval); } } /*************************************** * int整数からASCII文字に変換 ****************************************/ void itostring(char digit, unsigned int data, char *buffer){ char i; buffer += digit; // 最後の数字位置 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } /***************************** * I2c Start *****************************/ void I2CStart(void){ /* SCL,SDAは常時Highとする */ SDA = 0; // 先に SDA=Low TRISSDA = 0; // SDA出力 } /***************************** * I2c Stop *****************************/ void I2CStop(void){ SCL = 0; // SCL Low SDA = 0; // SDA Low TRISSDA = 0; // 出力モードに戻す SCL = 1; // 先にSCLをHigh SDA = 1; // 後からSDAをHigh } /**************************** * I2Cで1バイト出力 ****************************/ unsigned char I2COut(unsigned char data){ int i; unsigned char BitPos, ACK; /* Data Out */ TRISSDA = 0; // SDA出力モード BitPos = 0x80; // ビット位置初期値 for(i=0; i<8; i++) // 8ビット繰り返し { SCL = 0; // SCL Low if((data & BitPos) != 0) // ビット出力 SDA = 1; // SDA High else SDA = 0; // SDA Low BitPos = BitPos >> 1; // ビット位置移動 SCL = 1; // SCL Highに戻す } /* Ack チェック */ SCL = 0; // クロック1Low TRISSDA = 1; // 入力モードにしてACK入力 ACK = SDA; // ACKチェック for delay ACK = SDA; // ACKチェック SCL = 1; // クロックHighに戻す return(ACK); // ACKを戻り値とする } /********************************* * 液晶へ1文字表示データ出力 *********************************/ void lcd_data(unsigned char data){ I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x40); // 表示データ指定 I2COut(data); // 表示データ出力 I2CStop(); // ストップ __delay_us(30); // 遅延 } /******************************* * 液晶へ1コマンド出力 *******************************/ void lcd_cmd(unsigned char cmd){ I2CStart(); // スタート I2COut(0x7C); // アドレス I2COut(0x00); // コマンド指定 I2COut(cmd); // コマンド出力 I2CStop(); // ストップ /* ClearかHomeか */ if((cmd == 0x01)||(cmd == 0x02)) __delay_ms(2); // 2msec待ち else __delay_us(30); // 30μsec待ち } /******************************* * 初期化 *******************************/ void lcd_init(void){ delay_100ms(1); lcd_cmd(0x38); // 8bit 2line Normal mode lcd_cmd(0x39); // 拡張モード設定 lcd_cmd(0x14); // OSC 183Hz BIAS 1/5 /* コントラスト設定 */ lcd_cmd(0x70 + (CONTRAST & 0x0F)); lcd_cmd(0x5C + (CONTRAST >> 4)); // lcd_cmd(0x6A); // Follower for 5.0V lcd_cmd(0x6B); // Follower for 3.3V delay_100ms(3); lcd_cmd(0x38); // Set Normal mode lcd_cmd(0x0C); // Display On lcd_cmd(0x01); // Clear Display } /****************************** * 全消去 ******************************/ void lcd_clear(void){ lcd_cmd(0x01); //初期化コマンド出力 } /***************************** * 文字列表示 *****************************/ void lcd_str(char* ptr){ while(*ptr != 0) //文字取り出し lcd_data(*ptr++); //文字表示 } /******** End Of C_code *********/ /**** ここからはkeydefine.hです "keydefine.h" のファイル名で main.c と同じディレクトリに、保存してください。****/ #define CL 19, #define C$L 33, #define DL 45, #define D$L 57, #define EL 68, #define FL 79, #define F$L 89, #define GL 99, #define G$L 108, #define AL 116, #define A$L 124, #define BL 131, #define C 139, #define C$ 145, #define D 152, #define D$ 158, #define E 163, #define F 169, #define F$ 174, #define G 178, #define G$ 183, #define A 187, #define A$ 191, #define B 195, #define CH 198, #define C$H 202, #define DH 205, #define D$H 208, #define EH 211, #define FH 213, #define F$H 216, #define GH 218, #define G$H 220, #define AH 222, #define A$H 224, #define BH 226, #define R 0, #define CMD 255, #define END 0 #define TEMPO , //Length (Midi timebase like 48 tick) #define L1 192, //whole #define L2 96, //half #define L3 64, //triplets half #define L4 48, //quarter #define L4D 72, //dotted quarter #define L6 32, //triplets quarter #define L8 24, //eighth #define L8D 36, //dotted eighth #define L12 16, //triplets eighth #define L16 12, //sixteenth #define L16D 18, //dotted sixteenth #define L24 8, //triplets sixteenth #define L32 6, //32th #define L32D 9, //dotted 32th #define L48 4, //triplets 32th #define L64 3, //64th #define L96 2, //triplets 64th #define L192 1, //192th(The minimum unit) //Length (48 ticks timebase with rest time) #define T192 144,0,48, //whole #define T96 72,0,24, //half #define T64 48,0,16, //triplets half #define T48 36,0,12, //quater #define T72 54,0,18, //dotted quater #define T32 24,0,8, //triplets quater #define T24 18,0,6, //eighth #define T36 27,0,9, //dotted eighth #define T16 12,0,4, //triplets eighth #define T12 9,0,3, //sixteenth #define T18 14,0,4, //dotted sixteenth #define T8 6,0,2, //triplets sixteenth #define T6 5,0,1, //32th #define T9 7,0,2, //dotted 32th #define T4 3,0,1, //triplets 32th #define T3 2,0,1, //64th #define T2 1,0,1, //triplets 64th #define T1 1, //192th(The minimum unit) /**** keydefine.h 終わり ****/ /**** 以下の部分は "doraemon.dat" のファイル名で main.c と同じディレクトリに、保存してください。****/ const unsigned char songdata[]={ // ドラエモンのテーマ曲 CMD 85 TEMPO GL T36 // 約20秒 C T12 C T36 E T12 A T36 E T12 G L8D R L16 G T36 A T12 G T36 E T12 F T36 E T12 D L8D R L16 AL T36 D T12 D T36 F T12 B T36 B T12 A T36 G T12 F T48 F L8 E L8 AL L8 BL L4 C L8 D L2 R L2 GL T36 C T12 C T36 E T12 A T36 E T12 G L8D R L16 G T36 A T12 G T36 E T12 F T36 E T12 D L8D R L16 AL T36 D T12 D T36 F T12 B T36 B T12 A T36 G T12 F T24 F T24 E T24 D T24 BL L4 D L4 C L2 R L2 //stop CMD END // Music Last of data };