超小型ガイガーカウンタ by PIC12F1822

宇都宮

2011年04月03日 18:12


(写真はイメージです。そのままでは動作しない場合もあります。)

ガイガー・ミュラー管が運良く入手できたので超小型ガイガーカウンタを試作してみました。

使用したガイガー・ミュラー管(GM管)は、秋月電子で保安在庫品販売で入手した浜松ホトニクス製の D3372 です。





【回路図】

回路は下記サイトを参考に設計してみました。

 ・ガイガーカウンタの部屋
 ・使い捨てカメラ「写ルンです」の分解
 ・秋月電子「γ/β検出・ポケットガイガーカウンタキット」取説


写真ではコイン電池を使用していますが、電圧が十分でないかも知れません。
動作確認は 3.3Vのスイッチング電源を使用しました。


「写ルンです」から流用した部品
 ・トランス
 ・2次側ダイオード、コンデンサ(223)
 ・1次側スイッチングトランジスタ


【高圧発生回路】


高圧発生に使用したトランスは、参考サイトを元に、「写ルンです」の回路部品を流用しました。
データシートからGM管のプラトー電圧の目標値は650~700Vとしました。
小型化のため電源電圧は3Vのリチウムボタン電池を使用します。
「写ルンです」に使用されているトランスは、参考資料から約1:350 の巻き線比のため、1次側に電圧調整回路を入れて、2次側で700V程度 になるようにしました。



電解コンデンサ(一番大きい部品)には電気が溜まっています。
危険ですので分解には注意が必要です。




分析の結果、「写ルンです」のトランスの配線は下記の通りです。



2次の高圧測定には下記が使えるかもしれません。 次回注文してみたいと思います。
 ・高圧オシロスコープ・プローブ 100:1(250MHz)

また、高圧発生回路は下記基板が使えるかも知れません。値段も350円と手頃です。
 ・aitendo DC-ACインバータ[INV-EF002]


【使用した制御用マイコン】


今回試作した回路では制御に PIC 12F1822マイコンを使用しました。
 ・マイクロチップ 12F1822の参考サイト

このPIC 12F1822は比較的新しく、A/Dコンバータ、USART、EEPROMなどを実装して、価格が80円(秋月電子にて)というコストパフォーマンスが高いマイコンです。

今回は、主にEEPROM機能しか使っていませんが、価格が安いことや、使用方法になれるという点で採用しました。

PIC 12F1822用のCコンパイラは、マイクロチップ社の下記サイトからダウンロード可能です。
Hi-Tech社製で無償版がリリースされています。(Liteモードでインストール)
 ・HI-TECH C for the PIC10/12/16 MCU Family

書き込みは、秋月電子製のライターは未対応のようですので、ICD3経由でデバッグ、書き込みできるボードを作りました。





【ソフトウエア概略仕様】


モード切換え
 ・未定(未使用)


通常動作
 ・更新時間 10秒
 ・放射線検出時 → LED Red点灯 / ブザー x 1回

 ・放射線検出が定常状態 → LED Green 5secおきに点灯
 ・放射線検出がやや多い → LED Green 3secおきに点灯
 ・放射線検出が多い   → LED Green 1secおきに点灯



【ソースコード】


【main.c】

//───────────────────────────────────
//  Includeの定義
//───────────────────────────────────
#include <pic.h>
#include "port.h"
#include "timer.h"
#include "trigger.h"
#include "led.h"

//───────────────────────────────────
//  Define User Memory
//───────────────────────────────────
static unsigned char Timer100ms;
static unsigned char Timer10ms;
static unsigned char Flag10ms;
static unsigned char Flag1ms;

static unsigned char FlagDet = 0;
static unsigned char TimerDet = 0;
static unsigned int CountDet = 0;
static unsigned char TimerBuzz = 0;

