目次

メカハード

 ラジコンのベースに入っている制御基板のパワーデバイスの
 特性が不安だったので、交換することにしました。

 制御基板を外して、ワイヤーとコネクタをつけます。



 コネクタで、下の基板と接続します。



 新しい制御基板の回路は、以下。



 HブリッジICのMP4212を利用し、マイコン、FPGAとの間に
 フォトカプラを入れます。
 パワー系からの逆起電力をカットしておきます。

 ワイヤーで、制御基板を接続すると、次の写真の様に。



 制御基板は、スタッドを利用して、ベースに固定します。



 アクリル板を制御基板の上に配置し、アクリル基板上に
 カメラ、マイコン+FPGA基板を載せます。



 全体を組み上げていくと、以下のようになります。

 モータ制御基板を、スタッドに入れます。



 アクリル板の下に、モータ制御基板を配置。



 マイコン、FPGA、カメラ用の電池をアクリル板の
 左側にビス止めします。



 最後に、マイコン、FPGAを載せる基板を
 アクリル板にスタッドを用意して固定。



 メカハードをテストするファームウエアを
 ATtiny2313で作成しました。

 簡単なコマンドを決めて、過去のファームウエアで
 使える部分は、流用です。


#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>

#define OFF 0
#define ON  OFF+1

#define MASKFF 0xff
#define MASK7F 0x7f
#define MASK0F 0x0f
#define MASK02 0x02
#define MASK80 0x80

#define PWM_MAX 100

#define FOSC   20000000
#define BAUD   9600
#define MYUBRR (FOSC/16/BAUD)-1

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;
typedef   signed char  SBYTE ;
typedef   signed short SWORD ;

#define BSIZE 8
#define INTERVAL 30

const prog_char msg_h[] PROGMEM = "? help" ;
const prog_char msg_f[] PROGMEM = "F front   duty and direction" ;
const prog_char msg_r[] PROGMEM = "R reverse duty and direction" ;
const prog_char msg_s[] PROGMEM = "S show parameters" ;

/* variables */ 
volatile UBYTE uflag ;
volatile UBYTE cmd ;
volatile UBYTE sbuf[BSIZE] ;
volatile UBYTE sindex ;
volatile UBYTE xtmp ;
volatile UBYTE pcnt ;
volatile UBYTE fduty  ;
volatile UBYTE rduty  ;
volatile UBYTE fdutyx ;
volatile UBYTE rdutyx ;
volatile UBYTE fdir   ;
volatile UBYTE rdir   ;

void  user_initialize(void);
void  uart_putchar(UBYTE x);
void  crlf(void);
void  uart_puts(UBYTE *x);
UBYTE uart_get_hex(UBYTE x) ;
void  show_help(void);

/*------*/
/* main */
/*------*/
int main(void)
{
  UBYTE tmp ;
  UBYTE i ;
  /* */
  user_initialize();
  /* enable interrupt */
  sei();
  /* loop */
  while ( ON ) {
     if ( uflag == ON ) {
      uflag = OFF ;
      /* get command */
      cmd = *(sbuf+0) ;
      /* front duty or reverse duty */
      if ( cmd == 'F' || cmd == 'R' ) {
        crlf();
        /* duty */
        xtmp  = uart_get_hex( *(sbuf+1) ) ;
        xtmp *= 10 ;
        xtmp += uart_get_hex( *(sbuf+2) ) ;
        if ( cmd == 'F' ) {
          fduty = xtmp ;
        } else {
          rduty = xtmp ;
        }
        /* direction */
        xtmp = uart_get_hex( *(sbuf+3) ) ;
        /* judge inhibit */
        if ( xtmp == 3 ) { xtmp = 0 ; }
        /* set */
        if ( cmd == 'F' ) {
          fdir = xtmp ;
        } else {
          rdir = xtmp ;
        }
      }
      /* show */
      if ( cmd == 'S' ) {
        for ( i = 0 ; i < 2 ; i++ ) {
          tmp = 'F' ;
          if ( i == 1 ) { tmp = 'R' ; }
          uart_putchar(tmp) ;
          uart_putchar(' ') ;
          tmp = fduty ;
          if ( i == 1 ) { tmp = rduty ; }
          uart_putchar( tmp / 10 + '0' ) ;
          uart_putchar( tmp % 10 + '0' ) ;
          uart_putchar(' ') ;
          tmp = fdir ;
          if ( i == 1 ) { tmp = rdir ; }
          uart_putchar( tmp + '0' ) ;
          crlf();
        }
      }
      /* help */
      if ( cmd == '?' ) { show_help(); }
    }
  }
  /* dummy */
  return 0 ;
}

