コードに触ると曲が鳴り始める
音楽が流れているときにLEDが点滅する。
(Rev.2で追加)
曲の演奏が停止してから、しばらくするとアラーム音が鳴る。
曲の演奏の開始からアラーム音までは約3分。3分間のタイマとしても使える。
(1)曲の演奏中(2)曲の演奏停止からアラーム鳴動まで(3)アラーム鳴動中
上記の状態で、コードに触ると最初の状態に戻る。(キャンセル機能付き)
ブレッドボード
マイコン Microchip PIC12F1822
カーボン抵抗器 1/4W 150Ω、1/4W 100kΩ
フォトトランジスタ NJL7502L
ジャンパ線 3本
圧電サウンダ (13mm)PKM13EPYH4
LED φ5mm
電池ボックス(単3型×3本用)、バッテリースナップ
Rev. 2 , XC8 compiler用
/*
* File: pwm-touch-timer-12f1822.c
* Author: kaimu
*
* Created on 2015/03/06, 23:28
*/
/*
* Input
* CPS0 [PIN7] : Capasitive Sensing
* Output
* RA5 [PIN2] : LED (1...OFF, 0...ON)
* CCP1 (RA2) [PIN5] : piezo buzzer
*/
#include <xc.h>
#pragma config FOSC = INTOSC // Internal Oscillation
#pragma config WDTE = OFF // Watch dog timer - OFF
#pragma config PWRTE = ON // Power up Timer - ON
#pragma config MCLRE = OFF // Master Clear - OFF , use RA5 as I/O
#pragma config CP = OFF // Program Code protection - OFF
#pragma config CPD = OFF // Data code protection - OFF
#pragma config LVP = OFF // low voltage programming - OFF
#pragma config BOREN = OFF // 4V brown out reset - OFF
#pragma config CLKOUTEN = OFF // Clock out enabel - OFF
#define ledOn() ( RA5 = 0 )
#define ledOff() ( RA5 = 1 )
#define led() ( RA5 ^= 1 )
#define S_STANDBY 0x10
#define S_MELODY 0x20
#define S_TIMER 0x30
#define S_ALARM 0x40
volatile unsigned int STAGE = S_STANDBY;
#define MAX_TIMER_COUNT 2747 // 3min.
//#define MAX_TIMER_COUNT 228 // 15sec.
// count up every 256*256us = 65536us = 65.536ms (clock 4/4=1MHz, prescaler 1:256
// if you want t[s] timer, MAX_TIMER_COUNT = t / 0.065536
void wait(volatile unsigned long t)
// Delay
{
while(t-- > 0) NOP();
}
void initIo(void)
{
//OSCCON = 0b01111010; // PLL disable, 16MHz internal clock
//OSCCON = 0b01100010; // PLL disable, 8MHz internal clock
OSCCON = 0b01101010; // PLL disable, 4MHz internal clock
//OSCCON = 0b01011010; // PLL disable, 1MHz internal clock
//OSCCON = 0b00111010; // PLL disable, 500kHz internal clock
INTEDG = 0; // Interrupt on falling edge of RB0/INT pin
INTE = 1; // External Interrupt Enable
GIE = 1; //Interrupt Enable
ANSELA = 0b00000001; //RA0 Analog port, others digital port
CM1CON0 = 0x00; //Comparator disable
TRISA = 0b00001001; //I/O Direction. RA1-2,4-5 : output, RA0,3 : Input
LATA = 0b00000000; // PORTA Latch Settings
}
void initPwm(void)
{
//Timer2 settings for PWM standard mode
PR2 = 0; // PWM Period = [(PR2) +1 ]*4*(1/FOSC)*(Timer2 Prescale value)
T2CON = 0b00000010; //00 = Prescaler is 1, 01 = Prescaler is 4 10 = Prescaler is 16 11 = Prescaler is 64
APFCON &= ~(1<<CCP1SEL);//CCP1 function is on RA2
//CCP1SEL = 1;//CCP1 function is on RA5
CCP1CON = 0b00001100; //PWM mode: P1A, P1C active-high; P1B, P1D active-high
CCPR1L = 64; // PWM Duty Cycle (CCPR1L:CCP1CON<5:4>)*(1/FOSC)*(TMR2 Prescale Value)
//Start PWM
TMR2 = 0;
TMR2ON = 1;
}
volatile unsigned int CPSV[4]; // Capacitive Sensing parameter Threshold value for CPS0,1,2,3
#define CPSPERIOD 10 // Capacitive sensing Counting period
void initCPSV(void)
// Initialize Touch ON/OFF threshold value to 95% of Initial CPS value
{
volatile unsigned int i;
unsigned int cpsv0;
// CaPacitive Sensing settings
CPSCON0 = 0b00001000; // Oscillator is in Medium Range. Charge/Discharge Current is nominally 1.2uA
// Timer1 settings
T1CON = 0b11000001 ; // TIMER1 clock source is CAPOSC. Prescaler 1:1, TIMER1 ON
TMR1H = 0 ; // Initialize TIMER1
TMR1L = 0 ;
PEIE = 1 ; // Peripheral Interrupt Enable
GIE = 1 ; // General Interrupt Enable
CPSON = 1 ; // CPS module ON
for (i = 0; i <= 3; i++) {
CPSON = 0; // CPS module off
CPSCON1 = i; // CPS channel 0,1,2,3 select.
CPSON = 1; // CPS module on
TMR1H = 0; TMR1L = 0; // Initialize TIMER1
wait(CPSPERIOD);
cpsv0 = (TMR1H<<8) + TMR1L; // Get CPS Counted value
CPSV[i] = (unsigned int)((float)cpsv0 * 0.95); // When pad is touched, under 95% of initial value
}
}
int isTouch(unsigned int padno)
// Touch Sensor using Capacitive Sensing module
// RETURN VALUE:
// 0 : Pad is NOT touched.
// -1 : Pad is TOUCHED.
{
unsigned int v; // CPS module output value
int touched;
CPSON = 0; // CPS module off
if (padno > 3) {
return 0; // Invalid port no
} else {
CPSCON1 = padno; // CPS channel 0,1,2 select.
}
CPSON = 1; // CPS module on
TMR1H = 0; TMR1L = 0; // Initialize TIMER1
wait(CPSPERIOD);
v = (TMR1H<<8) + TMR1L; // Get CPS Counted value
if (v < CPSV[padno]) {
touched = -1;
} else {
touched = 0;
}
return touched;
}
volatile unsigned int TimerCounter;
void initTimer0(void)
//Initialize Timer 0
{
TMR0IF = 0 ; // interrupt flag clear
TimerCounter = 0 ; // Timer Interrupt Counter clear
OPTION_REG = 0b11010111; // Timer0 Internal clock, Prescaler 1:256
// Timer0 Interrupt occured every 65.536ms
TMR0IE = 1 ; // enable Timer0 interrupt
GIE = 1 ; // enable interrupt
}
void interrupt intr(void)
{
if (INTF == 1) {
INTF = 0;
}
if (TMR0IF == 1) {
TMR0IF = 0; //Clear TMR0 Interrupt flag
TimerCounter++;
}
}
void playSound(unsigned char melody)
// Melody format
/*
* (example) 0x12 ... first '1' is 'C', second '2' is length of sound
* first digit : 1 2 3 4 5 6 7 8 0
* sound name : C D E F G A B C rest
*/
{
unsigned int freq[] = {0, 238, 212, 188, 178, 158, 141, 125, 118};
volatile unsigned int oto, nagasa;
oto = (int)(melody & 0xf0)>>4;
nagasa = (int)( melody & 0x0f);
PR2 = freq[oto];wait((long)nagasa * 10000);
}
void main(void)
{
volatile unsigned int i;
// "Fujisan"
const unsigned char melody[]
= { 0x53, 0x51, 0x62, 0x52,
0x32, 0x11, 0x21, 0x32, 0x02,
0x23, 0x51, 0x52, 0x41, 0x31,
0x25, 0x02,
0x53, 0x51, 0x32, 0x12,
0x63, 0x71, 0x82, 0x62,
0x53, 0x61, 0x51, 0x41, 0x31, 0x21,
0x15, 0x02,
0x23, 0x21, 0x22, 0x22,
0x11, 0x21, 0x31, 0x41, 0x52, 0x02,
0x63, 0x71, 0x82, 0x62,
0x55, 0x02,
0x84, 0x62, 0x42,
0x34, 0x62, 0x52,
0x42, 0x32, 0x23, 0x11,
0x15, 0x02,
0x04, 0xff };
//Initialization
initIo();
initPwm();
initCPSV();
initTimer0();
while(1){
switch (STAGE) {
case S_STANDBY:
ledOff();
while(isTouch(0)) led(); // wait for pad untouched
wait(1000);
while ( ! isTouch(0)) ledOff(); // wait for pad touched
ledOn();
TimerCounter = 0;
STAGE = S_MELODY;
while (isTouch(0));
break;
case S_MELODY:
STAGE = S_TIMER; // next stage
// Play Melody
for (i = 0; melody[i] != 0xff; i++) {
playSound( melody[i] );
if (isTouch(0)) {
STAGE = S_STANDBY;
while(isTouch(0)) {
led();
}
break;
}
}
playSound(0x00);
break;
case S_TIMER:
if (TimerCounter > MAX_TIMER_COUNT) {
// Time Out
STAGE = S_ALARM;
}
if (isTouch(0)) {
// Cancel Time counting
STAGE = S_STANDBY;
while(isTouch(0)) {
playSound(0x11); //sound of notice
}
playSound(0x00); // stop sound
}
break;
case S_ALARM:
ledOn();
playSound(0x81);
if (isTouch(0)) {
// Cancel Timer counting
STAGE = S_STANDBY;
}
ledOff();
playSound(0x01); // Stop Sound
if (isTouch(0)) {
STAGE = S_STANDBY;
while(isTouch(0)) {
playSound(0x11); // sound of notice
}
playSound(0x00); // stop sound
}
break;
default:
ledOff();
playSound(0x00); // Stop Sound
} }
}