マイコンで、好きな時間だけLEDが光ったあと警報音が鳴るタイマを作りましょう。
圧電スピーカをコツンと叩くと、LEDが点滅し、決まった時間だけ点滅すると、警報音が鳴ってLEDが消灯します。
マイコン PIC12F1822P
LED
カーボン抵抗器 150Ω, 10kΩ
圧電スピーカ
電池スナップ
電池ボックス(単3電池2本用)
ブレッドボード
/* * File: bc17-06-shock-led-timer-12f1822.c * Author: kaimu * * Created on November 4, 2017, 5:31 PM *//* * LED1 : PIN 2 (RA4) : 1-OFF, 0-ON * Buzzer : PIN 6 (RA1) * ANALOG PORT : PIN 6 (AN1) * */#include <xc.h> // XC8コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む)#include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル// 数値を変更すると機能が調整できる。#define TIME_LIMIT 20 // LEDが点灯している時間(タイマの秒数) #define BEEP_ALARM_COUNT 2 // 警報音の鳴る回数// 上級者用#define LED_BLINK_PERIOD_MIN 50 // LEDが点滅する周期の最小値(20-100)#define BEEP_START_LENGTH 2000 // 起動音の長さ#define BEEP_START_HEIGHT 5 // 起動音の高さ#define BEEP_SHOCK_LENGTH 4000 // ブザーを叩いたときの音の長さ#define BEEP_SHOCK_HEIGHT 2 // ブザーを叩いたときの音の高さ#define BEEP_ALARM_LENGTH_1 4000 // 警報音(最初の音)の長さ#define BEEP_ALARM_HEIGHT_1 8 // 警報音(最初の音)の高さ#define BEEP_ALARM_LENGTH_2 2000 // 警報音(次の音)の長さ#define BEEP_ALARM_HEIGHT_2 16 // 警報音(次の音)の高さ#define SHOCK_THRESHOLD 50 // 衝撃の閾値 (0 ~ 1023)// 調整用設定終了// PICマイコンの動作設定その1// PIC micro controller Configuration 1#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なし。// 動作設定その2// Configuration 2#pragma config WRT = OFF // 書き込み保護なし。#pragma config PLLEN = OFF // PLLなし。#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。#pragma config BORV = LO // 電源電圧低下監視閾値はLowモード#pragma config LVP = OFF // 低電圧プログラムなし。// I/Oポートの初期化void initIo(void){ OSCCON = 0b01110010 ; // Internal clock 8MHz OPTION_REG = 0b00000000 ; // Weak Pull up ON ANSELA = 0b00000000 ; // ALL Digital PORT TRISA = 0b00001000 ; // Input : RA3, Output: others WPUA = 0b00001000 ; // Weak pull-up : RA3 PORTA = 0b00000000 ; // Initialize PORTA}// I/Oポートの定義 (LEDを接続するポートが変わった時はここを変更する)#define PORT_LED RA4#define TRISA_LED TRISA4#define PORT_ADC ANSA1#define PORT_BUZ RA1#define TRISA_BUZ TRISA1#define TRISA_ADC TRISA1#define PORT_NO_ADC 1// LED制御用関数inline static void ledOn(void) { PORT_LED = 0; }
inline static void ledOff(void) { PORT_LED = 1; }
inline static void ledBlink(void) { PORT_LED ^= 1; }
// ちょっと待つ処理を簡単に書くための関数void wait(volatile uint32_t i){ while (i-- > 0);}// A/D変換関数// A/D conversion functionsvoid initAdc(void){ PORT_ADC = 1; // PORT_ADCで定義されたポートをアナログポートにする。Analog port (see PORT_ADC def.) setting TRISA_ADC = 1; // A/D変換端子を入力モードにする。RA1 as input ADCON0 = 0b00000001 | (PORT_NO_ADC << 2); //AD変換を有効化。0:unimp, xxxxx:analog ch, 0:GOnDone, 1:ADC enable ADCON1 = 0b01000000; //0:(ADFM=0)Left justified (10bit res.), 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF CM1CON0 = 0x00; //コンパレータを無効化。Comparator disable}uint16_t getAdc(void)// A/D変換した値を得る。// 戻り値:// A/D 変換されたアナログ信号の大きさ(0〜1023){ uint16_t adcvalue; //ADC wait(10); GO_nDONE = 1; while (GO_nDONE); adcvalue = ADRESH<<2 | ADRESL>>6 ; return adcvalue;}uint16_t getShock(void){ uint16_t adcvalue; TRISA_ADC = 1; // Buzzer Port INPUT mode PORT_ADC = 1; // ADC port as Analog port adcvalue = getAdc(); return adcvalue;}#define T0UNIT 31 // Timer0Counter about 1sec ( 1 / (1 / ((Clock 8MHz / 4) / prescaler 256) * 256)void initTimer0(void)
{ TMR0 = 0x00; // Initialize TIMER0 TMR0CS = 0; //Internal instruction cycle clock (FOSC/4) PSA = 0; //Prescaler is assigned to the Timer0 module PS2 = 1; PS1=1; PS0 = 1; // Prescaler Rate Select bits set 1:256TMR0IE = 1; // Timer0 Intterupt Enable
PEIE = 1; GIE =1;}void initTimer1(void){ // Initialize TIMER1 TMR1CS1 = 0; TMR1CS0 = 0;// Internal clock (Fosc/4)// T1CKPS1 = 1; T1CKPS0 = 1;// prescaler 1:8 T1CKPS1 = 0; T1CKPS0 = 0;// prescaler 1:1 TMR1H = 0xff; TMR1L = 0x00; // Clear Timer1 counter TMR1ON = 1;// Enable Timer1 TMR1IE = 1; // Timer1 Intterupt Enable PEIE = 1; GIE =1; }volatile uint32_t T0Counter; // Timer0 overflow Countervolatile int32_t PWMCounter = 0, PWMPeriod = 0, PWMCounterOn2Off = 0; // PWM Control Parametersvolatile int32_t dpwm = 1; // LEDの明るさをPWM制御するためのカウンタの増分void interrupt isr(void)// When Interrupt caught ...{ if (TMR0IF) { // Timer0 Interruption TMR0IF = 0; // Clear Timer0 Interrupt Flag TMR0 = 0; // Clear Timer1 counter T0Counter++; } if (TMR1IF) { TMR1IF = 0; // Clear Timer0 Interrupt Flag TMR1H = 0xff; TMR1L = 0x00; // Clear Timer1 counter if (PWMPeriod > 0) { if (PWMCounter < PWMCounterOn2Off) { ledOn(); } else { ledOff(); } PWMCounter++; if (PWMCounter >= PWMPeriod) { // PWMの1周期が完了したら、 PWMCounter = 0; PWMCounterOn2Off += dpwm; if (PWMCounterOn2Off >= PWMPeriod) { dpwm = -1; // 徐々に暗くするPWMに変更 } else if (PWMCounterOn2Off <= 0) { dpwm = 1; // 徐々に明るくするPWMに変更 } } } else { ledOff(); } }}void pwmOff(void) { //PWMCounter = 0, PWMPeriod = 0, PWMCounterOn2Off=0; // PWMの設定(消灯) TMR1ON = 0; // Timer1 Intterupt Disable}void pwmOn(int32_t period){ PWMCounter = 0; PWMPeriod = period; PWMCounterOn2Off= 1; // PWMの設定 TMR1ON = 1; // Timer1 Intterupt Enable}void pwmSetPeriod(int32_t period){ PWMPeriod = period; // PWM周期の設定}// ブザー制御用関数inline static void buzToggle(void) { PORT_BUZ ^= 1; }
void beepBuz(uint32_t length, uint32_t height)// ブザを鳴らす// 引数:// length : 音の長さ// height : 音の高さ(小さいほど高い音){ uint16_t i; TRISA_BUZ = 0; // Buzzer Port OUTPUT mode PORT_ADC = 0; // ADC port as Digital port for (i = 0; i < length; i++) { buzToggle(); wait(height); } }void beepAlarm(void)// 決められた時間が経過したときの警報音を鳴らす{ uint8_t i; for (i = 0; i < BEEP_ALARM_COUNT; i++) { beepBuz(BEEP_ALARM_LENGTH_1, BEEP_ALARM_HEIGHT_1); beepBuz(BEEP_ALARM_LENGTH_2, BEEP_ALARM_HEIGHT_2); wait(2000); }}void beepShort(uint8_t n)//引数n回だけブザーを短く鳴らす{ uint8_t i; beepBuz(100, 16); wait(10000); for (i = 0; i < n - 1; i++) { beepBuz(100, 4); wait(10000); }}void waitUntilBuz(void)//ブザーの振動がおさまるまで待つ{ uint8_t silentCounter; // ブザーが振動していない回数 uint16_t adc; for (silentCounter = 0;silentCounter < 10;) { adc = getShock(); if (adc > SHOCK_THRESHOLD) { silentCounter++; } }}void main(void)// メイン関数。この関数から動作開始{ uint16_t adc; // A/D変換の値。A/D converted value int32_t pwmLedBlinkPeriod; // LEDのPWM制御の速度 uint32_t timeLimitCount; // 時間切れまでのカウント数 initIo(); // I/Oポートの初期化 initAdc(); // A/D変換ポートの初期化 initTimer0(); // Timer0の初期化 initTimer1(); // Timer1の初期化 beepBuz(BEEP_START_LENGTH, BEEP_START_HEIGHT); // 起動音を鳴らす pwmOff(); // PWMによるLED点滅を停止 waitUntilBuz(); // ブザーの振動がおさまるまで待つ while (1) { adc = getShock(); if (adc > SHOCK_THRESHOLD) { beepBuz(BEEP_SHOCK_LENGTH, BEEP_SHOCK_HEIGHT); // 衝撃を検出したときの音 //pwmLedBlinkPeriod = LED_BLINK_PERIOD; // 点滅間隔の初期化 pwmLedBlinkPeriod = TIME_LIMIT; // 点滅間隔の初期化 pwmOn(pwmLedBlinkPeriod); // Start PWM (LED点灯) T0Counter = 0;// タイマのリセット。計時開始。 timeLimitCount = T0UNIT * TIME_LIMIT; while (T0Counter < timeLimitCount) { //制限時間になるまでの処理 if (T0Counter % (T0UNIT * 5) == 0) { beepShort((timeLimitCount - T0Counter) / (T0UNIT * 60) + 1);// 残り分数+1の回数だけ音を6秒ごとにならす pwmLedBlinkPeriod -= 5; // LED点滅速度を徐々に速くする if (pwmLedBlinkPeriod <= LED_BLINK_PERIOD_MIN) { pwmLedBlinkPeriod = LED_BLINK_PERIOD_MIN; } // LED点滅速度が速すぎるときは最速に設定 pwmSetPeriod( pwmLedBlinkPeriod ); // LED点滅速度の設定 } } pwmOff();// PWMの設定(消灯) ledOn(); // LEDを点灯する。 beepAlarm(); //警報音を鳴らす。 ledOff(); // LEDを消灯する。 waitUntilBuz(); // ブザーの振動がおさまるまで待つ } } return;}