メカハード
ラジコンのベースに入っている制御基板のパワーデバイスの
特性が不安だったので、交換することにしました。
制御基板を外して、ワイヤーとコネクタをつけます。
コネクタで、下の基板と接続します。
新しい制御基板の回路は、以下。
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)
目次
前
次