概要
ArduinoでPWMインバータ制御でHブリッジドライバから正弦波出力をする。
3kHzぐらいまで。
やり方
PWMのDuty比を正弦波に合わせて変更する。
TCNT:Timerカウンターの最大値をICRレジスタとしたモード14を選択
OCR1A=TCNTになったときに自動的に、PB1(pin9),PB2(pin10)がClear(0)するように設定。
TOP(ICR)=TCNTになったとき自動的に、PB1(pin9),PB2(pin10)がSet(1)するように設定。
OCR1A割り込みが発生したときに
- Duty比を読み出し、OCR1A値を変更
サンプルプログラム
/*
PWMで正弦波を出す
*/
#define space_clock 10
volatile boolean sp_flag = false;
volatile int sin_pos = 0;
volatile int sin_length[100];
volatile int max_sin;
void setup() {
pinMode(11, OUTPUT);
pinMode(4, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(A0, INPUT);
digitalWrite(11, HIGH);
//digitalWrite(9,HIGH);
//digitalWrite(10,LOW);
//Timer1 max(ICR1) 正弦波 100分割 1/8分周
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (1 << WGM11) | (0 << WGM10) | (1 << COM1A1) | (1 << COM1B1);
TCCR1B |= (1 << WGM13) | (1 << WGM12) | (1 << CS10);
ICR1 = 1030; //TOP:ICR1 周波数はこちら
max_sin = 1030 - space_clock;
//COMPA 割り込み
TIMSK1 |= (1 << OCIE1A) ;
}
ISR(TIMER1_COMPA_vect) {
//コンペアマッチでclearされるように設定している
//正弦波になるように調整
OCR1A = sin_length[sin_pos];
OCR1B = sin_length[sin_pos];
sin_pos++;
if (sin_pos >= 100) {
sin_pos = 0;
sp_flag = !sp_flag;
if (sp_flag) {
TCCR1A &= ~_BV(COM1A1);
TCCR1A |= _BV(COM1B1);
} else {
TCCR1A &= ~_BV(COM1B1);
TCCR1A |= _BV(COM1A1);
}
}
if (sp_flag) {
TCCR1C |= (1 << FOC1A);
} else {
TCCR1C |= (1 << FOC1B);
}
}
void loop() {
delay(100);
int data = analogRead(A0);
//double fz = 510 + (data/1024.0 -0.5)*500;
double fz = data / 1024.0 * 1000;
int onoff_time = 500000 / fz; //1000000us/fz / 2
ICR1 = onoff_time * 0.16; //1clock = 1/16[us] ICR割り込み100回で半周期
max_sin = ICR1 - space_clock;
for (int i = 0; i < 100; i++) {
sin_length[i] = sin(i / 100.0 * 3.141592) * max_sin;
}
}
障害対応:ICR増加させた時に割り込みが発生しなくなる
原因
ICR1<OCR1A,ICR1<OCR1Bに一時的に設定されること
対策
- OCR1A,OCR1BをICR1より先に更新する
- OCR1A<ICR1,OCR1B <ICR1にする。