/************************************************* * EMF Meter Program * * Written for issue Nov. 2014 of Monthly FB News * * T.Tsujioka (JH1NRR/JL3YMC) * *************************************************/ // Last updated: 2014/10/25 #include #define _XTAL_FREQ 16000000 // Internal clock of 16MHz #pragma config CPUDIV = NOCLKDIV // CPU System Clock Selection bits #pragma config USBDIV = OFF // USB Clock Selection bit #pragma config FOSC = IRC // IRC oscillator #pragma config PLLEN = OFF // PLL disabled #pragma config FCMEN = OFF // Fail-Safe Clock Monitor disabled #pragma config IESO = OFF // Oscillator Switchover mode disabled #pragma config PWRTEN = OFF // Power-up Timer disabled #pragma config BOREN = OFF // Brown-out Reset enabled in hardware only (SBOREN is disabled) #pragma config BORV = 30 // Minimum setting #pragma config WDTEN = OFF // HW Disabled - SW Controlled #pragma config WDTPS = 32768 // Watch-dog Timer Postscale Select: 1:32768 #pragma config HFOFST = OFF // #pragma config MCLRE = ON // MCLR pin enabled; RA3 input pin disabled #pragma config STVREN = ON // Stack full/underflow will cause Reset #pragma config LVP = OFF // Single-Supply ICSP disabled #pragma config BBSIZ = OFF // Boot Block Size Selecct bit #pragma config XINST = OFF // Extended Instruction Set Enable bit #pragma config CP0 = OFF // Code Protection bit #pragma config CP1 = OFF // Code Protection bit #pragma config CPB = OFF // Boot Block Code Protection bit #pragma config CPD = OFF // Data EEPROM Code Protection bit #pragma config WRT0 = OFF // Table Write Protection bit #pragma config WRT1 = OFF // Table Write Protection bit #pragma config WRTC = OFF // Configuration Write Register Protection bit #pragma config WRTB = OFF // Boot Block Write Protection bit #pragma config EBTR0 = OFF // Table Read Protection bit #pragma config EBTR1 = OFF // Table Read Protection bit #pragma config EBTRB = OFF // Boot Block Table Read Protection bit int adc_value; int value; // リニア値 unsigned int log2_value; // 対数値 2^n unsigned int peak_pattern = 0; // 2^n unsigned int led_pattern; // 2^(n+1)-1 #define MAX_MEASUREMENTS 4096 // 実測によれば8040回の計測で約1秒ごとに平均表示となる int measurements = 0; long sum_adc_value = 0; int mean_adc_value = 0; unsigned char mode = 1; unsigned char mean_mode = 0; unsigned char preamp_mode = 0; unsigned int normal_offset = 0; unsigned int preamp_offset = 0; #define MODE_KEY PORTAbits.RA0 #define PEAK_RESET_KEY PORTAbits.RA1 #define ZERO_CAL_KEY PORTAbits.RA5 // 10ms遅延 void wait_10ms(unsigned char count) { while (count-- > 0) { __delay_ms(10); } } // LEDにled_pattern(10-bit)を表示 void show_led_pattern(int led_pattern) { PORTC = (led_pattern >> 2); PORTB = ((led_pattern << 6) & 0xff); } // LEDをcount回点滅させる void flush_led(unsigned char count) { show_led_pattern(0b0000000000); wait_10ms(30); while (count-- > 0) { show_led_pattern(0b1111111111); wait_10ms(10); show_led_pattern(0b0000000000); wait_10ms(20); } wait_10ms(10); } // メイン関数 void main(void) { // OSCCON = 0b01110000; // IRCF=16MHz, OSTS=HFINTOSC // Initialize Digital I/O TRISA = 0b11111111; // RA5:input, RA4/AN3:input, RA1-0:input TRISB = 0b00111111; // RB7-6:output, RB4/AN10:input TRISC = 0b00000000; // Disable USB module // Bits RA0 and RA1 are available only when USB is disabled. // In order for the digital inputs to function on the RA<1:0> port pins, // the interrupt-onchange pins must be enabled (IOCA<1:0>=11) // and the USB module must be disabled (USBEN=0). UCON = 0b00000000; // UCON.USBEN = 0; IOCA = 0b00000011; // IOCA.B0 = 1; IOCA.B1 = 1; // Initialize ADC // Use FOSC/16 for TAD=1us @ 16MHz so that TAD >= 0.7us // Use ADC_12_TAD so that TACQ > 7.45us OpenADC(ADC_FOSC_16 & ADC_RIGHT_JUST & ADC_12_TAD, ADC_CH10 & ADC_INT_OFF, ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS, ADC_0ANA); ANSEL = 0b00001000; // AN3 enabled ANSELH = 0b00001100; // AN11-10 enabled // ゼロ校正オフセットの初期値 normal_offset = 0; preamp_offset = 0; #if 1 SetChanADC(ADC_CH3); ConvertADC(); while( BusyADC()); normal_offset = ReadADC(); #endif #if 1 SetChanADC(ADC_CH11); ConvertADC(); while( BusyADC()); preamp_offset = ReadADC(); #endif // 初期値 mode = 1; preamp_mode = 0; mean_mode = 0; SetChanADC(ADC_CH10); // ADC LOOP while (1) { // モード切り替え if (MODE_KEY == 1) { // モードをインクリメント mode++; if (mode > 4) { mode = 1; } // フラッシュ表示 flush_led(mode); // ボタンを離すまで待つ while (MODE_KEY == 1); switch (mode) { case 1: preamp_mode = 0; mean_mode = 0; SetChanADC(ADC_CH10); break; case 2: preamp_mode = 0; mean_mode = 1; SetChanADC(ADC_CH10); break; case 3: preamp_mode = 1; mean_mode = 0; SetChanADC(ADC_CH11); break; case 4: preamp_mode = 1; mean_mode = 1; SetChanADC(ADC_CH11); break; } peak_pattern = 0; // mode切り替え後、ピークホールドをクリア sum_adc_value = 0; measurements = 0; // mode切り替え後、平均値計算を初期化 } // A/D変換 ConvertADC(); while( BusyADC()); adc_value = ReadADC(); // ゼロ校正オフセットの計測 if (ZERO_CAL_KEY == 1) { #if 0 if (preamp_mode) preamp_offset = adc_value; // 瞬時値を設定 else normal_offset = adc_value; #else int i, sum; sum = 0; for (i = 0; i < 16; i++) { ConvertADC(); while( BusyADC()); sum += ReadADC(); } sum /= 16; if (preamp_mode) preamp_offset = sum; // 平均値を設定 else normal_offset = sum; #endif peak_pattern = 0; // ゼロ校正後、ピークホールドをクリア sum_adc_value = 0; measurements = 0; // ゼロ校正後、平均値計算を初期化 } // オフセットを補正する if (preamp_mode) adc_value -= preamp_offset; else adc_value -= normal_offset; // 平均値の計算 sum_adc_value += adc_value; measurements++; if (measurements >= MAX_MEASUREMENTS) { mean_adc_value = sum_adc_value / MAX_MEASUREMENTS; sum_adc_value = 0; measurements = 0; } // 瞬時値と平均値の切り替え if (mean_mode) { value = mean_adc_value; } else { value = adc_value; } // 対数変換 if (value <= 0) log2_value = 0; else if (value <= 1) log2_value = 1; else if (value <= 3) log2_value = 2; else if (value <= 7) log2_value = 4; else if (value <= 15) log2_value = 8; else if (value <= 31) log2_value = 16; else if (value <= 63) log2_value = 32; else if (value <= 127) log2_value = 64; else if (value <= 255) log2_value = 128; else if (value <= 511) log2_value = 256; else if (value <= 1023) log2_value = 512; else log2_value = 0; // ピークホールド if (PEAK_RESET_KEY == 1) { peak_pattern = 0; } if (peak_pattern < log2_value) { peak_pattern = log2_value; } // LEDバーメータ表示 if (log2_value > 0) { led_pattern = ((log2_value * 2 - 1) | peak_pattern); } else { led_pattern = peak_pattern; } // if (measurements & 1) led_pattern |= 0b1000000000; // サンプリング周波数の測定用(DEBUG用) show_led_pattern(led_pattern); } }