目次

制御処理再検討

 MCR_VCの場合、画像処理関係のプログラムやハードウエアは
 カメラやセンサー専用とする、2プロセッサ方式が一般的。

 1プロセッサで画像処理と移動制御を扱う場合、移動に
 関する処理は、プロセッサ内蔵モジュールを使わない方
 が簡単になります。

 移動処理をプロセッサではなく、簡単なハードウエアで実現
 することを再度検討してみました。


DCモータ制御  DCモータは、回転速度と回転方向を制御します。  回転方向は、Hブリッジ回路を利用。  Hブリッジ回路にあるバイポーラトランジスタかMOSFET  のベースかゲートに、DUTY比の異なるパルスを与えれば  平均電力が変化して回転速度が変わります。  DUTY比の可変には、プロセッサ内部のタイマー/カウンタ  を利用するのがデジタル制御では、定番です。  比較するカウント値を変更することで、DUTY比を可変します。  アナログ回路では、3角波を生成して、コンパレータに入力し  比較電圧を変えれば、出力電圧のDUTY比を変えられます。  OPアンプを利用した発振器とコンパレータで、次の回路を  構成すれば、DUTY比を可変にできます。  reference(リファレンス電圧)は、次のR-2Rのラダー型  D/Aコンバータを利用すれば、8ビットでも12ビットでも  ある程度の精度で電圧を可変にできます。  回転方向を可変にするには、トランジスタあるいはMOSFETの  ベースかゲートにパルスを出力するかしないかだけの回路を  付加して対応できます。  ダイオードを利用したAND回路で実現できます。  左右にDCモータがある時、必要な部品を見積もってみます。  表面実装用部品を利用すれば、100mmx100mmの面積に  収容できるサイズになります。  制御のシーケンスは、以下でよいでしょう。
  1. パルス出力を停止(2つのenableに0を指定)
  2. D/Aコンバータ用レジスタにDUTY比値設定
  3. 回転方向設定(どちらかのenableに1を指定)
 D/Aコンバータ用レジスタが8ビットが2つあり  方向設定enableが4つあるので、マイコンからは  8ビットのI/Oアドレスが2つあれば充分。
