自作ーガイガーカウンタ

2016.03.12

LiIシンチレータをゲット、お試し

 やっと、中性子線を検出するLiIシンチレータを、eBayから調達。自宅でも、中性子線量を、定点観測したいと、思っていました。

12734031_566709220161850_7500143484
とりあえず、NaIシンチレータを、これに交換して、出力パルスなど、オシロで確認してみました。

12744028_566709233495182_703146221212745585_566709286828510_1383602318

波形は、パルス整形回路を通した後の波形で、数分に1度、パルスが出てきます。フォトマルからの生の波形は、反応しているようですが、パルスのレベルが低く、パルス幅も短いため、パルス整形回路では無視されます。

さて、中性子線量の定点観測装置を作るかどうか。平常では、宇宙線由来のものが主。同じ回路で、NaIシンチレータのγ線検出パルスは、下映像になる。

| | コメント (0) | トラックバック (0)

2012.12.09

GCMふくしま・計測ワークショップ・マニアゾーン

2012年7月15日、16日開催のGCMふくしま/こおりやまの計測ワークショップ・マニアゾーンでの作品展示の目録を、sourceforge.jpのプロジェクトTHMADにて公開しました。

ご一報です。

| | コメント (0) | トラックバック (0)

2012.11.11

宇宙風鈴への進化

Mywork_1209020312072105

【概要、特徴】
宇宙を音で感じる電子風鈴です。ロマンを感じませんか?

まあ、中身 は、光電子増陪管とCsIシンチレーションを使ったγ線分光計で、宇宙線 の全てを検出している訳ではなないのですが、中性子が、地上の水素 原子 と衝突すると、2200KeVのγ線を出しているという自然現象から、 2000KeV以上のγ線を検出したら、風鈴の音を出すようにしまし た。

つま り、地球自身がシンチレーションになっている壮大な電子風鈴なんです。

12110805 Img_1002


【後日追記1】 Maker Faire Tokyo 2012での作品展示(2012年12月1日〜2日)

1211020112110205

SAKURAボードユーザ会の出展スペースで、作品展示を行いました。


【後日追記2】 電子工作フェスティバル2012での作品展示(2012年12月9日)

入賞はしなかったのですが、招待展示となり、作品展示をショートプレゼンを行いました。

ずっこけぷれぜんの様子

| | コメント (0) | トラックバック (0)

2011.11.14

ガイガーオフ会@日立市に参加

昨日、日立市内で開催されたガイガーオフ会に参加致しました。ガイガーカウンタの自作関連のプレゼンも行いました。そのときの、プレゼン資料を、アップしてます。

 

ご参考

| | コメント (0) | トラックバック (0)

2011.11.06

自作GMカウンタの外付けGM管接続を標準化しなイカ?(1)

用途(高線量箇所の下見用途など)に応じてGM管を外付けしたくなる場合もあると思います。しかし、GM管を外付けするのためのケースなどの自作には、別の器量も必要になってきます。例えば、下写真のようなアーム付きのGM管モジュールは、電子回路の自作というよりも、造形が肝心です。

11110501 11110503

 この際、自作も分業出来た方が、ハッピーな気なしてます。そこで、「自作GMカウンタの外付けGM管接続を標準化しなイカ?」です。仕様が標準化されていれば、フリーマケットでも、部品として販売や頒布ができるというメリットもあります。
 最近、自作で使用されているGM管の標準稼働電圧の多くは、DC400V前後のものと思われます。この電圧供給をベースにして、更に、秋葉原で調達できる部品の組み合わせとして、外付けGM管モジュールとの接続仕様案を考えてみました。この仕様は、サバイバル的な環境を想定して、まず、精度よりも、つなげたら、最低限、線量の高低がわかる程度に動作することを目指しています。精度の向上は、本体た外付けGM管モジュール側の回路で補完していくことを前提に考えました。

 部品調達の容易性として調べると、まず、耐圧500V以上をクリアしてコンパクトなコネクタがそれほど安くないことが分かりました。その中で、秋葉原の店頭では、ヒロセ電機のRM12シリーズが、耐圧1000V以上で、高すぎない感じのものでした。また、知人からのご意見を考慮し、実装形態によって、3ピンと4ピンのものを混在して使用する下記案にしました。また、それらは、条件付きで変換ケーブルをかまして相互接続できるようにする。あと、接続ケーブルの部材としては、現在、耐圧600Vの2芯シールドケーブル(外径が4mm前後、ETFEシールド7/0.18×2芯, ETFEシールド0.51mm×2芯)までは、秋葉原で切り売りされていることを確認してます。接続ケーブルの長さは、長くて1メートル前後の範囲を想定。

【3ピン版】(本体からのDC400V供給のみ)
 GMカウンタ本体ケースとGM管モジュールケース側で、ヒロセ電機のRM12BRD-3S(メス)を使用します。なお、下回路図のピン番号は、ソケット部品に刻印されているピン番号です。

 

11110506 11110401

【4ピン版】(本体から、DC5Vも供給して外付けGM管モジュール側に昇圧回路を搭載)
 GMカウンタ本体ケースとGM管モジュールケース側で、ヒロセ電機のRM12BRD-4S(メス)を使用します。これも、下回路図のピン番号は、ソケット部品に刻印されているピン番号です。
