航空機モデル甚のLEDコントロヌラヌ

少し前に、 航空機モデルのゲヌトの䜜り方に関する蚘事に出䌚いたした。 実際、私は実際に電子機噚に関䞎したくありたせんでしたが、䜕らかの理由で、モデルに異なるりむンカヌを眮くずいうアむデアに倢䞭になりたした。 䞀郚の人は芁点を理解しおいたせん-䞊から䞋に向かっおLEDストリップでモデルにしがみ぀くほうがよく、遠くからでも矎しく芋えたす。 しかし、私はモデルをコピヌするこずを奜みたす。぀たり、すべおの電球、ストロボ、ヘッドラむト、その他のラむトは、オリゞナルず同じようにオンずオフを切り替える必芁がありたす。



いく぀かの理由から、提案されたオプションは私に合わなかった。 この蚘事では、航空機モデル甚の点滅および非点滅LEDコントロヌラヌのバヌゞョンに぀いお説明したした。



コントロヌラヌはATTiny13Aに基づいおいたす。 この蚘事は、AVRマむクロコントロヌラヌを扱う人にも圹立ちたす。 私はすべおを噛んで棚に眮いおみたので、この蚘事は䞻に初心者に興味がありたす。



このビデオから鉄片の胜力を掚定できたす。







゚ントリヌ



私がこの質問を遞び始め、その蚘事で提案されたボヌドをはんだ付けさえしたずき、これは私が必芁ずするものではないこずが刀明したした。 たず、順番にのみ点滅できるチャネルは2぀しかありたせん。 タむミングを調敎できたすが、アルゎリズムはファヌムりェアに組み蟌たれおいたす。 第二に、ボヌド䞊にはグラムを远加する3぀のボタンが既にありたす。 フラむトごずにりィンカヌをモデルごずに再配眮したり、LEDを再プログラムしたりするこずはありたせん。぀たり、これらのボタンは䞍芁です。 ワむダヌをコントロヌラヌに盎接はんだ付けし、必芁なアルゎリズムをプログラムするこずに䞀床同意したす。 最埌に、3番目に、ファヌムりェアは゜ヌスコヌドなしのバむナリ圢匏でしかありたせん。぀たり、䜕も倉曎するこずは䞍可胜です。



次のモデルを考えお、私はすぐに必芁なLEDの数ずそれらが点滅する方法を芋぀けたした。 「囜勢調査」の結果、4぀のチャネルが必芁であるこずがわかりたした各チャネルには2〜3個のLEDがありたした。





モデルは倧きく、飛ぶ。 そしお、それはLEDが芋えるべきであり、匷力でなければならないこずを意味したす。 前のモデルでは、私はシングルワットLEDでBANOを行いたした-明るい晎れた日の倕方でも、50mの距離から完党に芋えたす。 これが私のサむズです。



匷力なLEDに電力を䟛絊するこずはそれほど簡単ではないこずがわかりたした。 ボヌドには、リニアスタビラむザヌモヌタヌコントロヌラヌボヌド䞊からの電力しかありたせん。 ぀たり、1぀の匷力なLEDでももちろん抵抗を介しお接続するず、非垞に倧きな熱損倱が発生したす。 非垞に倧きいため、レギュレヌタヌの収瞮が溶けお穎になりたす。 蚈算の詳现はこちら



パルス電圧レギュレヌタの方が優れおいたすが、結局のずころ、LEDは電圧ではなく電流を安定化する必芁がありたす。 利点はmikruhaであるこずがわかりたした。 これは私がここで説明した準備の第2郚でした。



゚レクトロニクス



芁件を凊理したした。 それははんだごおを取る時間です。



私は電子工孊、䞀般的には初心者です。 そのため、私はAcinonyxから回路を創造的に䜜り盎したしたそれはVETERAN SCOOTERから回路を借りたした。 以䞋を倉曎する必芁がありたした。





䞀般に、オリゞナルの残りはほずんどありたせん。



ドラむバヌずしお、ZXLD1350超小型回路の䜿甚に成功したした。これは、シングルワットLED最倧電流350mAに電力を䟛絊するように正確に蚭蚈されおいたす。 さらに、総䟛絊電圧にすべおをたずめお投資した堎合、各チャネルで任意のLEDを盎列に配眮できたす。 ぀たり 3S11.1Vバッテリヌから回路に絊電する堎合、各チャンネルに最倧3個のLEDを眮くこずができ、それぞれの3.2Vが䞋がりたす。



PWM入力ず同じワむダを䜿甚しお、受信機ずは別にマむクロコントロヌラヌに電力を䟛絊したした。



画像



スキヌム。 各チャネルは、デヌタシヌトのスキヌムに埓っお構築されたす。 ボヌドにはこのようなチャネルが4぀ありたす1぀だけ描画したした。 私は3぀のLEDを描きたしたが、私が蚀ったように、各チャネルに任意の数のLEDを眮くこずができたす。 LEDを異なる色異なる電圧降䞋にするこずもできたす。䞻なこずは、LEDが同じ電流甚に蚭蚈されるこずです。 ドラむバ自䜓は、ダむオヌドを流れる電流が350mAを超えないように、このような電圧を遞択したす。



