- 実験値,100k sample/sec ぐらいが限度だった。
- 5V ADC を 1ch 読んでグラフ化。手を抜くため,分圧,増幅等しない。他の5V/3.3Vマイコンの波形が少し見られれば良いとする。
- 表示領域は128*16ドット。OLED用のバッファにデータを仮置き。つまりAD値を8ビットに圧縮。有効数字は約2桁。たぶんこれで十分。
- AD値は256回読む。簡易トリガー判定(下記)を行い,そのうち128回分のデータをグラフ化。
- 横時間軸はスイッチで加減できるようにする。手を抜くため,単純に2倍または1/2にする。
- 簡易トリガー
- 最初の立ち上がりのみ判定。
- 判定値はAD値の半分固定。
- 見つかったら,トリガーポイントを表示領域の中央にする。見つからなかったら最初の128個のデータを表示。
- 簡易周波数測定
- 最初の2回の立ち上がり時刻の差をとり,計算。表示するプログラムにまだバグがある。(kHz以上がうまく表示できない)
C言語の,データ型の変換やら,グローバル変数の扱いやらに手を焼きながら,これだけでも数日かかってしまった。まあ,これが楽しいのだけど。
/** Section: Included Files */ #include "mcc_generated_files/system.h" #include "mcc_generated_files/mcc.h" #include "oled.h" /* Main application */ #define FCY 16000000UL #include <libpic30.h> // #define address 0x3C unsigned int ADC_COUNT = 256; unsigned int ADC_SKIP_INIT = 0x08; unsigned int ADC_SKIP = 0x08; int PREV_SEC = 0; extern char prev_key_state; extern char current_key_state; extern char key_data; extern char pressed_key; extern char _KEY_STATE; extern unsigned char OLED_buffer[128 * 32 / 8]; char d1[30]=""; void My_TMR1_ISR(void) { // read AD value and store ADC_SKIP--; if (!ADC_SKIP) { if (ADC_COUNT) { ADC_COUNT--; OLED_buffer[255-ADC_COUNT]=(ADC1_ConversionResultGet())>>2; } /* sprintf(d1,"ADC_COUNT=%3d",ADC_COUNT); OLED_string(d1,0,0); OLED_write(); */ ADC_SKIP=ADC_SKIP_INIT; } } void show_status(void) { // sprintf(d1,"Last ADC %5d",ADC1_ConversionResultGet()); // OLED_string(d1,0,16); // TMR1 period 5us -> 200kHz sampling // switch (ADC_SKIP_INIT) { case 2: sprintf(d1,"100kHz/s "); break; case 4: sprintf(d1,"50kHz/s "); break; case 8: sprintf(d1,"25kHz/s "); break; case 16: sprintf(d1,"12.5kHz/s "); break; default: sprintf(d1,"SKIP %4d",ADC_SKIP_INIT); break; } OLED_string(d1,0,16); OLED_write(); } int main(void) { // initialize the device SYSTEM_Initialize(); TMR1_Stop(); __delay_ms(500); OLED_Init(0x3C); OLED_clear(); // 12345678901234567890 OLED_string(" Loading...", 0, 0); OLED_string(" PIC24FV16KM202", 0, 8); OLED_string(" with OLED 128*64.", 0, 24); OLED_write(); __delay_ms(500); OLED_clear(); OLED_write(); TMR1_SetInterruptHandler(My_TMR1_ISR) ; TMR1_Start(); show_status(); while(1) { // switch if (_KEY_STATE==3) { key_data=current_key_state; _KEY_STATE=0; // means clear if (key_data==3) { switch (pressed_key) { case 3: break; case 1: // 12345678901234567890 // OLED_string("RA1 pressed. ",0,24); // OLED_write(); pressed_key=3; // RA1 program TMR1_Stop(); if (ADC_SKIP_INIT<0x10000) {ADC_SKIP_INIT=ADC_SKIP_INIT<<1;} show_status(); ADC_SKIP=ADC_SKIP_INIT; ADC_COUNT=256; TMR1_Start(); break; case 2: // 12345678901234567890 // OLED_string("RB3 pressed. ",0,24); // OLED_write(); pressed_key=3; // RB3 program TMR1_Stop(); if (ADC_SKIP_INIT>2) {ADC_SKIP_INIT=ADC_SKIP_INIT>>1;} show_status(); ADC_SKIP=ADC_SKIP_INIT; ADC_COUNT=256; TMR1_Start(); break; case 0: // 12345678901234567890 // OLED_string("RA1 and RB3 pressed.",0,24); // OLED_write(); // RA1 and RB3 program pressed_key=3; TMR1_Stop(); show_status(); TMR1_Start(); break; } } else { pressed_key = pressed_key & key_data; } } /* sprintf(d1," AD = %5d",ADC1_ConversionResultGet()); OLED_string(d1,0,8); OLED_write(); */ if (!ADC_COUNT) { TMR1_Stop(); unsigned char i=0; // find trigger point // trigger result -> OFFSET. unsigned char OFFSET=0; unsigned char OFFSET_1=0; for(i=63; i<191; i++) { if ( ((unsigned char)(OLED_buffer[i])<127) & ((unsigned char)(OLED_buffer[i+1])>127) ) { if (OFFSET == 0) { OFFSET=i; } else if (OFFSET_1 == 0) { OFFSET_1=i; } } } // print measured freq uint32_t freq; uint8_t freq_unit; if ( (OFFSET>0) && (OFFSET_1>OFFSET) ) { // period = (OFFSET_1-OFFSET) * ADC_SKIP_INIT * 5us sprintf(d1,"%u",(OFFSET_1-OFFSET) * ADC_SKIP_INIT * 5); sprintf(d1,"%s[us]",d1); // OLED_string(d1,0,24); // freq to display STILL BUG!!! freq=100000000/(5*(OFFSET_1-OFFSET)*ADC_SKIP_INIT); // freq=(real freq)*100 if (freq>100000) { freq_unit='k'; freq=freq/1000; } else {freq_unit=' '; } if (freq>100000) { sprintf(d1,"%lu.%lu",freq/1000,freq-1000*freq/1000); } else if (freq>10000) { sprintf(d1,"%lu",freq/100); } else { sprintf(d1,"%lu",freq); } // sprintf(d1,"%lu",freq); sprintf(d1,"%s%c[Hz]",d1,freq_unit); OLED_string(d1,0,24); } // data shift using OFFSET. // At the same time, measure the AD value. if (OFFSET>0) { for(i=0; i<127; i++) { OLED_buffer[i]=OLED_buffer[i+OFFSET-63]; } } // convert to graph unsigned int bar,a,b,c,prev_a; for(i=0; i<127; i++) { a=(unsigned int)((unsigned char)OLED_buffer[i]); if (i>0) { b=prev_a; } else { b=a; } prev_a=a; // sprintf(d1,"a=%1x,b=%x,i=%x ",a,b,i); OLED_string(d1,0,16); OLED_write(); __delay_ms(100); if (b>a) { c=b; b=a; a=c; } a = (unsigned int)((0x8000)>>((unsigned char)(a>>4))); b = (unsigned int)((0x8000)>>((unsigned char)(b>>4))); // sprintf(d1,"a=%1x,b=%x,i=%x ",a,b,i); OLED_string(d1,0,24); OLED_write(); __delay_ms(100); a= ~(a-1); b=(b-1)|b; // sprintf(d1,"a=%1x,b=%x,i=%x ",a,b,i); OLED_string(d1,0,24); OLED_write(); __delay_ms(100); OLED_buffer[i]=((a&b) & 0xFF); OLED_buffer[i+128]=(a&b)>>8; } OLED_write(); ADC_COUNT=256; TMR1_Start(); /* sprintf(d1,"KEY_STATE = %d",_KEY_STATE); _KEY_STATE=0; OLED_string(d1,0,16); OLED_write(); */ } // __delay_ms(500); // switch test // _LATA0=_RA1; _LATA0=(_RA1)*(_RB3); // means LED=ON when RA1 and/or RB3 are pressed // _LATA0=_RB6; }; return 1; } /** End of File */ |
TMR1は5usecで割り込み。これを指定されたスキップ値で無視して,ADを取り込んでいる。
本当は,時間が長い時は,トリガーオフで「ロール」つまり逐一表示していくほうがいいのだけど,手を抜いて全てバッファで読み込むだけにしている。
0 件のコメント:
コメントを投稿