Arduinoはどのようにして特定の(つまり56 kHz)キャリア周波数を出力できますか?


9

私は、2点間でデータをワイヤレスで送信するための自由空間光学プロジェクトに取り組んでいます。これを達成するために、送信機には56 kHzの搬送周波数でパルスするArduino Unoに接続されたIR LEDを使用し、受信機には56 kHzのIR検出器モジュールを持つ2番目のArduinoを使用しています。

キャリア周波数を作成するために、pin highコマンドとpin lowコマンドの間にdelayMicroseconds()を使用してみました。この種の方法は機能しますが、周波数は常に同じであるとは限らず、信号をパルスするための追加の遅延(つまり、関数を呼び出してデクリメントするのに必要な時間)によって、信号が変化する可能性があります。

ATmega328のデータシートを読むと、チップのタイマーを使用してより正確なパルスを設定する方法があるようです。それは可能ですか?可能であれば、タイマーを使用して56 kHzパルスをどのように作成しますか?


56KHz周波数に必要な精度はどれくらいですか?つまり、プロジェクトで許容できる周波数範囲はどれですか。Arduinoタイマーを単独で使用すると、精度に制限があるためです。
jfpoilpret 2014

検出器で高レベルの応答性を維持するには、55.5kHz〜56.5kHzが理想的です。
jlbnjmn 2014

回答:


10

Arduino タイマーで56 kHz信号を生成することは確かに可能です。

タイマーは実際にはMCU内の特別なレジスターと見なすことができ、MCUクロック周波数(Arduino Unoでは16 MHz)の周波数で増分される値(0から開始)を保持します。プリスケーラ。その値が、指定したCompare Matchと呼ばれる制限に達すると、2つのことが起こります。

  • タイマーレジスタの値は0にリセットされます。
  • 1つのISR(割り込みサービスルーチン)コールバック関数が呼び出されます(独自のコードを指すように定義できます)。

アイデアは、そのISRを使用して、それが呼び出されるたびに(HIGH、次にLOW、次にHIGH...)論理ピンの出力を変更することです。

ここで、56 kHzの方形波を生成するには、ISRを56000 * 21秒あたりの時間と呼ぶ必要があります(* 2周期ごとに2回出力値を変更する必要があるため)。

以下のリストから、タイマーに必要なプリスケーラー値を選択できます。

  • 1(クロック周波数は分割されないため、16 MHz)
  • 8(クロック周波数は8で除算されるため、2 MHz)
  • 64
  • 256
  • 1024

Arduino Unoには2つのサイズのタイマー/カウンターがあります(実際にはタイマー/カウンターと呼ばれます)。8ビットと16ビットです。

Arduino Uno(ATmega328P)では、全体で3つのタイマーがありますが、一部はArduinoコアライブラリまたはスケッチで使用される他のライブラリで使用される場合があります(自分で確認する必要があります)。

  • timer0(8ビット)
  • timer1(16ビット)
  • timer2(8ビット):これには、より多くのプリスケーリングオプションがあります(1、8、32、64、128、256、および1024)。

ここで、16 MHzから56 kHzの波を生成する必要があるため、事前スケーリングを行わずに、次のようにカウントする必要があります。

16000000 / (56000 * 2) - 1 = 141.857- 1タイマーは0からこの値までカウントし、タイマーに達したでのみリセットされるため)

この計算から、2つの観測結果を引き出すことができます。

  1. 141.857 は整数ではないため、正確に56 kHzの波を生成することはできません。
  2. 事前スケーリングなしでは、285は8ビットの符号なし整数として表現できないため、16ビットのタイマーが必要です。

これからは、2つのオプションがあります。

  1. 16ビットタイマー(timer1)を使用し、プリスケーラー= 1を使用し142て、比較一致として選択します。次の頻度が得られます。16000000 / (2 * (142 + 1)) = 55944 Hz
  2. 8ビットタイマー(timer0)を使用し、プリスケーラー = 8を使用し17て、比較一致として選択します。次の周波数16000000 / (8 * 2 * (17 + 1)) = 55555 Hzでは精度が低下します。これはまだ必要な範囲内です。

さて、そのためのスケッチの書き方に関して、非常に完全で非常に興味深いこのインストラクターをチェックすることをお勧めします。

もちろん、ATmega328Pの完全なデータシートは、あなたが何をしているかをほんの少しだけ理解したい場合にも重要です。

いくつかの重要な注意事項:

  • ISRは無効な割り込みで実行されるため、可能な限り短くする必要があります。特に、ISRから呼び出されないArduinoライブラリの関数がいくつかあります。
  • Arduino Unoクロックはあまり正確ではないため(水晶の代わりにセラミック共振器を使用します。これははるかに正確でした)、これは出力周波数がさらにシフトすることを意味します。

2
また、指定された制限に達すると、ハードウェアはピンを切り替えることができます。したがって、ISRを使用する必要はまったくありません。ISRは、いったん開始すると中断できないため、常にジッタが発生します。ただし、ハードウェアは常にピンを望ましいレートでトグルします。
Nick Gammon

