LED2個、圧電スピーカ、タクトスイッチをPIC12F1822に接続した簡単な回路で、マイコン・プラグラミングを基礎から試せる解説書
アイデアとプログラミング次第で、LEDイルミネーション、ラーメンタイマーやオルゴールなどが作れる。
ブレッドボード
PICマイコン PIC12F1822
LED φ5mm (VF=2V程度)2個
炭素皮膜抵抗器 150Ω 2個
タクトスイッチ 2端子 5mmピッチリード
積層セラミックコンデンサ 0.1uF 5mmピッチリード
圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0
電池ボックス(単3形2本用)、バッテリースナップ
ジャンパ線
(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消灯 } }}