目次

デバッグ治具作成

 センサーとしてGameBoyCamera(GBC)を利用します。

 長いコースを用意できる期間が限られているため
 机上でセンサー情報を与えて、マシン動作を確認
 します。

 マシン動作の確認には、専用治具を作成しました。

 GBCにはArduinoを接続して、センサー情報は4ビットに
 抽象化してから、制御担当のマイコンに渡します。

 制御担当マイコンに、センサー情報を与えられるように
 8ピンのマイコンで治具を構成しました。
 回路図は、以下。




 出力しているセンサー情報が何かわかるように
 デコーダICを接続しています。

 マイコンPIC12F1501のソースコードは、以下。

#define OFF 0
#define ON  OFF+1

#define ALL_BLACK   0
#define ALL_WHITE   ALL_BLACK+1
#define LEFT_WHITE  ALL_BLACK+2
#define RIGHT_WHITE ALL_BLACK+3
#define CENTER      ALL_BLACK+4
#define TINY_RIGHT  ALL_BLACK+5
#define RIGHT       ALL_BLACK+6
#define BIG_RIGHT   ALL_BLACK+7
#define TINY_LEFT   ALL_BLACK+8
#define LEFT        ALL_BLACK+9
#define BIG_LEFT    ALL_BLACK+10
#define BOTH_WHITE  ALL_BLACK+11
#define ILLEAGAL    ALL_BLACK+12

#define MASKFF  0xff
#define MASK0F  0x0f
#define MASKF0  0xf0
#define XCNTMAX 12000
#define CNTBEGIN 6

typedef unsigned char UBYTE ;
typedef unsigned int  UWORD ;

volatile UWORD xcnt ;
volatile UBYTE tflag ;
volatile UBYTE dflag ;
volatile UBYTE eflag ;
volatile UBYTE state ;
volatile UBYTE pat[8] ;
volatile UBYTE tmp ;
volatile UBYTE sensor ;

/* function prototype */
void init_usr(void);
void gen_pat(void);

/* interrupt handler */
void interrupt(void)
{
  /* timer0 interrupt */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* impress */
    xcnt++ ;
    /* judge */
    if ( xcnt == XCNTMAX ) {
      /* clear */
      xcnt = 0 ;
      /* set flag */
      tflag = ON ;
    }
  }
  /* pin change interrupt */
  if ( INTCON.IOCIF == ON ) {
    /* clear flag */
    IOCAF.IOCAF5 = OFF ;
    /* event flag */
    eflag = ON ;
  }
}

void main(void)
{
  /* initialize */
  init_usr() ;
  /* endless loop */
  while ( ON ) {
    /* event */
    if ( eflag == ON ) {
      /* clear flag */
      eflag = OFF ;
      /* change mode */
      dflag++ ;
      dflag &= ON ;
    }
    /* timer interrupt */
    if ( tflag == ON ) {
      /* clear flag */
      tflag = OFF ;
      /* execute */
      if ( dflag == ON ) {
        /* get pattern */
        tmp = *(pat+state);
        /* handling */
        if ( state & ON ) {
          tmp >>= 4 ;
          state++ ;
          /* judge */
          if ( state == 16 ) { state = 0 ; }
        }
        tmp &= 0x0f ;
        /* generate code */
        sensor = ((tmp & 8) << 1) | (tmp & 7);
        /* impress */
        PORTA = sensor ;
      }
    }
  }
}

/* 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 */
  PORTA = CENTER ;
  /* I/O directions */
  TRISA = 0x28 ; /* bit0,1,2,4 as output , others as input */
  /* pull-up */
  WPUA = 0x20 ;
  /* pin change interrupt */
  {
    /* L -> H edge */
    IOCAP.IOCAP5 = ON ;
    /* enable */
    INTCON.IOCIE = ON ;
  }
  /* 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 flag */
  tflag = OFF ;
  dflag = OFF ;
  eflag = OFF ;
  /* initialize variables */
  xcnt = 0 ;
  /* sensor */
  gen_pat();
}