11110602  

 外付けGM管モジュールに、昇圧回路を内蔵する場合、カウンタ出力パルスは、GM管とレベル互換で、ピン3へ出力。多分、DC400Vでも動作はするが、LND712など標準稼働電圧がDC500VのGM管への対応で必要になることを想定。
 また、5V電源供給は、20mAを超えないレベルにします。個人的な実験によると、DC5VからDC500Vへ昇圧するのに、5mAを超えない程度だったので、20mAでも余裕あると思います。また、5V電源にノイズが乗らないように、コンデンサなどの挿入が推奨。また、GM管のパルスのバッファ回路を搭載するための電源として使用することも想定。ケーブル長が長いと、パルス信号が鈍るので、その補完をするためです。
 あと、この仕様の採用には、耐圧500V以上の3芯シールド線が必要ですが、今のところ、秋葉原の店頭での販売を確認してません。耐圧600Vのリード線を束ねて、網線パイプに通してシールド線そのものを自作する方が、早いかもしれません。

【ラベル表示】
 供給電圧は、DC400Vが基本としますが、別の電圧を出力する場合、その電圧をラベル表記するのが良いでしょう。まだ、未定なのは、この標準仕様のネーミングとコネクタへの表記。なんか、良いネーミングはなイカ? 暫定案「DYI, GM Tube External Connection Spec. 2011」(略:"DYI, GMTECS2011")

-----

あとは、上記の仕様を想定したときの電気特性の把握が必要かな。

ご参考

追伸、もし、ご賛同いただき、上記仕様をご採用して、何か頒布される方は、コメントで宣伝を投稿していただければ、随時、承認して、公開致します。但し、このコメント公開は、当該頒布物の品質を保証するものではないことに、細心のご注意下さい。

| | コメント (0) | トラックバック (0)

2011.10.09

自作ガイガーカウンタ2号機の野外テストまとめ(1)

東日本大震災後に自製したガイガーカウンタ(2号機)の実地動作テストの結果グラフを、ここに纏めて掲載する。


【タイプ0】(野外、JRの4路線の車内で測定)

上越新幹線
11100904
東北新幹線
11100901
常磐線
11100902
総武本線
11100903
参考値
11100905

注)参考値グラフは、登山用雑貨で流通しているランタン用マントル(動作確認に利用)の放射線量を、自作ガイガーカウンタで測定した時のグラフ。これに比べると、どれも、だいぶん低いカウント値になっている。

右上写真は、常磐線いわき駅周辺の土壌面の線量の計測になる。車両内からでは、色々、放射線を遮断する障害物があるので、多少高くても測定に現れないが、土壌に接近させて、市販の線量計でみると、平常の値より高い値を表示している。但し、絶対値としては、高めな値という範囲。これは、ガイガーミュラ管は、黒いプラケースに収納して遮光のみ行っているので、β線とγ線の両方がカウントされている。


【タイプ1】(都区内の屋内定点測定)

今日の動作確認の結果グラフ

これは、厚2mmのアルミケースに、本体を収納しているので、ほぼγ線の計測になっている。

11070502 11100906

右上写真は、測定結果のグラフをアンドロイド端末のWebブラウザで表示しているところ。


測定実施時期が、だいぶんズレているが、以上な感じになっている。今の時代は、個人でもお手製の測定器で、このような事が、思いつきで出来てしまう時代となっている。何とも凄い事だ。

| | コメント (0) | トラックバック (0)

2011.09.21

自作ガイガーカウンタ2号機タイプ0(Rev3,Rev.4)の製作

ブレッドボードから万能基板へポーティングしたついでに、スイッチなどの追加も行い、回路図が少々、変更になった(下回路図)。mbedの省電力試作を適用した結果、消費電流は、50mA弱となってます。DCDCコンバータ回路と、GM管周辺回路は、Rev.0-Rev.1と同じ。

11092101

この回路変更に伴いエンハンスしたソフトウェアは以下になりました。また、RTCへの日時設定も、オンボードのスイッチで行えるようにエンハンスしました。


// GM Counter firmware made by H. Inomata, (C) 2011
#include "mbed.h"
#include "string.h"
#include "SDFileSystem.h"
#include "PowerControl/PowerControl.h"
#include "EthernetPowerControl.h"
#include "ClockControl.h"
#include "TextLCD.h"

DigitalOut cntRst(p15);
DigitalOut pw400V(p16);

DigitalOut ledActive(p18);
DigitalOut ledEject(p19);

DigitalOut LCD_wr(p27);

InterruptIn intrQ01(p11);
InterruptIn intrQ04(p12);
InterruptIn intrQ08(p13);
InterruptIn intrQ12(p14);
DigitalOut rstCNT(p15);

InterruptIn swAdjust(p28);
DigitalIn swSd(p29);

InterruptIn swEject(p30);
InterruptIn swUp(p9); //
InterruptIn swDown(p10);

struct tm adjTm;

Serial pc(USBTX, USBRX); // tx, rx

SDFileSystem sd(p5,p6,p7,p8, "gm");

TextLCD lcd( p26, p25, p24, p23, p22, p21, TextLCD::LCD20x4 ); // rs, e, d4, d5, d6, d7

time_t seconds_prev;
time_t seconds_begin;
int need_mark = 0;
Timer myTimer;
Ticker myTicker;

void nrm_handler_intrQ04 (void);
void handler_swAdjust (void);
void nrm_handler_swEject (void);
void handler_ticker (void);

void adj_handler_swEject(void);  // input
void adj_handler_swUp(void);
void adj_handler_swDown(void);

void nrm_set_intr_handlers(void);
void adj_set_intr_handlers(void);

int statDetect;
int statEject;
int statAdjust; // 1: Year, 2: Month, 3: Day,
                // 4: Hour, 5: Min


#define USR_POWERDOWN    (0x104)
int semihost_powerdown() {
    uint32_t arg;
    return __semihost(USR_POWERDOWN, &arg); 
}

class Watchdog {
public:
 void kick(float s) {
     LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
     uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4 
     LPC_WDT->WDTC = s * (float)clk;         
     LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset        
     kick();
 }
 