3぀のチャンネルのADJ入力は、トランゞスタを介しおコントロヌラヌ出力に接続されたす。 ZXLD1350ドラむバヌには、コントロヌラヌからLEDをオン/オフできる特別なメカニズムがありたす。 さらに、入力電圧を倉曎するか、PWMを䜿甚するこずにより、茝床をスムヌズに調敎できたす。 これは0.3Vから2.5Vの有効な入力電圧であり、コントロヌラから5Vを出力したす。 幞いなこずに、デヌタシヌトでは、トランゞスタの圢の゜リュヌションを掚奚しおいたす。 このトランゞスタが論理状態を反転させるこずだけを考慮する必芁がありたす-コントロヌラヌの足のれロはLEDをオンにし、ナニットをオフにしたす。 ただし、これはプログラムで修正する問題ではありたせん。



重量を節玄するために、䞡面ボヌドを䜜成するこずにしたした。 私はLUTずは友達になりたせんでしたが、フォトレゞストですべおが初めおうたくいきたした。 私もはんだマスクで遊んでみたしたが、技術に違反し、マスクが病気になりたしたそしお、いく぀かの堎所で完党に萜ちたした。 ゚ラヌは将来的に考慮されたすが、この詊みはそのたたにしたす。 ずにかく初めお転がりたす。



画像



画像



PCBレむアりト。 端の十字はドッキングマヌクです。 私はテクストラむトを少し䜙癜で切り取り、十字の堎所に穎を開けおからマスクを組み合わせたした。 穎の金属化は行わず、ゞャンパヌを管理したした。 さお、コンデンサヌの脚は偎面間のゞャンパヌずしおも機胜したす。



画像



完成品。 フレヌムで䜙分なテキ゜ラむトがトリミングされたした。 その結果、27x22mmのショヌルず4gの重量になりたした。 さお、ワむダずコネクタの別の2gが刀明したした。 デバむスは、暙準の3ピンJRコネクタを介しお受信機に接続されたす。 LEDドラむバは、バッテリヌバランシングコネクタから電力を受け取りたす。



画像



画像



1WはZXLD1360チップを少し芋るこずができたす。 3W LED電流750mAに電力を䟛絊するように蚭蚈されおいたす。 配線図ずピン配眮は同じであるため、ボヌドの配線が適切です。 䞀郚のパヌツの倀のみを倉曎する必芁がありたす、デヌタシヌトを吞っおください。



䞡面ボヌドの゚ッチングをただ行っおいない人のために、片面甚のいく぀かのオプションを投皿したす-チャンネル2、3、4。



私はebeeで䞭囜人からLEDを買いたした 。 ラゞ゚ヌタヌなしで特に賌入したしたが、どこにでも収たりたせん。 ラゞ゚ヌタヌずしおアルミニりム片を䜿甚したした。 LEDは、特殊な熱䌝導性テヌプたたは接着剀を䜿甚しお取り付けるこずができたす。 これはテストバヌゞョンでの倖芳ですここではラゞ゚ヌタヌが小さく、りォヌムアップ䞭です



画像



そしお、以前のモデルも同様です。



画像



ファヌムりェア



今、あなたはこの鉄片に呜を吹き蟌む必芁がありたす。 Scooter VETERANからのファヌムりェアの゜ヌスがむンタヌネット䞊で芋぀からなかったので、私はすべお自分でやらなければなりたせんでした。 いいえ、もちろん、䜕が入っおいるかを芋るためにファヌムりェアを分解したしたが、ATTiny13仕様を読むだけの方がはるかに䟿利でした。



マむクロコントロヌラヌには1KBのフラッシュしかないずいう事実にもかかわらず、私はCで曞くこずにしたした。これはより䟿利で芖芚的です。 もちろん、Arduinoのスケッチは䜕らかの方法で簡単になりたすが、私が蚈画したすべおがコントロヌラヌのメモリに収たるわけではありたせん。 したがっお、䞋䜍レベルに移動しお、レゞスタを盎接プログラムする必芁がありたした。 驚いたこずに、コンパむラヌAtmel Studio 6のgcc 3.4.2はかなり良いコヌドを生成したした。 確かに、コンパむラが最適ではない動䜜をする堎所がいく぀かありたしたが、これらの堎所は調敎するこずができたした。



ファヌムりェアのアヌキテクチャ䞊の問題は、いく぀かの抂念的に異なるアクションを同時に行う必芁があるこずです-ここで点滅、 ここで点滅せず、 ここで魚を包み 、PWM入力を聞き、それからPWM出力を生成したす。



叀兞的な䟋を挙げたしょう。 1぀のLEDを点滅させる必芁がある堎合はどうなりたすか それでは、プログラムは次のようになりたす。

while(1) { led1(on); delay(500); led1(off); delay(500); }
      
      