/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
  /* PORT B */
  PORTB = 0b00000000 ; /* 00000000 */
  DDRB  = 0b11111111 ; /* oooooooo */
  /* PORT D */
  PORTD = 0b00000001 ; /* 00000000 */
  DDRD  = 0b11111110 ; /* oooooooi */
  /* initialize flags */
  uflag = OFF ;
  /* initialize UART */
  {
    /* initialize pointer */
    sindex = 0 ; 
    /* set Baud Rate Registers */
    UBRRL = MYUBRR ;
    /* Enable receive interrupt , receive module and transmit module */
    UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
  }
  /* initialize timer1 */
  {
    /* compare match (1/64) -> about 300kHz */
    TCCR1B = (1 << WGM12) | (3 << CS10) ;
    TCNT1 = 0 ;
    OCR1A = INTERVAL ;
    OCR1B = 60000 ;
    /* set TIMER1 interrupt */
    TIMSK = (1 << OCIE1A) ;
  }
  /* initialize duty ratio */
  fduty  = 0 ;
  rduty  = 0 ;
  fdutyx = 0 ;
  rdutyx = 0 ;
  /* initialize direction */
  fdir   = 0 ;
  rdir   = 0 ;
}

/* receive interrupt */
ISR(USART_RX_vect)
{
  UBYTE tmp ;
  /* get 1 charactor */
  tmp = UDR ;
  /* store */
  *(sbuf+sindex) = tmp ;
  /* update counter */
  sindex++ ;
  /* judge */
  if ( tmp == '\r' ) {
    sindex = 0 ;  
    uflag  = ON ;
  }
}

/* timer1 interrupt */
ISR(TIMER1_COMPA_vect)
{
  volatile UBYTE tmp ;
  /* default */
  tmp = 0 ;
  /* judge */
  if ( pcnt < fdutyx ) { tmp |= 3 ; }
  if ( pcnt < rdutyx ) { tmp |= 12; }
  /* increment */
  pcnt++ ;
  /* judge */
  if ( pcnt == PWM_MAX ) {
    pcnt = 0 ;
    fdutyx = fduty ;
    rdutyx = rduty ;
  }
  /* impress */
  tmp &= ((rdir << 2) | fdir);
  PORTB = tmp ;
}

void  uart_putchar(UBYTE x)
{
  while ( !(UCSRA & (1 << UDRE)) ) ;
  UDR = x ;
}

void  crlf(void)
{
  uart_putchar('\r');
  uart_putchar('\n');
}

void  uart_puts(UBYTE *x)
{
  while ( *x != '\0' ) {
    uart_putchar( *x ) ;
    x++ ;
  }
  crlf();
}

UBYTE uart_get_hex(UBYTE x)
{
  UBYTE result ;
  /* default */
  result = 0 ;
  /* judge */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }

  return result ;
}

void show_help(void)
{
  char msg[32] ;
  /* set message */
  strcpy_P(msg,msg_h); uart_puts((UBYTE *)msg);
  strcpy_P(msg,msg_f); uart_puts((UBYTE *)msg);
  strcpy_P(msg,msg_r); uart_puts((UBYTE *)msg);
  strcpy_P(msg,msg_s); uart_puts((UBYTE *)msg);
}

 コマンドは、4種類用意しました。

  • ? help
  • F set front duty and direction
  • R set reverse duty and direction
  • S show parameters  PWM波形を分岐させるために、次の回路と等価な  コードを書いてあります。  メカハードの制御は、FPGAに任せようと考えて  いるので、PWM用のVHDLコードを定義しました。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity pwmax is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input DIR : in std_logic_vector(1 downto 0) ; TRG : in std_logic ; -- duty ratio DUTY : in std_logic_vector(6 downto 0) ; -- output POUT : out std_logic_vector(1 downto 0) --; ); end pwmax; architecture Behavioral of pwmax is signal iCNT : integer range 0 to 100 ; signal iDUTY : integer range 0 to 100 ; signal iDUTYX : integer range 0 to 100 ; signal iOUT : std_logic_vector(1 downto 0) ; signal iDIR : std_logic_vector(1 downto 0) ; -- trigger signal iTRG : std_logic ; signal iTRG_SFT : std_logic_vector(2 downto 0) ; begin -- output POUT <= "00" when ( iDIR = "11" ) else (iOUT and iDIR) ; -- input iDIR <= DIR ; -- internal clock iOUT <= "11" when ( iCNT < iDUTY ) else "00" ; -- counter process(nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; elsif rising_edge( CLOCK ) then if ( iCNT = 100 ) then iCNT <= 0 ; iDUTY <= iDUTYX ; else iCNT <= iCNT + 1 ; end if ; end if; end process; -- trigger process(nRESET,CLOCK) begin if ( nRESET = '0' ) then iTRG_SFT <= "000" ; elsif rising_edge( CLOCK ) then iTRG_SFT <= iTRG_SFT(1 downto 0) & TRG ; end if; end process; iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ; -- BUS interface process(nRESET,CLOCK) begin if ( nRESET = '0' ) then iDUTYX <= 0 ; elsif rising_edge( CLOCK ) then if ( iTRG = '1' ) then iDUTYX <= conv_integer( DUTY ) ; end if ; end if; end process; end Behavioral;  信号は、下図に合わせています。  DUTY比は、0〜99をDUTYに設定し、TRGを使い設定します。  パルス出力は、DIRで次のように振り分けます。
  • DIR=(0,0) => POUT=(0,0)
  • DIR=(0,1) => POUT=(0,pulse)
  • DIR=(1,0) => POUT=(pulse,0)
  • DIR=(1,1) => POUT=(0,0)
  • 目次

    inserted by FC2 system