 void kick() {
     LPC_WDT->WDFEED = 0xAA;
     LPC_WDT->WDFEED = 0x55;
 }
};

Watchdog w;

void updateLEDs(void) {
    if (statDetect || statEject || statAdjust ) {
        ledActive = 1;
    } else {
        ledActive = 0;
    }
    if (statEject) {
        ledEject = 1;
    } else {
        ledEject = 0;
    }
}

int main() {
    LCD_wr = 0;
    statDetect = 0;
    statEject = 0;
    statAdjust = 0;

    updateLEDs();

    need_mark = 0;
    
    lcd.cls();
    lcd.printf( "      d(^_^)b      ");
    lcd.locate(0,1);
    lcd.printf( "A GM Counter goes, " );
    lcd.locate(0,2);
    lcd.printf( " designed by Digi-P");
    lcd.locate(0,3);
    lcd.printf( "      (C)2011      ");

    
    setSystemFrequency( 0x3, 0x1, 6, 1 );    // need a change to 4800bps
    PHY_PowerDown();
    
    Peripheral_PowerDown(
        LPC1768_PCONP_PCADC |
//        LPC1768_PCONP_PCUART0 |
        LPC1768_PCONP_PCUART1 |
        LPC1768_PCONP_PCUART2 |
        LPC1768_PCONP_PCUART3 |
//        LPC1768_PCONP_PCSSP0 |
//        LPC1768_PCONP_PCSSP1 |
        LPC1768_PCONP_PCCAN1 |
        LPC1768_PCONP_PCCAN2 |
        LPC1768_PCONP_PCENET |
        LPC1768_PCONP_PCUSB |
//      LPC1768_PCONP_PCI2C0 |
        LPC1768_PCONP_PCI2C1 |
        LPC1768_PCONP_PCI2C2 |
        LPC1768_PCONP_PCPWM1 |
        LPC1768_PCONP_PCMCPWM
    );
    
    semihost_powerdown();
    
    w.kick(180.0);
    seconds_begin = seconds_prev = time(NULL);
        
    myTimer.reset();
    myTimer.start();

    nrm_set_intr_handlers();

    myTicker.attach( &handler_ticker, 60.0);
    
    rstCNT = 0; // go counter
    pc.printf( "\rBegin Geiger Counter!\n" );

 
    while(1) {
        Sleep();
//        DeepSleep();
    }
    
}

void nrm_set_intr_handlers(void)
{
    swAdjust.fall( handler_swAdjust );
    swEject.fall( nrm_handler_swEject );
    intrQ04.fall( nrm_handler_intrQ04 );
    swUp.fall( NULL );
    swUp.fall( NULL );
}

void adj_set_intr_handlers(void)
{
    swAdjust.fall( handler_swAdjust );
    swEject.fall( adj_handler_swEject );
    swUp.fall( adj_handler_swUp );
    swDown.fall( adj_handler_swDown );
    intrQ04.fall( NULL );
}


void handler_ticker (void) {
    time_t seconds = time(NULL);
    struct tm *tc = localtime( &seconds );        
    int min = tc->tm_min;
    pc.printf( "\r--- %d --- \n", min );
    if ( (min % 10) == 0 ) {
        need_mark = 1;
    }
}

void nrm_handler_intrQ04 (void) {

    FILE *fp;
    time_t seconds;
    struct tm *tc;
    int myYear, myMon, myDay;
    int myHour, myMin, mySec;
    char fName[256];
    int diff_msec;
    float cpm;
    statDetect = 1;
    diff_msec = myTimer.read_ms();
    myTimer.reset();
    seconds = time(NULL);
    seconds_prev = seconds;
    tc = localtime( &seconds );
    myYear = tc->tm_year;
    myMon = tc->tm_mon;
    myDay = tc->tm_mday;
    myHour = tc->tm_hour;
    myMin = tc->tm_min;
    mySec = tc->tm_sec;

    updateLEDs();
    
    if (1)
//    if (need_mark == 1)
    {
        need_mark = 0; 
        
           
        if ( (swSd == 0) && (statEject == 0) ) {
            SDFileSystem sd(p5,p6,p7,p8, "gm");
            sprintf( fName, "/gm/%04d%02d%02d.csv", myYear+1900, myMon+1, myDay ); 
            fp = fopen ( fName, "a" );
//            fp = fopen ( "/gm/test.txt", "a" );
            if (fp != NULL ){
                       
                fprintf( fp , "%04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d\n",
                    myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
                    seconds, diff_msec, (16*60*1000*10)/(diff_msec)  );
                fclose( fp );
                pc.printf( "\r%04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d ",
                    myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
                    seconds,  diff_msec,  (16*60*1000*10)/(diff_msec) );
                lcd.cls();
                lcd.printf(  "GM Counter works ..." );
                lcd.locate(0,1);
                cpm = (16.0*60.0*1000.0)/(diff_msec);
                lcd.printf( " %8.2f CPM (L)", cpm );                
                lcd.locate(0,2);
                lcd.printf( "  %7d sec passed", seconds - seconds_begin);
                lcd.locate(0,3);
                lcd.printf(" %04d/%02d/%02d (%02d:%02d)",
                    myYear+1900, myMon+1, myDay, myHour, myMin );

            } else {
                pc.printf( "\rcan't open sd " );
                lcd.cls();
                lcd.printf( "GM Counter works ..." );
                lcd.locate(0,1);
                lcd.printf("can't open sd-mem!");
            }
        } else {
            pc.printf( "\rnone of sd or skip writeing it " );
            lcd.cls();
            lcd.printf( "GM Counter works ..." );
            lcd.locate(0,1);
            lcd.printf("skip to log it!");
            if ( (swSd != 0) && (statEject != 0) ) statEject = 0;
        }
    } else {
        pc.printf( "\rskip - %04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d ",
            myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
            seconds, diff_msec, (16*60*1000*10)/(diff_msec) );
            
        lcd.cls();
        lcd.printf(  "GM Counter works ..." );
        lcd.locate(0,1);
        cpm = (16.0*60.0*1000.0)/(diff_msec);
        lcd.printf( " %8.2f CPM (_)", cpm );                
        lcd.locate(0,2);
        lcd.printf( "  %7d sec passed", seconds - seconds_begin);
        lcd.locate(0,3);
        lcd.printf(" %04d/%02d/%02d (%02d:%02d)",
            myYear+1900, myMon+1, myDay, myHour, myMin );
    }
    if ( statAdjust != 0 ) {
        pc.printf( "- sw H - " );
    } else {
        pc.printf( "- sw L - " );
    }
    if ( statEject != 0 ) {
        pc.printf( "- ej H - " );
    } else {
        pc.printf( "- ej L - " );
    }
    if ( swSd != 0 ) {
        pc.printf( "- sd H - \n" );
    } else {
        pc.printf( "- sd L - \n" );
    }
    statDetect = 0;
    updateLEDs();
    w.kick();
}