しかし、2぀のLEDを点滅させる必芁があり、呚波数が異なる堎合でもどうでしょうか たあ、もちろん、あなたはこのような䜕かを歪曲しお曞くこずができたす



 while(1) { led1(on); delay(300); led2(on); delay(200); led1(off); delay(500); led2(off); delay(200); }
      
      







しかし、タむミングずオンオフの順序を遞択するこずは非垞に難しいでしょう。 可胜であれば、もちろん疑わしい。 そしお、3぀のダむオヌドで点滅する必芁がある堎合はどうなりたすか そしお4぀



正しい解決策はタむマヌを䜿甚するこずです。 しかし、問題がありたす。マむクロコントロヌラヌのタむマヌは1だけで、それでも8ビットです。



実際、タむマヌが1぀ある堎合、倚くの゜フトりェアタむマヌを䜜成できたす。 このように芋えたすハヌドりェアタむマヌは高呚波数で刻々ず過ぎおいたす。 タむマヌ操䜜ごずに、ハンドラヌは、プログラムタむマヌの蚭定時間が切れたかどうかを確認したす。 刀明した堎合は、ハンドラヌを呌び出す必芁がありたす。



コヌドでどのように芋えるか芋おみたしょう。



 // Pointer to a timer handler typedef void (*eventHandler)(); // Software timers list typedef struct timer_t { uint16_t timeout; eventHandler handler; } timer_t; #define TIMERS_LIST_SIZE 5 timer_t timersList[TIMERS_LIST_SIZE];
      
      







プログラムタむマヌは、メむン鉄タむマヌがハンドラヌを呌び出す前にスクロヌルしなければならない回数のカりンタヌです。 ハンドラヌぞのポむンタヌが添付されたす。 これらの゚ントリのうち3぀はタスクに十分ですが、念のため、5぀の芁玠のサむズでプログラムタむマヌのリストを䜜成したした。



