ふとマイコンを使ったPWM出力を使って電力制御ができるはずと思い至ってプログラム書いてみた。
過去に作った8ビットのADCルーチンはそのまま活用。実はミス見つけたのでこっそり直した。
昔、コンパレータかやや高速なオペアンプを使い、擬似的な三角波を作り、これと可変抵抗からの電圧を読み込んでPWM制御をやった。
256段階のPWM制御でいいのであればマイコンのPWMでいいんじゃないかと思う次第。
PWMは1.2MHzで255カウントするので、1200/256=4.7kHz程度。目視であれば十分な速度。もしもっと速度を早くしたいなら、内臓クロックが1.2MHz以外にも、2.4MHz、4.8MHz、9.6MHzと選べるので、
9.4kHz(=2.4MHz/256)、18.8kHz(=4.8MHz/256)、37.5kHz(=9.6MHz/255)も選べる。せいぜい9.4kHz程度でいいかと思うけど。
以下プログラムのコード。
delayを使わないので、F_CPUのdefineは不要なんだけど、入ってる。
/*
* _20130923_Tiny13A_ADCtoPWM.c
*
* Created: 2013/09/23 23:42:27
* Author: m
*/
/*
ATTiny13A Pin割り振り
1:PB5 RESET ADC0 →出力端子に設定しちゃうとリセット出来なくなるので使わない
2:PB3 CLKI ADC3
3:PB4 ADC2
4:GND
5:PB0 MOSI OC0A
6:PB1 MISO OC0B
7:PB2 SCK ADC1
8:VCC
*/
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#define Level4 179 // =255/5*3.5
#define Level3 153 // =255/5*3.0
#define Level2 128 // =255/5*2.5
#define Level1 102 // =255/5*2.0
unsigned char AnalogRead8bit(unsigned char Ch)
{
//8bit分解能で十分なのを前提に設定を行っている。
unsigned char ADC_result;
//デジタル入出力からの切り離し
DIDR0
= (0<<ADC0D) //ADC0ピンの切り離し。しかし、ADC0はリセット端子になってるから設定しちゃダメ
| (1<<ADC1D) //同ADC1を切り離す(1設定で切り離し実行、0設定で接続)
| (1<<ADC2D) //同ADC2
| (1<<ADC3D); //同ADC3
ADMUX
= (0<<REFS0) //Reference: 0でVCC参照, 1で1.1V内部電圧源
| (1<<ADLAR) //ADC Left Adjust Result: 1にセットすると左詰で結果を出してくる
| (Ch); //ADMUX1, ADMUX0で入力チャンネルを選べる 00から11までADC0からADC3まで対応
ADCSRA
= (1<<ADEN) //ADC enable
| (1<<ADSC) //ADC Start Conversion 1にすると変換開始
| (0<<ADATE) //ADC Auto Trigger Enable (for Continuous Conversion)
| (0<<ADIF) //ADC Interrupt Flag 変換完了すると1になるらしい
| (0<<ADIE) //ADC Interrupt Enable 変換完了したときに割り込み許可
| (0b100); //Clock Division: ADコンバータはクロック50-200kHzで性能がよい
//分周は0のとき2、それ以上の時2^n分周 1.2MHz(Default)のとき16分周(100)で75kHz。9.6MHzのとき128分周(111)で75kHz
loop_until_bit_is_set(ADCSRA,ADIF); //ADIFビットが1になるまでムダループ
ADC_result = ADCH;
//ピン切り離しの解除
DIDR0
= (0<<ADC0D) //ADC0ピンの切り離し。しかし、ADC0はリセット端子になってるから設定しちゃダメ
| (0<<ADC1D) //同ADC1を接続(1設定で切り離し実行、0設定で接続)
| (0<<ADC2D) //同ADC2
| (0<<ADC3D); //同ADC3
return ADC_result;
}
void SetPWM(unsigned char Duty_0_255)
{
TCCR0A
= (1<<COM0A1) //OC0A端子をターゲットに、COM0A1:A0は高速PWM設定で以下の動作(高速PWMで使うモードのみセット)
| (0<<COM0A0) //10;BottomでHigh, 比較一致でLow、11;BottomでLow、比較一致でHigh
| (0<<COM0B1) //COM0B1:B0は出力がOC0Bになるだけで、同じ設定
| (0<<COM0B0) //
| (1<<WGM01) //WGMレジスタはTCCR0BのWGM02とあわせて設定
| (1<<WGM00); //WGM2:0が 011で8bit高速PWM動作
TCCR0B
= (0<<FOC0A) //非PWM動作のときのみ有効。今回は0設定
| (0<<FOC0B) //同上
| (0<<WGM02) //TCCR0AのWGMビット参照
| (0<<CS02) //CS0xでプリスケーラ設定
| (0<<CS01) //000停止、001=1分周、010=8分周、011=64分周、100=256分周、101=1024分周
| (1<<CS00); //110=T0ピン下降端(外部クロック)、111=T0ピン上昇端(外部クロック)
OCR0A=Duty_0_255;
//OCR0B=0b00000; //OCR0Bは使わないのだ!
}
int main(void)
{
DDRB = 0b00000011; //出力端子設定
while(1)
{
SetPWM(AnalogRead8bit(2));
}
}