void handler_swAdjust (void) {
    rstCNT = 1;
    adj_set_intr_handlers();
    
    statAdjust = 1;
    updateLEDs();
    time_t curTime = time(NULL);
    struct tm *curTm;
    curTm = localtime( &curTime );
    adjTm.tm_year = curTm->tm_year;
    if ( (adjTm.tm_year + 1900) < 2011 ) {
        adjTm.tm_year = (2011 - 1900);
    }
    adjTm.tm_mon = curTm->tm_mon;
    adjTm.tm_mday = curTm->tm_mday;
    adjTm.tm_hour = curTm->tm_hour;
    adjTm.tm_min = curTm->tm_min;
    adjTm.tm_sec = 0; // default
    lcd.cls();
    lcd.printf( "Input : Year (U/D)\n" );
    lcd.printf( " %04d/%02d/%02d %02d:%02d\n",
        adjTm.tm_year + 1900,
        adjTm.tm_mon + 1,
        adjTm.tm_mday,
        adjTm.tm_hour,
        adjTm.tm_min
    );
}

void adj_handler_swEject(void) { // to next
    time_t newTime;
    lcd.cls();
    switch( statAdjust++ ) {
    case 1: // set year
        lcd.printf( "Input : Month (U/D)\n" );
        break;
    case 2: // set month
        lcd.printf( "Input : Day (U/D)\n" );
        break;
    case 3: // set day
        lcd.printf( "Input : Hour (U/D)\n" );
        break;
    case 4: // set hour
        lcd.printf( "Input : Min (U/D)\n" );
        break;
    case 5: // set min
        newTime = mktime( &adjTm );
        set_time( newTime );
        statAdjust = 0;
        nrm_set_intr_handlers();
        rstCNT = 0; // go couting
        updateLEDs();
        lcd.printf( "set to RTC:\n" );
        if (statEject == 1) {
            lcd.printf( " You can eject a SD!\n" );
        } else {
            lcd.printf( " waiting for a one!\n" );
        }
        break;
    default:
        ;
    }
    lcd.printf( " %04d/%02d/%02d %02d:%02d\n",
        adjTm.tm_year + 1900,
        adjTm.tm_mon + 1,
        adjTm.tm_mday,
        adjTm.tm_hour,
        adjTm.tm_min
    );    
}


void adjTimeValue( int val )
{
    lcd.cls();
    switch( statAdjust ) {
    case 1: // year
        adjTm.tm_year += val;
        if ( (adjTm.tm_year + 1900) < 2011 ) adjTm.tm_year = (2011 - 1900);
        if ( (adjTm.tm_year + 1900) > 2021 ) adjTm.tm_year = (2021 - 1900);
        lcd.printf( "Input : Year (U/D)\n" );
        break;
    case 2: // month
        adjTm.tm_mon += val;
        if (adjTm.tm_mon < 0 ) adjTm.tm_mon = 11;
        if (adjTm.tm_mon > 11) adjTm.tm_mon = 0;
        lcd.printf( "Input : Month (U/D)\n" );
        break;
    case 3: // Day
        adjTm.tm_mday += val;
        if (adjTm.tm_mday < 1 ) adjTm.tm_mday = 31;
        if (adjTm.tm_mday > 31 ) adjTm.tm_mday = 1;        
        lcd.printf( "Input : Day (U/D)\n" );
        break;
    case 4: // Hour
        adjTm.tm_hour += val;
        if ( adjTm.tm_hour < 0 ) adjTm.tm_hour = 23;
        if ( adjTm.tm_hour > 23 ) adjTm.tm_hour = 0;
        lcd.printf( "Input : Hour (U/D)\n" );
        break;
    case 5: // Min
        adjTm.tm_min += val;
        if ( adjTm.tm_min < 0 ) adjTm.tm_min = 59;
        if ( adjTm.tm_min > 59 ) adjTm.tm_min = 0;
        lcd.printf( "Input : Min (U/D)\n" );
        break;
    default:
        lcd.printf( "Input: Error (NOP)\n" );
    }
    lcd.printf( " %04d/%02d/%02d %02d:%02d\n",
        adjTm.tm_year + 1900,
        adjTm.tm_mon + 1,
        adjTm.tm_mday,
        adjTm.tm_hour,
        adjTm.tm_min
    );
}

void adj_handler_swUp(void) {
    adjTimeValue( 1 );
}