Arduino Unoがセラミック共振器を使用していることは少し意外ですが、そのソースはArduino UNO FAQです「Unoはプロセッサクロックに共振器または水晶を使用していますか?」の近くにあります)。
Peter Mortensen

3

私が見つけたtone()いずれかのピンに高周波パルスを生成するために有用。56 KHzを処理できる必要があります。(編集:jfpoilpretで述べたように、実際に16 MHz Arduinoに到達できる最も近いのは約55.944 KHzです)

問題は明らかにそれをデータ信号と組み合わせることです。低レベルのコードに頼らずにソフトウェアでそれを行うことはできないと思います。それはデジタルなので、ハードウェアではかなり簡単なはずです。

データ信号を別のピンに出力し、ANDゲートを使用してキャリアと組み合わせるだけです。結合された信号は、直接IRトランスミッターに送信されます。

ANDゲートが手元にない場合は、トランジスタのペアを使用して独自に作成するのは非常に簡単です。「トランジスタとゲート」をオンラインで検索してください。


レシーバーは、多くの場合、アクティブロー出力を備えています。LEDの上部を56khzに接続し、下部をデータピンに接続すると、データピンがLowになるとIR出力が発生し、受信機がLowになります。いいえ、ゲートは必要ありません。LEDと抵抗が必要です。問題は、現在のioピンが駆動できるすべてのものに限定されています。
EternityForest

2

jfpoilpretの受け入れられた回答は非常によく書かれており、完全に有効であり、99%のケースでは、彼が説明するとおりに行います。彼のソリューションは定義されたパラメーターの範囲内にあるため、非常にうまく機能するはずです。しかし、「非常によく」より優れている点は何ですか。完璧!結局のところ、問題は正確な値を生成することです。ほとんどの場合(間違いなくすべて)、十分に近いことが適切であり、1秒を1秒にする必要があるときに時計として何かを処理する場合でも、継承された部分の欠陥に苦しむ必要があります。

私が提案することは常に可能であるとは限りません。場合によっては可能ですが、この場合よりもはるかに手間と労力がかかります。それはケースバイケースで依存する価値がありますか?私の目標は、主に、ややフリンジのケースでより良い将来の参照の代替を示すことです。これは、エレクトロニクスの経験があまりない初心者のArduinoユーザーを対象に書かれています。

より進んだ人にとっては、これはおそらく冗長すぎて、だまされて見えるでしょう。しかし、私は、それらの同じ人々はおそらくすでにそれを知っていて、この答えを必要としないと信じています。これは、すべてのマイクロコントローラー、すべてのメーカーとアーキテクチャにも当てはまります。しかし、他のマイクロコントローラーについては、正しいデータシートを調べて、適切なレジスターとプリスケールの名前と値を見つける必要があります。

あなたのケースでは、特定の周波数が必要ですが、その良い点は、正確に56 kHzが実際に非常に簡単に実現できることです(パーツの実際的な欠陥は数えません)。これも完璧な例です。

信号の生成は、jfpoilpretでよく説明されているように、マイクロコントローラーのタイマーとクロックソースに依存します。彼の答えは、1つの視点のみの問題を扱っており、それはタイマーをいじっています。しかし、クロックソースをいじることもできますが、相乗効果とすばらしい結果の両方を実現することもできます。環境のパラメーターを変更することにより、この場合はシステムをハッキングし、クロックソースを置き換えることで、特定の問題にはるかに簡単かつ簡単に対処できます。

まず、ピンの状態を切り替えるため、信号周波数の2倍のISRを実行する必要があります。これは毎秒112,000回です。すでに指摘したように、56,000と16,000,000はうまく加算されません。信号周波数またはタクト周波数を変更する必要があります。ここでは、不変の信号周波数を扱い、より良いクロック速度を見つけましょう。

ゼロを追加するだけであり、この種の計算はほとんどの人にとって最も単純であるため、56 kHz(または112 kHzですが、実際には同じです)の1桁以上大きいクロックを選択するのが最も簡単です。残念ながら、この世界のすべては何かとのある種の妥協です。すべての値が機能するわけではありません。

最初の例は、タクトジェネレータの速度が低すぎる場合です。

56,000 Hzのクロックを選択した場合、サイクルごとにISRを呼び出す必要があり、他には何もできないため、何もできません。それは全く役に立たない。10倍速い速度(560 kHz)を選択した場合、9(タイマーが最大値に到達するための10サイクル-ISR関数を呼び出すための1サイクル)マイクロコントローラーサイクルで作業が行われますが、これでは十分ではありません。多くの場合、より多くの計算能力が必要になります。

一方、あまりにも大きい値を選択した場合、56 MHzとなるため、マイクロコントローラーはそれを使用できません。速すぎます。そのため、ショップで最大の価値を選択するだけでは、それを削減することはできません。

