はじめに
導体をPWMで制御しているとき、電流を測定したい。(DCブラシモータの電流計測に使える?→知らん)
→PWMのON時間中にAD変換をしたい。(シャント抵抗の電圧値を測定→電流計測)
今回想定するような回路を以下に示す。
右の回路はFETによる駆動回路とシャント抵抗による電流計測。
右上の銅線まきまきは、導体。←この導体の電流や抵抗値が知りたい、制御したい。
左の抵抗2つは、電源電圧測定用、導体の抵抗値や消費電力を測定したい場合必要。
まず結果
PWMが1[kHz]、デューティ比0.05以上の場合、良好な結果が得られた。(Arduino Nanoを使用)
位相/周波数PWM動作で、PWMは反転で出力がいい感じ
電源電圧とアクチュエータの電流を同時には測定できませんでした。(PWMの周期ごとに交互に測定した{Arduinoの限界})
検索すべきワード
Arduino PWM周波数変更
Arduino タイマ割り込み
など
なにをすれば実現できそうか
1. タイマでPWMを発生させる
Arduino標準のPWM(analogWrite())の機能では、周波数の設定が機能がなく、どのみちタイマ割り込みの設定で、タイマを設定するため、PWMはAVRの機能で実装する。
2. タイマ割り込みを使う
PWMを発生させているタイマを利用して、PWMがONになっているときに、AD変換を行う。
3. 割り込み中にAD変換する
今回は、Arduino標準のAD変換であるanalogRead()を利用する。
→ 分周を変更し、高速化してもよいが、最高の精度は得られないかも。
このとき、割り込みで多くの時間を消費することになる。AD変換完了割込みを使うことで回避できるが、今回はほっとく。
実験環境
使用器具
- Arduino Nano
- シャント抵抗(カーボン抵抗1/4[W])
- 電流を計測したいもの
- Nch MOSFET 2SK4017
- その他FETゲート電流制限抵抗など
補足
今回はArduino Nanoを使用しました。これにはATmega328pが搭載されており、Arduino Unoも同じMCUで構成されているため、同じプログラムが実行できます。(AVRの機能を利用するためMCUが変わると利用できない)
Arduino Nanoは16[Mhz]だよ
今回はPWMの出力に9番ピンをつかったよ
具体的に方法の検討
タイマは何を使うか→Timer1
ArduinoでPWMを利用できるPINは6本存在しています。それらは3, 5, 6, 9, 10, 11ピンです。
今回はPWM出力ピンを9または10を前提に開設します。以下に理由を書きます。
Arduino Nanoに搭載されているATmega328pには、タイマとよばれるカウンタが存在します。
これらはクロックごとに自動的に加算されていきます。このカウンタは1クロックに1加算ということも可能ですが、分周によって、2クロックごと、8クロックごとなど、加算の仕方を変更することができます。
ATmega328pにはタイマが3つ(Timer0,Timer1,Timer2)搭載されており、個別に数値を加算させていくことが可能です。また、それぞれカウンタの上限値、分周を個別に設定することが可能です。それぞれのタイマが対応したピンにPWMを出力可能です。
各タイマとPWM出力ピンの関係、Arduino内で使用されている関数を以下の表に示します。
タイマ | ピン番号 | bit数[bit] | すでにArduinoで使用されている機能 |
---|---|---|---|
Timer0 | 5, 6 | 8 | delay(),millis(),micros() |
Timer1 | 9, 10 | 16 | Servoライブラリ |
Timer2 | 3, 11 | 8 | タイマ割込みライブラリ |
ここでTimer0の設定を変更すると、delay()など、Arduinoで利用されている関数の時間がくるいます。
Timer2でもいいけど、まあ今回はTimer1で説明します。
これらの理由から今回は、設定を変更しても影響の少ないTimer1を利用してPWMを発生させます。
PWM周波数の決定
→今回は1[kHz]以下で、最小デューティ比とのバランス
AD変換の実行時間について
ATmega328pのAD変換機は1つ内臓されており、ArduinoのA0~A7までのピンの電圧を10[bit]で測定することができる。なお、同時に測定することはできない。(ADCが1つしか内臓されていないため)
なお、あるピンを測定時、104[us]よりも後に、他のピンを変換することはできる。
Arduino NanoのAD変換は、変換開始から理論値で104[us]で完了する。また、測定には104[us]の時間がかかるが、AD変換開始直後に、測定するピンの電圧を保持する機構が内蔵されているため、電圧を保持した後は、電圧が変換しても、AD変換開始直後の電圧値を測定できる。
また、AD変換の電圧保持にはAD変換クロックの約2クロックの時間が必要であり、これは(1/16[MHz])×128[分周]×2[クロック]=16[us]の時間、電圧が変化しなければ、イイ感じに電圧を測定できる。(ハズ ここは詳しく知らない
(AD変換クロックは、Arduinoでは標準で128分周されている)
PWMとAD変換のタイミング
PWMのON時に、AD変換をするために、Timer1により、PWMの発生とタイマ割り込みを行う。
また、PWMには高速PWM動作や位相/周波数基準PWM動作など存在するが、今回は位相/周波数基準PWM動作、出力を反転で構成した。以下説明
タイマの動作の種類
ここでは、比較AなどをPWMしきい値と表しています。
高速PWM動作
高速PWM動作ではカウンタが加算されていき、TOP値になると0に戻る。
位相/周波数基準PWM動作
位相/周波数基準PWM動作ではカウンタが加算されていき、TOP値になると、減算されていく。
なぜ位相/周波数基準PWM動作を選択するのか
今回タイマ割り込みを利用するばあい、割り込み要求ができるのが、比較一致した場合か、TOP値と一致した場合です。
ここで、位相/周波数基準PWM動作の反転出力(黄)に注目すると、PWM出力がONのとき、かつON時間の1/2の時に、カウンタがTOP値と一致し、割り込みが発生することが分かる。
では、高速PWM動作ではどうなのかというと、高速PWM動作の非転出力では、カウンタがTOP値での割り込みの時、同時に出力が立ち上がり、電圧が上昇する。
もしFETの立ち上がりが遅く、AD変換の電圧保持時、電圧が安定していない場合などを考え、位相/周波数基準PWM動作を選択した。
→もしかしたら、そこまで考えなくてもいいのかもしれない。実際これをすると必要なON時間が2倍になる(ちょっと損かも)。
デューティ比とPWM周波数の決定
まず、必要なON時間を求め、その後最小デューティ比と、PWM周波数を求める。
必要ON時間は32[us]である。
→AD変換では開始後16[us]は、測定したい電圧である必要があり、位相/周波数基準PWM動作では、ON時間の半分しか使えないことがわかったため。
最小デューティ比を決める。これはアクチュエータの動作にさほど影響を与えない程度に決定する。(物による)例えばデューティ比0.05(5[%])
必要なON時間と最小デューティ比からPWM周波数を決定する。
→必要なON時間32[us]、最小デューティ比0.05から、32[us]/0.05=640[us]→1562[Hz]以下となる。
もし、最小デューティ比を倍の0.1にすると、PWM周波数は約3[kHz]以下となる。
実際にやっていく
やること
- タイマの設定
- タイマ割り込みの設定
- AD変換
タイマの設定
指定した周波数でPWMを出力できるようにする
今回は9番ピンをPWMの出力に割り当てる。
Timer1のTOP値を自由に指定できるレジスタICR1(捕獲レジスタ)に設定する。
pinMode(9, OUTPUT);
//Timer1 変更
TCCR1A &= B11111100;
TCCR1A |= B00000000; //WGM11,10, TOP値ICR1:00
位相/周波数基準PWM動作に設定する
TCCR1B &= B11100111;
TCCR1B |= B00010000; //位相,周波数基準 WGM13,12 位相/周波数基準:10
分周なしに設定
TCCR1B &= B11111000;
TCCR1B |= B00000001; //1分周:001
PWMの周波数を設定する。
top = (muc_frq / frq/2); //マイコンの周波数/PWMの設定周波数/2(←この2は位相/周波数基準PWM動作であるため)
ICR1 = top; //レジスタに代入
デューティ比を設定する。
OCR1A = (unsigned int)(top * duty);
ここでdutyは0~1
最後にPWMを出力させる(反転動作)
TCCR1A &= B00111111;
TCCR1A |= B11000000; //PWM動作 pin9出力
この時点で9番ピンから指定したPWMが出力される。
タイマ割り込みの設定
//カウンタがTOP値になったときこの関数が呼ばれる。 この関数はloopやsetuoではない、外に記述する。
ISR(TIMER1_CAPT_vect) {
//AD変換
}
setup関数内にTimer1の捕獲割込みを有効化する。+全割込み許可
//タイマ1 捕獲割込み 有効
TIMSK1 &= B11011111;
TIMSK1 |= B00100000;
sei(); //割込み 許可
おわりに
電流値を測定するには、シャント抵抗の電圧値と抵抗値から、電流を導出する。
電源電圧を利用することで、導体の抵抗値がわかる。(ハズ
参考サイト
- [analogWrite()](https://gar![uploading-0]()
retlab.web.fc2.com/arduino_reference/language/functions/analogio/analogWrite.html
) - Timer1で任意の周期の割り込みを発生させるためのレジスタ設定
- ArduinoのTimerを初心者が1からなんとなくわかるためのメモ