void adj_handler_swDown(void) {
    adjTimeValue( -1 );
}


void nrm_handler_swEject (void) {
    lcd.cls();    
    if (statEject == 1) {
        statEject = 0;
        lcd.printf( "GM Counter works,...\n" );
        lcd.printf( " waiting for a one.\n");
    } else {
        statEject = 1;
        lcd.printf( "You can eject a SD!\n" );
    }
    updateLEDs();
}

こんな感じ。一応、回路図並びにソフトウェアのAS-ISは、営利目的/非営利目的に関わらず無償利用&無保証で使用許諾します。全ての著作権並びに、翻案権は、作者に帰属します。

注)本記事の内容は、製作物そのものの品質、安全性/信頼性を保証するものではないことにご注意下さい。


【動作テスト例1】 (上越新幹線の往復にて)

11100101_2 11100102

 


【動作テスト例2】 (総武本線の往復にて)

11100801 11100802

注)GPSのグラフは、別の装置で測位したもの。


【定電圧機能追加時の回路(Rev.4)】

電池など電源電圧の変動が大きい場合は、昇圧回路の出力を一定に保つ定電圧回路の追加が必要になる。下回路は、定電圧回路を追加した昇圧回路。mbed側は、上記と同じ。
11101003 ご参考、

| | コメント (0) | トラックバック (0)

2011.07.26

自作ガイガーカウンタ2号機タイプ0(Rev.0, Rev1)の製作

