[BC19-03]3LEDガジェットPIC12F1822
8ピンマイコンPIC12F1822の全てのI/O ピンを使ったマイコンガジェット。
3つのLEDを光らせ、圧電ブザから音階(っぽく聞こえるもの)を鳴らせる。タクトスイッチと光センサで、接触・非接触インタフェースも使える。
回路図
回路図
実体配線図
実体配線図
使用部品
使用部品
PICマイコン PIC12F1822-I/P 1個
LED φ5mm VF1.9から2.9V 程度 3個
カーボン抵抗器 150Ω(茶緑茶金)3個
カーボン抵抗器100kΩ(茶黒黄金)1個
フォトトランジスタ NJL7502L 1個
タクトスイッチ2PIN 1個
積層セラミックコンデンサ 0.1uF (104) 1個
ブレッドボード EIC-801 1個
圧電サウンダ (13mm) Murata PKM13EPYH4
ジャンパ線(φ0.65mm単線)いくらか
ソースコード例
ソースコード例
/*
* File: pwmled-adc-pwmbuz-12f1822.c
* Author: KAIMU
*
* Created on 2019/11/03
*/
/*
* Input
* RA4/AN3 (PIN2) : photo transistor, bright:0, dark:1
* RA3 (PIN4) : Tact switch , ON:0, OFF:1 , weak pull-up
* Output
* CCP1 (RA2) [PIN5] : Piezo Speaker
* RA0 [PIN7] : LED0 , active High
* RA1 [PIN6] : LED1 , active High
* RA5 [PIN2] : LED2 , active High
*/
#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なし。
// 動作設定その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ポートの定義 (LEDを接続するポートが変わった時はここを変更する)
#define PORT_LED_0 RA0
#define TRISA_LED_0 TRISA0
#define PORT_LED_1 RA1
#define TRISA_LED_1 TRISA1
#define PORT_LED_2 RA5
#define TRISA_LED_2 TRISA5
// Tact Switch のI/Oポートの設定定義
#define PORT_TACT_SW RA3
#define TRISA_TACT_SW TRISA3
#define WPU_TACT_SW WPUA3
// A/D変換用I/Oポートの設定定義
#define PORT_ADC ANSA4
#define TRISA_ADC TRISA4
#define PORT_NO_ADC 3
#define led0on() (PORT_LED_0 = 1)
#define led0off() (PORT_LED_0 = 0)
#define led0() (PORT_LED_0 ^= 1)
#define led1on() (PORT_LED_1 = 1)
#define led1off() (PORT_LED_1 = 0)
#define led1() (PORT_LED_1 ^= 1)
#define led2on() (PORT_LED_2 = 1)
#define led2off() (PORT_LED_2 = 0)
#define led2() (PORT_LED_2 ^= 1)
//#define isswon() ( PORT_TACT_SW == 0 )
#define isswon() ( RA3 == 0 )
void wait(volatile uint32_t 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 = 0b00000000; //ALL digital port
CM1CON0 = 0x00; //Comparator disable
TRISA = 0b00001000; //I/O Direction. RA0-2,4-5 : output, RA3 : Input
//OPTION_REGbits.nWPUEN = 1; //// weak pull-up disable
//WPUA = 0b00000000; // weak pull-up disable
OPTION_REGbits.nWPUEN = 0; //// weak pull-up enable
WPUA = 0b00001000; // weak pull-up 3 enable
LATA = 0b00000000; // PORTA Latch Settings
}
// A/D変換関数
void initAdc(void) {
PORT_ADC = 1; // PORT_ADCで定義されたポートをアナログポートにする。
TRISA_ADC = 1; // A/D変換端子を入力モードにする。
ADCON0 = 0b00000001 | (PORT_NO_ADC << 2); //AD変換を有効化。
ADCON1 = 0b01000000; // 0:(ADFM=0)精度10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを無効化。
}
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;
}
int8_t isdark(void)
// 光センサの出力から、「暗い」かどうか判断する。
// 戻り値; 「暗い」と判断したとき -1
// それ以外 0
{
uint16_t photo; // 光センサの出力値
int8_t result; // 戻り値
uint16_t darkness_threshold = 900; //「暗い」と判断する閾値
photo = getAdc(); // 光センサの出力をA/D変換
if (photo > darkness_threshold) { //「暗い」とき
result = -1;
} else { // 「明るい」とき
result = 0;
}
return result;
}
// PWM (CCP1) 制御関数 (ブザー用PWM)
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;
}
void stopPwm(void) {
CCP1ASE = 1;
TMR2ON = 0;
}
void startPwm(void) {
CCP1ASE = 0;
TMR2ON = 1;
}
void pwmPulseWidth(uint8_t value) {
CCPR1L = value;
}
void pwmPulseFreq(uint8_t value) {
PR2 = value;
}
// LED用PWM関連
volatile int32_t PWMCounter = 0, PWMPeriod = 0, PWMCounterOn2Off = 0; // PWM Control Parameters
volatile int32_t dpwm = 1; // LEDの明るさをPWM制御するためのカウンタの増分
void pwmledoff(void) {
PWMCounter = 0, PWMPeriod = 0, PWMCounterOn2Off = 0; // PWMの設定(消灯)
TMR1ON = 0; // Timer1 Interrupt Disable
TMR1IE = 0; // Timer1 Interrupt Disable
led0off(); //LED0 off
}
void pwmledon(int32_t period) {
PWMCounter = 0;
PWMPeriod = period;
PWMCounterOn2Off = 1; // PWMの設定
TMR1ON = 1; // Timer1 Interrupt Enable
TMR1IE = 1; // Timer1 Interrupt Enable
}
void setpwmledperiod(int32_t period) {
PWMPeriod = period; // PWM周期の設定
}
void initTimer1(void) {
// Initialize TIMER1 to control PWM-LED Flash
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;
}
void intTimer1(void) {
// Timer1割込みのとき実行される関数
// LED0をじわっと点灯
TMR1H = 0xff;
TMR1L = 0x00; // Clear Timer1 counter
if (PWMPeriod > 0) {
if (PWMCounter < PWMCounterOn2Off) {
led0on();
} else {
led0off();
}
PWMCounter++;
if (PWMCounter >= PWMPeriod) {
// PWMの1周期が完了したら、
PWMCounter = 0;
PWMCounterOn2Off += dpwm;
if (PWMCounterOn2Off >= PWMPeriod) {
dpwm = -1; // 徐々に暗くするPWMに変更
} else if (PWMCounterOn2Off <= 0) {
dpwm = 1; // 徐々に明るくするPWMに変更
}
}
} else {
led0off();
}
}
// Timer0 制御関数
volatile uint32_t TimerCounter; // Counter of Timer Interrupt
#define T0UNIT 15UL // TimerCounter at 1 sec.
void initTimer0(void)
//Initialize Timer 0
// count up every 256*256us = 65536us = 65.536ms (clock 4/4=1MHz, prescaler 1:256
// if you want t[s] timer, TimerCount <= t / 0.065536
{
TMR0IF = 0; // interrupt flag clear
TimerCounter = 0; // Timer Interrupt Counter clear
OPTION_REG &= 0b11000000; // Masking Timer0 bits
OPTION_REG |= 0b00010111; // Timer0 Internal clock, Prescaler 1:256
// Timer0 Interrupt occured every 65.536ms
TMR0IE = 1; // enable Timer0 interrupt
GIE = 1; // enable interrupt
}
void waittimeout0(uint32_t timeLimit) {
uint32_t timeLimitCount = timeLimit * T0UNIT; // 時間切れまでのカウント数
TimerCounter = 0; // タイマのリセット。計時開始。
timeLimitCount = T0UNIT * timeLimit;
while (TimerCounter < timeLimitCount) {
//制限時間になるまでの処理
}
}
void starttimer0() {
TimerCounter = 0; // タイマのリセット。計時開始。
}
int8_t istimeout0(uint32_t timeLimit)
//指定時間に達していなければ、0xffを返し、指定時間に達していたら0x0を返す。
{
uint8_t retvalue;
if (TimerCounter < T0UNIT * timeLimit) {
retvalue = 0xff;
} else {
retvalue = 0x00;
}
return retvalue;
}
//割込処理
void initExtInt(void) {
// 外部割込み初期化
IOCAN3 = 1; //Interrupt-On-Change port-A Negative edge (RA3)
IOCIE = 1; //Interrupt-On-Change Interrupt Enable
GIE = 1; //Global Interrput Enable
}
void stopextint(void) {
IOCAN3 = 0; //Interrupt-On-Change port-A Negative edge (RA3) disable
}
void startextint(void) {
IOCAN3 = 1; //Interrupt-On-Change port-A Negative edge (RA3) enable
}
void buz(void) {
pwmPulseFreq(0x50);
pwmPulseWidth(0x20);
startPwm();
wait(2000);
stopPwm();
}
void startbuz(uint8_t freq) {
pwmPulseFreq(freq);
pwmPulseWidth(0x20);
startPwm();
}
void stopbuz(void) {
stopPwm();
}
void initialize(void) {
initIo(); // I/O port初期化
initPwm(); // PWM (CCP1) 初期化
initTimer0(); // Timer0 初期化
initTimer1(); // Timer1 初期化
pwmledoff(); //LEDじわっと点灯の停止
while (isswon()); //タクトスイッチがOFFするまで待つ
initExtInt(); // 外部割込み初期化
initAdc(); // A-D convertor 初期化
stopPwm(); // PWM (CCP1) 無効化
}
////// ここまで、プログラミングのためのデータや関数を定義する /////
// 割込み処理関数
void intRA3(void) {
// RA3変化による外部割込み発生時に処理される
buz(); // ブザを鳴らす
}
void __interrupt() intr(void)
// Interrupt processing function
{
if (INTF == 1) {
INTF = 0;
}
if (TMR0IF == 1) {
TMR0IF = 0; //Clear Timer0 Interrupt flag
TimerCounter++;
}
if (TMR1IF) {
TMR1IF = 0; // Clear Timer1 Interrupt Flag
intTimer1(); // Timer1割込みの処理関数を実行
}
if (IOCAF3 == 1) {
// cleae external interrupt flag
IOCAF3 = 0;
if (isswon()) {
// タクトスイッチがON(LOW)なら割込み処理
// IOCAN3 = 1(立下がりエッジ検出)のとき、立上りエッジを検出してしまうための対策
intRA3(); // RA3変化割込みの処理関数を実行
}
}
}
// 割込み処理関数ここまで
////// この後のmain(void) { から }までの間に、プログラムが書ける。 /////
void main(void) {
initialize(); // マイコン初期化
pwmledoff(); // LED PWM点灯を停止
led0off();
led1off();
led2off(); //LED0,1,2を消す
startbuz(189); //E(ミ)の音
wait(5000);
startbuz(212); //D(レ)の音
wait(5000);
startbuz(232); //C(ド)の音
wait(5000);
stopbuz(); //音を止める
while (1) { //無限ループ。次の}までの間を無限回繰り返す。
if (isdark()) {
// 暗いとき
pwmledon(50); //LED0をじわっと光らせる
starttimer0();
while (istimeout0(10)) {
//10秒間実行
if (!isdark()) break; //明るくなったら抜ける
}
pwmledoff(); //LED0じわっと点灯終了
while (isdark()); // 暗い間待つ
} else {
// 明るいとき
if (isswon()) {
pwmledoff(); //LED0のじわっと点灯を停止
//スイッチONになったら
led0on();
led1on();
led2on(); //LED0,1,2点灯
starttimer0(); // タイマ0計時開始
waittimeout0(5); //5秒待つ
led0on();
led1on();
led2off(); // LED0,1点灯, LED2消灯
buz(); //ブザ鳴らす
starttimer0(); // タイマ0計時開始
while (istimeout0(5)) {
//5秒待つ
if (isdark()) break; //暗くなったらおしまい
}
led0on();
led1off();
led2off(); // LED0点灯, LED1,D2消灯
buz(); //ブザ鳴らす
starttimer0(); // タイマ0計時開始
while (istimeout0(5)) {
//5秒待つ
if (isdark()) break; //暗くなったらおしまい
}
led0off();
led1off();
led2off(); // LED0,1,D2消灯
for (int8_t i = 0; i < 5; i++) {
//5回繰り返す
startbuz(50); //終了音
wait(20000);
stopbuz();
wait(10000);
}
}
}
}
}
////// この上の } より上にプログラムが書ける。 /////