土曜日, 11月 09, 2019

PIC24FV16KM202 w/microstick 簡易オシロスコープ 途中だけど

趣味,勉強も兼ねて,作ってみた。プログラム組んでみた。自分自身で出す1kHz/50% PWMを直結して読んでみた。あまりテストしていないので,まだまだ誤りが多いと思うが...

  • 実験値,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 件のコメント: