PIC16F18346の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
電池ケース オルゴール
2020-11-3

すでに作成した、赤外線受信機とオルゴールをまとめ、電池ケースにコンパックトに収納しました。使用した電池ケースは、単3が4本入りケース上部に電源SWが取り付けられている電池ケースです。電池は2本のみ使用し、残り2本のスペースにPIC16F18346、赤外線リモコンセンサー、LED、圧電スピーカーを組み込みました。


 ↓ 電池ケースの裏蓋を外した内部


回路図
電源は乾電池2本で3vが供給されます。ケース内の配線が最短距離になるように、LEDは、RC2,RC3,RC4,RC5 の4端子を使用します。
配膳図には示されていませんが、写真の製品にはICSP用に丸ピンソケットがプログラミングに必要なpinに取り付けられています。
電池ケース
単3、4本入り SW付き電池ケースです。
電池は2本のみ使用し、残り2本の間にある隔壁を取り外し、PIC16F18346、赤外線リモコンセンサー、LED、圧電スピーカーを組み込みます。
電源SWに近い一の電池2本を使用するため、取り外す電池を受ける電極も取り外しますが、電源コードのついている電極はそのまま位置を移動し再利用します。
電池ケースの側面に5mmの穴を5個ドリルであけ、LEDとセンサー受光部を外に出し、部品はシリコンボンドで固定します。
PIC
PIC16F18346を上面をケースに接着し、LED、センサーなどを立体配線しています。
LED
使用部品数を削減するために、抵抗付きLEDを使用します。
電源は3vですが12v用抵抗付きLEDを使用すると丁度良い明るさになります。
圧電スピーカー
PICに重ねて接着してあります。電池ケースの蓋と干渉しないように取り付け高さに注意して作業します。

リモコンボタンの機能割振り

LEDの点滅を制御する「LED」モードとオルゴール曲を演奏する「Song」モードがあります。


入力切換
機能モードを切り替える。
「LED」モード中:ビープ音が2回鳴り「Song」モードに切替え
「Song」モード中:全LEDが2回点滅し「LED」モードに切替え
数字キー
12の点灯パターンまたは12曲の演奏を切り替える。
音量
「Song」モード:音量を増減する。リセット直後は音量最大
「LED」モード:点滅の変化方向を反転する。
チャンネル
「Song」モード:演奏のピッチを変化させる。
「LED」モード:点滅速度を増減する。

プログラム

このプログラムは、main.c,config.c,config.h,gakufu.h,ir.c,ir.h,led.c,led.h,song.c,song.hの10本のファイルから構成されています。スペースの関係で、このページには、main..cのファイルだけ掲載します。他のファイルは、下のアイコンからダウンロードしてください。また、楽譜ファイル(gakufu.h)は、このホームページPIC16F18346のオルゴール項目にあるPCアプリで作成したものと同一の構成です。そのまま、使用することが可能です。PICkit3などですぐに書き込める box_orgel.hex も同梱しています。

Orgel ソースファイル B03_orgel.zip

main.c

/*  File: オルゴール  main.c  8 MHz NCO PWM DSM
 * LED RC2-5 * SP RA4 * Ir RA5
 *
 *     Language: MPLABX XC8
 *     Target: PIC16F18346
 */

// 音が減衰する程度  指定値(ms)で1/16減少
#define EnvelopeConst 50
// 音符と音符の間の無音時間(ms)
#define Silent        30

#include <xc.h>
#include <stdint.h>
#include <stdlib.h>
#include "config.h"
#include "song.h"
#include "led.h"
#include "ir.h"

#define _XTAL_FREQ 8000000

// 共通変数 ************************************************
uint8_t boxMode = mSong;        // 0:Song 1:Steady 2:Flash 3:Randum
uint8_t irState = 0;
uint16_t revdData = 0;