//───────────────────────────────────
// Here be interrupt function
// - the name is unimportant.
//───────────────────────────────────
static void interrupt isr(void) 
{
    if( RA1 == 0 )
    {
        FlagDet = 1;        // 放射能検出
    }
    INTF = 0;               // clear the interrupt

    if(T0IF)                // timer interrupt
    {
        Flag1ms = 1;
        if( Timer10ms != 0 )
        {
            Timer10ms --;
        }
        else
        {
            Flag10ms = 1;
            Timer10ms = 9;
        }
        T0IF = 0;           // clear the interrupt flag
    }
}


//───────────────────────────────────
// Main
//───────────────────────────────────
void main(void)
{
    init_port();
    init_trigger();
    init_led();
    init_timer0();
    GIE = 1;            // Enable interrupts
    
    TimerBuzz = 50;

    for(;;){
        // 1msec 処理
        if( Flag1ms )
        {
            Flag1ms = 0;
            trigger_main();
            led_timer_1ms();
            led_main();
        }

        // 10msec 処理
        if( Flag10ms )
        {
            Flag10ms = 0;
            Timer100ms ++;

            if( TimerBuzz == 0 )
            {
                PortBuzzOff;
                PortRedOff;
            }
            else
            {
                PortBuzzOn;
                PortRedOn;
                TimerBuzz --;
            }
            
            if( FlagDet == 1)   // 放射能検出
            {
                FlagDet = 0;
                if( TimerBuzz == 0 )
                {
                    TimerBuzz = 5;
                }
                if( CountDet < 50000 )
                {
                    CountDet ++;
                }
                else
                {
                    led_set_mode(LED_MODE_HIGH);
                }
            }
        }

        // 100msec 処理
        if( Timer100ms >= 10 )
        {
            Timer100ms = 0;
            
            // 10secおきに更新
            TimerDet ++;
            if( TimerDet > 10 )
            {
                if( CountDet > 10 )
                {
                    led_set_mode(LED_MODE_HIGH);
                }
                else
                {
                    if( CountDet > 1 )
                    {
                        led_set_mode(LED_MODE_MIDDLE);
                    }
                    else
                    {
                        led_set_mode(LED_MODE_NORMAL);
                    }   
                }
                CountDet = 0;
                TimerDet = 0;   
            }   
        }
    }
}



【port.c】

#include <pic.h>
#include "port.h"

void init_port(void)
{
    WPUA = 0b00001000;      // Pullup   
    TRISA = 0b00001010;     // 1:入力、0:出力設定
    ANSELA = 0b00000000;    // A/D 禁止
    PORTA = 0b00110001;

    OPTION_REG &= 0b01111111;// Pullup許可
    CLKOUT = 1;         // CLKOUT function is disabled
    
    INTE = 1;
    IOCAN1 = 1;         // INTERRUPT-ON-CHANGE PORTA NEGATIVE EDGE REGISTER
}


【trigger.c】

#include <pic.h>
#include "port.h"
#include "trigger.h"

static char TrgInterval = 0;

//───────────────────────────────────
// initialize trigger
//───────────────────────────────────
void init_trigger(void)
{
    PortTrigOff;
}

//───────────────────────────────────
// Trigger main (2msec)
//───────────────────────────────────
void trigger_main(void)
{
    TrgInterval ++;
    if( TrgInterval >= 40 ) // 40msec (25Hz)
    {
        PortTrigOn;
        TrgInterval = 0;
        PortTrigOff;
    }
}


【led.c】

#include <pic.h>
#include "led.h"
#include "port.h"

static LED_MODE mode = LED_MODE_NORMAL;
static long TimerGreen = 3000;
static char FlagGreen = 0;
 
//───────────────────────────────────
// initialize LED
//───────────────────────────────────
void init_led(void)
{
    PortGrnOff;
    PortRedOff;
}

//───────────────────────────────────
// Set mode
//───────────────────────────────────
void led_set_mode(LED_MODE value)
{
    mode = value;

    FlagGreen = 1;
    TimerGreen = 20;
    PortGrnOn;
}

//───────────────────────────────────
// LED 1msec Timer
//───────────────────────────────────
void led_timer_1ms(void)
{
    if( TimerGreen > 0 )
    {
        TimerGreen --;
    }   
}
    