バッテリ駆動を前提に、自作DCDCコンバータを使うタイプ0のプロトタイプ(Rev.0)が、一応、完成。これは、GM管のパルスの計数を、mbed NXP LPC1768を使用して、SDメモリへCSVファイルとして、記録するロガーとして動作する。プロトタイプなので、ブレッドボードで作って、適当な容器に、全部、突っ込んでみた(^_^;A

11072504 11072505

回路図は、以下になる。

11071806
--- 全体 ---
11071307
--- GM管部 ---

11071302
--- DCDCコンバータ部 ---

 こんな感じで、回路自身は、それほど複雑でもない。mbed組込マイコンが、複雑な部分を吸収している。自作DCDCコンバータも、入手が困難な特殊なトランスを使わず、一般的なチョークコイルで、済むようにした。これで、是非とも、レンズ付きフィルムを壊して、ストロボ回路を取り出したりせず、本来のカメラとして使用して欲しい。
 さて、mbed NXP LPC1768のプログラムは、以下になる。これは、あくまでも、上記の回路の動作テストの為に開示するもので、各人が自分のオリジナリティを発揮して欲しいところでもある。注意としては、下記プログラムでは、オートレンジの機能を入れていないので、1秒間で、16カウントを超える場合、正確な測定はできません。


// Geiger Counter firmware for mbed NXP LPC 1768
// AS-IS is freeware, non-supported and non-warranty, (C) 2011, digiponta 
//
#include "mbed.h"
#include "string.h"
#include "SDFileSystem.h"
#include "PowerControl/PowerControl.h"
#include "EthernetPowerControl.h"
#include "ClockControl.h"

DigitalOut ledActive(p27);
DigitalOut cntRst(p15);
DigitalOut pw400V(p16);
DigitalOut ledEject(p18);

InterruptIn intrQ01(p11);
InterruptIn intrQ04(p12);
InterruptIn intrQ08(p13);
InterruptIn intrQ12(p14);

InterruptIn swAdjust(p28);
InterruptIn swEject(p17);

DigitalIn swSd(p29);
Serial pc(USBTX, USBRX); // tx, rx

SDFileSystem sd(p5,p6,p7,p8, "gm");

time_t seconds_prev;
int need_mark = 0;

void handler_intrQ04 (void);
void handler_swAdjust (void);
void handler_swEject (void);

int statDetect;
int statEject;
int statAdjust;

void updateLEDs(void) {
    if (statDetect || statEject || statAdjust ) {
        ledActive = 1;
    } else {
        ledActive = 0;
    }
    if (statEject) {
        ledEject = 1;
    } else {
        ledEject = 0;
    }
}

int main() {
    struct tm *tc;
    int min;
    time_t seconds;

    statDetect = 0;
    statEject = 0;
    statAdjust = 0;

    updateLEDs();

    need_mark = 0;
//    setSystemFrequency( 0x3, 0x1, 6, 1 );    
    PHY_PowerDown();
    
    Peripheral_PowerDown(
        LPC1768_PCONP_PCADC |
//        LPC1768_PCONP_PCUART0 |
        LPC1768_PCONP_PCUART1 |
        LPC1768_PCONP_PCUART2 |
        LPC1768_PCONP_PCUART3 |
//        LPC1768_PCONP_PCSSP0 |
//        LPC1768_PCONP_PCSSP1 |
        LPC1768_PCONP_PCCAN1 |
        LPC1768_PCONP_PCCAN2 |
        LPC1768_PCONP_PCENET |
        LPC1768_PCONP_PCUSB |
//      LPC1768_PCONP_PCI2C0 |
        LPC1768_PCONP_PCI2C1 |
        LPC1768_PCONP_PCI2C2 |
        LPC1768_PCONP_PCPWM1 |
        LPC1768_PCONP_PCMCPWM
    );
    
    seconds_prev = time(NULL);
    
    intrQ04.fall( handler_intrQ04 );
    swAdjust.fall( handler_swAdjust );
    swEject.fall( handler_swEject );
    
    pc.printf( "\rBegin Geiger Couter!\n" );
    
    while(1) {
        wait( 60 );
        seconds = time(NULL);
        tc = localtime( &seconds );        
        min = tc->tm_min;
        pc.printf( "\r--- %d --- \n", min );
        if ( (min % 10) == 0 ) {
            need_mark = 1;
        }
    }
}

void handler_intrQ04 (void) {

    FILE *fp;
    time_t seconds;
    int diff;
    struct tm *tc;
    int myYear, myMon, myDay;
    int myHour, myMin, mySec;
    char fName[256];

    statDetect = 1;
    
    seconds = time(NULL);
    diff =   seconds - seconds_prev;
    seconds_prev = seconds;
    tc = localtime( &seconds );
    myYear = tc->tm_year;
    myMon = tc->tm_mon;
    myDay = tc->tm_mday;
    myHour = tc->tm_hour;
    myMin = tc->tm_min;
    mySec = tc->tm_sec;

    updateLEDs();
    if (1)
//  if (need_mark == 1)
    {
        need_mark = 0; 
        
        if ( (swSd == 0) && (statEject == 0) ) {
            SDFileSystem sd(p5,p6,p7,p8, "gm");
            sprintf( fName, "/gm/%04d%02d%02d.csv", myYear+1900, myMon+1, myDay ); 
            fp = fopen ( fName, "a" );
            if (fp != NULL ){
                       
                fprintf( fp , "%04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d\n",
                    myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
                    seconds, diff, (16*600)/(diff)  );
                fclose( fp );
                pc.printf( "\r%04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d ",
                    myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
                    seconds, diff, (16*600)/(diff) );
            } else {
                pc.printf( "\rcan't open sd " );
            }
        } else {
            pc.printf( "\rnone of sd or skip writeing it " );
            if ( (swSd != 0) && (statEject != 0) ) statEject = 0;
        }
    } else {
        pc.printf( "\rskip - %04d/%02d/%02d %02d:%02d:%02d, %d, %d, %d ",
            myYear+1900, myMon+1, myDay, myHour, myMin, mySec,
            seconds, diff, (16*600)/(diff) );

    }
    if ( statAdjust != 0 ) {
        pc.printf( "- sw H - " );
    } else {
        pc.printf( "- sw L - " );
    }
    if ( statEject != 0 ) {
        pc.printf( "- ej H - " );
    } else {
        pc.printf( "- ej L - " );
    }
    if ( swSd != 0 ) {
        pc.printf( "- sd H - \n" );
    } else {
        pc.printf( "- sd L - \n" );
    }
    statDetect = 0;
    updateLEDs();
}

void handler_swAdjust (void) {
    char cc;
    int val;
    struct tm t;
   
    statAdjust = 1;    
    updateLEDs();
   
    pc.printf( "\rPlease, set date and time.\n" );
    while(1) {
        val = 0;
        pc.printf( "\rYear: " );
        if (scanf( "%d", &val ) < 1) {
            goto MY_EXIT;
        }
        pc.printf( "Year = %d\n", val );
        t.tm_year = val - 1900;
        
        pc.printf( "\rMonth: " );
        if (scanf( "%d", &val ) < 1) {
            goto MY_EXIT;
        }
        pc.printf( "Month = %d\n", val );
        t.tm_mon = val - 1;
        
        pc.printf( "\rDay: " );
        if (scanf( "%d", &val ) < 1) {
            goto MY_EXIT;
        }
        pc.printf( "Day = %d\n", val );
        t.tm_mday = val;
    
        pc.printf( "\rHour: " );
        if (scanf( "%d", &val ) < 1) {
            goto MY_EXIT;
        }
        pc.printf( "Hour = %d\n", val );
        t.tm_hour = val;
        
        pc.printf( "\rMin: " );
        if (scanf( "%d", &val ) < 1) {
            goto MY_EXIT;
        }
        pc.printf( "Min = %d\n", val );
        t.tm_min = val;
        
        t.tm_sec = 0;
        
        pc.printf( "\rSet %04d/%02d/%02d %02d:%02d:00 to RTC? (y/n/c)\n", 
            t.tm_year + 1900,
            t.tm_mon + 1,
            t.tm_mday,
            t.tm_hour,
            t.tm_min
        );
        while(1) {
            if ( scanf( "%c", &cc ) < 1 ) {
                goto MY_EXIT;
            }
            if ( cc == 'y' ) {
                time_t seconds = mktime( &t );
                pc.printf( "\rseconds = %d \n" , seconds );
                set_time ( seconds );    
                goto MY_EXIT;
            }
            if ( cc == 'c' ) {
                goto MY_EXIT;
            }
            if ( cc == 'n' ) break;
        }
    }
MY_EXIT:
    statAdjust = 0;
    updateLEDs();
}

void handler_swEject (void) {
    if (statEject == 1) {
        statEject = 0;    
    } else {
        statEject = 1;
    }
    updateLEDs();
}

こんな感じ。ハードウェアで作ると複雑だが、プログラムにすれば、それほど複雑にもならないことが、何とも、相乗効果的な容易さが発揮されている。
 さて、動作テストは、下記のグラフのようになった。線源としては、少々、相性が悪いラジュウム温泉素(主にα線源)だが、接近させてみた。

11072507 11072506

 こんな感じで、SDメモリへ書き込まれたCSVファイルを開いてみると、線源をGM管へ密着させた期間、それなりにカウントCPM値が上がっていることを確認した。

 後は、消費電流に関して、以上の回路とmbedのプログラムでは、105mA前後の消費電流を実測している。今回、エネループ・モバイルブースタ(実質2000mh)を電源に使っているが、これだと、20h前後しかもたないことになる。自作DCDDコンバータの消費電流が、3.5mA前後であるので、大部分が、mbedで消費されている。
 mbedで紹介されている省電力試作を幾つか試してみた結果、上記に合わせ、更に、CPUクロックダウン(2分の1)と、プログラミング用USB機能の電源停止を組み合わせると、消費電流が、55mA前後になることを実測した。ここまで下がると、36h(1.5日間)はもつ計算になる。


【2分の1へクロックダウン】
 上記プログラムのsetSystemFrequency( 0x3, 0x1, 6, 1 );のクロック周波数ダウン(2分の1)を有効にした場合は、mbedとパソコンのシリアル通信設定を、9600bpsから4800bpsへ変更する必要がある。変更しないと、文字化けする。これで、多分、エネループ・モバイルブースタで、24h前後、もつようになる計算。

【プログラミング用USB機能の電源停止】
 ファームウェアmbedMicrocontroller_ExperimentalPowerdown.ifを適用して、
main関数の頭で、semihost_powerdownで、プログラミング用USBの電源を落とすと、消費電流は、クロックダウンの削減効果と合わせて、55mA前後になった。SDメモリへのデータの書き込みも正常動作しているようだ。これで、エネループ・モバイルブースタで、36h(1.5日間)もつようになる計算

【sleepの適用】
 mbedのsleepを使用するように、プログラム修正すると、55mAの消費電流が、50mAまで下がった。sleepは、任意の割り込みで戻ってくる ので、whileループで囲っておく必要がある。例: while(1) { sleep() ); } あと、全ての処理は、割り込みかタイマーベースの処理へ変える必要がある。