void gen_pat(void)
{
  *(pat+0) = (CENTER << 4) | CENTER ;
  *(pat+1) = (RIGHT  << 4) | TINY_RIGHT ;
  *(pat+2) = (CENTER << 4) | TINY_RIGHT ;
  *(pat+3) = (LEFT   << 4) | TINY_LEFT  ;
  *(pat+4) = (CENTER << 4) | TINY_LEFT  ;
  *(pat+5) = (BIG_RIGHT << 4) | CENTER  ;
  *(pat+6) = (TINY_RIGHT << 4) | RIGHT  ;
  *(pat+7) = (CENTER << 4) | CENTER ;
}

 センサー情報は、16パターンを8バイトに格納しています。

 センサー情報は4ビットなので、1バイトに2パターンを
 格納。センサー情報設定は、ひとつの関数にまとめてある
 ので、更新すれば複雑なパターンもエミュレートできます。

 ピン数の多いマイコンを利用すれば、シリアルインタフェースを
 利用して、センサー情報の出現パターンを変更したり、いくつか
 の出現パターンをまとめて入れておけるようになります。

 部品が揃うまで、CPLDの中にシーケンサとデコーダを入れて
 対応しました。

 シーケンサのVHDLコードは、以下。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity tseq is
  Port (
    -- system 
    nRESET : in  std_logic;
    CLOCK  : in  std_logic; -- 4MHz
    -- monitor
    MCLK   : out std_logic ;
    -- counter out
    SQOUT  : out std_logic_vector(3 downto 0)
  );
end tseq;

architecture Behavioral of tseq is
  -- clock divider
  signal iCNT : integer range 0 to 3999999 ;
  signal iCLK : std_logic ;
  --
  signal iSEQ : std_logic_vector(3 downto 0) ;
begin
  -- output
  SQOUT <= iSEQ ;
  MCLK  <= not iCLK ;

  -- clock divider
  process ( nRESET , CLOCK ) 
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge( CLOCK ) then
      if ( iCNT = 3999999 ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iCLK <= '1' when ( iCNT > 1999999 ) else '0' ;

  -- counter 
  process ( nRESET , iCLK ) 
  begin
    if ( nRESET = '0' ) then
      iSEQ <= "0000" ;
    elsif rising_edge( iCLK ) then
      iSEQ <= iSEQ + '1' ;
    end if ;
  end process ;

end Behavioral;

 デコーダのVHDLコードは、74LS138の真理値表示の一部を
 そのまま記述。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity tx138 is
  port (
    DIN  : in  std_logic_vector(3 downto 0) ;
    DOUT : out std_logic_vector(15 downto 0) --;
  ) ;
end tx138;

architecture Behavioral of tx138 is
  signal iDIN  : integer range 0 to 15 ;
  signal iDOUT : std_logic_vector(15 downto 0) ;
begin
  -- input
  iDIN <= conv_integer(DIN) ;

  -- output
  DOUT <= not iDOUT ;

  -- decoder
  iDOUT <= X"0001" when ( iDIN =  0 ) else
           X"0002" when ( iDIN =  1 ) else
           X"0004" when ( iDIN =  2 ) else
           X"0008" when ( iDIN =  3 ) else
           X"0010" when ( iDIN =  4 ) else
           X"0020" when ( iDIN =  5 ) else
           X"0040" when ( iDIN =  6 ) else
           X"0080" when ( iDIN =  7 ) else
           X"0100" when ( iDIN =  8 ) else
           X"0200" when ( iDIN =  9 ) else
           X"0400" when ( iDIN = 10 ) else
           X"0800" when ( iDIN = 11 ) else
           X"1000" when ( iDIN = 12 ) else
           X"2000" when ( iDIN = 13 ) else
           X"4000" when ( iDIN = 14 ) else
           X"8000" when ( iDIN = 15 ) else
           X"0000" ;

end Behavioral;

 出力したいセンサー情報をまとめます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity tpat is
  Port (
    DIN  : in  std_logic_vector(3 downto 0) ;
    DOUT : out std_logic_vector(3 downto 0) --;
  );
end tpat;

architecture Behavioral of tpat is
  -- constant table
  CONSTANT ALL_BLACK   : integer :=  0 ;
  CONSTANT ALL_WHITE   : integer :=  1 ;
  CONSTANT LEFT_WHITE  : integer :=  2 ;
  CONSTANT RIGHT_WHITE : integer :=  3 ;
  CONSTANT CENTER      : integer :=  4 ;
  CONSTANT TINY_RIGHT  : integer :=  5 ;
  CONSTANT RIGHT       : integer :=  6 ;
  CONSTANT BIG_RIGHT   : integer :=  7 ;
  CONSTANT TINY_LEFT   : integer :=  8 ;
  CONSTANT LEFT        : integer :=  9 ;
  CONSTANT BIG_LEFT    : integer := 10 ;
  CONSTANT BOTH_WHITE  : integer := 11 ;
  CONSTANT ILLEAGAL    : integer := 12 ;
  -- internal registers
  signal iDIN  : integer range 0 to 15 ;
  signal iDOUT : integer range 0 to 15 ;
begin
  -- input
  iDIN <= conv_integer(DIN) ;

  -- output
  DOUT <= conv_std_logic_vector(iDOUT,4) ;

  -- decoder
  iDOUT <= CENTER     when ( iDIN =  0 ) else
           CENTER     when ( iDIN =  1 ) else
           TINY_RIGHT when ( iDIN =  2 ) else
           RIGHT      when ( iDIN =  3 ) else
           TINY_RIGHT when ( iDIN =  4 ) else
           CENTER     when ( iDIN =  5 ) else
           TINY_LEFT  when ( iDIN =  6 ) else
           LEFT       when ( iDIN =  7 ) else
           TINY_LEFT  when ( iDIN =  8 ) else
           TINY_LEFT  when ( iDIN =  9 ) else
           CENTER     when ( iDIN = 10 ) else
           CENTER     when ( iDIN = 11 ) else
           BIG_RIGHT  when ( iDIN = 12 ) else
           RIGHT      when ( iDIN = 13 ) else
           TINY_RIGHT when ( iDIN = 14 ) else
           CENTER     when ( iDIN = 15 ) else
           ILLEAGAL ;

end Behavioral;

 3つのブロックをトップレベルで接続。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity mcrd is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 4MHz
    -- monitor
    MCLK   : out std_logic ;
    -- sequencer output
    SQOUT  : out std_logic_vector(3 downto 0) ;
    -- decoder output
    DCOUT  : out std_logic_vector(15 downto 0) --;
  );
