MPLABX XC8 でPIC16F84Aを使って、今まで勉強したことを応用して、ラーメンタイマー(3分タイマー)を作ってみました。
表示は7セグメントLEDを使い、スタートボタンを押すと3分(3.00表示)から1秒ごとにカウントダウンし、0.00になったら、ピピピ ピピピとブザーを鳴らします。リセットを押すとまた3.00に戻ります。(スタートボタンは、もう一度押すとカウントストップします)
電源は、電池2本(3V)です。
回路図です。
7セグメントLEDは、超高輝度の3桁のものC-533SRを使い、ダイナミック点灯表示です。ダイナミック点灯と1秒カウントのために、TMR0割り込みを利用して、6.5536msごとに割り込みをかけています。
ブレッドボードです。
/*
* PICと7セグメントLEDとの接続
* PIC LED
* RB0 A
* RB1 B
* RB2 C
* RB3 D
* RB4 E
* RB5 F
* RB6 G
* RB7 DP
* RA0 #1
* RA1 #2
* RA2 #3
*
* RA3は、START/STOPスイッチ
* RA4には、BUZZERを接続する。
* RESETは、MCLR
*/
* PICと7セグメントLEDとの接続
* PIC LED
* RB0 A
* RB1 B
* RB2 C
* RB3 D
* RB4 E
* RB5 F
* RB6 G
* RB7 DP
* RA0 #1
* RA1 #2
* RA2 #3
*
* RA3は、START/STOPスイッチ
* RA4には、BUZZERを接続する。
* RESETは、MCLR
*/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 10000000
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled)
#pragma config CP = OFF // Code Protection bit (Code protection disabled)
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled)
#pragma config CP = OFF // Code Protection bit (Code protection disabled)
unsigned char digit = 1;
unsigned char counter = 0;
unsigned char timer_data[3] = {3,0,0}; //3min 00sec
signed char work0,work1,work2;//timer用作業レジスタ
unsigned char val = 1; //input value
unsigned char old_val = 1;
unsigned char state = 0; //swtch's state 0=stop
unsigned char cnt1s = 153;// 6.5536×153 = 1002.7ms
unsigned char T1s = 0;
unsigned char seg_data[10] = {
// gfedcba // data for 7segment LED
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
void interrupt isr(void){
T0IF = 0; // TMR0割り込みクリア
cnt1s --;
if(cnt1s == 0){
cnt1s = 153;//1sカウンタセット
T1s = 1;//1s経過フラッグを立てる
}
digit <<= 1;
counter ++;
if(counter >= 3){
digit = 1;
counter = 0;
}
PORTA =(PORTA & 0xF0) | digit;
if(digit == 1){
PORTB = seg_data[timer_data[counter]] | 0x80;//digit0ならDPを表示
}else{
PORTB = seg_data[timer_data[counter]];
}
}
//BUZZER音 RA4=0でBUZZER ON
void beep(){
while(1){
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(200);
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(200);
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(600);
}
}
unsigned char counter = 0;
unsigned char timer_data[3] = {3,0,0}; //3min 00sec
signed char work0,work1,work2;//timer用作業レジスタ
unsigned char val = 1; //input value
unsigned char old_val = 1;
unsigned char state = 0; //swtch's state 0=stop
unsigned char cnt1s = 153;// 6.5536×153 = 1002.7ms
unsigned char T1s = 0;
unsigned char seg_data[10] = {
// gfedcba // data for 7segment LED
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
void interrupt isr(void){
T0IF = 0; // TMR0割り込みクリア
cnt1s --;
if(cnt1s == 0){
cnt1s = 153;//1sカウンタセット
T1s = 1;//1s経過フラッグを立てる
}
digit <<= 1;
counter ++;
if(counter >= 3){
digit = 1;
counter = 0;
}
PORTA =(PORTA & 0xF0) | digit;
if(digit == 1){
PORTB = seg_data[timer_data[counter]] | 0x80;//digit0ならDPを表示
}else{
PORTB = seg_data[timer_data[counter]];
}
}
//BUZZER音 RA4=0でBUZZER ON
void beep(){
while(1){
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(200);
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(200);
RA4 = 0;//ピ
__delay_ms(200);
RA4 = 1;
__delay_ms(600);
}
}
void main() {
TRISA = 0b00001000; //RA3 INPUT 他OUTPUT
TRISB = 0x00; //PORTB ALL OUTPUT
PORTA = 0x00; //PORTA clear
PORTB = 0x00; //PORTB clear
RA4 = 1;//BUZZER OFF
//TMR0関係のセットアップ
OPTION_REG = 0x85;//prescaler 1:32 interrupt time interval 0.4us×64×256=6.5536ms
TMR0 = 0x00; //TMR0 clear
T0IE = 1; //TMR0 interrupt enable
GIE = 1; //general interrupt enable
while(1){
val = RA3;
if((val == 0 )&&(old_val == 1)){
state = 1 - state;
__delay_ms(20);
}
old_val = val;
if(state){
if(T1s){
T1s = 0;//1sフラッグクリア
work0 = timer_data[0];//min
work1 = timer_data[1];//10sec
work2 = timer_data[2];//sec
TRISA = 0b00001000; //RA3 INPUT 他OUTPUT
TRISB = 0x00; //PORTB ALL OUTPUT
PORTA = 0x00; //PORTA clear
PORTB = 0x00; //PORTB clear
RA4 = 1;//BUZZER OFF
//TMR0関係のセットアップ
OPTION_REG = 0x85;//prescaler 1:32 interrupt time interval 0.4us×64×256=6.5536ms
TMR0 = 0x00; //TMR0 clear
T0IE = 1; //TMR0 interrupt enable
GIE = 1; //general interrupt enable
while(1){
val = RA3;
if((val == 0 )&&(old_val == 1)){
state = 1 - state;
__delay_ms(20);
}
old_val = val;
if(state){
if(T1s){
T1s = 0;//1sフラッグクリア
work0 = timer_data[0];//min
work1 = timer_data[1];//10sec
work2 = timer_data[2];//sec
work2 --;
if(work2 < 0){
work1 --;
work2 = 9;
}
if(work1 < 0){
work0 --;
work1 = 5;
}
if((work0 == 0)&&(work1 == 0)&&(work2 == 0)){
timer_data[2] = 0;
beep();//000になったら、ピピピ
}
timer_data[0] = work0;
timer_data[1] = work1;
timer_data[2] = work2;
}
}
}
}
if(work2 < 0){
work1 --;
work2 = 9;
}
if(work1 < 0){
work0 --;
work1 = 5;
}
if((work0 == 0)&&(work1 == 0)&&(work2 == 0)){
timer_data[2] = 0;
beep();//000になったら、ピピピ
}
timer_data[0] = work0;
timer_data[1] = work1;
timer_data[2] = work2;
}
}
}
}
今回のトラブルシューティング
タイマーの基本的なプログラムができ、ブザー音ピピピを出すところで、トラブりました。
RA4の罠です。RA0~RA3とRA4とでは、IOポートの構造が違うのです。
RA0~RA3がFETのトーテムポール出力になっているのに対して、RA4は、オープンドレイン出力なのです。
RA4には、電子ブザーを接続しています。出力0の時、ブザーが鳴るよう負論理になります。
最後に、ダイナミック点灯に割り込みを使っているせいか、ブザー音のピピピがときどき、ピピーになったりします。
プログラムで改善できると思うのですが、ま愛嬌ってことでご勘弁を。
PIC16F84(84A)を使ってMPLABXとXC8の基本的なプログラミングの仕方が勉強できました。
次は、PIC16F628Aを使って、シリアル通信、A/D変換、SPI、I2Cなどの勉強をしたいと思います。