//───────────────────────────────────
// LED main
//───────────────────────────────────
void led_main(void)
{
    if( TimerGreen == 0 )
    {
        if( FlagGreen == 0 )
        {
            FlagGreen = 1;
            TimerGreen = 20;
            PortGrnOn;
        }
        else
        {
            FlagGreen = 0;
            PortGrnOff;

            switch( mode )
            {
            case LED_MODE_NORMAL:
                TimerGreen = 5000;
                break;
                
            case LED_MODE_MIDDLE:
                TimerGreen = 3000;
                break;
                
            case LED_MODE_HIGH:
                TimerGreen = 1000;
            }
        }   
    }
}


【timer.c】

#include <pic.h>
#include "timer.h"

//───────────────────────────────────
// initialize timer 0 (1msec)
//───────────────────────────────────
void init_timer0(void)
{
    OSCCON = 0b01100010; // PLL Disable / 2MHz Internal clock
    PS2 = 0;            // Clk 1/2
    PS1 = 0;
    PS0 = 0;
    PSA = 0;
    
    TMR0CS = 0;         // select internal clock
    TMR0IE = 1;         // enable timer interrupt
}


【port.h】

#ifndef _PORT_H_
#define _PORT_H_

/**********************************************
    マクロ定義
**********************************************/
#define PortBuzzOn  RA0 = 0
#define PortBuzzOff RA0 = 1

#define PortTrigOn  RA2 = 1
#define PortTrigOff RA2 = 0

#define PortRedOn   RA5 = 0
#define PortRedOff  RA5 = 1

#define PortGrnOn   RA4 = 0
#define PortGrnOff  RA4 = 1

/**********************************************
    外部参照関数
**********************************************/
void init_port(void);

#endif


【led.h】

#ifndef _LED_H_
#define _LED_H_

/**********************************************
    定数/型定義
**********************************************/
typedef enum
{
    LED_MODE_NORMAL,        // 定常状態
    LED_MODE_MIDDLE,        // 中くらい
    LED_MODE_HIGH           // 高い
} LED_MODE;

/**********************************************
    外部参照関数
**********************************************/
void init_led(void);
void led_timer_1ms(void);
void led_main(void);
void led_set_mode(LED_MODE value);

#endif


【timer.h】

#ifndef _TIMER_H_
#define _TIMER_H_

/**********************************************
    外部参照関数
**********************************************/
void init_timer0(void);

#endif


【trigger.h】

#ifndef _TRIGGER_H_
#define _TRIGGER_H_

/**********************************************
    外部参照関数
**********************************************/
void init_trigger(void);
void trigger_main(void);

#endif






【ビルド時の注意点】


MPLABでビルドする際には、「Configuration bits」 ダイアログ(下記)で
CLKIN を I/O に設定しないと RA4 端子が I/O として使用できません。



また、MCLR端子を I/O として使用する場合は MLRE の設定と共に
下記のように LVP を禁止に設定しておく必要があります。



この説明は、ユーザーズマニュアル(50ページ)にも記載されています。

MCLRE: RA3/MCLR/VPP Pin Function Select bit
 If LVP bit = 1:
  This bit is ignored.
 If LVP bit = 0:
  1 = MCLR/VPP pin function is MCLR; Weak pull-up enabled.
  0 = MCLR/VPP pin function is digital input



【HEXコード】


下記URLよりダウンロード可能です。

http://hmmk.co.jp/sample/GM_Counter.hex



【動作検証】


1分間に1回程度検出しているようですが、正常に動作しているか不明です。
回路およびプログラム変更で、1分間に5回程度検出しています。

下記動画は放射能レンズを近づけた実験です。




【その他】


たまたま見かけた「Software Design (ソフトウェア デザイン) 2011年 07月号」にArduinoで作るガイガーカウンタの記事が載っていました。
5ページにわたってわかりやすく書かれていましたし、回路図も載っていました。

関連記事