現在、念のため、動作確認を継続している。最終的には、機能の見直しも含め、ブレッドボードから、通常の電子基板での実装へ移行したい。

あと、学校は夏休みも始まったばかり、中学生レベルでも十分作れそうなので、夏休みの工作にうってつけな感じ。レッツトライ! ただ、ガイガーミュラー管(駆動電圧400V前後)が、現在、海外(例えば、eBay)からの通販でしか買えないので、親御さんの出番だ。

(追記:2011年7月31日) 現時点、少々、殺風景だったので、20x4行のLCDキャラクタ表示器を付けてみている。これも、少々の配線と、プログラム追加でできてしまいました(下画像)。この追加にり、最終的な消費電流は、LEDバックライトなしで、50mAだった。据えおきで済んでいるようだ。

11080101

(追記:2011年8月2日) せっかくロガー機能をメインに製作したものなので、職場の夏休みに入ったタイミングで、自作ガイガーカウンタを持って、東北新幹線に乗って、上野と仙台を往復してきた。測定結果は、下グラフになった。

11080201_3

なお、行き(やまびこ273号)の停車駅は、上野(9:02頃発)→大宮(9:21)→宇都宮(9:46)→郡山(10:13)→福島(10:27)→仙台(10:56)で、帰り(新幹線はやて160号 )の停車駅が、仙台(11:48頃発)→大宮(13:10)→上野(13:30)と、少々、所要時間が異なっている。
 一応、比較のため、テスト用線源として使用しているランタンマントル(登山用雑貨)を接近させたときに測定グラフも下に示す。

11080204

今回の野外動作テストの測定値のピンポイントピークは、比較すると、テスト用線源の7分の1から5分の1となっている。

(追記:2011年8月15日) だめ押しで、常磐線スーパーひたちで、上野駅といわき駅の間の車内線量も測ってみた。結果は、下グラフ。東北新幹線の時よりは、低い値になっていた。

11081502

いわき駅周辺では、地面の上の測定を頼まれたので、やってみた。2つスパイクの後ろのスパイクになる。このとき、Dose RAE2(γ線のみ)は、0.21μsV/hを表示していた。

11081503

なお、自作ガイガーカウンタは、β線とγ線の両方を検出するので、少なくても2倍のカウント値を表示していると思う。


(追記:2011年9月9日) 最近、動作の安定性をはかるため、ブレッドボード上に配線していた回路を、万能基板へと実装を移した(下写真)。

11090901

注)本記事の内容は、製作物そのものの品質、安全性/信頼性を保証するものではないことにご注意下さい。

| | コメント (0) | トラックバック (0)

2011.07.05

自作ガイガーカウンタ2号機タイプ1(Rev.3=最終版)の製作

更に色々、試した結果、電源電圧の振れ幅が、だいぶん大きく、その影響を少なくするために、回路図を見直しました(2011年7月10日)。最新の回路図と実装図は下記となります。

11070205 11070403

こんな感じ。動作確認の結果は下グラフになった。

Gmgraph_20110710

出力パルスに最大値を示す緑色線の振れ幅は、10%程度のおさまっているようだ。


2011年7月5日時点の内容 → 自作ガイガーカウンタの電源に使用している家庭用AC100Vの電圧に、日中、変動が、だいぶんあるようなので、その安定化と、GM管も、J305βγで使うDC400V前後に特化して回路Rev.3へ置き換えることにした。下左画像が、回路図で、右下画像が、実装素となる。現在、長期動作確認中。2号機タイプ1としては、これで最終版とします。

11070203 11070402

今回採用の定電圧ダイオードは、デッドストックながら、1Z390を使用した、これは、200V定電圧ダイオード2本のカスケードや、100V定電圧ダイオードの4本のカスケードでも、同様の動作が得られる。100V定電圧ダイードは、チップ型であれば、現行生産品もあるよだ。 

さて、動作テストは、GM管の駆動電圧は、408Vの出力が出ていた。また、GM管のパルス出力は、約40mVと、Rev.2とだいたい同じ。

11070501 11070502

正常に、パスル出力も出ることを、確認。web公開測定システムへ接続して、テスト用線源(マントル)を接近させてみると、、、、

11070503_2

線源への反応もあるので、このまま、動作テストを継続。