end mcrd ;

architecture behavioral of mcrd is
  -- clock divider
  signal iCLK : std_logic ;

  -- sequencer
  signal iSQOUT : std_logic_vector(3 downto 0) ;

  -- internal pattern
  signal iPATOUT : std_logic_vector(3 downto 0) ;
  
  -- decoder
  component tx138 is
    port (
      DIN  : in  std_logic_vector(3 downto 0) ;
      DOUT : out std_logic_vector(15 downto 0) --;
    ) ;
  end component;

  component tpat is
    Port (
      DIN  : in  std_logic_vector(3 downto 0) ;
      DOUT : out std_logic_vector(3 downto 0) --;
    );
  end component;

  -- sequencer
  component tseq is
    Port (
      -- system 
      nRESET : in  std_logic;
      CLOCK  : in  std_logic; -- 4MHz
      -- monitor
      MCLK   : out std_logic ;
      -- counter out
      SQOUT  : out std_logic_vector(3 downto 0)
    );
  end component;

begin
  -- output
  MCLK  <= not iCLK ;
  SQOUT <= iSQOUT ;

  -- module instance (decoder)
  DECXinst : tx138 port map (
      DIN  => iPATOUT ,
      DOUT => DCOUT 
  );

  -- module instance (pattern)
  TPATinst : tpat port map (
      DIN  => iSQOUT  ,
      DOUT => iPATOUT
    );
  
  -- module instance
  TSEQinst : tseq port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK ,
      -- monitor
      MCLK   => iCLK ,
      -- counter out
      SQOUT  => iSQOUT
  );

end behavioral;

 XC9572を利用した場合のピン割り当ては、以下。

# system
NET "CLOCK"  LOC = "P5"  ;
NET "nRESET" LOC = "P39" ;

# monitor 
NET "SQOUT<0>" LOC = "P1" ;
NET "SQOUT<1>" LOC = "P2" ;
NET "SQOUT<2>" LOC = "P3" ;
NET "SQOUT<3>" LOC = "P4" ;
NET "MCLK"     LOC = "P9" ;

# lower
NET "DCOUT<0>" LOC = "P11" ;
NET "DCOUT<1>" LOC = "P12" ;
NET "DCOUT<2>" LOC = "P13" ;
NET "DCOUT<3>" LOC = "P14" ;
NET "DCOUT<4>" LOC = "P18" ;
NET "DCOUT<5>" LOC = "P19" ;
NET "DCOUT<6>" LOC = "P20" ;
NET "DCOUT<7>" LOC = "P22" ;

# upper
NET "DCOUT<8>"  LOC = "P24" ;
NET "DCOUT<9>"  LOC = "P25" ;
NET "DCOUT<10>" LOC = "P26" ;
NET "DCOUT<11>" LOC = "P27" ;
NET "DCOUT<12>" LOC = "P28" ;
NET "DCOUT<13>" LOC = "P29" ;
NET "DCOUT<14>" LOC = "P33" ;
NET "DCOUT<15>" LOC = "P34" ;

 波形観測用にサウンドカードに接続する
 アダプタを作成しました。回路は、以下。



 実際に利用するPC上のソフトウエアは、フリー
 で使えるものをダウンロードしました。




 サウンドカードでは、最高周波数として10kHz程度の
 交流信号のみ観測できます。周波数の上限としては
 厳しいですが、あるとないとでは大違いです。

 利用するにはデスクトップタイプのPCが必要ですが
 1チャネルでもよければ、ノートPCでも使えます。

 手軽に持ち運びできるように、タッパウエアに入れ
 使い勝手を良くしています。





 電源は006P電池を利用し、9Vを4.5V
 の正負電源にします。



 GBC(GameBoyCamera)を利用するとき、レンズの前に偏光板を
 おくかどうかやLED照明を使うかどうかの条件を決めます。

 偏光板の着脱とLED光照射の指定を簡単にするため、マイコン
 による条件の指定をすると、その環境を用意できるように
 治具を作成。

 偏光板は、サーボモータでGBCのレンズの前に置くか遠ざける
 ようにし、LED照明はMOSFETのスイッチで電流を流すか止める
 ことができるようにします。



 治具のハードウエアは簡単ですが、条件設定をArduinoから
 できるように、PIC12F1501のファームウエアを書きました。

