[BC19-04] マイコン・プログラミング入門

2-LED, Buzzer , TACT switch PIC12F1822 Platform

LED2個、圧電スピーカ、タクトスイッチをPIC12F1822に接続した簡単な回路で、マイコン・プラグラミングを基礎から試せる解説書

アイデアとプログラミング次第で、LEDイルミネーション、ラーメンタイマーやオルゴールなどが作れる。

使用部品

ブレッドボード

PICマイコン PIC12F1822

LED φ5mm (VF=2V程度)2個

炭素皮膜抵抗器 150Ω 2個

タクトスイッチ 2端子 5mmピッチリード

積層セラミックコンデンサ 0.1uF 5mmピッチリード

圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0

電池ボックス(単3形2本用)、バッテリースナップ

ジャンパ線

回路図


MPLAB XIDEの使い方 PDFファイル

MPLAB XIDE 5.30でのプロジェクト作成手順


mplabxide_how2make_project.pdf

サンプルコード ( XC8 Compiler )


機能: 衝撃を検出すると警報音とLED点灯が10秒間継続するライト


動作:

(1)最初にピッとブザーが鳴り、LED0→LED5の順で3回点滅する。(起動チェック)

(2)異常がないときは、LED5が点灯している。

(3)衝撃を検出するとブザーが鳴り、LED5が消灯してLED0が点灯する。10秒間、ブザー鳴動とLED0の点灯を続けた後、1秒間ブザー鳴動は停止し、LED0が消灯する。

(4) スイッチが押されたときは、ピッピッと2回ブザーが鳴った後、LEDが消灯し、ブザー鳴動も止まる。(緊急停止)その後(2)に戻る。


#include <xc.h>
#include <stdint.h>

#pragma config FOSC     = INTOSC   // 内部クロック使用。
#pragma config WDTE     = OFF      // ウォッチドッグタイマなし。
#pragma config PWRTE    = ON       // 64ms後にプログラム開始。
#pragma config MCLRE    = OFF      // 外部リセットなし。RA3は入力ピン。
#pragma config CP       = OFF      // コード保護なし。
#pragma config CPD      = OFF      // データ保護なし。
#pragma config BOREN    = ON       // 電源電圧低下時のリセットあり。
#pragma config CLKOUTEN = OFF      // クロック出力不可。
#pragma config IESO     = OFF      // 内部外部クロックなし。
#pragma config FCMEN    = OFF      // FCMなし。

#pragma config WRT    = OFF        // 書き込み保護なし。
#pragma config PLLEN  = OFF        // PLLなし。
#pragma config STVREN = ON        //スタックオーバー/アンダーフローでリセット。
#pragma config BORV   = LO         // 電源電圧低下監視閾値はLowモード
#pragma config LVP    = OFF        // 低電圧プログラムなし。

void wait(volatile uint32_t i) {
    while (i-- > 0);
}

void led0on(void) {
    // RA0に接続したLEDを点灯
    RA0 = 1;
}

void led0off(void) {
    // RA0に接続したLEDを消灯
    RA0 = 0;
}

void led5on(void) {
    // RA5に接続したLEDを点灯
    RA5 = 0;
}


void led5off(void) {
    // RA5に接続したLEDを消灯
    RA5 = 1;
}

uint8_t isswon() {
    //スイッチが押されているときに0でない値、スイッチが押されていないときに0を返す。
    return (RA3 ^ 1);
}

void startccp(uint8_t p) {
    ANSA2 = 0; // PORT_ADCで定義されたポートをディジタルポートにする。
    TRISA2 = 0; // RA2を出力モードにする
    PR2 = p; // 音の周期の設定
    CCP1ASE = 0; // CCP1シャットダウンイベントステータスをクリアしてCCP1を実行許可
    TMR2ON = 1; // Timer2を実行許可
}

void stopccp(void) {
    CCP1ASE = 1; // CCP1シャットダウンイベントステータスをセットしてCCP1を実行禁止
    TMR2ON = 0; // Timer2 停止
}


uint32_t TimerCounter; // 時間計測用変数

void waittimeout0(uint32_t t) {
    // t [s]間何もせずに待つ
    TimerCounter = 0; // タイマカウンタのクリア
    while (TimerCounter <= t * 15); // t[s]間待つ
}

uint16_t adc(void)
// A/D変換 戻り値はA/D変換値 0~1023
{
    uint16_t adcv; // A/D変換値を格納する変数を宣言
    stopccp(); //ポートRA2のccpを停止
    ANSA2 = 1; //ポートRN2をアナログポートにする。
    TRISA2 = 1; // A/D変換端子(RA2)を入力モードにする。
    //A/D変換
    wait(10); // 少し待つ
    GO_nDONE = 1; //A/D変換の開始
    while (GO_nDONE); // A/D変換が完了するまで待つ
    adcv = ADRESH << 2 | ADRESL >> 6; // A/D変換で得られた値を変数adcvへ
    return adcv;
}

