目次
前
次
安全機構
ファームウエアを検討し、雛形となるコードも作成したので
ハードウエアとソフトウエアで安全機構を入れます。
安全機構なしでも走行に問題はありませんが、フライングや
コースアウト時のメカ損傷等を防ぐために必須と考えました。
最初に次の安全機構を用意。
- 規定時間後の自動停止
- DCDCコンバータの誤動作防止
円滑な競技運営のため、150秒程度の時間規定が設けられています。
スタートしてから120秒後にモータを停止するタイマーを用意。
スタートゲートが開いてから、タイマーに対してトリガーを与え
120秒後にパルスで知らせる回路を考えました。
タイミングチャートでは、次のようにします。
システムの一部として使えるように、PIC12F1501を利用して実現。
マシンのメカは複数あるので、制御基板とは別基板にします。
制御基板に接続して利用できるため、予備マシンを使う場面
でも着脱で対応できます。
テスト用に半田付け基板で動作実験しました。
テスト用基板の回路は、以下。
プログラムは、次のように短くしています。
/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
#define TXOUT PORTA.F0
#define TICK PORTA.F1
#define OFF 0
#define ON OFF+1
#define MASKFF 0xff
#define XMAX 120 /* 120 seconds */
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define DFLAG xflags.BIT.B0
#define EFLAG xflags.BIT.B1
#define OFLAG xflags.BIT.B2
#define XFLAG xflags.BIT.B3
volatile UBYTE xcnt ;
volatile UWORD ycnt ;
volatile UBYTE xinterval ;
/* function prototype */
void init_usr(void);
/* interrupt handler */
void interrupt(void)
{
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* set flag */
XFLAG = ON ;
}
/* LTRG PORTA.F5 rising edge interrupt */
if ( INTCON.IOCIF == ON ) {
/* clear flag */
IOCAF.IOCAF5 = OFF ;
/* set event flag */
EFLAG = ON ;
}
}
void delay_ms(UBYTE x)
{
UBYTE xlast ;
xlast = xcnt + x ;
while ( xcnt < xlast ) ;
}
void main(void)
{
/* initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* counter increment */
if ( XFLAG == ON ) {
/* clear flag */
XFLAG = OFF ;
/* increment */
xcnt++ ;
/* monitor */
TICK = OFF ;
if ( xcnt & ON ) { TICK = ON ; }
/* increment */
if ( DFLAG == ON ) { ycnt++ ; }
/* judge */
if ( ycnt == 1000 ) {
ycnt = 0 ;
xinterval++ ;
if ( xinterval == XMAX ) { OFLAG = ON ; }
}
}
/* timer out */
if ( OFLAG == ON ) {
/* clear flag */
OFLAG = OFF ;
/* disable */
DFLAG = OFF ;
/* send pulse */
TXOUT = ON ;
delay_ms(10);
TXOUT = OFF ;
}
/* wait trigger */
if ( EFLAG == ON ) {
/* clear flag */
EFLAG = OFF ;
/* clear counter */
ycnt = 0 ;
xinterval = 0 ;
/* enable increse counter */
DFLAG = ON ;
}
}
}
/* define function body */
void init_usr(void)
{
/* select 16MHz */
OSCCON = (0xf << 3) | 0x03 ;
/* disable A/D converter */
ADCON0.ADON = OFF ;
ADCON2 = 0 ;
ANSELA = 0 ;
/* disable D/A converter */
DACCON0 = 0 ;
DACCON1 = 0 ;
/* disable compare module */
CM1CON0.C1ON = OFF ;
CM1CON0.C1OE = OFF ;
/* I/O state */
PORTA = 0x00 ;
/* I/O directions */
TRISA = 0x38 ; /* bit0,1,2 as output , others as input */
/* PIN change interrupt */
{
/* PORTA.5 rising edge */
IOCAP.IOCAP5 = ON ;
/* enable compare match interrupt */
INTCON.IOCIE = ON ;
}
/* initialize timer 0 */
{
/*
16MHz/4 = 4MHz (Fosc)
Fosc/4 = 1MHz
1MHz/4 = 250kHz prescaler = 1:4
*/
OPTION_REG = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.TMR0IE = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
/* clear flags */
xflags.DR = 0 ;
/* initialize variables */
xcnt = 0 ;
ycnt = 0 ;
xinterval = 0 ;
}
スタートゲートが開くまでは、モータを回さないようにと
DCDCコンバータからの出力をカットします。
DCDCコンバータの出力では、GND側をフローティングにするか
0Vのラインに接続するかを制御できるようにしました。
回路は簡単。
スタートゲートが開いたときに、タイマーにトリガーを与え
同時に'H'レベルを上の回路に与えます。基板に実装すると
次のようになります。
制御基板からは、電源と制御信号を接続し、DCDCコンバータ
基板とは2本のGND制御を接続。
- Vcc
- CONDC
- RDCDC
- LDCDC
- GND
DCDCコンバータ出力に安全機構をつけると
以下のようになりました。
ハードウエアに加えて、ソフトウエアの安全機構を用意。
システムタイマーを設定し、いつでも参照できるように
します。システムタイマーのカウンタを1ms単位とし
32ビットサイズで扱います。
1msで32ビットのカウンタをインクリメントしていけば
約49日程度の時間を扱えます。MCR大会の会場で制御
基板の電源を間違って入れても、1時間程度で自動で
電源オフにします。
電源投入から1時間でパワーオフするには、3600x1000ms
をカウント。これをタイマー割込みルーチンの中に入れて
対応。
具体的なコードは、以下。
volatile ULONG syscnt ;
volatile UBYTE sysflag ;
void IRQ_Handler(void) __irq
{
/* judge timer0 interruption (100us) */
if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
/* clear timer0 interrupt flag */
T0CLRI = 0xff ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0xfff) == 0 ) { GP4DAT ^= (1 << 23); }
/* system timer */
if ( timcnt & 0x3ff) == 1000 ) {
syscnt++;
if ( syscnt == 3600000L ) { sysflag = ON ; }
}
}
}
フラグsysflagでイベントを通知し、モータに接続したDCDCコンバータ
の電源出力をカットするように信号を出力。
if ( sysflag == ON ) {
/* clear flag */
sysflag = OFF ;
/* power off */
turn_bit(OFF,CONDC_BIT);
}
DCDCコンバータの電力制御は、次の関数で扱います。
void turn_bit(UBYTE which,UBYTE bx)
{
if ( which ) { GP1DAT |= (1 << bx); }
else { GP1DAT &= ~(1 << bx); }
}
タイマー割込みでは、120秒経過したことを外部回路が
通知しているかを監視します。シフトレジスタに外部
回路の出力信号を取り込んで、レジスタの全ビットが
1になったら、通知します。
volatile UBYTE tsft ;
volatile UBYTE toutflag ;
void IRQ_Handler(void) __irq
{
/* judge timer0 interruption (100us) */
if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
/* clear timer0 interrupt flag */
T0CLRI = 0xff ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0xfff) == 0 ) { GP4DAT ^= (1 << 23); }
/* system timer */
if ( timcnt & 0x3ff) == 1000 ) {
syscnt++;
if ( syscnt == 3600000L ) { sysflag = ON ; }
}
/* time out handling */
if ( (GP1DAT & 0x00040000 ) {
tsft <<= 1;
tsft |= ON;
}
if ( tsft == 0xff ) { toutflag = ON ; }
}
}
イベント通知フラグtoutflagの論理値を判断し
DCDCコンバータの出力をカットしてモータ停止
とする操作を追加します。
if ( toutflag == ON ) {
/* clear flag */
toutflag = OFF ;
/* power off */
turn_bit(OFF,CONDC_BIT);
}
if ( sysflag == ON ) {
/* clear flag */
sysflag = OFF ;
/* power off */
turn_bit(OFF,CONDC_BIT);
}
制御基板上のプロセッサは、2つのタイムアウト処理を
2つのイベント通知フラグで検知できます。
単純なハードウエアとソフトウエアの追加ですが、動く物体を
停止させて、コースアウトして壁に激突あるいは観測者に衝突
するようなときに対応できるようになりました。
スタートしてから120秒後に自動停止、パワーオンから1時間後
に自動停止だけですが、大きな質量をもつ物体の暴走事故の発生
確率を下げられます。
目次
前
次