元のArduino Uno R3は16 MHzのストッククロックを備えているため、動作が遅いことが保証されているものはすべて低速です。56 MHzより大きく16 MHzより低い次の値は5.6 MHzです。これにより、50サイクルごとにISRを呼び出すことができ、完璧な112,000 Hzのタイマー周波数が作成されます。そして、信号は正確に56 kHzになります。ISR呼び出し間でプログラムを実行するために49 MCUサイクルがありますが、それでも元のクロックの速度の約1/3です。112をベースとして使用し、11.2 MHzクロックを使用すると、ストックの16 MHz共振器の約2/3が得られます。ISR関数は100サイクルごとに呼び出され、完全な56 kHz信号を生成します。

ただし、これらの値には2つの大きな問題があります。

  • 最初の問題はニーズによって大きく異なります。見つけやすいレジスタ値(OCR iirc)を使用する正確な信号周波数を取得するには、最大計算能力の約1/3(11.2 MHzを使用)を犠牲にします。あなたはそれで大丈夫かもしれませんし、そうでないかもしれません。

  • 2番目の問題は、ハードショートッパーです。値を見つけるのは非常に簡単ですが、製造されたクロックソースとして存在しないことがよくあります。これは、5.6 MHzと11.2 MHzの両方が欠けているFarnellの共振器Webページです。

これを回避するには、利用可能な共振器の値を調べて、正確に必要な値を生成するために使用できる他の何かを見つけます。56を4で除算すると、14が得られ、幸いにも14 MHzの共振器があります。これにより、速度とパワーが大幅に向上し、レジスタ値を簡単に見つけることができます。1秒あたり112,000回ISRを呼び出すには、10進数の124または16進数の0x7Cの値をOCRレジスタに入れる必要があるため、ISRを呼び出すために124サイクル+ 1をカウントすると、目的の完全な値が得られます。

NB

  1. ISR-割り込みサービスルーチン(これは、生成された割り込みでのみ実行されるコードです)
  2. プログラムの大きさは、メモリサイズによって異なります。それはクロック速度とは関係がなく、ISRを呼び出す頻度とは関係がありません。
  3. マイクロコントローラーがプログラムコマンドで起動すると、カウンターが増加します。割り込みが発生すると、ISRが呼び出され、この値が特殊レジスターに格納されます。ISRコードが完了すると、プログラムカウンターの値がこの特殊レジスターから復元され、プログラムは、中断されたところから、あたかも発生しなかったかのように続行します。

    私は非常に馬鹿げた例を挙げます。あなたが純粋主義者なら、私はあなたに警告します:鼻と目の出血が起こるかもしれません。

    あなたがどこかからどこかに歩く必要があると想像してください。ステップバイステップのルート指示は、メインプログラムとそのコマンドです。歩いたり走ったりする速さは、「クロック速度」に依存しますが、ルートの指示には依存しません(前進30歩、左1ターン90進、前進10歩、右45進など)。常に同じです。 。小さな子供や貪欲な腐敗した地元の政治家があなたの靴をときどき解くと想像してみてください。これは、割り込みを生成するイベントです。次に、最後のステップの後で停止し、ひざまずいて靴をもう一度結びます。これはISRプログラムです。

    次に、停止した場所から続行します。あなたは最初から始めません。世の中を気にせずにいつも歩くときは、一歩おきに靴を結ぶ必要があるとしても、気にしないでください。しかし、オリンピックで100メートルを走る(または空腹の肉食の捕食者から走る)など、時間の制約がある状態でそれを行うと、靴を止めて結ぶことは悲惨な結果をもたらす可能性があります。マイクロコントローラーも同様です。たとえコードが1行だけ実行されたとしても、低速ではありますが、プログラムは続行されます。速度をまったく気にしなくても問題ありません。他のタイマーに依存するアクションを使用するなど、時間に関連する何らかの操作を行う必要がある場合、干渉は非常に望ましくなく、問題になる可能性があります。

  4. 少ないほうがいいですね!クロックが速いほど良いとは限りません。遅いクロックのデバイスはかなり少ない電力を使用します。これは、バッテリ駆動デバイスの重要なポイントになる可能性があります。

  5. 必要なサイクルは、次の式から導き出されます:(
    クロック速度/(プリスケーラ値*必要なISR呼び出し周波数))-1


TLDR:セラミック16 MHz発振器をデソルダーし、整数除算で正確に 56 kHz を許可する別のものに置き換えます(たとえば、14 MHzと250で除算)。
Peter Mortensen、2018年

0

出力と入力の間でキャリアピンモードを切り替えるだけで、キャリアのオンとオフを切り替えることができます。これを使用して、37KHz赤外線(リモート制御)ポートを介してヒートポンプを制御しました。


0

キャリアを作成するためにISRを使用する必要はありません。タイマーを設定して、必要なキャリア周波数で50%PWM出力を生成するだけです。ISRは、通常は0.5または1ms間隔で、はるかに快適な速度でキャリアを変調する役割を果たします。私の経験では、キャリア周波数の5%エラーはほとんどのIRレシーバーで許容されています。Freetronics EtherMega 2560(タイマーがたくさんあります)を使用しましたが、他のCPUでも同様に動作するはずです。


キャリアの変調はどの程度正確に実装されていますか?タイマー出力キャプチャピンのモードを入力(キャリアオフ)と出力(キャリアオン)の間で変更しますか?
Peter Mortensen、2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.