uint8_t isshock(void) {
    if (adc() > 100) { //衝撃検出時には
        return 0xff; // 0xff(真となる値)を返す
    } else { //衝撃がなければ
        return 0x00; // 0x00(偽となる値)を返す
    }
}

void __interrupt() intr(void)
// 割込み処理関数
{
    if (INTF == 1) { //割込みが発生したことを示すフラグが立ったら、
        INTF = 0; //割込み発生フラグをクリアする。クリアしないと次の割込みが発生しない。
    }
    if (TMR0IF == 1) {
        TMR0IF = 0; // TMR0フラグをクリアする。
        TimerCounter++;
    }
    if (IOCAF3 == 1) { // RA3の変化による割込みが発生したら

        if (isswon()) {//タクトスイッチが押されていれば、立下りと判断
            //(IOCAN3=1によるネガティブエッジ設定がXC8 compiler v2.10では反映されないことへの対応策)
            stopccp(); // ブザーを止める
            for (uint8_t i = 0; i < 2; i++) {
                startccp(150); // 音を鳴らす
                wait(8000);
                stopccp(); //音を止める
                wait(8000);
            }
            led0off(); // LED0を消灯する。
            TimerCounter = 0x0fffffff; // Timerもクリアする
        }
        // RA3の変化による割込みのフラグをクリア。クリアしないと次の割込みが発生しない。
        IOCAF3 = 0;
    }
}

void main(void) {

    // I/Oポートの初期化
    OSCCON = 0b01101010; // PLL disable, 4MHz internal clock
    ANSELA = 0b00000000; //ALL digital port
    TRISA = 0b00001000; //I/O Direction. RA0-2,4-5 : output, RA3 : Input
    OPTION_REGbits.nWPUEN = 0; //ウィークプルアップを有効にする。
    WPUA = 0b00001000; // RA3のウィークプルアップを有効にする。
    LATA = 0b00000000; // PORTA Latch Settings

    // A/D変換の設定
    ANSA2 = 1; // PORT_ADCで定義されたポートをアナログポートにする。
    TRISA2 = 1; // A/D変換端子を入力モードにする。
    ADCON0 = 0b00000001 | (2 << 2); //AD変換(ポートAN2)を有効化。
  ADCON1 = 0b01000000; //0:(ADFM=0)精度10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
    CM1CON0 = 0x00; //コンパレータを無効化。

    //Timer2 をPWM 標準モードに設定
    PR2 = 0; // PWM Period = [(PR2) +1 ]*4*(1/FOSC)*(Timer2 Prescale value)
    T2CON = 0b00000010; // 周波数のプリスケーラ(倍率)を16倍にする
    APFCON &= ~(1 << CCP1SEL); //CCP1 をポート RA2 に割り当てる
    CCP1CON = 0b00001100; //PWM モード: P1A, P1C, P1B, P1D アクティブHigh
    CCPR1L = 64; // PWMデューティ比(CCPR1L:CCP1CON<5:4>)*(1/FOSC)*(TMR2 Prescale Value)

    // タイマ0割込みの設定
    TMR0IF = 0; // タイマ0割込みフラグをクリアする。
    OPTION_REG &= 0b11000000; // ウィークプルアップ設定用の第7,6ビットを保持。
    OPTION_REG |= 0b00010111; // タイマ0のクロックを内部クロックの1/256に
    TMR0IE = 1; // タイマ0割込み許可

    //ポート変化割込みの設定
    IOCAP3 = 0; //ポートRA3がLowからHighに変化(ポジティブエッジ)したときに割込み発生しないよう設定
    IOCAN3 = 1; //ポートRA3がHighからLowに変化(ネガティブエッジ)したときに割込み発生するよう設定
    IOCIE = 1; //ポートが変化したときの割込みを許可
    GIE = 1; //これまで許可したあらゆる割込みを許可

    //ブザー
    startccp(100); // 音を鳴らす
    wait(3000);
    stopccp(); //音を止める

    //最初のLED点滅
    for (uint8_t i = 0; i < 3; i++) {
        led0on();
        led5off();
        wait(5000);
        led0off();
        led5on();
        wait(5000);
    }
    led0off();
    led5off(); // LED全部消灯

    while (1) {

        led5on(); // LED5点灯
        
        if (isshock()) { // 衝撃があったとき
            startccp(100); // 音を鳴らす
            led0on();
            led5off(); // LED0を点灯, LED5は消灯

            waittimeout0(10); //10秒間何もせずに待つ

            led0off(); // LED0消灯
            led5off(); // LED5消灯
        }
    }
}