2010年
8月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

セットアップ日記


2010年08月10日 AVR tiny261を使って

_ マイコン制御サイリスタ

ゼロクロスのサイリスタを使っているが、電流計でモニタしてみると、電流のON/OFFの頻度がそれほど高くないようで、電流計の読みがぶれる。基本的には、電源が50Hzだとすると半波を数えると100Hzとなり、出力の大きさにもよるが、ON/OFFのタイミングは、少なくとも10Hz程度はあるはずで、電流計のぶれもそれほど大きくはならないように感じる。オシロで見てみると、一秒間に数回しか切り替えていないように見える。電流が大きくなると、サイリスタはノイズを発生するので、ノイズの少ないゼロクロス方式を使おうと考えているのだが、電流計のぶれが気になる。

気に入らなければ作るしかないかということで、以前計画したAVRを用いてサイリスタユニットを作る計画を実行に移すことにした。石としては、AD変換を使いたいので、tiny261を使うことにする。基本的な回路は以前書いた通りだが、マイコンはトランスで電気的に浮いているので、入力は直接抵抗に流して、その電圧を読むことにした。

電源電圧がゼロになるところは、トランスで電圧を落として、整流して片側だけにした電圧をツェナーダイオードで頭を落としたものを、INT0/ADC9とINT1/ADC2に入力する。そして、falling edgeを割り込みで検出して、そのあとAD変換して、約1V以下になるのを待っている。回路の特性なのか、1V以下になったあとも、なかなか0Vにはならず、だらだらとdecayするので、例えば0.5Vになるのを待っていると、電源電圧のゼロを検出できないようだ。アナログ比較器を使おうかとも思ったが、配線をやり直すのが面倒なので止めにした。

あとは、読み取った出力に応じて、パルスを出す場合と出さない場合を判断するだけだ。しかし、出力がちょうど50%のときには、交流の電圧が正または負の片側だけしか使わないことになってしまうのだが、これは問題ないのだろうか。なんだか気持ち悪い。まあ、そんな偶然はあまり無いから良いか。

とりあえず、汚いけどソースはこんな感じ。

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000
#include <util/delay.h>
#define setbit(PORT,BIT) PORT|=_BV(BIT)
#define clearbit(PORT,BIT) PORT&=~_BV(BIT)
#define checkbit(PORT,BIT) (PORT&_BV(BIT))
#define POWER_ZERO 45 // 220ohm*4mA
#define POWER_MAX 180 // 220ohm*(20-4)mA
static volatile unsigned int power=0;
// AD converter
void adc_init(){
  clearbit(ADMUX,REFS1);  // Vcc
  clearbit(ADMUX,REFS0); // Vcc
  setbit(ADMUX,ADLAR); // bit3-9
  clearbit(ADCSRB,MUX5); // ADC setting
  clearbit(ADCSRA,ADPS2); // CK/4 
  setbit(ADCSRA,ADPS1); // CK/4
  clearbit(ADCSRA,ADPS0); // CK/4
}
int adc_read(){
  unsigned char c;
  setbit(ADCSRA,ADSC); // adc start
  _delay_us(16);
  while(checkbit(ADCSRA,ADIF)==0);
  c=ADCH;
  setbit(ADCSRA,ADIF);
  return c;
}
void pulse(unsigned char c){
  setbit(ADCSRA,ADEN); // enable adc
  while(adc_read()>0x40);
  setbit(PORTB,c);
  _delay_ms(1);
  clearbit(PORTB,c);
  clearbit(ADCSRA,ADEN); // disable adc
}
void read_power(){
  unsigned int c;
  setbit(ADCSRA,ADEN); // enable adc
  ADMUX&=0xf0;
  ADMUX|=0x00; //ADC0
  adc_read();
  c=adc_read();
  c+=adc_read();
  c/=2; //average
  if(c>POWER_ZERO+POWER_MAX){c=POWER_ZERO+POWER_MAX;}
  if(c>POWER_ZERO){power+=c-POWER_ZERO;}
  clearbit(ADCSRA,ADEN); // disable adc
}
void pin_init(){
  clearbit(GIMSK,INT0); /* disable INT0 */
  clearbit(GIMSK,INT1); /* disable INT1 */
  setbit(MCUCR,ISC01); /* interrupt falling */
  clearbit(MCUCR,ISC00); /* 00:L, 10:fall, 11:raise */
  setbit(GIMSK,INT0); /* enable INT0 */
  setbit(GIMSK,INT1); /* enable INT1 */
}
ISR(INT0_vect){
  cli();
  ADMUX&=0xf0;
  ADMUX|=0x09; //ADC9
  if(power>=POWER_MAX){power-=POWER_MAX;pulse(0);}
  read_power();
  sei();
}
ISR(INT1_vect){
  cli();
  ADMUX&=0xf0;
  ADMUX|=0x02; //ADC2
  if(power>=POWER_MAX){power-=POWER_MAX;pulse(1);}
  read_power();
  sei();
}
int main()
{
  cli(); /* disable interuption */
  PORTA=0x00;
  PORTB=0x00;
  DDRA=0x00;
  DDRB=0x03;
  pin_init();
  adc_init();
  _delay_ms(100);
  sei();
  for(;;);
}
あとは、パルス出力をフォトサイリスタで受けて、その出力をメインのサイリスタに入れるだけのはずだ。しかし、極性などを間違え無いように気を使わないといけない。
[]