マむクロコントロヌラのタむマヌの蚭定の問題に぀いおは、少し埌で説明したす。 そしお今、゜フトりェアタむマヌの実装に぀いお。 初期化関数はシンプルに芋えたす-タむマヌのリストをリセットしたす



 void setupEventQueue() { // Clear timers list memset(timersList, 0, sizeof(timersList)); }
      
      







プログラムタむマヌを远加するには、空のスロットを探し、そこにタむムアりト倀ずハンドラヌぞのポむンタヌを入力するだけです。 コントロヌラのスペヌスを節玄するための゚ラヌチェックはありたせん。



 void addTimer(eventHandler handler, uint16_t timeout) { // Search through the timers list to find empty slot for(timer_t * timer = timersList; timer < timersList + TIMERS_LIST_SIZE; timer++) { if(timer->handler != NULL) continue; // Add the timer to the list timer->handler = handler; timer->timeout = timeout; break; } }
      
      







䞻なサむクルは次のずおりです。



 void runEventLoop() { runTimer(); // Set up sleep mode set_sleep_mode(SLEEP_MODE_IDLE); while(1) // Main event loop { wdt_reset(); // Sleep until the timer event occurs sleep_enable(); sleep_cpu(); sleep_disable(); //Iterate over timers for(timer_t * timer = timersList; timer < timersList + TIMERS_LIST_SIZE; timer++) { // Skip inactive timers if(timer->handler == NULL) continue; if(timer->timeout) // Decrement timeout value { timer->timeout--; } else // If it is already zero - execute handler { timer->handler(); timer->handler = NULL; } } } }
      
      







たず、タむマヌを開始したす以䞋で詳しく説明したすが、それほど簡単ではありたせん。 積極的に埅぀のではなく、睡眠を䜿甚したす。 各サむクルの開始時に、プロセッサはアむドルモヌドに入りたす。 これは、CPU自䜓がスリヌプ状態になるこずを意味したすが、すべおのタむマヌOK、すべお、1぀ですは匕き続き動䜜したす。 タむマヌが最埌たでカりントし、れロにリセットされるず、割り蟌みが発生し、プロセッサが起動しおプログラムがさらに進みたす。 必芁なものだけです。



はい、LEDりむンカヌで倚くの電力を節玄するこずはできたせんが、将来は同じフレヌムを眠りに萜ちるこずが非垞に圹立぀他のアプリケヌションで䜿甚できたす。



目が芚めたら、゜フトりェアタむマヌのリストを調べる時間です。 各レコヌドで、カりンタヌ倀を枛らしたす。 すでにれロに達しおいる堎合は、ハンドラヌを呌び出し、その埌、リストからタむマヌを削陀したすハンドラヌぞのポむンタヌにNULLを曞き蟌むこずにより。



すべおが1぀のスレッドで行われるため、ミュヌテックスずロックは䞍芁です。



固定呚波数でLEDを点滅させるには、プロセッサは次のようになりたす。LEDの状態を反転させ、しばらくしおから同じプロセッサを再床呌び出すようシステムに芁求したす。



 #define LED_A_PIN PORTB0 void toggleLedATask() { PORTB ^= (1 << LED_A_PIN); addTimer(toggleLedATask, TIMEOUT_MS(300)); }
      
      







これが機胜するには、ハンドラヌが䜕らかの圢で初めお呌び出す必芁がありたす。 これを行うには、メむンルヌプを開始する前に、0ミリ秒の遅延぀たり、最初の機䌚でハンドラヌを呌び出す時間であるずいうメッセヌゞをキュヌに入れたす。



 int main(void) { // Set up ports PORTB = 1 << LED_A_PIN; // LEDs switched off DDRB = 1 << LED_A_PIN; // output mode for LED pins setupEventQueue(); addTimer(toggleLedATask, TIMEOUT_MS(0)); sei(); runEventLoop(); }
      
      







たず、出力甚のピンをここで構成したす。 LEDはむンバヌタを介しお接続されおいるこずを思い出させおください。 したがっお、デフォルトのLEDをオフにするには、ポヌトにナニットを曞き蟌む必芁がありたす。



たあ、前埌に点滅するのは面癜くない。 䜕かもっずかっこいい たずえば、䞀床フラッシュしおから、䞀時停止した埌、2回点滅しおから3回繰り返しお、振っお、かき混ぜないでください。 たあ、これも難しくありたせん。



 #define LED_B_PIN PORTB1 uint8_t delayIndex = 0; const uint16_t delays[] = { TIMEOUT_MS(100), //on TIMEOUT_MS(700), //off TIMEOUT_MS(100), //on TIMEOUT_MS(200), //off TIMEOUT_MS(100), //on TIMEOUT_MS(700), //off TIMEOUT_MS(100), //on TIMEOUT_MS(200), //off TIMEOUT_MS(100), //on TIMEOUT_MS(200), //off TIMEOUT_MS(100), //on TIMEOUT_MS(1200), //off }; void complexLedTask() { PORTB ^= (1 << LED_B_PIN); uint16_t delay = delays[delayIndex]; delayIndex ++; if(delayIndex >= sizeof(delays)/sizeof(uint16_t)) //dim(delays) delayIndex = 0; addTimer(complexLedTask, delay); }
      
      







タむミングの衚を䜜成するだけです。 ハンドラヌは毎回、LEDの状態を倉曎し、衚に瀺されおいる時間埅機したす。



いく぀かのLEDを同時に独立しお点滅させるには、ポヌトを蚭定しおハンドラヌのリストに远加するこずを忘れずに、いく぀かの同様のハンドラヌを远加するだけです。



 int main(void) { // Set up ports PORTB = 1 << LED_A_PIN | 1 << LED_B_PIN | 1 << LED_C_PIN; // LEDs switched off DDRB = 1 << LED_A_PIN | 1 << LED_B_PIN | 1 << LED_C_PIN; // output mode for LED pins setupEventQueue(); addTimer(toggleLedATask, TIMEOUT_MS(0)); addTimer(complexLedTask, TIMEOUT_MS(0)); addTimer(blinkLedCTask, TIMEOUT_MS(0)); sei(); runEventLoop(); }
      
      







もちろん、このスタむルのプログラミングにただ慣れる必芁がありたすが、䞀般に、このアプロヌチはうたく機胜したす。 倧芏暡なコンピュヌタヌ甚のマルチスレッドアプリケヌションを䜜成しおいる堎合、通垞、各スレッドには氞遠のルヌプがあり、堎合によっおは䜕らかのスリヌプたたは埅機がありたす。 䞊蚘のハンドラヌは同じ氞遠のルヌプの本䜓であり、addTimer呌び出しは同じスリヌプであるず考えおください。



メむンタむマヌはどのくらいの頻床でチェックする必芁がありたすか 頻繁にカチカチ音をたおない堎合、枬定された時間間隔の粟床が䜎䞋したす。 䞀方、タむマヌサむクルごずに、䞀定数の有甚なアクションを実行する必芁がありたす。 そしお、これらのアクションは、次のタむマヌサむクルの前に完了する必芁がありたす。 そのため、タむマヌはカチカチ音をたお、あたり頻繁に同じではありたせん。



぀たり たれではありたせん。 しかし、どのように正確に さお、前のタスクでは、可胜な倀の範囲は非垞に広いです。 ただし、「PWM入力を聞く」ずいうタスクも芚えおおく必芁がありたす。 より具䜓的には、持続時間が800-2200ÎŒsのパルスがあり、この長さを枬定する必芁がありたす。 タスクでは、リモヌトコントロヌルからのコマンドによっおLEDをオン/オフしたす。これを考慮したす。パルスが1500 µsより短い堎合、LEDはオフになり、長くなるずオンになりたす。



マむクロコントロヌラずタむマヌの蚀語に翻蚳しお、枬定された時間の長さにタむマヌのティックがいく぀入るかをカりントしたす。 この問題は、パルス幅がしきい倀にほが等しいずきに発生したす。 その埌、誀ったアラヌムが発生し、パルス長が倉わるずLEDが点滅したす。 たばたきの可胜性を枛らすには、パルス長をより正確に枬定する必芁がありたす。 タむマヌの分解胜は1〜2ÎŒsの範囲内にあるべきだず思いたす-そのような分解胜は枬定の十分な粟床を提䟛したす。



特定の数倀に぀いお話しおいるため、マむクロコントロヌラヌの呚波数を把握する必芁がありたす。 コントロヌラヌは、内郚ゞェネレヌタヌず倖郚ゞェネレヌタヌからクロックを䟛絊できたす。 倖郚ゞェネレヌタヌはより正確ですが、これらは远加の詳现ず重量です。 はい、そしお正確さは本圓に必芁ありたせん。 128kHz、4.8MHz、および9.6MHzは、内郚ゞェネレヌタヌから利甚できたす。 128kHzでは十分ではありたせん。他の2぀のオプションから遞択したす。



タむマヌは、マむクロコントロヌラヌず同じ呚波数を持぀か、8、64、256、たたは1024の分呚噚を䜿甚できたす。タむマヌ自䜓は0から255たでカりントしおから0にリセットされたす。分呚噚が1ティックを䜿甚しない堎合タむマヌは1぀のプロセッサティックに察応したす。これはほずんどの堎合、1぀のコマンドに察応したす。 完党なタむマヌサむクルごずに有甚な䜜業を行う぀もりでした。 しかし、256チヌムごずにこの䜜業を行う必芁がある堎合、この䜜業を行う時間がないでしょうたたは非垞に小さいはずです。



したがっお、4.8 MHzから9.6 MHz、および分呚噚8、64、および256を遞択する必芁がありたす。私にずっおは、分呚噚8を備えた4.8 MHzのバリ゚ヌションはかなり良いです。 タむマヌは、4.8 MHz / 8 = 600 kHzの呚波数で䜜動したす。 これは、1ティックに1.666mksがかかるこずを意味したす。 垌望する1〜2 mkにちょうど収たりたす。 フルタむマヌサむクルには1,666 * 256 = 426.66ÎŒsかかりたす。 プログラムタむマヌずしお、16ビット倉数を䜿甚したす。これは、期間65536 * 426.66ÎŒs= 27.96 sを枬定できるこずを意味したす同じ426.66ÎŒsの粟床で



タむマヌ開始コヌド



 void runTimer() { // Reset timer counter TCNT0 = 0; // Run timer at 4.8MHz/8 = 600 kHz // This gives 1.667 uSec timer tick, 426.667 uSec timer interval // Almost 28 seconds with additional 16bit SW timer value TCCR0A = 0; // Normal mode TCCR0B = 0 << CS02 | 1 << CS01 | 0 << CS00; // run timer with prescailer f/8 }
      
      







䞊蚘のコヌドでは、䞍可解なTIMEOUT_MSマクロを䜿甚したした。 それを解読する時が来たした。



 #define TIMEOUT_MS(t) ((uint32_t)t * 600 / 256) //4.8MHz / (8 prescailer * 256 full timer cycle * 1000 since we are counting in ms)
      
      







このマクロは、指定されたミリ秒数の枬定に必芁な426.6ÎŒsでサむクル数を決定したす。 残念ながら、完党な匏解説にある匏にぶ぀かるず、コンパむラは凊理できないひどい枊を生成し始めたした。 今では理解できない600/256に数匏を数え盎す必芁がありたした。



しかし、PWM入力のリスニングに戻りたす。 わかりやすくするために、すべおがどのように機胜するかをもう䞀床説明したすが、蚀い換えれば。 メむンの8ビットタむマヌは0から255たで刻みたす。タむマヌサむクルが完了するたびに、プログラムタむマヌのリストを凊理し、必芁に応じおハンドラヌを実行したす。 さらに、8ビットタむマヌ自䜓の倀を䜿甚しお、入力でのパルス長を枬定したす。 これは非垞に簡単に行われたす。衝動が始たるず、タむマヌの倀を蚘憶したす。 パルスが進むず、タむマヌは刻み続けたす。 パルスが終了するたでに、タむマヌは新しい倀に䜎䞋したす。 したがっお、倀の差により、1ティックの時間1,666ÎŒsを乗算するだけでパルス長を蚈算できたす



やめお 8ビットタむマヌがありたす。぀たり、この方法で枬定できるのは最倧256 * 1.66 = 426.66マむクロ秒のパルスのみで、最倧2200マむクロ秒の入力パルスです。 関係ありたせん 必芁に応じお倚くの䞊䜍バむトを远加するこずにより、タむマヌカりンタヌを人為的に拡匵できたす。 通垞のバむナリ挔算は機胜したす-䞋䜍バむトがオヌバヌフロヌするず、䞊䜍バむトが増加したす。



 // Additional high byte for 8bit timer value volatile uint8_t tcnth; void runTimer() { // Reset timer counters tcnth = 0; TCNT0 = 0; // Run timer at 4.8MHz/8 = 600 kHz // This gives 1.667 uSec timer tick, 426.667 uSec timer interval // Almost 28 seconds with additional 16bit SW timer value TCCR0A = 0; // Normal mode TCCR0B = 0 << CS02 | 1 << CS01 | 0 << CS00; // run timer with prescailer f/8 TIMSK0 = 1 << TOIE0; }
      
      







ほずんどすべおが同じです。 tcnth倉数のみが远加されたした-タむマヌ内の䞋䜍バむトに加えお「䞊䜍」バむト。 最埌の行も重芁です-タむマヌオヌバヌフロヌ割り蟌みが含たれおいたす。 この割り蟌みは、䞊䜍バむトをむンクリメントしたす。



 ISR(TIM0_OVF_vect) { // Increment high byte of the HW counter tcnth++; }
      
      







tcnth倉数はvolatile宣蚀されおいるこずに泚意しおください。 このキヌワヌドがないず、プログラムの別の郚分のコンパむラヌは、倉数が倉曎されないず刀断し、過剰を最適化する堎合がありたす。 圌は、倉数が割り蟌み実際には別のスレッドで倉化するこずを知りたせん。



パルスの開始ず終了をキャッチするには、このために特別に蚭蚈されたピン倉曎割り蟌みを䜿甚できたす。これは、入力の倀が倉曎されたずきに呌び出される割り蟌みです。 T.O. 入力を絶えずポヌリングする必芁はありたせん-マむクロコントロヌラヌがすべおの䜜業を行いたす。 この割り蟌みのハンドラヌのみを蚘述できたす



 uint16_t pwmPulseStartTime; #define PWM_THRESHOLD 900 // number of pulses in 1500 uS at 4.8MHz with /8 prescailer = 1500 * 4.8 / 8 = 900 // Pin Change interrupt ISR(PCINT0_vect) { /* // Get the current time stamp uint16_t curTime = (tcnth << 8) + TCNT0; Unfortunately gcc generates plenty of code when constructing 16 bit value from 2 bytes. Let's do it ourselves */ union { struct { uint8_t l; uint8_t h; }; uint16_t val; } curTime; // Get the current time stamp curTime.h = tcnth; curTime.l = TCNT0; // It may happen that Pin Change Interrupt occurs at the same time as timer overflow // Since timer overflow interrupt has lower priority let's do its work here (increment tcnth) if(TIFR0 & (1 << TOV0)) { curTime.h = tcnth+1; curTime.l = TCNT0; } if(PINB & (1 << PWM_INPUT_PIN)) // On raising edge just capture current timer value { pwmPulseStartTime = curTime.val; } else // On failing edge calculate pulse length and turn on/off LED depending on time { uint16_t pulseLen = curTime.val - pwmPulseStartTime; if(pulseLen >= PWM_THRESHOLD) PORTB |= (1 << LED_C_PIN); else PORTB &= ~(1 << LED_C_PIN); } }
      
      







ハンドラヌの最初の郚分は、タむマヌカりンタヌの倀をプルするこずに専念しおいたす远加の倖郚バむトによっお拡匵されたす。 残念ながら、額の倀を読み取るこずはできたせんでした-時々、LEDが自発的に点滅したした。 これは、2぀の割り蟌みがほが同時に発生したためです。 たた、タむマヌ割り蟌みの優先床は䜎いため、ハンドラヌは必芁なずきに呌び出されないこずがありたした。 その結果、䞊䜍バむトは増加したせんでした。぀たり、合蚈倀は256単䜍少なくなりたした。 これは䞍可欠です。



解決策は非垞に簡単です-タむマヌオヌバヌフロヌが発生したかどうかを確認し、発生した堎合は、オヌバヌフロヌハンドラヌず同じ䜜業を行いたす-䞊䜍バむトに+1したす。



この時点で、私はgnatによっお生成されたコヌドの非最適性に぀たずきたした。 コヌドtcnth << 8+ TCNT0はこのようにコンパむルされ、シフトず远加が行われたす。 たた、最適化が含たれおいるにもかかわらず-O1。 この堎所では、2バむトを16ビット数ずしお解釈する必芁がありたす。 私は組合で庭を囲わなければなりたせんでした。



ハンドラヌの2番目の郚分は、実際に圹立぀仕事をしたす。 衝動の始たりを捉えた堎合は、倉数pwmPulseStartTimeのタむムスタンプを芚えおおいおください。 パルスの終わりを捉えた堎合-タむムスタンプの違いを考慮し、倀に応じおLEDをオン/オフしたす。 応答のしきい倀は1500ms、぀たりそれぞれ1.66 µsのタむマヌの900ティックです。



ここで䞍足しおいるのは、このピン倉曎割り蟌みの初期化です。



 #define PWM_INPUT_PIN PCINT3 void setupPWMInput() { // Initialize the timestamp value pwmPulseStartTime = 0; // Set up pin configuration PORTB |= 1 << PWM_INPUT_PIN; // pull-up for PCINT3 DDRB &= ~(1 << PWM_INPUT_PIN); // output mode for LED pins, input mode for PCINT3 pin // Use PCINT3 pin as input PCMSK = 1 << PWM_INPUT_PIN; // Enable Pin Change interrupt GIMSK |= 1 << PCIE; }
      
      







ほずんどすべおの準備が敎いたした。芁件のうち、滑らかな点滅のみが実装されおいたせん。実際、コントロヌラヌはLEDのオンずオフのみを切り替えるこずができたす。䞭間倀はありたせん。しかし、所定のデュヌティサむクルLEDがオンになっおいる時間ずオンになっおいない時間の比率ですばやくすばやくオン/オフを切り替えるず、人は、LEDがただ滑らかに茝いおいるように芋えたすが、茝床は䜎くなっおいたす。デュヌティサむクルを少しず぀倉曎するず、LEDの茝床がスムヌズに倉化するように芋えたす。



LEDをオンたたはオフにするコヌドを䜜成できたす。タむマヌの利点は、必芁なだけ実行できるようになりたした。しかし、なぜ、PWM生成が既にコントロヌラヌに組み蟌たれおいるのでしょうかさらに、レッグOC0AおよびOC0BPB0およびPB1で、最倧2぀の生成チャネルを独立しお制埡できたす。



このように動䜜したす。単䞀のタむマヌが所定の速床で通垞どおり回転したす。サむクルの開始時に、ナニットは1に蚭定され、特定の倀レゞスタOCR0AおよびOCR0Bで蚭定に達するず、ナニットはれロに蚭定されたす。次に、サむクルが繰り返されたす。レゞスタの倀が倧きいほど、デュヌティサむクルが倧きくなり、ダむオヌドが明るくなりたす。これは非反転モヌドず呌ばれたす。 LEDはむンバヌタを介しお接続されおいるため、反転モヌドの方が適しおいたす。レゞスタの倀をオンにし、タむマヌが終了しおリセットされたらオフにしたす。



 // Current PWM value volatile uint8_t pwmAValue = 1; volatile uint8_t pwmBValue = 1; void runTimer() { // Reset counter counters tcnth = 0; TCNT0 = 0; OCR0A = pwmAValue; OCR0B = pwmBValue; // Run timer at 4.8MHz/8 = 600 kHz // This gives 1.667 uSec timer tick, 426.667 uSec timer interval // Almost 28 seconds with additional 16bit SW timer value //TCCR0A = 1 << COM0A1 | 1 << COM0A0 | 1 << COM0B1 | 1 << COM0B0 | 1 << WGM01 | 1 << WGM00; // Fast PWM on OC0A and OC0B pins, inverting mode TCCR0A = 1 << COM0A1 | 1 << COM0A0 | 1 << WGM01 | 1 << WGM00; // Fast PWM on OC0A pin, inverting mode TCCR0B = 0 << CS02 | 1 << CS01 | 0 << CS00; // run timer with prescailer f/8 TIMSK0 = 1 << TOIE0; }
      
      







タむマヌの初期化を少し調敎する必芁がありたした。WGM00およびWGM01ビットは、高速PWM生成モヌドを有効にしたす。ビットCOM0A0、COM0A1、COM0B0、およびCOM0B1は、チャネルAおよびBの反転モヌドを有効にしたす。より正確には、コメント行には、OC0Aのみのコメントなしの䞡方が含たれたす。



pwmAValue倉数の倀は時々倉化するため、䜕らかの方法でタむマヌに通知する必芁がありたす。これは、オヌバヌフロヌハンドラで行うのが最適です。



 ISR(TIM0_OVF_vect) { // Update the PWM values OCR0A = pwmAValue; OCR0B = pwmBValue; // Increment high byte of the HW counter tcnth++; }
      
      







もちろん、倀を盎接OCR0AおよびOCR0Bレゞスタに盎接プッシュできたすが、これはデヌタシヌトで掚奚されおいたせん。これにより、ピンの倀が本来よりも早くたたは遅く倉曎されるず、「スリップ」が発生する可胜性がありたす。芖芚的には、これは明るさの望たしくないシャヌプで短期的な倉化に珟れたす。



明るさ自䜓は、すでによく知られおいる゜フトりェアタむマヌで倉曎できたす。たずえば、次のように



 uint8_t directionA = 0; void pwmLedATask() { if(directionA) // Incrementing { pwmAValue += 2; if(pwmAValue == 255) directionA = 0; } else //decrementing { pwmAValue -= 2; if(pwmAValue == 1) directionA = 1; } addTimer(pwmLedATask, TIMEOUT_MS(2)); }
      
      







pwmAValue倉数の倀をむンクリメントたたはデクリメントするだけで、適切なレゞスタに入力されたす。ただし、実際の点滅ビヌコンを゚ミュレヌトするには、もっずきれいなものを考え出す必芁がありたす。たずえば、次のように



 typedef struct complexPWM { uint8_t step; uint8_t maxValue; uint16_t delay; } complexPWM; complexPWM pwmItems[] = { {0, 1, TIMEOUT_MS(1000)}, {2, 127, TIMEOUT_MS(2)}, {-2, 33, TIMEOUT_MS(2)}, {2, 255, TIMEOUT_MS(2)}, {-2, 1, TIMEOUT_MS(2)} }; uint8_t pwmTableIndex = 0; void complexPWMTask() { complexPWM * curItem = pwmItems + pwmTableIndex; pwmAValue += curItem->step; if(curItem->maxValue == pwmAValue) pwmTableIndex++; if(pwmTableIndex == sizeof(pwmItems)/sizeof(complexPWM)) //dim(pwmItems) pwmTableIndex = 0; addTimer(complexPWMTask, curItem->delay); }
      
      







点滅するビヌコンのように芋えるかどうかはわかりたせんが、このコヌドでは、事前フラッシュが明るさ127で行われ、明るさを33に枛らしおフルフラッシュ最倧255にしたす。



おそらくファヌムりェアのすべおです。すべおのgibletsずmorgulkiにより、すべおが500〜600バむトに干枉したす-予備も残っおいたす。 1぀の重芁なポむント-ヒュヌズビットを匷調するために残っおいたす。これらはhfuse = 0xff、lfuse = 0x79ず同じです。デコヌドに぀いおは、デヌタシヌトを芁求したす。簡単に蚀うず、これらのバむトの数ビットにより、コントロヌラヌは4.8 MHzで動䜜するようになりたす。残りのビットはデフォルト状態のたたです。



実際の倖芳は、蚘事のヘッダヌにあるビデオから掚定できたす。



おわりに



この蚘事では、BANO、着陞灯、ゲヌトなど、さたざたな航空機モデルの電球甚のコントロヌラヌのバヌゞョンに぀いお説明したした。あずはファヌムりェアを少し遞ぶだけで、コピヌモデルは実際のモデルのように芋えたす。



さらに、そのようなりむンカヌは車に乗せるこずができたす。たた、たずえば、広告看板を匷調衚瀺できたす。すべおがあなたの手にありたす。



しかし、単䞀の飛行機ではありたせん。ラむトの点滅に加えお、匱いコントロヌラヌのプログラミングに関連する蚘事で他のいく぀かのポむントを取り䞊げたした。







LEDを点滅させるタスクを無芖するず、マむクロコントロヌラヌ䞊の「マルチタスク」「マルチスレッド」アプリケヌションに適したフレヌムワヌクであるこずがわかりたした。もちろん、これはRTOSではありたせんが、すでに倚くのルヌチン操䜜を排陀しおいたす。ファヌムりェアでは、このフレヌムワヌクを別のモゞュヌルEventQueue.c / .hに配眮したした。健康を䜿甚しおください。



良い点は、3぀の完党に独立したタスク長時間のカりント、入力でのパルス幅の枬定、出力でのPWMの生成を取埗したこずです。単䞀の8ビットタむマヌで凊理できたした。さお、远加された゜フトりェアタむマヌでは、ただ倚くの䟿利なこずができたす。



しかし、コヌドはあたり構造化されおいたせんでした。異なるタスクは同じ機胜で解決されたすが、各タスクはいく぀かの堎所に分散されたす。しかし、これはコンパクトなサむズの料金です。同様に、ボタンや情報を入力する他の手段の欠劂。しかし、もう䞀床、プログラマヌのワむダヌをコントロヌラヌに盎接はんだ付けし、コヌドで目的の点滅オプションを構成し、それをすべおファヌムりェアの圢で泚ぎ蟌むのにうんざりしおいたせん。



この蚘事は参考資料ではありたせん。特定のビットずレゞスタの説明のためにデヌタシヌトにアクセスする必芁はありたせん。これは、AVRラむンのゞュニアコントロヌラヌのわずかな手段を䜿甚しお有甚なものを䜜成する方法の䞀䟋です。



最初は、最終的なコンパむル枈みhexファむルを蚘事に添付する予定はありたせんでした。事実は、すべおのモデルが異なるずいうこずです。別の数のチャネルが必芁な堎所、別の点滅が必芁な堎所、いく぀かの入力を远加する必芁がある、たたは別の操䜜を行う必芁がある堎合がありたす。代わりに、自分の考えに完党に䞀臎するように自分でファヌムりェアを倉曎するこずをお勧めしたす。そこはすべおシンプルです



ただし、すべおの航空機モデラヌがコンパむラず友達であるわけではありたせん。だから私はそれでもいく぀かの䞭間バヌゞョンをコンパむルしたした1぀のチャンネルが2秒ごずに点滅ストロボし、PWMチャンネルが二重点滅でもう少し頻繁に点滅し、3぀目のチャンネルはリモコンからのコマンドによっおオンになりたす。このファヌムりェアは、さらにdopilivaniyaの開始点になりたす。私がコヌドに残した蚘事に瀺されおいる䟋は、呌び出しに぀いおのみコメントしおいたす。



頑匵っお



ファヌムりェア゜ヌスずPCBレむアりト。



All Articles