目次

3相交流信号生成

 技術者の知人から、3相交流信号をマイコンで生成できた
 とオシロスコープの静止画が送られてきました。



 廃棄した冷凍庫の中に、3相交流信号を生成して
 コンプレッサを動かしていました。
 これに触発されて、Arduinoで3相交流信号を生成
 します。

 3相交流信号は、正弦波を3個生成し、位相差を
 120度、240度とする。

 この仕様で考えると、正弦波の1周期を配列に格納し
 カウンタで値を出力するなら、3つのカウンタで配列
 から取り出してくる値を変えればいけるはず。

 正弦波の1周期を128として、正弦波の波形を
 配列に格納。それをカウンタ値が+1される都度
 引き出して、出力。

 単純な考え方でよいのですが、ArduinoはD/A変換器を
 もっていないので、正弦波の値を生成できたとしても
 出力する術がないと思い勝ちです。

 PWMを利用すると、デジタル値をアナログ値へと変換
 できるので、D/A変換器の代用で使う。

 この手を利用して、次のコードを考えました。

  if ( eflag == ON ) {
    /* clear flag */
    eflag = OFF ;
    /* calculate */
    i = state ;
    k = (i + 42) & 0x7f ;
    j = (i + 85) & 0x7f ;
    uu = *(stbl+i);
    ww = *(stbl+j) ;
    vv = *(stbl+k) ;
    /* impress */
    if ( tflag == ON ) {
      analogWrite(UP,uu);
      analogWrite(VP,vv);
      analogWrite(WP,ww);
    } else {
      PORTB = 0x00 ;
    }
    /* update */
    state++ ;
    state &= 0x7f ;
  }

 関数analogWriteは、D/A変換で利用できるので
 3つの端子から正弦波を出力。

U PB1
V PB2
W PB3

 analogWriteは、PWMを利用するので、正弦波を出力する
 ピンを、次のように決めました。

 変数i、j、kを利用して、iから位相差に相当する
 値を加えてj、kの値を生成。

 j、kは0から128の範囲に収まるように128で
 割った余りを代入しておきます。

 正弦波は、中央値を電源電圧の半分とし、中央値から
 上下に振れるように考えます。

 正弦波の値を、配列に格納する処理は、以下。

  for ( i = 0 ; i < BSIZE ; i++ ) {
    *(stbl+i) = (byte)(127*(sin(i*PI/64)+1));
  }

 予期しない時に、正弦波を出力しないようにモニタを
 入れて対応します。

 モニタで使うコマンドは、次のように決定。

 正弦波を出力するか停止するのかをフラグtflagで
 制御できるようにしておきます。

 コマンドインタプリタは、次のように定義。

  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf() ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help(); }
    /* enable */
    if ( cmd == 'G' ) {
      state = 0 ;
      tflag = ON ; 
    }
    /* disable */
    if ( cmd == 'g' ) { tflag = OFF; }
  }

 文字出力、文字列出力、改行および受信割込みハンドラは
 以下でよいでしょう。

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

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

void show_help()
{
  rs_puts("? help")    ; crlf();
  rs_puts("G enable")  ; crlf();
  rs_puts("g disable") ; crlf();
}

/* receive interrupt */
void serialEvent()
{
  char ch;
  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 まとめると、以下。

#include <MsTimer2.h>
#include <math.h>

#define OFF 0
#define ON  OFF+1

#define XINTERVAL 10
#define BSIZE     128

#define UP 9
#define VP 10
#define WP 11

/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();

/* variables */
boolean tflag ;
boolean eflag ;
boolean uflag ;

byte state ;
byte sbuf[8] ;
byte sindex ;

byte cmd ;
byte i ;
byte j ;
byte k ;
byte stbl[BSIZE] ;
byte uu ;
byte vv ;
byte ww ;

void setup()
{
  /* initialize serial */
  Serial.begin(9600);
  sindex = 0 ;
  rs_puts("Hello !");
  crlf();
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  /* initialize port values */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x00 ;
  /* initialize port direction */
  DDRB = 0xff ;
  DDRC = 0xff ;
  DDRD = 0xfe ;
  /* variables */
  state = 0 ;
  for ( i = 0 ; i < BSIZE ; i++ ) {
    *(stbl+i) = (byte)(127*(sin(i*PI/64)+1));
  }
  /* 5ms period */
  MsTimer2::set(XINTERVAL,update_trigger);
  /* enable */ 
  MsTimer2::start();
}

void loop()
{
  /* command interpreter */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf() ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help(); }
    /* enable */
    if ( cmd == 'G' ) {
      state = 0 ;
      tflag = ON ; 
    }
    /* disable */
    if ( cmd == 'g' ) { tflag = OFF; }
  }
  /* handling */
  if ( eflag == ON ) {
    /* clear flag */
    eflag = OFF ;
    /* calculate */
    i = state ;
    k = (i + 42) & 0x7f ;
    j = (i + 85) & 0x7f ;
    uu = *(stbl+i);
    ww = *(stbl+j) ;
    vv = *(stbl+k) ;
    /* impress */
    if ( tflag == ON ) {
      analogWrite(UP,uu);
      analogWrite(VP,vv);
      analogWrite(WP,ww);
    } else {
      PORTB = 0x00 ;
    }
    /* update */
    state++ ;
    state &= 0x7f ;
  }
}

void update_trigger()
{
  /* set flag */
  eflag = ON ;
}

void show_help()
{
  rs_puts("? help")    ; crlf();
  rs_puts("G enable")  ; crlf();
  rs_puts("g disable") ; crlf();
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

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

/* receive interrupt */
void serialEvent()
{
  char ch;
  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}



目次

inserted by FC2 system