別のPWMプログラムまたはZenによるAttiny13aリハビリテーション

私はHabrとその多くの住民に挨拶します!



ここで議論されていることは初心者のためにあまり設計されていないことをすぐに予約しなければなりませんが、それでも興味と勉強への渇望がある場合は、知ってください。



そして、今回は、すでに多くのネットワークを生み出しているハイブリッドPWMの実装について説明します。 ですから、もう1つ、2つ、または3つ(ボーナス)は不要ではない、または不要ではないと思います。



だから、まず第一に、なぜハイブリッドなのか:第一に、それは100%ハードウェアではなく、100%ソフトウェアでもないからです。

これはどういう意味ですか:ハードウェアカウンターは実装に使用されますが、出力はI / Oポートの1つのチャネルではなく、タイマー割り込みでポートチャネルをマスクする構成マスクを使用して3つ一度に生成されます。

ハードウェアとの違いは何ですか? はい、すべてがシンプルです-Attiny13aマイクロコントローラーのチャネル間。



より詳細に。

誰がそれを必要とし、なぜですか? さて、そのようなタスクのアプリケーションの主な分野は、モーターの制御-非同期、双極および単極-ステッピング、光と音響効果のコントローラー、超音波デバイス(超音波槽、彫刻機、ミキサーなど)などです。 もちろん、そのような目的のために専用のコントローラーが作成されましたが、手元に小さなペットがいる場合、LHを探してお金をかけ、掘るのはなぜですか。



彼の興味が突然現れたとき、私は最初の質問に焦点を当てました。一方、ある開発者(彼を "Saddened"と呼びます)が、十分なPWMハードウェアチャネルを持たないAttiny13aマイクロコントローラーが自慢できなかったという事実によって悲しまれたフォーラムの1つを読みました想定されるソフトウェアの実装に必要なパフォーマンス。

「Saddened」は多くのオプションを試し、定数を変更し、Cコードを最適化し、割り込みを有効にしましたが、すべて無駄でした。 そして、彼がフォーラムで提起したトピックは、いくつかのぼんやりした年に悪化し、未解決で報われないままでした。



上記のマイクロコントローラの9.6 MHzで動作するPWMプログラムモードの速度に興味がありました。 そして、「Sorrowed」で説明されているすべての側面を可能な限り使用して実装する小さなソースをスケッチし、Proteusのソフトウェアエミュレーションで、約4 kHzの周波数で、13番目のPWM Tinikの3つの足でゆっくり受信しました。



少し…少なすぎる! そして、どういうわけかそれはすべて奇妙です...しかし、非常に興味深いのは、そのような単純なタスクを破らなければ、それは本当に最初の小さな失望の1つであり、より生産的で洗練されたチップへの直接的な道であり、それに応じて価値があるからです 一方で、それはかなりプラスですが、それでも理解できます。



そして、私は考えました:「そして、なぜ、タスクが比較を通じて実装されるとき、実際、なぜ同期はタイマーのオーバーフローに基づいているのですか?!」

オーバーフローモードでは、タイマーは、フルサイクルを通過した後、オーバーフロー時に1回だけ割り込みを発生させる必要があるためです。 ソースをわずかに変更して、約40 kHzを受信しました。 「すでに良いが、それでも-ここで何かがおかしい!」



一般的に、私はもうあなたを退屈させません。すべての変数はレジスタで宣言され、コードはパフォーマンスのために最適化されました。

およびサイズ(ほとんどすべてが消えた)、さらにゲームで相対パルス変位を持つ2つのモードが得られました。

その後、新しい最適化が行われ、その結果、最も遅いモード(6フェーズ)がインラインアセンブラーに書き換えられました。 そして、これは偶然に行われたもので、コンパイル後に取得したコードに注意を向けたとき、簡単に言えば、驚いたことになりました! レジスターで変数を宣言する場合でも、コンパイラーはすべての操作をタイムペアで実行することを決定したため、コードはほぼ2倍になり、サイズの最適化が有効になりました。 最初のオプションからいくつかの余分な動きと40バイトのゲイン、および周波数のほぼ10 kHzの増加。



結果は3つのモードです。

1.位相シフトのあるパルス、利用可能な最大周波数は、CLK = 9.6 MHzで75.500 kHz(CLK = 20 MHz、周波数は160 kHzに近い)、PWMデューティサイクル= 33.3%、期間-3フェーズ:





2.パルスは3分の1ずつシフトし、最大周波数は37.400 kHz(CLK = 20 MHzで75 kHz)、デューティサイクル= 50%、周期は6フェーズです(アセンブラを使用しないと28 kHzの制限を超えることはできません。詳細についてはソースコードを参照)。





3.パルスは、最初のモードの最大周波数の半分、デューティサイクル= 66.6%、期間-3段階でオフセットされます。