typedef unsigned char UBYTE ;
typedef unsigned int  UWORD ;

/* pin assignment */
#define SOUT PORTA.F0
#define LOUT PORTA.F1
#define SWCR PORTA.F2
#define SWDN PORTA.F4
#define SWUP PORTA.F5

#define OFF 0
#define ON  OFF+1

#define CNTBEGIN 236

#define MASK03 0x03

#define SCNTMAX 2000
#define XCNTMAX 10000

#define LUPPER 200
#define LLOWER 100

volatile UWORD scnt ;
volatile UWORD xcnt ;
volatile UBYTE duty  ;
volatile UBYTE dutyx ;

volatile UBYTE sflag ;
volatile UBYTE eflag ;

volatile UBYTE usft ;
volatile UBYTE dsft ;
volatile UBYTE csft ;

/* function prototype */
void  init_usr(void);

/* interrupt handler */
void interrupt(void)
{
  /* generate 100kHz */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* set flag */
    sflag = ON ;
    /* increment */
    xcnt += 1 ;
    /* judge */
    if ( xcnt == XCNTMAX ) {
      xcnt = 0 ;
      eflag = ON ;
    }
  }
}

void main(void)
{
  /* initialize */
  init_usr() ;
  /* endless loop */
  while ( ON ) {
    /* generate servo motor PWM */
    if ( sflag == ON ) {
      /* clear flag */
      sflag = OFF ;
      /* impress */
      if ( scnt < dutyx ) { SOUT = ON ;  }
      else                { SOUT = OFF ; }
      /* update */
      scnt += 1 ;
      /* judge */
      if ( scnt == SCNTMAX ) {
        /* clear */
        scnt = 0 ;
        /* update */
        dutyx = duty ;
      }
    }
    /* shift register handling */
    if ( eflag == ON ) {
      /* clear flag */
      eflag = OFF ;
      /* shift */
      usft = usft + usft ;
      dsft = dsft + dsft ;
      csft = csft + csft ;
      /* mask */
      usft &= MASK03 ;
      dsft &= MASK03 ;
      csft &= MASK03 ;
      /* update LSB */
      if ( SWUP == OFF ) { usft |= ON ; }
      if ( SWDN == OFF ) { dsft |= ON ; }
      if ( SWCR == OFF ) { csft |= ON ; }
      /* judge */
      if ( usft == MASK03 ) { duty = LUPPER ; }
      if ( dsft == MASK03 ) { duty = LLOWER ; }
      if ( csft == MASK03 ) {
        if ( LOUT == ON ) { LOUT = OFF ; }
        else              { LOUT = ON  ; }
      }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* select 16MHz */
  OSCCON = (15 << 3) | MASK03 ;
  /* 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 directions */
  TRISA = 0x3C ; /* bit 0 and bit 1 as output , others as input */
  /* pull-up */
  WPUA = 0x3C ;
  /* initialize Timer 0 */
  {
    /*
       16MHz/4 = 4MHz -> 4MHz/2 = 2MHz prescaler = 1:2
       2MHz = 2000kHz , 2000kHz / 100kHz = 20
    */
    OPTION_REG = 0x00 ;
    /* 256 - 20 = 236 */
    TMR0 = CNTBEGIN ;
    /* enable timer0 overflow interrupt */
    INTCON.T0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* clear flag */
  sflag = OFF ;
  eflag = OFF ;
  /* initialize variables */
  scnt = 0 ;
  xcnt = 0 ;
  duty = LLOWER ;
}

 タイマー割込みで、スイッチの状態を読込み、サーボモータに
 与えるパルス幅を変えられるようにしました。上、下を指定
 するボタンとLED光の照射制御の3ボタンにまとめています。

 GBCとArduinoは、1枚のプレートに実装したので、空いている
 スペースにPIC121501とモータドライバを半田付けした基板を
 入れます。




目次

inserted by FC2 system