目次
前
次
electric dice
CQ出版の雑誌、エレキジャックの付属基板が
部屋を掃除していたら出てきました。
付属基板を見ると、電子サイコロとわかりました。
PIC16F84の手持ちがあるので、これで電子サイコロの
プログラムを作成することに。
18ピンのPICでは、ポートA、ポートBの2ポートの
構成が大部分で、基板パターンから、LEDとスイッチ
の接続は、以下とわかりました。
- RB7(output) LED
- RB6(output) LED
- RB5(output) LED
- RB4(output) LED
- RB3(output) LED
- RB2(output) LED
- RB1(output) LED
- RB0(input) push switch
RB0は、外部割込み端子となっているので
プッシュスイッチを押すたびに、次の動作
をすれば、サイコロになります。
2つの状態を、プッシュスイッチを押すことで
行き来するようにすれば、動作をエミュレート
が可能。
IDLE 表示パターンは変化しない
RUN 1から6を繰り返し表示
LEDの配置は、次のようになっています。
RUNのときの表示パターンを、まとめておきます。
表示パターンを、配列に格納しておき、RUNのとき
には、カウンタで配列の添字を使い、パターンを
引き出して、ポートBに出力すればよいでしょう。
配列に格納する8ビットは、次のように確定。
配列を宣言して、点灯パターンを格納するコードは
以下でよいでしょう。
typdef unsigned char UBYTE ;
UBYTE lpat[6] ;
*(lpat+0) = 0x10 ;
*(lpat+1) = 0x28 ;
*(lpat+2) = 0x92 ;
*(lpat+3) = 0xaa ;
*(lpat+4) = 0xba ;
*(lpat+5) = 0xee ;
RUNの状態のときは、タイマー割込みで時間経過を
通知してもらい、次の関数でLEDにパターンを表示
することに。
#define STATEMAX 6
void dice(void)
{
/* impress */
PORTB = *(lpat+state);
/* update */
state++ ;
/* judge */
if ( state >= STATEMAX ) { state = 0 ; }
}
カウンタは、変数stateに割当しておきます。
タイマー割り込みが発生したときは、次のように
RUNであることをフラグで判定して、関数を呼び
出す仕様にして対応。
while (ON) {
/* timer interrupt */
if ( tflag == ON ) {
tflag = OFF ;
/* dice */
if ( eflag == ON ) {
dice();
}
}
}
フラグtflagは、タイマー割込みが発生したことを
知らせるイベント通知フラグとします。
また、フラグeflagはIDLEかRUNのどちらの状態に
いるのかを通知するとします。
割込みハンドラは、次のように定義。
void interrupt(void)
{
/* external interrupt */
if ( INTCON.INTF ) {
/* clear flag */
INTCON.INTF = OFF ;
/* increment */
eflag++ ;
/* adjust 1 bit */
eflag &= ON ;
}
/* timer interrupt */
if ( INTCON.T0IF ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = 131 ;
/* increment */
xcnt++ ;
/* judge */
if ( xcnt == 200 ) {
/* clear */
xcnt = 0 ;
/* set flag */
tflag = ON ;
}
}
}
プッシュボタンを押すと、RB0に'L'が印加されるので
フラグeflagを計数フラグとして、インクリメント。
フラグは、1ビットだけの判定で使いたいので、値は
プッシュスイッチを押すたびに、0→1→0→1と
反転します。
タイマー割込みは、タイマー0を使い、カウンタの値が
131から256まで数えて、255から0に戻るオーバーフロー
割込みを発生させておきます。
変数xcntは、LEDの表示パターンが目視できるほどに
遅くするために使います。
割込みハンドラを定義したので、初期化を関数に
まとめていきます。
void usr_init(void)
{
/* initialize PORT values */
PORTA = 0x00 ;
PORTB = 0x00 ;
/* set directions */
TRISA = 0x00 ;
TRISB = 0x01 ;
/* initialize timer 0 */
{
/*
(10MHz/4)/2 = 1.25MHz ((Fosc/4)/2)
1 : 256
*/
OPTION_REG = 0x07 ;
/* 256 - 125 = 131 */
TMR0 = 131 ;
}
/* enable interrupt */
INTCON = (ON << GIE) | (ON << T0IE) | (ON << INTE);
/* others */
xcnt = 0 ;
state = 0 ;
tflag = OFF ;
eflag = OFF ;
/* LED pattern */
*(lpat+0) = 0x10 ;
*(lpat+1) = 0x28 ;
*(lpat+2) = 0x92 ;
*(lpat+3) = 0xaa ;
*(lpat+4) = 0xba ;
*(lpat+5) = 0xee ;
}
割込み利用は、タイマー0のオーバーフロー割み、外部割込みで
よいですが、PICはグローバル割込みをイネーブルにしないと関数
interruptが使えません。忘れやすく、割込みが発生しないとなる
ので、要注意です。
まとめると、以下。
#define OFF 0
#define ON OFF+1
#define STATEMAX 6
typedef unsigned char UBYTE ;
UBYTE xcnt ;
UBYTE tflag ;
UBYTE eflag ;
UBYTE state ;
UBYTE lpat[6];
/* prototype */
void usr_init(void);
void get_flag(void);
void dice(void);
/* interrupt handler */
void interrupt(void)
{
/* external interrupt */
if ( INTCON.INTF ) {
/* clear flag */
INTCON.INTF = OFF ;
/* increment */
eflag++ ; INTCON.
/* adjust 1 bit */
eflag &= ON ;
}
/* timer interrupt */
if ( INTCON.T0IF ) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = 131 ;
/* increment */
xcnt++ ;
/* judge */
if ( xcnt == 200 ) {
/* clear */
xcnt = 0 ;
/* set flag */
tflag = ON ;
}
}
}
void main(void)
{
/* initialize */
usr_init();
/* endless loop */
while (ON) {
/* timer interrupt */
if ( tflag == ON ) {
tflag = OFF ;
/* dice */
if ( eflag == ON ) {
dice();
}
}
}
}
void usr_init(void)
{
/* initialize PORT values */
PORTA = 0x00 ;
PORTB = 0x00 ;
/* set directions */
TRISA = 0x00 ;
TRISB = 0x01 ;
/* initialize timer 0 */
{
/*
(10MHz/4)/2 = 1.25MHz ((Fosc/4)/2)
1 : 256
*/
OPTION_REG = 0x07 ;
/* 256 - 125 = 131 */
TMR0 = 131 ;
}
/* enable interrupt */
INTCON = (ON << GIE) | (ON << T0IE) | (ON << INTE);
/* others */
xcnt = 0 ;
state = 0 ;
tflag = OFF ;
eflag = OFF ;
/* LED pattern */
*(lpat+0) = 0x10 ;
*(lpat+1) = 0x28 ;
*(lpat+2) = 0x92 ;
*(lpat+3) = 0xaa ;
*(lpat+4) = 0xba ;
*(lpat+5) = 0xee ;
}
void dice(void)
{
/* impress */
PORTB = *(lpat+state);
/* update */
state++ ;
/* judge */
if ( state >= STATEMAX ) { state = 0 ; }
}
サイコロを振るために使うプッシュスイッチは
次の大きなサイズのデバイスを使います。
目次
前
次