ここでの周波数とは、ある周期(または1パルスの周期)で繰り返されるまで、3つのチャネルに沿ったパルスの完全な繰り返しを意味します。 はい、デューティサイクルの変更はこのタスクの範囲に含まれていませんでしたが、2番目のタイマー比較レジスタを使用してこれを行うのは非常に簡単です(ただし、これは最初のモードにのみ当てはまります)。 この場合、周波数の変更は実装され、位相幅の変更を通じて実装されます(ソースコードの詳細)。



なぜこれほど多くのモードがあるのですか? これがすべてではなく、その多くはすべて特定のデバイスの特性によるものです。

そのため、たとえば、非同期モーターは最初のモードで制御され、ユニポーラステップショップは2番目のモードで制御されます(ただし、必要なチャンネルの数はこれより少なくても多くてもかまいませんが、例があれば、チャンネル数の増減は何もありません)。



低い周波数をプログラムで取得するには、タイマー分周器のレジスタを変更する必要があります。

これが多すぎる場合(たとえば、ステッピングモーターの場合)、マイクロコントローラーの周波数を下げる必要があります。

したがって、128 kHzのチップ周波数で、CLK分周器を設定し、タイマー分周器と最小パルス幅(最大周波数)なしで、2番目のモードを使用する場合、パルス周波数は62 Hzです。



非同期モーターの制御について説明すると、12フィールドのエンジンを使用する場合、最初のモードである約20 kHz(〜78/4)を使用したときに最大パルス繰り返し率が得られます。回転(毎秒)。 :o)



もちろん、上記の計算は、ホールセンサーまたは逆EMFからの読み取り、位相持続時間の調整など、完全な制御を必要とするオーバーヘッドを反映していません。 しかし、このような頻度のマージンにより、これらのタスクはメインプログラムサイクルで簡単に解決できます。



それとは別に、一行の状況に神経質な教祖に謝罪しますが、ここでは迅速なコメントの便宜のために意図的に行われました。 第二の、そしてより平凡な理由:私は我慢が嫌い-/ *アスタリスク付きのコメント* /、ただしインラインに切り替えるとき-他には何も与えられなかった。



肥大化してハンドラーに成長し始めたときにプロジェクトで私のコードを使用する場合は、レジスターで使用される変数のすべての宣言をキーワード「volatile」で武装する必要があります。その結果、コンパイラーはリクエストで吐き出したいことをスナップし、彼が喜ぶなら、彼は彼の裁量でこれらのレジスタを使用します(そのようなものが不足している場合)。



コーディング時にはできるだけ簡潔にしようとしながら、コメントのより詳細な情報を可能な限り完全に反映しようとしました。





もちろん、必要な場合を除き、ご質問にお答えし、信号構成の変更を支援させていただきます。

上記のすべてについて、私は次のことを示したいと思います。私は自分自身をスーパーオプティマイザー、スーパープログラマー、およびスーパーエレクトロニックエンジニアとして位置づけていません。

私は、新参者が無敵のタスクはないと信じ、専門家は書き終えるには時期尚早のチップに注意を払い、多くのクラスの価値のあるアプリケーションを見つけることができるように、すべてを書きました。



PS:初心者向け:私見では、高周波を使用しているため、プロジェクトは初心者にとっては十分に興味深いものではありません。 ただし、コントローラーは、位相幅を変更するためのメインサイクルのコメント化されていないライン、周波数分周器(4.8 / 8)がオン(コードが最適化されるか後になるまで覚えていない)で4.8 MHzのファームウェア、およびPB0、PB1ラインに接続されたLED PB2は、デスクトップフラッシャーの役割では面白そうです。

一部の、特に神経質な人は、「このゴミは厄介です-肘の脳に」と言いますが:)



PPS:新規参入者ではありません:さらに、最適化、および使用(友人なしで行います!)

byte A=0, B=1, C=2; if (A==0 || B==1 || C==2) doSomething(); / if (A==0 && B==1 && C==2) doSomething();
      
      





そして、フォームの「間違った」使用:

 if (A==0 | B==1 | C==2) doSomething(); / if (A==0 & B==1 & C==2) doSomething();
      
      





結果は同じになりますが、2番目の例ははるかに長い時間実行され、コードは大幅に膨らみます。

なぜ?! そして、私は言いません、あなた自身が推測する! :)



このメモを止めて、添付資料に慣れることを提案します。

Proteus 8.1のプロジェクトとAtmel Studio 6.2で作成されたソースコード

ご清聴ありがとうございました、すぐに会いましょう!



商用プロジェクトでの使用、ソースコードの転売、および営利目的での使用は禁止されています。

他のサイトで使用される場合、ソースコードは無料で配布されます。

または、他の情報源では、著者の表示と配置の通知は必須です。



All Articles