// //  周波数カウンタ&波形発生テストプログラム // 2007/6/26 完成 by TEP // // ロータリーエンコーダーで発振周波数設定→自発振周波数を周波数カウンタで測定 // ゲートタイム 1秒 // #include #include // 定数の定義 (ピンコネクション) #define SW_ON 0 #define SW_OFF 1 #define LOW 0 #define HIGH 1 #define SW1 p1_0 #define RE_A p1_1 #define RE_B p1_2 #define LCD_DB p1 #define LCD_DB7 p1_6 #define LCD_DB6 p1_5 #define LCD_DB5 p1_4 #define LCD_DB4 p1_3 #define LCD_STB p3_3 #define LCD_RS p3_4 #define F_OUT p3_5 // CMP1_2 TimerC output #define F_IN p1_7 // CNTR00 TimerX input // 変数の定義 char Sw1_state = 0; // タクトスイッチ用 char Newdata,Olddata; // ロータリーエンコーダー用 char Newport0,Newport1; char Oldport0,Oldport1; signed char Enc_direction; unsigned long Count; // 波形発生設定用数値 unsigned long Count1; // 波形発生設定用数値 unsigned long Freq; // 波形発生周波数表示用 unsigned int GateCount; // 周波数カウンタゲートカウンタ unsigned int GateMode; // 周波数カウンタゲートタイム選択フラグ unsigned long Dumy; // 周波数カウンタ表示用 unsigned long InFreq; // 周波数カウンタ表示用 char Msg0[] = "SG & Fcounter \0"; // 表示メッセージバッファ char Msg1[] = "PLEASE PUSH SW1 \0"; char Msg_SG1[] = "Signal Genarator\0"; char Msg_SG2[] = "SET:1000KHz \0"; char Msg_FC0[] = "Freq Counter \0"; char Msg_FC1[] = "SET 0,000,000 Hz\0"; char Msg_FC2[] = "SET 000,000KHz\0"; char Msg_FC3[] = "SET 00MHz\0"; char Msg_FC4[] = " Hz\0"; char MsgSpace[]= " \0"; // 関数の宣言 液晶関係など void Lcd_init(void); void Lcd_output(char *str); void Lcd_clear(void); void Lcd_cmd(char cmd); void Lcd_data(char asci); void Lcd_out(char code, char flag); void Lcd_locate(char x, char y); void Lcd_cursol(char c_mode); void Lcd_line_print(char y,char *str); void Itostring(int digit, unsigned long data, char *buffer); void Itostring_F(int digit, unsigned long data, char *buffer); void Delay(long usec); void Delay_ms(unsigned long msec); // 関数の宣言 その他 void sfr_iod(void); void sfr_init(void); void main_ck(void); void Get_encdata(void); void Get_sw_data(void); //-------------------------------------------------------------- // メインルーチン //-------------------------------------------------------------- void main(void) { main_start: main_ck(); // メインクロック切替 sfr_iod(); // ポート入出力設定 sfr_init(); // 初期化 Lcd_init(); // LCD初期化 Lcd_cursol(1); Lcd_line_print(1,Msg0); // オープニングメッセージ Lcd_line_print(2,Msg1); while (Sw1_state==0) { Get_sw_data(); // スイッチでスタート } Sw1_state = 0; Delay_ms(500); // 波形発生開始 Freq = 100; // 初期値 100KHz Count1 = 20000 / Freq ; // TM1レジスタ値 Count = Freq; // RE用変数のセット tm1 = Count1+1; // PWM周期 tm0 = Count1 / 2; // PWMデューティ比 tcc0 = 1; // 出力開始 F_OUTPUT: Lcd_line_print( 1,Msg_SG1 ); // 発生周波数表示 Itostring ( 4,Freq,Msg_SG2+4 ); Lcd_line_print( 2,Msg_SG2 ); Count = Freq; while(1){ Get_encdata(); // Rエンコーダー入力 if (Count != Freq){ // 設定値変更か? // 発生周期数変更 tcc0 = 0; Freq = Count; Count1 = 20000 / Freq ; // TM1レジスタ値 Itostring ( 4,Freq,Msg_SG2+4 ); Lcd_line_print( 2,Msg_SG2 ); tm1 = Count1+1; // PWM周期 tm0 = Count1 / 2; // PWMデューティ比 tcc0 = 1; // タイマC 開始 } Get_sw_data(); // 切替スイッチ入力 if (Sw1_state == 1){ // スイッチで周波数カウンタモードへ移行 Sw1_state = 0; Delay_ms(500); goto F_COUNT; } } F_COUNT: // 周波数カウンタ開始 Lcd_line_print(1,Msg_FC0); Lcd_line_print(2,Msg_FC1); GateMode = 1; // 表示モード 1=Hz, 2=KHz, 3=MHz Count = 1; // RE用変数のセット while(1){ Get_encdata(); // エンコーダー入力 switch(Count) { case 0: Count = 1; break; case 1: Lcd_line_print(2,Msg_FC1); GateMode = 1; Msg_FC4[13] = ' '; // 周波数表示用バッファに単位記号を追加 break; case 2: Lcd_line_print(2,Msg_FC2); GateMode = 2; Msg_FC4[13] = 'K'; // 周波数表示用バッファに単位記号を追加 break; case 3: Lcd_line_print(2,Msg_FC3); GateMode = 3; Msg_FC4[13] = 'M'; // 周波数表示用バッファに単位記号を追加 break; default: Count = 3; } Get_sw_data(); // 切替スイッチ入力 if (Sw1_state == 1){ // スイッチで周波数カウンタ開始 Sw1_state = 0; Delay_ms(500); goto F_COUNT_START; } } F_COUNT_START: InFreq = 0; // カウンタリセット GateCount = 40; // ゲートタイムセット 25ms×40=1秒 asm("FSET I"); // 割り込み許可 tzs = 1; // timer Z 開始 txs = 1; // timer X 開始 while (1){ // 周波数カウンタ timer X アンダーフロー時処理 if (ir_txic){ ir_txic = 0; InFreq++; } // 周波数カウンタ ゲートタイムアップ時処理 if (GateCount <= 0){ tzs = 0; // タイマZ 停止 txs = 0; // タイマX 停止 /// 周波数計算 Dumy = 0xFF - tx; //intからlongへ変換 InFreq = InFreq * 0x10000 + Dumy * 0x100; Dumy = 0xFF - prex; //intからlongへ変換 InFreq = InFreq + Dumy + 700; switch(GateMode) { case 1: Itostring_F(8,InFreq,Msg_FC4+5); Lcd_line_print(2,Msg_FC4); break; case 2: InFreq = InFreq / 1000; Itostring_F(8,InFreq,Msg_FC4+5); Lcd_line_print(2,Msg_FC4); break; case 3: InFreq = InFreq / 1000000; Itostring_F(8,InFreq,Msg_FC4+5); Lcd_line_print(2,Msg_FC4); } // 次の測定開始 GateCount = 40; // ゲートタイム 1秒再設定 InFreq = 0; prex = 256-1; // 0xFFFFからダウンカウント tx = 256-1; tzs = 1; // タイマZ 開始 txs = 1; // タイマX 開始 } Get_sw_data(); // 切替スイッチ入力 if (Sw1_state == 1){ Sw1_state = 0; Delay_ms(500); tzs = 0; txs = 0; goto F_OUTPUT; // スイッチで波形発生モードへ移行 } } } //-------------------------------------------------------------- // timer Z 割り込み処理 //-------------------------------------------------------------- #pragma interrupt timer_Z (vect=24) //割り込み処理宣言 void timer_Z(void) { if(!GateCount) //1秒経過したか? { tzs = 0; //1秒タイマ停止 txs = 0; //カウント停止 } GateCount--; //割り込みカウンタ−1 } //-------------------------------------------------------------- //   ポート入出力の設定 //-------------------------------------------------------------- void sfr_iod(void) { pd1_3 = 1; // LCD pd1_4 = 1; // LCD pd1_5 = 1; // LCD pd1_6 = 1; // LCD pd3_3 = 1; // LCD pd3_4 = 1; // LCD pd1_2 = 0; // RE pd1_1 = 0; // RE pd1_0 = 0; // SW pd1_7 = 0; // F IN pd3_5 = 1; // F OUT p3_5 = 1; } //-------------------------------------------------------------- //   ポートデータの初期設定 //-------------------------------------------------------------- void sfr_init(void) { //timer C の設定(波形発生) tcc01 = 0; // カウントソース 20MHz tcc12 = 1; // コンペア1と一致時にTCレジスタをクリア tcc13 = 1; // アウトプットコンペアモード tcc15 = 1; // コンペア0と一致でCMP出力をLレベルに tcc16 = 1; // コンペア1と一致でCMP出力をHレベルに tcc17 = 1; // コンペア1と一致でCMP出力をHレベルに tcout5 = 1; // CMP1_2(pin26)に出力 tcc00 = 0; // 停止 // timer X の設定(周波数カウンタ部) txmr = 0b00000010; // イベント・カウンタ・モード prex = 256-1; // 0xFFFFからダウンカウント tx = 256-1; txs = 0; // timer Z の設定(ゲートタイム) tzmr = 0; // タイマモード、カウント停止 pum = 0; // タイマZ出力波形制御レジスタ tzck0 = 1; // カウンタ・ソース選択 tzck1 = 0; // f8 = 2.5MHz prez = 250 - 1; // プリスケーラ値 tzpr = 250 - 1; // タイマZプライマリ = 25mS ilvl0_tzic = 1; // タイマZ割込み優先レベル2 ir_tzic; // タイマZ割込み要求フラグ クリア } //-------------------------------------------------------------- //   クロックの切替 (20MHz) //-------------------------------------------------------------- void main_ck(void) { asm("FCLR I"); prcr = 1; cm13 = 1; cm15 = 1; cm05 = 0; cm16 = 0; cm17 = 0; cm06 = 0; asm("nop"); asm("nop"); asm("nop"); asm("nop"); ocd2 = 0; prcr = 0; } //-------------------------------------------------------------- // 数値から文字列に変換(Char型)ゼロサプレス処理済み //-------------------------------------------------------------- void Itostring(int digit, unsigned long data, char *buffer) { char i; char f = 0; buffer += digit; //文字列の最後 for(i=digit; i>0; i--){ //最下位桁から上位へ buffer--; //ポインター1 *buffer = (data % 10) + '0'; //その桁数値を文字にして格納 data = data / 10; //桁-1 } for(i=1; i0; i--){ //最下位桁から上位へ buffer--; //ポインター1 if ((i % 3) == 0 ) { *buffer = (data % 10) + '0'; //その桁数値を文字にして格納 data = data / 10; //桁-1 buffer --; *buffer = ','; } else { *buffer = (data % 10) + '0'; //その桁数値を文字にして格納 data = data / 10; //桁-1 } } for(i=1; i= 100) { //100以上なら50ステップ Count = Count + 50; } else { //100以下なら1ステップ Count++; } } } } if ((Oldport1==0)&&(Newport1==2)){ //Switch Edge detect if (Newport0==1){ //rotate if (Count>0) { //ゼロ以下にはならない if (Count <= 100){ Count --; } else if (Count <= 1000) { Count = Count - 50; } } } } Olddata = Newdata; //Refresh data } } //-------------------------------------------------------------- // スイッチ入力処理(ディレイによるチャタリング除去) //-------------------------------------------------------------- void Get_sw_data(void) { if (SW1 == SW_ON){ Delay_ms(30); if (SW1 == SW_ON){ Sw1_state = 1; Delay_ms(30); } } } //---------------------------------------------------- // 液晶表示器制御ライブラリ //---------------------------------------------------- //----- LCD初期化関数 ----- void Lcd_init() { Delay(20000); //20msec wait Lcd_out(0x03, 1); //8bit mode set Delay(5000); //5msec wait Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x02, 1); //4bit mode set Delay(1000); Lcd_cmd(0x2C); //DL=0 4bit mode Lcd_cmd(0x08); //display off C=D=B=0 Lcd_cmd(0x0E); //display on D=B=1 C=0 Lcd_cmd(0x06); //entry I/D=1 S=0 Lcd_cmd(0x01); //all clear } //----- データ出力サブ関数 ----- void Lcd_out(char code, char flag) { LCD_DB = (LCD_DB & 0b10000111) | (code << 3); //出力データ下位4ビットを出力 if (flag == 0) //表示データかコマンドか LCD_RS = 1; //表示データの場合RS=1 else LCD_RS = 0; //コマンドデータの場合RS=0 asm("NOP"); //NOP スキュー確保 LCD_STB = 1; //STB ON asm("NOP"); asm("NOP"); //パルス幅確保230nsec以上 asm("NOP"); asm("NOP"); LCD_STB = 0; //STB OFF } //----- 1文字表示関数 ----- void Lcd_data(char asci) { Lcd_out(asci>>4, 0); //上位4ビット出力 Lcd_out(asci, 0); //下位4ビット出力 Delay(50); //50μsec待ち } //----- コマンド出力関数 ----- void Lcd_cmd(char cmd) { Lcd_out(cmd>>4, 1); //上位4ビット出力 Lcd_out(cmd, 1); //下位4ビット出力 if((cmd == 0x01) || (cmd == 0x02)) Delay(2000); //2msec待ち else Delay(50); //50usec待ち } //----- 全消去関数 ----- void Lcd_clear() { Lcd_cmd(0x01); //初期化コマンド出力 } //----- 文字列出力関数 ----- void Lcd_output(char *str) { while(*str != 0x00) //文字列の終わり判定 { Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } } //----- カーソル位置に移動 ----- void Lcd_locate(char x, char y) { char i; if (y == 1){ Lcd_cmd(0x02); x--; while ( x ){ Lcd_cmd(0x14); x--; } }else if (y == 2){ Lcd_cmd(0x02); x--; for (i=1;i<=40;i++){ Lcd_cmd(0x14); } while ( x ){ Lcd_cmd(0x14); x--; } } } //----- カーソル表示制御 ----- void Lcd_cursol(char c_mode) { switch ( c_mode){ case 1: // 1.カーソルOFF、ブリンクOFF Lcd_cmd(0x0c); break; case 2: // 2.カーソルOFF、ブリンクON Lcd_cmd(0x0d); break; case 3: // 3.カーソルON、ブリンクOFF Lcd_cmd(0x0e); break; case 4: // 4.カーソルON、ブリンクON Lcd_cmd(0x0f); break; } } //----- 文字列出力関数(行指定あり) ----- void Lcd_line_print(char y,char *str) { if (y == 1){ Lcd_cmd(0x80); } else if(y == 2){ Lcd_cmd(0xC0); } while(*str != 0x00){ //文字列の終わり判定 Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } } //----- ディレイ関数 msec単位 ----- void Delay_ms(unsigned long msec) { msec = (msec * 5000) / 40000; //クロックで補正 msec = msec * 1000; //時間調整 while(msec--){} } //----- ディレイ関数 1usec単位 ----- void Delay(long usec) { usec = (usec * 20000) / 45000; while(usec--){} }