目次
前
次
Go/Stop装置
Go/Stop装置は、ミニ四駆やマイクロマウス等の
タイムトライアル競技でスタートの合図を送る装置。
写真のGo/Stop装置は、ある工業系大学で開かれた
ロボットコンテストで使われていました。
予選会場が複数ある場合、同じような装置が
多数必要になり、ワンチップマイコンで実現
できるかを考えてみました。
Go/Stop装置の動作は、次の状態遷移図で表現可能。
ボタンスイッチ、4個のLED、圧電ブザーをPICに
接続して、Go/Stop装置を実現します。
LEDはデコーダICの74HC139に接続し、ピンの割り当て
を以下とします。
利用するPICは、PIC12F629。
8ピンのワンチップマイコンなので、4LEDを直接
接続する余裕がなく、デコーダICを使いました。
I/Oの設定を、Cの関数の中に入れておきます。
/* I/O state */
GPIO = 0x10 ;
/* I/O directions */
TRISIO = 0xe8 ; /* bit0,1,2,4 as output , others as input */
点灯するLEDは、74HC139への出力で選択するので
次のように制御します。
/* clear 74HC139 control bits */
GPIO = GPIO & 0xfc ;
/* turn on LED_3 */
if ( x.F0 == ON ) { GPIO = GPIO | 3 ; }
/* turn on LED_2 */
if ( x.F1 == ON ) { GPIO = GPIO | 2 ; }
/* enable LED_1 */
if ( x.F2 == ON ) { GPIO = GPIO | 1 ; }
状態遷移図で描いた状態を遷移させるために
シーケンスで、LEDの点灯を制御します。
音を入れると、次の関数で実現。
void plc(UBYTE x)
{
/* judge */
if ( x > 8 ) return ;
/* default */
xf = XCNTMAX ;
/* clear 74HC139 control bits */
GPIO = GPIO & 0xfc ;
/* turn on LED_3 */
if ( x.F0 == ON ) { GPIO = GPIO | 3 ; }
/* turn on LED_2 */
if ( x.F1 == ON ) { GPIO = GPIO | 2 ; }
/* enable LED_1 */
if ( x.F2 == ON ) { GPIO = GPIO | 1 ; }
/* judge */
if ( x.F3 == ON ) { xf = YCNTMAX ; }
/* calculate */
TMR1L = xf & 0xff ;
TMR1H = xf / 256 ;
/* enable decoder */
XENA = OFF ;
/* send sound 500ms */
T1CON.TMR1ON = ON ;
delay_ms(500);
T1CON.TMR1ON = OFF ;
/* disable decoder */
XENA = ON ;
/* delay */
delay_ms(250);
}
シーケンサで、LED点灯と音だしを処理したので
シーケンサを動かすトリガーをボタンクリックで
与えられるようにします。
ボタンの状態に変化があったことを
シフトレジスタを使って検出。
if ( eflag.F0 == ON ) {
/* clear flag */
eflag.F0 = OFF ;
/* shift */
sft = sft * 2 ;
/* mask */
sft = sft & 3 ;
/* get switch state */
if ( XPSHS == OFF ) { sft = sft + 1 ; }
/* judge */
eflag.F1 = OFF ;
if ( sft == ON ) { eflag.F1 = ON ; }
}
利用するブロックを定義したので
ステートマシンを扱うコードを作成。
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* shift register */
if ( eflag.F0 == ON ) {
/* clear flag */
eflag.F0 = OFF ;
/* shift */
sft = sft * 2 ;
/* mask */
sft = sft & 3 ;
/* get switch state */
if ( XPSHS == OFF ) { sft = sft + 1 ; }
/* judge */
eflag.F1 = OFF ;
if ( sft == ON ) { eflag.F1 = ON ; }
}
/* LED handling */
if ( eflag.F1 == ON ) {
/* run */
plc(1);
plc(2);
plc(4);
plc(8);
/* exit */
eflag.F1 = OFF ;
}
}
}
音出しには、タイマー1のオーバーフロー割込みを使います。
PIC12F629は、内部に4MHzのクロックジェネレータをもつので
1MHzがタイマー1に入力されます。周波数を、タイマー1の
オーバーフローで処理するとして、使う周波数を以下に設定。
#define XCNTMAX 65398 /* 450Hz */
#define YCNTMAX 65466 /* 900Hz */
LED0を点灯したときに、高い周波数を出力し
他では低い周波数を使います。
シーケンサは、イベントフラグを利用して
回すようにしておきます。これだとフラグ
値を見るだけで、どのLEDを点灯するかが
わかるので、ワンホットコーディングが
できます。
LEDは別基板にする条件で半田付けすると以下。
スピーカとアンプを集めて、実装すると
次のようにまとめられます。
ファームウエアとしてまとめます。
/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
#define OFF 0
#define ON OFF+1
#define XSND GPIO.B2
#define XENA GPIO.B4
#define XPSHS GPIO.B5
#define CNTBEGIN 131
#define XCNTMAX 65398
#define YCNTMAX 65466
volatile UBYTE eflag ;
volatile UBYTE sft ;
volatile UBYTE loop ;
volatile UBYTE scnt ;
volatile UWORD xf ;
/* function prototype */
void init_usr(void);
void plc(UBYTE x);
/* interrupt handler */
void interrupt(void)
{
/* timer 0 generate 1kHz */
if ( INTCON.T0IF) {
/* clear flag */
INTCON.T0IF = OFF ;
/* initialize */
TMR0 = CNTBEGIN ;
/* set flag */
eflag.F0 = ON ;
}
/* timer 1 overflow */
if ( PIR1.TMR1IF ) {
/* clear flag */
PIR1.TMR1IF = OFF ;
/* initialize */
TMR1L = xf & 0xff ;
TMR1H = xf / 256 ;
/* increment */
scnt = scnt + 1 ;
/* default */
XSND = OFF ;
/* sound out */
if ( eflag.F1 == ON ) { XSND = scnt.F0 ; }
}
}
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* shift register */
if ( eflag.F0 == ON ) {
/* clear flag */
eflag.F0 = OFF ;
/* shift */
sft = sft * 2 ;
/* mask */
sft = sft & 3 ;
/* get switch state */
if ( XPSHS == OFF ) { sft = sft + 1 ; }
/* judge */
eflag.F1 = OFF ;
if ( sft == ON ) { eflag.F1 = ON ; }
}
/* LED handling */
if ( eflag.F1 == ON ) {
/* run */
plc(1);
plc(2);
plc(4);
plc(8);
/* exit */
eflag.F1 = OFF ;
}
}
}
/* define function body */
void init_usr(void)
{
/* I/O state */
GPIO = 0x10 ;
/* I/O directions */
TRISIO = 0xe8 ; /* bit0,1,2,4 as output , others as input */
/* disable compare module */
CMCON = 0x07 ;
/* pull-up */
WPU = 0x20 ;
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/8 = 125kHz prescaler = 1:8
125kHz/250 = 500Hz
*/
OPTION_REG = 0x02 ;
/* 256 - 131 = 125 */
TMR0 = CNTBEGIN ;
/* enable timer0 overflow interrupt */
INTCON.T0IE = ON ;
}
/* initialize Timer 1 */
{
/*
4MHz/4 = 1MHz -> 1MHz/8 = 125kHz
125kHz / 880 or 440
*/
T1CON = 0x30 ;
/* enable timer1 overflow interrupt */
PIE1.TMR1IE = ON ;
INTCON.PEIE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
/* clear flag */
eflag = OFF ;
/* others */
sft = 0;
scnt = 0 ;
}
void plc(UBYTE x)
{
/* judge */
if ( x > 8 ) return ;
/* default */
xf = XCNTMAX ;
/* clear 74HC139 control bits */
GPIO = GPIO & 0xfc ;
/* turn on LED_3 */
if ( x.F0 == ON ) { GPIO = GPIO | 3 ; }
/* turn on LED_2 */
if ( x.F1 == ON ) { GPIO = GPIO | 2 ; }
/* enable LED_1 */
if ( x.F2 == ON ) { GPIO = GPIO | 1 ; }
/* judge */
if ( x.F3 == ON ) { xf = YCNTMAX ; }
/* calculate */
TMR1L = xf & 0xff ;
TMR1H = xf / 256 ;
/* enable decoder */
XENA = OFF ;
/* send sound 500ms */
T1CON.TMR1ON = ON ;
delay_ms(500);
T1CON.TMR1ON = OFF ;
/* disable decoder */
XENA = ON ;
/* delay */
delay_ms(250);
}
パンケースの中に入れて使いやすくできます。
目次
前
次