サーボモータ制御  サーボモータは、20msごとに1msから2msの幅のパルスを  出力すればよい制御できます。  1ms幅のパルス出力は固定なので、0.1ms幅の'1'を  0から10個出力します。  10ビットレジスタにパターンを設定し、データセレクタ  で、0ビットから9ビットの各値を出力します。  4ビットのレジスタを3個用意し、パラレル入力シフト出力  の8ビットシフトレジスタを使えば実現できます。  0.1ms幅(10kHz)でカウンタを0から199まで回します。  これはフリーランカウンタで充分です。  カウンタの値が0から20で、サーボモータにパルスを出力  し、値を変更したいときは、21から199の間に10ビット  を3回に分けて与えます。  カウンタ値が21から199であれば、10ビット値変更を  許可するイネーブル信号を出して対応します。  カウンタの値が0から9で、'1'を出力し、10から20までは  セレクタの値を出力、21から199までは'0'を出力する  制御回路を用意します。  カウンタは12ビットカウンタの4040を利用し、カウンタ  出力を加工して対応します。  条件が複雑なときには、ROMをデコーダとして利用します。  カウンタは0から199を繰り返すので、199になったときに  4040をリセットする信号を出力します。  A7からA0で199になったときに、出力D5を1にし、それ以外は  0になるようにパターンを設定します。  カウンタが0から9と21から199では、nSTBを1にして  セレクタを動かさないようにします。  0から9 出力D4=D3=1  21から199 出力D4=D3=1  カウンタが10から20までは、nSTB1、nSTB2とSEL2からSEL0  を組み合わせて、データセレクタを動かします。  組み合わせをリストすると、以下。     nSTB2 nSTB1 SEL2 SEL1 SEL0  10  1 0 0 0 0  11  1 0 0 0 1  12  1 0 0 1 0  13  1 0 0 1 1  14  1 0 1 0 0  15  1 0 1 0 1  16  1 0 1 1 0  17  1 0 1 1 1  18  0 1 0 0 0  19  0 1 0 0 1  20  0 1 0 1 0 D4 D3 D2 D1 D0  ROMに書込むビットパターンは、プログラムで生成します。  Tcl/Tkで記述すると、以下。 for {set i 0} {$i < 200} {incr i} { # default set xdat 255 # reset if { $i == 199 } { set xdat [expr $xdat - 32] } # 10 -> 20 if { $i < 21 && 9 < $i } { if { $i < 18 } { set xdat [expr 16 + $i - 10] } else { set xdat [expr 8 + $i - 18] } } # calculate set tmp [format "%02X %02X" $i $xdat] # show puts $tmp }  実際にROMに書込むには、手持ちのROMライターを利用します。  ROMがなければ、CPLDで代用します。  CPLDならXC9536、XC9572のようなマクロセル数が少ないデバイス  で対応できます。
DCモータ制御2  DCモータを1方向だけに回転する場合、DUTY比だけを設定し  波形出力を小型マイコンに任せる方法もあります。  8ビットレジスタにDUTY比(0から100%)を設定しておくと  PICがシフトレジスタにトリガーを与えて、DUTY比をコピーし  シフトクロックで取込みます。  PICのファームウエアは、以下。 #define OFF 0 #define ON OFF+1 #define PCNTMAX 100 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; 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 TMP xflags.BIT.B0 #define TFLAG xflags.BIT.B1 #define DIN PORTA.F5 #define SCLK PORTA.F4 #define PULSEOUT PORTA.F0 #define CNTBEGIN 246 volatile UBYTE pcnt ; volatile UBYTE qcnt ; volatile UBYTE xcnt ; volatile UBYTE ycnt ; volatile UBYTE zcnt ; /* function prototype */ void init_usr(void); void send_clk(); /* interrupt handler */ void interrupt(void) { /* timer0 interrupt */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* impress */ TMP = OFF ; if ( pcnt < xcnt ) { TMP = ON ; } PULSEOUT = TMP ; /* increment */ pcnt++ ; /* judge */ if ( xcnt == PCNTMAX ) { /* clear counter */ pcnt = 0 ; /* reload */ xcnt = zcnt ; } /* set event flag */ TFLAG = ON ; } } void main(void) { /* initialize */ init_usr() ; /* endless loop */ while ( ON ) { /* direction */ if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* copy counter value */ qcnt = pcnt ; /* clear */ if ( qcnt == 7 ) { ycnt = 0 ; } /* get data */ if ( 8 <= qcnt && qcnt < 16 ) { /* get shift data */ ycnt |= (DIN << (qcnt & 7)); /* send shift pulse */ send_clk(); } /* generate code */ if ( qcnt == 16 ) { zcnt = ycnt ; } } } } /* define function body */ void init_usr(void) { /* select 16MHz */ OSCCON = (0x0f << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; /* disable D/A converter */ DACCON0.DACEN = OFF ; /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O state */ LATA = 0 ; /* I/O directions */ TRISA = 0x20 ; /* bit0,4 as output , others as input */ /* pull-up */ WPUA = 0x20 ; /* initialize Timer 0 */ { /* 16MHz/4 = 4MHz (BUS clock) -> 4MHz/4 = 1MHz prescaler = 1:4 */ OPTION_REG = 0x01 ; /* 256 - 10 = 246 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.TMR0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flags */ xflags.DR = 0 ; /* initialize clock logic level */ SCLK = ON ; /* initialize variables */ xcnt = 0 ; ycnt = 0 ; zcnt = 0 ; pcnt = 0 ; } void send_clk() { /* SCLK : L */ SCLK = OFF ; /* SCLK : H */ SCLK = ON ; }  DCモータのDUTY比を与える部分を、サーボモータの20msに一度  1msから2msのパルスを出力するよう変更すれば、サーボモータ  にも対応できます。 #define OFF 0 #define ON OFF+1 #define MASKFF 0xff #define PCNTMAX 2000 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; 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 TMP xflags.BIT.B0 #define TFLAG xflags.BIT.B1 #define DIN PORTA.F5 #define SCLK PORTA.F4 #define PULSEOUT PORTA.F0 #define CNTBEGIN 246 volatile UWORD pcnt ; volatile UBYTE qcnt ; volatile UBYTE xcnt ; volatile UBYTE ycnt ; volatile UBYTE zcnt ; /* function prototype */ void init_usr(void); void send_clk(void); /* interrupt handler */ void interrupt(void) { /* timer0 interrupt */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* impress */ TMP = OFF ; if ( pcnt < xcnt ) { TMP = ON ; } PULSEOUT = TMP ; /* increment */ pcnt++ ; /* judge */ if ( xcnt == PCNTMAX ) { /* clear counter */ pcnt = 0 ; /* reload */ xcnt = zcnt ; } /* set event flag */ TFLAG = ON ; } } void main(void) { /* initialize */ init_usr() ; /* endless loop */ while ( ON ) { /* direction */ if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* copy counter value */ qcnt = pcnt & MASKFF ; /* clear */ if ( qcnt == 7 ) { ycnt = 0 ; } /* get data */ if ( 8 <= qcnt && qcnt < 16 ) { /* get shift data */ ycnt |= (DIN << (qcnt & 7)); /* send clock */ send_clk(); } /* generate code */ if ( qcnt == 16 ) { zcnt = ycnt ; } } } } /* define function body */ void init_usr(void) { /* select 16MHz */ OSCCON = (0x0f << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; /* disable D/A converter */ DACCON0.DACEN = OFF ; /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O state */ LATA = 0 ; /* I/O directions */ TRISA = 0x28 ; /* bit0,4 as output , others as input */ /* pull-up */ WPUA = 0x20 ; /* initialize Timer 0 */ { /* 16MHz/4 = 4MHz (BUS clock) -> 4MHz/4 = 1MHz prescaler = 1:4 */ OPTION_REG = 0x01 ; /* 256 - 10 = 246 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.TMR0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flags */ xflags.DR = 0 ; /* set clock logic level */ SCLK = ON ; /* initialize variables */ xcnt = 150 ; ycnt = 0 ; zcnt = 150 ; pcnt = 0 ; } void send_clk(void) { /* SLCK : L */ SCLK = OFF ; /* SLCK : H */ SCLK = ON ; }  DCモータ、サーボモータともにDUTY比、パルス幅を担当する  カウンタの値が9から15の間に、パラメータを取得します。  カウンタの値が16のときに、内部レジスタに転送します。  100kHzでカウンタを動かすので、DCモータの場合1周期の間に  4回、サーボモータの場合1周期の間に100回、パラメータを  更新します。  74HC165に上位プロセッサが、非同期でパラメータを設定した  としても、PICは1周期中に何度もパラメータを更新している  ので、モータの挙動がおかしくなる確率は小さくなります。

目次

inserted by FC2 system