| | コメント (2) | トラックバック (0)

2011.06.23

自作ガイガーカウンタ測定値のWEB公開システムプロト(3)

何とも、iPad/iPhone/iPod Touchでは、Javaアプレットが動作しないということなので、グラフを、JPEG画像ファイルへ出力するJavaアプリを作ってみた。これを、定期 的に実行して、Webサーバへ置いておけば、iPad/iPhone/iPod Touchでも、グラフとして、自作ガイガーカウンタの計測値が見れる。

Gmgraph_20110622
さて、このJavaアプリのシースコードは、下記になります。


import java.awt.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.applet.Applet; 
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.geom.*;
import java.io.IOException;

public class test_img 
{

	public static void main(String args[]){

		int sx=2;
		int sy=3;
		int wx=320;
		int wy=240;
		int sz_x = 410;
		int sz_y = 240;
		int oft_y=0;
		int oft_x=100;

		Date dt = new Date();
		Calendar cal = Calendar.getInstance();

		int myYear = cal.get(Calendar.YEAR);
		int myMon = cal.get(Calendar.MONTH) + 1;
		int myDay = cal.get(Calendar.DATE);

		String myDate;

		BufferedImage myImage = new BufferedImage( sz_x, sz_y, 
			BufferedImage.TYPE_INT_BGR);

		try {
			// 背景画像(410x290)が必要(最初は白地でやって調整して)
			myImage = ImageIO.read(new File("11062008.jpg"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		Graphics2D off = myImage.createGraphics();
		off.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
			RenderingHints.VALUE_ANTIALIAS_ON);

		myDate = "" + myYear;
		if (myMon < 10) {
			myDate = myDate + "0" ;
		}
		myDate = myDate + myMon;
		if (myDay < 10) {
			myDate = myDate + "0" ;
		}
		myDate = myDate + myDay + ".";

		// これは、計測データを取ってくるサイトのホスト名
		// 同じPCで済む処理だけど、WEB経由で取り出してるよ
		String url;    String host = "example.org";
		int port = 80;
		Socket sock;
		BufferedReader sockin;
		BufferedWriter sockout;
		String str;
		int x=30,y=30,h=40,n=3;
		int i=0;
		int j=0;
		int px_cur=0, py_cur=0;
		int px_prv=0, py_prv=0;

		url = "http://" + host +  "/demo/gmdata_" + myDate + "csv";

		System.out.println( url );

		try {
			wx = sx * 24 * 6;
			off.setColor( Color.BLACK );
			off.drawLine(0+oft_x,wy-1+oft_y,
				wx+oft_x,wy-1+oft_y ); // X
			off.drawLine(0+oft_x,wy-10*sy+oft_y,
				wx+oft_x, wy-10*sy+oft_y ); // X

			for (i=0; i<8; i++ ) {
				off.drawLine(0+oft_x,10*i*sy+oft_y,
					wx+oft_x,10*i*sy+oft_y); // X
			}
			off.drawLine(0+oft_x,0+oft_y,
				0+oft_x,wy+oft_y); // Y
			for (i=12; i<(6*24); i+=12 ) {
				off.drawLine(sx*i+oft_x,sy*10+oft_y,
					sx*i+oft_x,wy+oft_y); // Y
			}
			off.drawLine(sx*i+oft_x,0+oft_y,
				sx*i+oft_x,wy+oft_y); // Y

			off.setColor( Color.BLUE );
			off.drawString( "DATE: " + myYear 
				+ "/" + myMon + "/" + myDay, 
				7+oft_x, 15+oft_y );

			sock = new Socket ( host, port );
			sockin = new BufferedReader(
			new InputStreamReader(sock.getInputStream()));
			sockout = new BufferedWriter(
			new OutputStreamWriter(sock.getOutputStream()));

			sockout.write("GET " + url +" HTTP/1.1\r\n");
			sockout.write("Host: " + host + "\r\n");
			sockout.write("Connection: close\r\n");
			sockout.write("\r\n");
			sockout.flush();

			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);
			str = sockin.readLine();
			System.out.println(str);

			int py_sum = 0;

			off.setPaint( Color.red );

			while ((str = sockin.readLine()) != null) {
				System.out.println(str);

				px_cur = j * 1;

				StringTokenizer st = new StringTokenizer(str, ",");
				st.nextToken();
				st.hasMoreTokens();
				py_cur = Integer.valueOf(
					st.nextToken().replaceAll(" ", "" ))*sy;
				py_sum += py_cur;

				off.draw( new Line2D.Double(
					px_prv*sx+oft_x, wy-py_prv+oft_y, 
					px_cur*sx+oft_x, wy-py_cur+oft_y 
				) );

				j++;
				px_prv = px_cur;
				py_prv = py_cur;
			}

			sockout.close();
			sockin.close();
			sock.close();

			int cpm_avg = (py_sum*10) / (j * sy);

			off.setColor( Color.BLUE );
			off.drawString( "J305Beta/Gamma AVG: " 
				+ cpm_avg + "/10 [CPM]", 
				7+oft_x, 28+oft_y );

			} catch (Exception ex) {
				ex.printStackTrace();
			}

			try {
				boolean result 
					= ImageIO.write( myImage, "jpg", 
					new File( "gmgraph_" + myDate + "jpg"));
			} catch( Exception e ) {
				e.printStackTrace();
			}

			System.exit(0);	
	  }
}

こんな感じ。これを、計測プログラムの直後に実行するように、タスクスケージュールしてみた。

11062401_2

この公開は、ここから閲覧できます。

なお、本サイトの提供する情報は、品質、信頼性、安全性などを保証するものではないことを、ご注意ください。

 

| | コメント (0) | トラックバック (0)