通常のanalogWrite関数では「R4」でも「R3」同様にPWM周波数が490Hzに固定されているようなんですが、「R4」には「PwmOut」というクラスが用意されていて、そっちを使うと周波数(周期)をμ秒単位で指定できて、さらにピン毎でそれぞれ異なる周波数を設定できるよう。試しにPwmOutクラスを使って、PWM周波数を変更してみました。
▼Arduino UNO R4▼
最初はR3同様、RA4M1のレジスタを触りに行こうかと思っていたのですが pwm.h なるものが準備されているのを発見。もとより準備されてる物を使った方がはるかに簡単です。
まずは普通にAnalogWriteでPWM出力
void setup() { analogWrite(2, 128); } void loop() {}
まずは通常のanalogWriteの記述してデフォルトの周波数を確認してみます。あえて2番ピンからPWM出力指示。ArduinoのデータシートではPWMの割り当ては6本だけ(2番ピンは割り当て無し)ですが、RA4M1のデータシートではかなり多くのピンにPWMの割り当てがありました。なので試しに2番ピンからPWM出力を記述してます。
出力結果
2番ピンからでもPWM出力されました。また周波数はR3同様の490Hz程度。2番ピンからのPWM出力はArduino仕様にはないので自己責任で。ちなみにR4の場合、PWMピン3/5/6/9/10/11番全てのピンでデフォルト周波数は490Hz程度でした。
PwmOutクラスを使ったPWM出力(周波数の変更)
// 2023/11/29 imo lab. // 2024/11/01 修正 // https://garchiving.com/ #include "pwm.h" PwmOut pwm3(3);//3pin PwmOut pwm5(5);//5pin PwmOut pwm6(6);//6pin void setup() { pwm3.begin(20000.0f,50.0f); //3pin 周期 50us = 20kHz; パルス幅 25us = 50% pwm5.begin(); pwm6.begin(); //5pin 周期 1ms = 1kHz; パルス幅 200us = 20% pwm5.period(1); //ms pwm5.pulse_perc(20); //% //6pin 周期 200us = 5kHz; パルス幅 20us = 10% pwm6.period_us(200); //us pwm6.pulseWidth_us(20);; //% } void loop() {}
3番、5番、6番ピンにそれぞれ異なる周波数、パルス幅を出力するようにしてます。analogWriteに比べると少しだけ使い方が複雑です。(2024/11/01 コメントでコンパイルエラーの情報提供を頂いたのでスケッチ修正してます。)
出力結果
上から順に3、5、6番ピンです。ともに設定通りの周波数とDuty比で PWM がそれぞれ出力されてます。ただし複数ピンで同時にPWM出力する場合には、どうもArduinoで指定されているPWMピン(3/5/6/9/10/11番ピン)からしかうまく出力されないようです。
簡単にソース解説
#include "pwm.h" PwmOut pwm3(3);//3pin PwmOut pwm5(5);//5pin PwmOut pwm6(6);//6pin
pwm.hをインクルード。インスタンス化の引数はピン番号。
pwm3.begin(20000.0f,50.0f); //3pin 周期 50us = 20kHz; パルス幅 25us = 50% pwm5.begin(); pwm6.begin();
.beginでPWM出力を開始します。引数は周波数[Hz]、パルス幅[duty比]で、ともにfloat型。引数無しの場合は、デフォルトの490Hz、duty50%になります。昔(2023/11頃)はここの引数がint型でした。いつも間にかfloat型に変わっていたようです。
//5pin 周期 1ms = 1kHz; パルス幅 200us = 20%
pwm5.period(1); //ms
pwm5.pulse_perc(20); //%
//6pin 周期 200us = 5kHz; パルス幅 20us = 10%
pwm6.period_us(200); //us
pwm6.pulse_perc(10); //%
周期、パルス幅は個別にも設定できます。周期は「ms」「μs」で指定、またパルスは、「時間」、デューティ比「%」などいろいろな単位で指示できる関数が準備されてます。
とりあえず周波数1MHz(周期1μs)までは出力されることは確認しました。PWM周波数をピン毎に柔軟に設定できるのはanalogWriteよりいいですね。
コメント
今年初旬ではこのプログラムは動作しましたが2024年11月1時点では下記エラーが出てコンパイルできませんません。
error: call of overloaded ‘begin(int, int)’ is ambiguous pwm3.begin(50, 1);
原因はpwm.hの中に以下の様にbeginの定義が2つある為だと思います。Aruduino IDE Ver2.3.3です。
bool begin(uint32_t period_usec, uint32_t pulse_usec, bool raw = false, timer_source_div_t sd = TIMER_SOURCE_DIV_1);
bool begin(float freq_hz, float duty_perc);
そこで、上のbiginをコメントにしたpwm_.hを作り同じホルダーにおいて、#include “pwm_.h”と定義したところうまくコンパイルし、正常動作するようになりました。
記事に追加してくださると幸いです。
丸山さん、サイト拝見下さり有難うございます。。内容確認し記事に反映したいと思います。情報提供ありがとうございます。
さっそく内容確認してみました。確かにコンパイルできなくなってますね。提案頂いたように”pwm.h”を直接修正してもコンパイルできるようですが、2次不具合が心配だったためヘッダファイルは修正せずにコンパイル通るように記事内容を修正しておきました(.beginでは引数無し)。
pwm.hのままでも動作できるようにプログラムを変更できました。
pwm.hを見ますとbool begin(float freq_hz, float duty_perc);と書かれているので、最初の引数は周波数、次の引数はをデューティ比を指定するようです。
それと、両引数ともfloatの必要があります。
そこで周波数20kHz、Duty50%の場合は以下とすると動作しました。
pwm3.begin(20000.0f, 50.0f); //周波数 20kHz; デューティ比 50%