ジャムびんLEDランタンをつくってみた(2)~マイコンプログラム編~

2023/06/11

PIC 自作

t f B! P L

前回は製作したジャムびんLEDランタンの全体像について紹介しました。今回は、マイコンの設定、プログラム等について紹介していきます。

各ピンの割り当て

使用したマイコンは「PIC12F683」です。各ピンの割り当てはこのようにしました。

マイコンのピン割り当て
     
  • 1ピン:電源入力  
  • 2ピン:(未使用)  
  • 3ピン:アナログ入力  
  • 4ピン:MCLR  
  • 5ピン:デジタル出力(MOSFETをドライブ)  
  • 6ピン:A/D変換用基準電圧入力  
  • 7ピン:(未使用)  
  • 8ピン:GND

基本思想・設定

割り込みは使用せず、すべての処理はメインループにて行っています。

メインループ処理
  • ほとんど処理がないため、低速で構わないので、消費電力を下げるためにクロック(Fosc)を「31kHz」と低く設定しました。
  • 未使用ピンは入力にして、Weak pull upとしました。
  • 4ピンはMCLRとして使う予定はなかったが、デジタル入力と設定しても、(デジタルI/Oとしたときには)内蔵Weak pull upが無効っぽいので、MCLRとしました。一応、外部抵抗(10kΩ)でプルアップしています。
  • ウォッチドックタイマ(WDT)は有効としています。

プリスケーラはタイマ0に使うことにしたので、WDTのタイムアウト時間は、プリスケーラなしでの最大値

WDTタイムアウト時間

としました。WDTのクリア処理は、メインループ内で毎回実行します。

タイマOFF機能

タイマOFF用の時間管理はタイマ0を使うことにしました。本当はタイマ1の方が良いのですが、厳密な時間管理は不要なので、まあいいかと。

タイマ0のクロックを内部クロックとして(31kHz/4=7750Hz)、プリスケーラは256と設定すると、TMR0レジスタは33.024msごとにカウントアップされます。

TMR0レジスタは8bitなので、256カウントでオーバーフローします。今回の設定では、オーバーフローは8.454144sで発生するので、オーバーフローが426回発生したら1h経過と判断できます。

タイマ0設定と1時間計時

TMR0レジスタがオーバーフローしたらT0IFフラグが1となり、割り込みを許可していると、これをトリガに割り込みが発生させることができます。しかし、今回は割り込みを使うほどでもなかったので、メインループでこのフラグ(T0IF)をポーリングでチェックして処理しています。

タイマOFF機能の処理フローチャートはこんな感じです。(メインループ内で処理)

タイマOFF機能の処理フロー

過放電防止機能

製作したLEDランタンでは、昇圧DC/DCコンバータでニッケル水素電池1.2Vを5Vに昇圧して回路を動かています。使用した昇圧DC/DCコンバータボードは入力電圧0.9Vでも動作します。

しかし、ニッケル水素電池の放電終止電圧は1.0Vくらいと言われているので、この1.0Vで回路動作を停止して、ニッケル水素電池の過放電を防止する、というのがこの機能の目的です。

処理としては、A/D変換によってニッケル水素電池の電池電圧を取得して、しきい値(1.0V)を5回連続で下回ったら、電源をラッチしているMOSFETをOFFして回路を停止させます。

また、立ち上げ直後は判定から除外しています。

過放電防止機能の処理フローチャートはこんな感じです。(メインループ内で処理)

過放電防止機能フロー

ソースコード

main.c


/*******************************************************
 NiMH過放電防止&タイマOFF

2023,5/26  Ver.0.00
電気系ものづくりブログ https://www.sonohen.page/

MCU:PIC12F683

Internal OSC Freq:31kHz
GP0:
GP1:Vref
GP2:GPIO(out):電源ラッチ
GP3:MCLR
GP4:AN3:Ni-MH Voltage
GP5:

*********************************************************/

#include <xc.h>

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = ON        // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

/*関数のプロトタイプ宣言*****************/
void Setting(void);
unsigned char ADC8bit(unsigned char);

#define START_UP 150            //起動後、この回数メインループが回るまでは過放電防止判定しない

void main( void ){

unsigned short time_cnt;    
unsigned char Vbat;
unsigned char Low_cnt;
unsigned char MainLoopCnt;

//各種設定
Setting(); 
time_cnt = 0;
Low_cnt = 0;
MainLoopCnt = 0;

GPIObits.GP2 = 1;   //電源ラッチON

//Mainloop
while(1){
    
    if(INTCONbits.T0IF){       //flag check
      //8.454144s毎
      time_cnt++;  
      if(time_cnt >= 426){      //1h=3600s
          GPIObits.GP2 = 0;   //電源ラッチOFF(Auto Power off)
      }
      INTCONbits.T0IF = 0;       //flag clear
    }
    
    if(MainLoopCnt < START_UP){  //電源投入直後は過放電判定しない
        MainLoopCnt++;
    }
    
    Vbat = ADC8bit(3);
    if( (Vbat < 95) && (MainLoopCnt >= START_UP) ){  //(Vbat < 1V)?
        Low_cnt++;
        if(Low_cnt > 4){    //5回連続
           GPIObits.GP2 = 0;   //電源ラッチOFF(過放電防止) 
        }
    }
    else{
        Low_cnt = 0;
    }
    
    CLRWDT();
    
    }
}

setting.c

#include <xc.h>

#define _XTAL_FREQ 31000  //CLK:31kHz

void Setting(void){

OSCCON = 0x00;     // 0000_0000  31kHz
WDTCON = 0x17;     // 0001_0111  プリスケーラ65536, WDT:2.11sくらい?

TMR0 = 0;

OPTION_REG = 0x47; // 0100_0111 GPIOプルアップ、TMR0クロックソースFosc/4、PS=256(TMR0)
    
INTCON =0x00;      // 0000_0000 割り込み不許可
PIE1 = 0x00;
PIR1 = 0x00;

CMCON0 = 0x07;      //0000_0111 Comp OFF
TRISIO = 0x3B;      //0011_1011 GP2:out

ANSEL = 0x3A;       //0011_1010 ADC_clk:Frc, AN3,1:Analog
WPU = 0x21;         //0010_0001 GP5,0 Weak Pull-up
  
ADRESL = 0x00;     // ADC Result Clear
ADRESH = 0x00;
ADCON0 = 0x40;     //データ左詰め、Vref=AN1、
    
}

/*******************************************************/
//内蔵ADCを8bitで使う
//注意:ADFMにてデータを左詰め設定をしておくこと
/*******************************************************/
unsigned char ADC8bit(unsigned char ch){

    ADCON0bits.ADON = 1;    //ADC enable
        
    if(ch<4){
      ADCON0bits.CHS = ch;      //channel set
    }
    else{
      return (0);
    } 
    
    __delay_us(20);  //wait 20us

    ADCON0bits.GO = 1;    //ADC start

    while(ADCON0bits.GO){
    }

    return (ADRESH);
    
}

当ブログはアフィリエイト広告を利用しています。

このブログを検索

最新記事

ブログ運営者:そのへんの誰か


このブログのURL

QooQ