/************************************************************** * Multe Function Frequency Counter * * Condition: * 12.8MHz External VCTCXO-12.8MHz * * CPU: PIC24FJ64GA002 * * LCD: SC1602BS * * タイマ4 : 正確な1秒のインターバルタイマで、この割り込みでタイマ1をゲート * タイマ1と5:周波数カウンタでソフトウェアで結合して32ビットとして扱う * タイマ1は外部入力(T1CK)で非同期カウンタ、タイマ5はソフトウェアでカウント * タイマ2 : OC1用タイマ * OC1 : 1/1または1/640のPWM周期(出力はRP7へ) * タイマ3 : OC2用タイマ(T3CKはRP8ピンに割り当て) * OC2 : PWM出力(出力はRP6へ) * * Original Program: Mr.Gokan * Mod. N.Ishii 2018.5.30 ***************************************************************/ #include "p24FJ64GA002.h" #include "LCD_Lib3.h" // Set Configuration Word 1 _CONFIG1 ( JTAGEN_OFF & // JTAG Port: OFF GCP_OFF & // Code Protect:OFF GWRP_OFF & // Write Protect: OFF BKBUG_OFF & // Background Debug: OFF COE_OFF & // Clip On Emulation: OFF ICS_PGx1 & // Select ICD Pin: EMUC/EMUD-> PGC1/PGD1 For Common Use FWDTEN_OFF // WDT: OFF ) // Set Configuration Word 2 // 12.8MHz External Oscillator _CONFIG2 ( IESO_OFF & // 2 Speed Start Up: OFF FNOSC_PRI & // Select Main OSC (XT,HS,EC) FCKSM_CSDCMD & // Change Clock Control: OFF, Clock Monitor: OFF OSCIOFNC_OFF & // OSCO/RA3 function: OSC0 IOL1WAY_ON & // RP Register Protection: Valid One Writes To RP Registers I2C1SEL_PRI & // I2C1 pins Select: Use Primary I2C1 pins POSCMOD_EC // Oscillator Selection: EC Mode ) /// Function Prottypes void ltostring(char digit, unsigned long data, char *buffer); void Pulse(void); void Peri_Init(void); /// Message Data for LCD const char MsgStart[] = "Start!"; const char MsgOut[][17] = { {"Output Off "}, {"Output = 0.01Hz "}, {"Output = 0.1Hz "}, {"Output = 1Hz "}, {"Output = 10Hz "}, {"Output = 100Hz "}, {"Output = 1kHz "}, {"Output = 10kHz "}, {"Output = 100kHz "}, {"Output = 200kHz "}, {"Output = 400kHz "}, {"Output = 800kHz "}, {"Output = 1.6MHz "}, {"Output = 3.2MHz "}, {"Output = 40kHz "}, {"Output = 50kHz "}}; // Add /// グローバル変数宣言 //// 周波数表示用メッセージバッファ char MsgData[] = "Freq= xxxxxxxxHz"; unsigned char StateFlag; // Status Variable unsigned long Result; // Measurement Result Data unsigned int SWState, Old_SW; // Switching Frequency Data /******************************** * Function Main ********************************/ int main(void) { /// Initialize Clock CLKDIV = 0; // Division: 1/1 /// Initialize Port AD1PCFG = 0xffff; // All Digital Ports TRISA = 0xFFFF; // Port_A is All Input TRISB = 0x00AF; // RB0-3,5,7 is Input PORTB = 0x03FF; /// Set Internal Pull Up Registor CNPU1 = 0x003C; /// Set Pin Mapping RPINR3bits.T3CKR = 7; // RP7 is T3CK Output RPOR4bits.RP8R = 18; // RP8 is OC1 Output RPOR3bits.RP6R = 19; // RP6 is OC2 Output /// 周辺モジュールの初期設定 Peri_Init(); /// 開始メッセージ表示 lcd_init(); // Initialize LCD lcd_clear(); lcd_str((char *)MsgStart); StateFlag = 0; // Initialize Status ////// メインループで計測値表示 //////////// while(1) { //// タイマ1のカウントオーバーフローでタイマ5をカウントアップ if(IFS0bits.T1IF == 1){ // T1 Over Flow ? IFS0bits.T1IF = 0; TMR5++; // T5 Count Up } ///// 周波数表示 if(StateFlag == 2) // End of Measurement ? { Result = TMR5 * 0x10000 + TMR1; // 測定値合体 ltostring(8, Result, MsgData+6);// 数値をASCIIに変換しバッファへ格納 lcd_cmd(0x80); // 1行目の先頭へ lcd_str(MsgData); // 計測値表示 TMR1 = 0; // 次の測定準備 TMR5 = 0; // カウンタクリア lcd_cmd(0xC0); // LCD2行目の先頭へ lcd_str((char *)&MsgOut[SWState][0]); // 基準パルス出力周波数表示 StateFlag = 0; // ステート変数初期化 } //// 基準パルス出力制御 Pulse(); } } /********************************************* * タイマ4割り込み処理(正確な1秒インターバル **********************************************/ void __attribute__((interrupt, auto_psv)) _T4Interrupt(void) { IFS1bits.T4IF = 0; // Clead IF Flag // LATBbits.LATB4 = !LATBbits.LATB4; // デバッグ用LED点滅 if(StateFlag == 0){ // 初期常態か? Nop(); // 時間調整用 T1CONbits.TON = 1; // 周波数カウント開始 StateFlag = 1; // ステート更新 } else{ // 計測中の場合 T1CONbits.TON = 0; // 周波数カウント停止 StateFlag = 2; // ステート更新 } } /****************************** * 周辺モジュール初期化関数 *******************************/ void Peri_Init(void) { /// タイマ1の設定 : 外部クロック, 1/1, 非同期 T1CON = 0b0000000000000010; TMR1 = 0; /// タイマ2設定 : 内部クロック, 1/1, 10kHz周期 T2CON = 0b1000000000000000; PR2 = 639; // 100uS /// タイマ3設定 : 外部クロック(OC1から), 1/1, 1Hz周期 T3CON = 0b1000000000000010; PR3 = 9999; // 1Sec /// タイマ4設定:内部クロック, 1/256, FCY = 6.4MHz 1秒出力 T4CON = 0b1000000000110000; PR4 = 24999; // 1Sec IPC6bits.T4IP = 5; // Interrupt Level 5 IFS1bits.T4IF = 0; IEC1bits.T4IE = 1; // Enable T4 Interrupt /// タイマ5設定 ソフトウェアカウンタ T5CON = 0b0000000000000010; /// OC1設定 : PWMモード、タイマ2使用 OC1CON = 0x06; OC1RS = (PR2+1) / 2; // Duty is 50% /// OC2設定 : PWMモード、タイマ3使用 OC2CON = 0x0E; OC2RS = (PR3+1) / 2; // Duty is 50% } /********************************** * 数値からASCII文字列に変換する関数 ***********************************/ void ltostring(char digit, unsigned long data, char *buffer) { char i; buffer += digit; // 文字列の最後へ for(i=digit; i>0; i--) { // 最下位桁から上位へ buffer--; *buffer = (data % 10) + '0'; // その桁数値を文字にして格納 data = data / 10; // 桁-1 } } /*************************** * Control Pulse Output ****************************/ void Pulse(void) { /// スイッチの読み込みして周波数選択コードに変換 SWState = (~PORTA & 3) + (~(PORTB << 2) & 0x0C); if(SWState != Old_SW) { Old_SW = SWState; // スイッチ状態更新 TMR2 = 0; // Reset Timer TMR3 = 0; switch(SWState) { case 0: /// Off T3CON = 0b0000000000000010; // Timer Off break; case 1: /// 0.01Hz T3CON = 0b1000000000000010; // EXT 1/1 PR2 = 31999; // 200Hz PR3 = 19999; // 0.01Hz break; case 2: /// 0.1Hz T3CON = 0b1000000000000010; // EXT PR2 = 3199; // 2kHz PR3 = 19999; // 0.1Hz break; case 3: /// 1Hz T3CON = 0b1000000000000010; // EXT PR2 = 319; // 20kHz PR3 = 19999; // 1Hz break; case 4: /// 10Hz T3CON = 0b1000000000000010; // EXT PR2 = 319; // 20kHz PR3 = 1999; // 10Hz break; case 5: /// 100Hz T3CON = 0b1000000000000010; // EXT PR2 = 319; // 20kHz PR3 = 199; // 100Hz break; case 6: /// 1kHz T3CON = 0b1000000000000010; // EXT PR2 = 31; // 200kHz PR3 = 199; // 1kHz break; case 7: /// 10kHz T3CON = 0b1000000000000010; // EXT PR2 = 31; // 200kHz PR3 = 19; // 10kHz break; case 8: /// 100kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 63; break; case 9: /// 200kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 31; break; case 0xA: /// 400kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 15; break; case 0xB: /// 800kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 7; break; case 0xC: /// 1.6MHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 3; break; case 0xD: /// 3.2MHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 1; break; //// Add ------------------------------------ case 0xE: /// 40kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 159; break; case 0xF: /// 50kHz T3CON = 0b1000000000000000; // INT 1/1 PR3 = 127; break; ////----------------------------------------------- default: /// Off T3CON = 0b0000000000000010; // EXT 1/1 break; } OC1RS = (PR2+1) / 2; OC2RS = (PR3+1) / 2; // Duty 50% } }