//---------------------- main ------------------------
void main(void) {
    uint16_t code;
    OSCFRQ  = 0b00000110;   // HFOSC  16MHz
    OSCCON1 = 0b01100001;   // HFINT1 DIV 2 = 8MHz
    int_pins();
    int_modules();
    srand(10);              // 乱数初期値
    PEIE = 1;               // 周辺機能割込みの使用許可
    GIE  = 1;               // 全割込みの使用許可

    TMR1IF = 1;             // Gap フラグ セット
    while(1){               // 繰り返しループ ------------------
        if(TMR1IF){                     // Gap 検出で
            irState = leaderStart;      //   Ir受信リセットし
            TMR1IF = 0;                 //   次のIr信号受信まで
            if(boxMode == mSteady){     //   Steady Modeなら
                // ------------         //   ----------
                SLEEP();                //     Sleep
                // ------------         //   ----------
            }
        }
        if(revdData){                   // IR受信した
            code = revdData;
            revdData = 0;
            // ---- 受信データーの処理 -----------------------------------
            if(boxMode){
                switch (code){
                    case 0xC0C8: modeSong(); break; // Key 切換
                    case 0xC084: steady(1); break;  // Key 1 LED1 反転
                    case 0xC044: steady(2); break;  // Key 2 LED2 反転
                    case 0xC0C4: steady(3); break;  // Key 3 LED3 反転
                    case 0xC024: steady(4); break;  // Key 4 LED4 反転
                    case 0xC0A4: steady(0); break;  // Key 5 全消灯
                    case 0xC064: steady(9); break;  // Key 6 全反転
                    case 0xC0E4: flash(0); break;   // Key 7 点滅1
                    case 0xC014: flash(1); break;   // Key 8 点滅2
                    case 0xC094: flash(2); break;   // Key 9 点滅3
                    case 0xC054: flash(3); break;   // Key 10 点滅4
                    case 0xC0D4: flash(4); break;   // Key 11 点滅5
                    case 0xC034: random(); break;   // Key 12 点滅6
                    case 0xC098: speed(inc); break; // Key +
                    case 0xC018: speed(dec); break; // Key ー
                    case 0xC078: dir(0); break;     // Key 大
                    case 0xC0F8: dir(1); break;     // Key 小
                    default:     steady(0);  break; // 他のKey 全消灯
                }
            }else{
                switch (code){
                    case 0xC0C8: modeLED(); break;      // Key 切換
                    case 0xC084: playSong(1); break;    // Key 1 LED1 反転
                    case 0xC044: playSong(2); break;    // Key 2 LED2 反転
                    case 0xC0C4: playSong(3); break;    // Key 3 LED3 反転
                    case 0xC024: playSong(4); break;    // Key 4 LED4 反転
                    case 0xC0A4: playSong(5); break;    // Key 5 全消灯
                    case 0xC064: playSong(6); break;    // Key 6 全反転
                    case 0xC0E4: playSong(7); break;    // Key 7 点滅1
                    case 0xC014: playSong(8); break;    // Key 8 点滅2
                    case 0xC094: playSong(9); break;    // Key 9 点滅3
                    case 0xC054: playSong(10); break;   // Key 10 点滅4
                    case 0xC0D4: playSong(11); break;   // Key 11 点滅5
                    case 0xC034: playSong(12); break;   // Key 12 点滅6
                    default:     LATC = 0;  break;      // 他のKey 全消灯
                }
            }
        }
    }   // while
}

//----------------------割込み処理------------------------
void interrupt isr(void){
    // Ir信号がOnOffした ---------------------------------
    if(IOCIF){              //IRsencerからの割込みを確認
        IOCAF = 0;          // 割込みフラッグをクリア
        irRx();             // 受信処理 ----->
    }
    if(boxMode){            // LED Modeの時だけ
        // Timer0からの割り込み
        if(TMR0IF){
            TMR0IF = 0;
            led_isr();      // 点滅制御 ----->
        }
        if(CCP4IF){         // Randum Mode で
            CCP4IF=0;       //  LEDを50mSで消灯
            TMR5ON = 0;
            if(boxMode == mRandum)LATC=0;
        }
    }
}