STM32プログラマブルマむクロコントロヌラ-すぐに䜿える

以䞋は、 STM32VLDiscoveryに代衚されるプログラム可胜なマむクロコントロヌラヌでの私の最初の経隓です 。その結果は、電話などで制埡されるLEGOマシンでした。 私は行動のステップバむステップガむドの圢で自分の道を蚭定しようずしたしたが、私はすぐにあなたに譊告したす、それを正しくする方法ではありたせん。 最初の2぀のセクションは序文であり、このマむクロコントロヌラヌには盎接適甚されたせん。



画像



内容



  1. マむクロ゚レクトロニクスずの最初の接觊。
  2. 非プログラマブルロゞック゚レメントでの自動車の構築。
  3. STM32の䜿甚を開始する。 開発環境。 マむクロコントロヌラヌをマシンに接続したす。
  4. 前茪の回転角床を決定したす-ADCを介したフィヌドバック。
  5. DACを䜿甚しおサりンドを再生したす。






1.マむクロ゚レクトロニクスずの最初の接觊



理由は関係ありたせんが、電話からのコマンドを受け付けるデバむスを䜜成するずいう考えが生たれたした。 どうやっおやるの Bluetooth、WiFi、USBなどを介しお可胜です。 しかし、携垯電話の出力からヘッドセットに送られる音を認識する方が簡単で、より普遍的であるように芋えたす以䞋、問題の解決のために、最も単玔な実装、結果指向の方法が遞択されたす。

サりンドはスマヌトフォン甚の特別なプログラムで合成できたすが、興味深いオプションがありたす-DTMF信号。 これらは暙準であり、すべおの携垯電話およびほずんどの固定電話番号をダむダルするずきたたは音声メニュヌでで䜿甚され、音声チャネルで問題なく送信されたす。



タスク1DTMF信号認識


DTMF埩号化を実装するための3぀のオプションがむンタヌネットから印刷されおいたす私の考えは新しいものではありたせん。 賌入されたす





゚ラヌを収集、怜蚌、修正したす...動䜜したす。 ショック。



ここで、これらすべおを匷制的にマシンを制埡する必芁がありたす。 さらに、マシンのアクションが抌された番号に論理的に察応するように2-前方、4-巊偎、6-右偎、8-埌方。



タスク2DTMFデコヌダヌからの信号の4぀の特定の組み合わせは、4぀の機胜のいずれかをアクティブにする必芁がありたす


最も単玔なオプションは、10進デコヌダヌです。 オヌプンコレクタヌ付きのK155ID10を賌入したした-バむナリコヌド甚の4぀の入力、10の出力は0〜9の数字を衚し、目的の出力は「0」、残りは「1」になりたす。 このデコヌダヌは負荷で䜿甚され、動䜜電流は80 mA癜熱電球、リレヌに達するこずができ、䟿利です。 トランゞスタはただ䜿甚する必芁がありたしたが。



タスク3モヌタヌの極性反転、Hブリッゞ


子䟛の頃はすべお、レゎから車を集めたした。レゎは、電池の極性を手動で切り替えるこずで行き来したしたモヌタヌずリモコン付きのレゎセットはありたせんでした。 さあ、倧人のおもちゃを遊ぶ時間です。

普通の人はトランゞスタでHブリッゞを䜜りたす。 高床-これらず同じトランゞスタでタヌンキヌ゜リュヌションを賌入したす。 私は電磁継電噚を切り替えたした。 埌で匷力な最倧3Aのコレクタ電流甚NPNおよびPNPトランゞスタヌTIP31 C STおよびTIP32 C STを賌入し、それらからこのHブリッゞを組み立おたしたが、䜕らかの理由でオンボヌドLEDでのみ動䜜し、モヌタヌはオンになりたせんでした力。 理由はわかりたせん。



スむッチングリレヌには、モヌタヌごずに2぀必芁ですトランゞスタたたはクロヌズリレヌには4぀必芁です。 デフォルトでは、モヌタヌの䞡方の接点玩具のように通垞のコレクタヌはマむナスに接続されおいたす。 制埡信号がリレヌの1぀に適甚されるず、モヌタヌ接点がプラスに切り替わり、モヌタヌが䜜動を開始したす。 このような接続の倧きな利点は、どのような状況でもリレヌの故障のために短時間で短絡するこずさえできないこずです。 欠点は、制埡電圧がリレヌから陀去されるず、モヌタヌが短絡しおブレヌキになるこずです。 解決策は、別のリレヌを閉じるこずです。 さお、モヌタヌを回転させるには、フリヌランニングのためにそれを閉じる必芁がありたす-それを開いお、「ブレヌキ」のために-それを再び閉じたす。 このリレヌは埌で远加されたす。



タスク4タむプラむタヌを組み立おる


マシンには2぀のモヌタヌがありたす。1぀はレゎディファレンシャルを介しお埌茪を回転させ、2぀目は前茪を回転させたす。 ギアボックス内のプラスチックギアはシステムの効率を向䞊させたせんが、すべお機胜したす。



ボヌドに4぀のリレヌを配眮したす。 ブレッドボヌドは高電流甚に蚭蚈されおいない各モヌタヌは1〜1.6 Aを消費するず蚀われたしたが、短時間で結果が埗られない堎合、プロゞェクトは次の゚アロックを維持するリスクがありたす。 ちなみに、リレヌを含めるず電圧サヌゞが発生し、ルヌプず誀動䜜が発生したした。 確かにこれは特別なスキヌムによっお解決されたすが、私はバッテリヌを備えた別のナニットからモヌタヌに電力を䟛絊したした。



電磁リレヌ、2぀の電源-あたりにもハヌドコアはありたせんか さらにもっず



これらすべおを10進デコヌダヌに接続するこずは残りたす。 必芁な結論は、4぀のNPNトランスフォヌマヌBC547の゚ミッタヌであり、そのベヌスには、DTMFデコヌダヌからキヌが抌されたずいう信号「5番目の出力」、コレクタヌ、各リレヌがありたす。 曲がった、奇劙な、しかしそれは動䜜したす。



画像



画像







2.非プログラマブルロゞック゚レメントでの自動車の構築



マシンが同時に乗るこずず回転するこずができるはずだず仮定したす。 論理的には、1、3、7、9の数字を䜿甚するず、2぀のリレヌがトリガヌされたす。 最初は、トランゞスタ゚ミッタから10進デコヌダヌにダむオヌドを接続しおこれを実装する予定でしたが、うたくいきたせんでした。 10進デコヌダヌが「0」を指定した堎合、この「れロ」で開くPNPトランゞスタが必芁であるこずがわかりたした。 しかし、NPNしかありたせんでした。



タスク51、3、7、たたは9を抌すず、マシンが移動しお回転するはずです。


゚ンタヌテむンメント/開発/䜿甚の目的で、論理芁玠4-I、4-OR、NOT、AND-NOT、OR-NOT、およびANDを1぀ず぀賌入したした。 最初の考えは、10進数デコヌダヌからの出力ずDTMFデコヌダヌからの「5番目の出力」を単玔な論理回路で䜿甚するこずで、最終的に必芁なトランゞスタヌおよびそれらを介しおを開きたす。 しかし 「ナニット」ずしおの10進埩号噚K155ID10は、䜕かで2ボルトを生成したす。 自由に䜿える論理芁玠はどれも、そのような信号を「ナニット」ず芋なしたせんでした。 4-IKR1533を陀く。 DTMFで「裞の」4ビットのバむナリコヌドを䜿甚するず、利甚可胜な芁玠から必芁なロゞックを組み立おるこずができたせんでした。 通垞の10進数の埩号化機胜は、タスクを䜕床も促進したす。 そしお、それはそのような小さなm笑になりたした-するのは難しいですが、できたす 午前䞭に寝お詳现を調べるずいう考えは拒吊されたした。



10進デコヌダヌは、埩号化された数倀の出力を陀くすべおの結論に「アンデッド」を䞎えるこずを思い出しお、次のこずを行いたす。

最初に... m ... 4-I芁玠の入力のカルテットで、数字1、2、3、および「ナニット」を指定したす。 2番目-7、8、9、および「ナニット」。 最初の出力から、1、2、たたは3が抌された堎合車が前進する堎合、2番目の出力から-7、8、9戻る堎合から「れロ」が埗られたす。 それ以倖の堎合、4-I芁玠の出力は䞡方ずも「ナニット」です。

今回る。 残りの5぀のロゞック゚レメントを䜿甚しお、トリッキヌな回路を収集したす。 4ず6の数字を拒吊するこずにしたしたその堎で車茪を回すのはなぜですかが、1ず7巊、3ず9右だけのタヌンのダむアグラムを䜜成するこずさえできたした。



その結果、ボヌド䞊別のものを賌入する必芁がありたした、DTMFデコヌダヌ、むンゞケヌタヌ、そのデコヌダヌ、10進数デコヌダヌ、4-AND、NOT、4-OR、OR-NOT、AND-NOT、4トランゞスタ、4リレヌ。

マシンは6぀の異なるコマンドを実行したすが、前茪を䞭倮に戻す方法を知りたせん。 LEGOパヌツの効率ず䜎いモヌタヌ出力により、リタヌンスプリングやゎムは䜿甚できたせん。

リレヌは時々数回クリックしたすが、理由は明らかではありたせん干枉。

ロゞックを操䜜するロゞックがマスタヌされたした。



画像



3. STM32の䜿甚を開始する



開発環境

配線プログラミングからコヌドプログラミングに切り替えたしょう。 プログラム可胜なマむクロコントロヌラ/チップに぀いおは、Raspberry Piが匷力すぎる、Arduinoが高䟡であり、䞀般的ではないずいう挠然ずした考えしかありたせんでした。 その時、売り手であるミハむルは、579ルヌブルのSTM32VLDiscoveryを私に曞いた。 ここでの圌に぀いおだけでなく 、 圌らがすでに曞いたものであり、圌の研究で本圓に助けになりたした。



コントロヌラはブレッドボヌドに固定できたすが、いずれにも固定できたせん。 同時に、6本の足がぶら䞋がったたたになりたす-ただ数十本あるので、それらを䜿わずに行うこずができたす。 プログラムがデバむスに入ったミニUSBコヌドからボヌドを切断するこずなく、メモリにダりンロヌドされたプログラムの機胜を確認するこずもできたす。 そしお、あなたはそれから食べるこずができたす。



CooCoxのCoIDE環境では、タンバリンずのダンスが1回だけ必芁でした。特定のファむルを特定のフォルダヌに手動でダりンロヌドするこずは、䜜業を開始するための最適な遞択のようです。 確かに、ファヌムりェアをデバむスにアップロヌドできたせんでした。ボヌドメヌカヌのST-LINKナヌティリティを䜿甚する必芁がありたす。 圌らは䟿利なSublime Text 2から盎接コンパむルできるず蚀っおいたすが、呜什の長さは詊しおみるにはあたりにも懐疑的でした。



私がCで曞いたこずがないこずを考えるず、最も単玔な点滅するLEDでさえ倧きな困難を匕き起こしたした。 さらに、䞍明瞭なレゞスタ、16進システム、プルアップ抵抗噚の目的を十分に理解しおいない人向けの出力ず入力のさたざたな動䜜モヌド...しかし、誰かの既補の䟋のコピヌアンドペヌスト方法がトリックを行いたした。 次に、デバむスの䟡栌により、ハヌドりェアの正しい接続に煩わされるこずがなくなりたす。 たずえば、各GND脚をグラりンドに接続する必芁があるかどうか、および4本の指のバッテリヌからデバむスに電力を䟛絊するこずが有害かどうかはただわかりたせんでした。



コヌドにより近い。 ここでは他の人の䟋を匕甚したり説明したりはしたせんが、私のベストプラクティスをいく぀か玹介したす。 それらは、Web䞊の特定の問題に察する蚱容可胜な解決策がなかったずきに登堎したした。



タスク6遅延


たずえば、LEDをオンにし、しばらくしおからオフにしたす。 倚くの堎合、遅延は䜕回も実行される空のルヌプによっお実装されたす。 この方法は確かに単玔ですが、LEDの点滅に加えお、ボヌドに䜕も必芁ない堎合にのみ適甚できたす。 サむクルのみを䞭断できたすが、すみたせんが、䞭断する少し埌でか、サむクルを終了するための远加条件を蚭定したす。 それ以倖の堎合、このサむクルが続く間、ボヌドは䜕もせず、䜕にも反応したせん。



私が提案するのは、プログラムで必芁なすべおの遅延に察しおメむン無限ルヌプをすぐに䜿甚するこずです。各パスは特定の倉数の倀を増やしたす「x」ず呌びたしょう。 倉数が特定の倀に達するずすぐに、サむクルの本䜓で特定の条件がトリガヌされたすその数はいく぀でも可胜です。 欠点は、そのような遅延がどれくらい続くかを事前に知らないこずです。 これが問題にならない堎合は、経隓的に必芁な倀を遞択しお䜿甚したす。



コヌド
int main(void) { unsigned int x=0; char something; while(1) { if (x>5000) { //  }; if (x==10000) { //  .    ,    x. }; if (something==1)//   { x=0; //        } if (x<15000) { x++; }; //  x       0,   x  15000. }; };
      
      









タスク7指定された間隔での間隔


氎晶振動子を倉曎せず、プロセッサヌ呚波数が24 MHzのたたであったずしたす。 特別な呜什によっお2400番目のプロセッサヌ数に達したずきに割り蟌みを䜜成するこずにより、100 Hzの呚波数10ミリ秒ごずでTIM6_DAC_IRQHandler関数これは割り蟌みハンドラヌの実行を取埗したす。 以䞋のコヌドは元々どこかで取られおいたす。



コヌド
 unsigned int ti=0; int main(void) { //     6 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); TIM6->PSC = 24000 - 1; //   1000    TIM6->ARR = 10 - 1; //     10-  TIM6->DIER |= TIM_DIER_UIE; //     TIM6->CR1 |= TIM_CR1_CEN; //  ! NVIC_EnableIRQ(TIM6_DAC_IRQn); //  TIM6_DAC_IRQn  }; //   TIM6_DAC void TIM6_DAC_IRQHandler(void) { ti++; TIM6->SR &= ~TIM_SR_UIF; //     }
      
      









この割り蟌みの䞻な目的は、10ミリ秒ごずに増加する倉数tiを䜿甚するこずです。 すぐに、割り蟌みはメむンプログラムコヌドに「くさび」をかけるだけでなく、割り蟌みハンドラ内で毎回倉化するため、倉数tiの比范や割り圓おの操䜜を歪める可胜性があるこずがわかりたした。 別の倉数を倉数tiの倀に割り圓おる代わりに、叀い倀の䞀郚ず新しい倀の䞀郚が割り圓おられる状況が発生する堎合がありたす。 Webで芋぀かった問題の解決策の䞭で、私はおよそ以䞋を匷調したした。





このような問題を解決したした。 倉数 "ti"が「代入」されるたで、ロヌカル倉数stiに割り圓おたす。 粟床が基本的でない堎合は、少し「バックラッシュ」を远加できたす。



 do { sti=ti; } while (ti>1+sti);
      
      







ロヌカル倉数sti自䜓は、倉数tiの倀が必芁な堎所に同様のルヌプを挿入しないためにのみ䜿甚されたす。



さらにプログラムでは、sti倉数に恐れるこずなくアクセスし、れロにするこずさえできたす。 このすべおを䜿甚しお、このコマンドたたはそのコマンドがタむプラむタヌに䞎えられる時間を修正し、埌でタむプラむタヌがルヌトを繰り返すこずができるようにしたした。 圓然、れロ化は無駄にすべきではありたせん。したがっお、メむンプログラムルヌプの最埌に、簡単なコヌドが远加されたした。



 if (sti==0) { do { ti=0; } while (ti>1); }
      
      







割り圓おの時点たたは終了条件のチェック時に、倉数tiが倉化し、誀った圢匏で「提瀺」されるず、サむクルが繰り返されたす。 割り蟌みレヌトが高いほど、ルヌプを終了する条件が2回目にトリガヌされる頻床が高くなりたす。 圓然、䞭断の頻床が高すぎる堎合、ルヌプは長くかかりたせん。 倱敗した割り圓おの詊行回数を制埡するために、LEDを䜿甚したした。



タスク8ディスプレむずしおのLED


時々、プログラムを調敎するために、デバむスの操䜜䞭に特定の倉数の倀を取埗したいのですが、ディスプレむやむンゞケヌタヌが手元にないか、それらを接続したくありたせん。 その埌、LEDを必芁な回数だけ点滅させたり、䞀時停止したり、再床点滅させたりするこずができたす。これらの目的のために、メむンルヌプの本文で次のコヌドを䜿甚したす。



 // - if ((todisp>0) && (sti%10==0)) { if ((sti%(todisp*20+100)<todisp*20) && (sti%20<10)) { GPIOC->BSRR=GPIO_BSRR_BS8; } else { GPIOC->BRR=GPIO_BRR_BR8; }; };
      
      







プログラムの任意の時点で、倉数をdisp、たずえば3に割り圓おたす。ボヌド䞊のLED No. 8が3回点滅し、シリヌズ間で2回目の䞀時停止を行いたす。 倉数stiは倉数tiを介しお10ミリ秒ごずにむンクリメントされたすが、代わりに倉数xを䜿甚しお、メむンルヌプの各パスでむンクリメントできたす。 この堎合、係数をわずかに増やす必芁がありたす。



䜿甚䟋
 while (1) { do { sti=ti; todisp++; } while (ti>1+sti); todisp--; if ((todisp>0) && (sti%10==0)) { if ((sti%(todisp*20+100)<todisp*20) && (sti%20<10)) { GPIOC->BSRR=GPIO_BSRR_BS8; } else { GPIOC->BRR=GPIO_BRR_BR8; }; }; }
      
      









この䟋では、割り蟌みのために割り圓お操䜜sti = tiが倱敗し、比范操䜜ti> 1 + stiがtrueを返すたびに比范時に割り蟌みが発生した堎合にも起こりたす、LEDが1回点滅したす倍以䞊。 原則ずしお、ボヌド操䜜のn分埌にLEDが点滅する回数を枬定し、平均サむクル時間割り蟌みの頻床に基づいおを蚈算するこずもできたす。たた、割り蟌みを䜿甚する際のこれらすべおの予防措眮が決しお䞍芁であるこずを確認できたす。



タスク9マむクロコントロヌラヌをマシンに接続したす


LEDで十分な数の実隓を行った埌、埐々にそれらをホむヌルに倉曎できたす。 叀いベヌスロゞック回路から最も必芁なもののみを取埗したす。DTMFデコヌダヌ、矎容甚デコヌダヌ付きむンゞケヌタヌ、トランゞスタヌ付きリレヌです。 最埌に、10進デコヌダヌを忘れるこずができたす



DTMFデコヌダヌからの出力は、これらの目的のために遞択したコントロヌラヌの入力に接続されたす。 コントロヌラヌからの出力再び、プログラムで遞択および初期化から抵抗噚たずえば、3 kOhmを介しお埓来のNPNトランゞスタヌのベヌスに出力BC547を䜿甚。 ゚ミッタヌ-「プラス」コレクタヌ-察応するリレヌのコむル。 メむンモヌタヌのショヌト「ブレヌキ」モヌドを防ぐ5番目のリレヌを远加し、方向指瀺噚/寞法を奜みに合わせお調敎したす。 モヌタヌの「プラス」は、別のバッテリヌパックからリレヌに接続されたす。 回路ずモヌタヌの䞡方に電力を䟛絊するために、私はそれぞれ4本の指電池/蓄電池甚のプラスチックケヌス2個を䜿甚したす。 圌らはたった40ルヌブルの費甚がかかり、子䟛の頃私はい぀もスコッチテヌプずホむルで苊しめられたした...



DTMFデコヌダヌからのワむダが、前埌に移動するリレヌの真䞊を通過するこずが刀明したした。 おそらくこれは、リレヌがオンになったずきに既存の電力サヌゞに干枉を远加したす。 その結果、クラスメヌトぞのプレれンテヌション䞭に、リレヌは定期的に割れ始め、マシンはたったく戻るこずを拒吊したした-リレヌはノンストップで切り替わり、均䞀な割れを発したした。 「プラス」の方向にリレヌコむルに䞊列に接続されたダむオヌドは、この状況に圱響したせんでした。 プログラムをファむナラむズしおいたす-10ミリ秒ごずに入力倀をチェックし、5぀の入力の組み合わせが連続しお6回同じ堎合にのみ倉曎に反応したす。 目の遅延はほずんど感知できず、干枉の問題は解決されたす。 これが、プログラマブルマむクロコントロヌラヌの䞻な利点です



4.前茪の回転角を決定する-ADCアナログ-デゞタルコンバヌタヌを介したフィヌドバック



第二郚では、前茪を機械的に䞭倮に揃えるこずはできないず述べたした。 マシンは盎線で走行できるはずなので、問題を解決する時が来たした



タスク10レオスタットを接続する


解決策はそれ自䜓を瀺唆しおいたす-スプリングではない堎合、ホむヌルを揃えるたでモヌタヌを反察方向に回転させたす。 手元にはデゞタル゚ンコヌダはありたせんが、玠晎らしい10kΩレオスタットがあり、ボヌドには12ビットADC2でもがあり、むンタヌネットには接続回路ずコヌドがありたす。 レオスタットの端を「プラス」ず「マむナス」に、スラむダヌ-1kΩ抵抗を介しお入力に接続したす。 ずころで、ADCの目的のために、入力を䜿甚するこずはできたせん。 䟋で指定されたものを䜿甚したした。 サンプルコヌドは、ADCを含む各ラむブラリのCoIDEで盎接芋぀けるこずができたすCoIDEでADCラむブラリを接続するこずを忘れないでください。 コピヌず貌り付けのコヌドは私のプログラムにあり、最も重芁なこずは、それが機胜するこずです。



レオスタットを機械に取り付け、レオスタットシャフトを回転機構の「枛速機」の出力シャフトず同軞に接続したす。これはモヌタヌから3番目です。 LEGO以倖のパヌツずLEGOパヌツをペアリングするプロセスは垞に実行されたすが、モヌタヌは䟝然ずしおレオスタットを回転させ、ホむヌルを回転させたす。 困難を䌎い、私は蚀わなければならない。 レオスタットからボヌドたで3本のワむダが䌞び、モヌタヌから4本のワむダが䌞びおいたす。



タスク11レオスタットからのデヌタを䜿甚する


経隓的な方法では、0から4095の数倀を遞択したす。これは、前茪を盎接取り付けた堎合の前茪の回転角の蚱容される巊右の境界に察応したす。 この範囲は䞍感垯ず呌ばれおいるようです-その䞭で、車茪は䞭倮で敎列しおいるず芋なされたす。 たた、最倧回転角に達したずきにモヌタヌをオフにする倀を遞択したした。



コヌド
 js= 2500; //    j —     0  4095 () gist=150; //    full=500; //      while (1) { //... if ((x>=max*7) && (inpok)) // inpok  0,         .             . if ((num==1) || (num==4) || (num==7)) // { GPIOC->BRR=GPIO_BRR_BR7; if (j>0+full) { GPIOC->BSRR=GPIO_BSRR_BS6; } else { if (j<0+full-gist) { GPIOC->BRR=GPIO_BRR_BR6; } } } else { GPIOC->BRR=GPIO_BRR_BR1; } if ((num==3) || (num==6) || (num==9)) // { GPIOC->BRR=GPIO_BRR_BR6; if (j<4250-full) { GPIOC->BSRR=GPIO_BSRR_BS7; //   « » } else { if (j>4250-full+gist) { GPIOC->BRR=GPIO_BRR_BR7; //   « » } } } else { GPIOC->BRR=GPIO_BRR_BR3; } //     if ((num==2) || (num==5) || (num==8)) { if (j<js-gist*3) //       { GPIOC->BRR=GPIO_BRR_BR6; //   « » (    ) GPIOC->BSRR=GPIO_BSRR_BS7; //   « » } else { if (j>js-gist*2) { GPIOC->BRR=GPIO_BRR_BR7;   « » } }; if (j>js+gist*3) { GPIOC->BRR=GPIO_BRR_BR7; GPIOC->BSRR=GPIO_BSRR_BS6; } else { if (j<js+gist*2) { GPIOC->BRR=GPIO_BRR_BR6; } }; }; }; //.. }
      
      









機械が極端な条件で操䜜され、巚倧な過負荷の圱響䞋で、ホむヌルが適切なコマンドなしで突然回転角床を倉曎するず、同じコヌドが垌望の䜍眮に戻りたす。 たずえば、4を抌し、ホむヌルがすでに巊端の䜍眮にある堎合、リレヌはオンになりたせん。



思い出しおください、いく぀かのコヌドは他の誰かの䟋から取られたした。



機械制埡プログラムの最終コヌド
 /** ***************************************************************************** * @title ADC_simple.c * @author Claude * @date 2010 Dec 29 * @brief ADC Example, Blink a LED according to ADC value ******************************************************************************* */ #include<stm32f10x_rcc.h> #include<stm32f10x_gpio.h> #include<stm32f10x_adc.h> #include "stm32f10x.h" #include "stm32f10x_conf.h" GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; unsigned int i,j,js,gist,full,ti=0; /* Blink a LED, blink speed is set by ADC value */ int main(void) { unsigned int x,max; unsigned int move[10]; unsigned int oldsti=0,sti=0,time[10],tit=0; unsigned short recheck=5; unsigned char todisp=0,todisp2=0; x=0; unsigned char ji,ju,inp0,inp1,inp2,inp3,inpok,ink,in0,in1,in2,in3,inok,num,oldnum,back; max=250; inp0=0; inp1=0; inp2=0; inp3=0; inpok=0; ink=0; back=0; num=0; void backreset(void) { back=0; for (ju=0;ju<10;ju++) { time[ju]=0; move[ju]=0; } GPIOC->BRR=GPIO_BRR_BR9; } GPIO_InitTypeDef PORT,GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); PORT.GPIO_Pin = (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12| GPIO_Pin_8 | GPIO_Pin_9); PORT.GPIO_Mode = GPIO_Mode_Out_PP; PORT.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init( GPIOC , &PORT); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //   A GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_9 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); //   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); PORT.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5); PORT.GPIO_Mode = GPIO_Mode_Out_PP; PORT.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init( GPIOA , &PORT); // input of ADC (it doesn't seem to be needed, as default GPIO state is floating input) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ; // that's ADC1 (PA1 on STM32) GPIO_Init(GPIOA, &GPIO_InitStructure); //clock for ADC (max 14MHz --> 72/6=12MHz) RCC_ADCCLKConfig (RCC_PCLK2_Div6); // enable ADC system clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // define ADC config ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // we work in continuous sampling mode ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 1,ADC_SampleTime_28Cycles5); // define regular conversion config ADC_Init ( ADC1, &ADC_InitStructure); //set config of ADC1 // enable ADC ADC_Cmd (ADC1,ENABLE); //enable ADC1 // ADC calibration (optional, but recommended at power on) ADC_ResetCalibration(ADC1); // Reset previous calibration while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); // Start new calibration (ADC must be off at that time) while(ADC_GetCalibrationStatus(ADC1)); // start conversion ADC_Cmd (ADC1,ENABLE); //enable ADC1 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // start conversion (will be endless as we are in continuous mode) // debug information RCC_ClocksTypeDef forTestOnly; RCC_GetClocksFreq(&forTestOnly); //this could be used with debug to check to real speed of ADC clock //     6 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); TIM6->PSC = 24000 - 1; //      1000    // TIM6->ARR = 1000 ; //       TIM6->ARR =4; TIM6->DIER |= TIM_DIER_UIE; //    TIM6->CR1 |= TIM_CR1_CEN; //  ! NVIC_EnableIRQ(TIM6_DAC_IRQn); // TIM6_DAC_IRQn  j= 2500; js=j; gist=150; full=500; if (back==0) { for (ju=0;ju<10;ju++) { time[ju]=0; move[ju]=0; } } while (1) { // adc is in free run, and we get the value asynchronously, this is not a really nice way of doing, but it work! j = ADC_GetConversionValue(ADC1) ; // value from 0 to 4095 /* possible change : * ADC_ContinuousConvMode = DISABLE * then on the infinite loop, something like : * * ADC_SoftwareStartConvCmd(ADC1, ENABLE); // start ONE conversion * while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // wait end of conversion * j = ADC_GetConversionValue(ADC1) * 500; // get value * */ do { sti=ti; } while (ti>1+sti); //if ((back!=2) || GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)) if (oldsti!=sti) { oldsti=sti; if (ink<recheck) { in0+=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5); in1+=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6); in2+=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7); in3+=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8); inok+=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9); ink++; if (ink==recheck) { ink=0; if ((in0==0 || in0==recheck) && (in1==0 || in1==recheck) && (in2==0 || in2==recheck) && (in3==0 || in3==recheck) && (inok==0 || inok==recheck)) { if (in0==recheck) { in0=1; } if (in1==recheck) { in1=1; } if (in2==recheck) { in2=1; } if (in3==recheck) { in3=1; } if (inok==recheck) { inok=1; } if ((back==2) && (inok==1)) { backreset(); } if ( (back!=2) && (back!=4) && ((inp0!=in0) || (inp1!=in1) || (inp2!=in2) || (inp3!=in3) || (inpok!=inok)) ) { x=0; inp0=in0; inp1=in1; inp2=in2; inp3=in3; inpok=inok; oldnum=num; if (inp0) // -  { if (inp1) { if (inp2) { if (inp3) { num=15; } else { num=7; }; } else { if (inp3) { num=11; } else { num=3; }; }; } else { if (inp2) { if (inp3) { num=13; } else { num=5; }; } else { if (inp3) { num=9; } else { num=1; }; }; }; } else { if (inp1) { if (inp2) { if (inp3) { num=14; } else { num=6; }; } else { if (inp3) { num=10; } else { num=2; }; }; } else { if (inp2) { if (inp3) { num=12; } else { num=4; }; } else { if (inp3) { num=8; } else { num=0; }; }; }; }; }; } in0=0; in1=0; in2=0; in3=0; inok=0; } } }; //  if ((todisp>0) && (sti%10==0)) { if ((sti%(todisp*20+100)<todisp*20) && (sti%20<10)) { GPIOC->BSRR=GPIO_BSRR_BS8; } else { GPIOC->BRR=GPIO_BRR_BR8; }; }; if ((todisp2>0) && (sti%10==2)) { if ((sti%(todisp2*20+100)<todisp2*20) && (sti%20<10)) { GPIOC->BSRR=GPIO_BSRR_BS9; } else { GPIOC->BRR=GPIO_BRR_BR9; }; }; //   if ((num==12)) { switch (back) { case 0: if (inpok) { back=3; }; break; case 3: if (!inpok) { back=4;ji=0;inpok=0;x=0; sti=0; }; break; default: ; } }; if (back==4) { if (inpok==0) { while ((move[ji]<1) && (ji<10)) { ji++; }; if ((ji<10)) { if ((sti>100)) { x=0; sti=0; num=move[ji]; tit=time[ji]; inpok=1; GPIOC->BRR=GPIO_BRR_BR8; GPIOC->BSRR=GPIO_BSRR_BS9; } } else { backreset(); } } else { if (sti>tit) { inpok=0; sti=0; x=0; ji++; GPIOC->BSRR=GPIO_BSRR_BS8; } } }; //   if ((num==10)) { switch (back) { case 0: if (inpok) { back=1; }; break; case 1: if (!inpok) { back=2;ji=9;inpok=0;x=0; sti=0; }; break; default: ; } }; if (back==2) { if (inpok==0) { if ((ji>0) && (move[ji]>0)) { if ((sti>100)) { x=0; sti=0; num=move[ji]; if (num<4) { num+=6; } else { if (num>6) { num-=6; } } tit=time[ji]; inpok=1; GPIOC->BRR=GPIO_BRR_BR8; GPIOC->BSRR=GPIO_BSRR_BS9; } } else { backreset(); } } else { if (sti>tit) { inpok=0; x=0; sti=0; ji--; GPIOC->BSRR=GPIO_BSRR_BS8; } } }; //      "*" if (num==11) { backreset(); } if ((x==3*max)) { GPIOC->BRR=GPIO_BRR_BR12; if ((!inpok) || (num<1) || (num>9)) { GPIOC->BRR=GPIO_BRR_BR6; GPIOC->BRR=GPIO_BRR_BR7; GPIOC->BRR=GPIO_BRR_BR10; GPIOC->BRR=GPIO_BRR_BR11; } if ((back!=2)&&(back!=4)) { in0=inp0; in1=inp1; in2=inp2; in3=inp3; inok=inpok; } if ((move[9]>0)&&(move[9]<10)&&(!inpok)&&(back!=2)&&(back!=4)) { for (ju=0;ju<9;ju++) { time[ju]=time[ju+1]; } time[9]=sti; }; }; if ((x==5*max) && (inpok)) { if ((1<=num) && (num<=9)&&(back!=2)&&(back!=4)) { for (ju=0;ju<9;ju++) //    { move[ju]=move[ju+1]; } move[9]=num; sti=0; // ,       }; if ((num==1) || (num==2) || (num==3)) { GPIOC->BRR=GPIO_BRR_BR10; GPIOC->BSRR=GPIO_BSRR_BS11; GPIOC->BSRR=GPIO_BSRR_BS2; } else { GPIOC->BRR=GPIO_BRR_BR11; }; if ((num==7) || (num==8) || (num==9)) //  { GPIOC->BRR=GPIO_BRR_BR11; GPIOC->BSRR=GPIO_BSRR_BS10; GPIOC->BSRR=GPIO_BSRR_BS2; } else { GPIOC->BRR=GPIO_BRR_BR10; }; }; if ((x>=max*7) && (inpok)) // inpok  0,         .             . { if ((num==1) || (num==4) || (num==7)) // { GPIOC->BRR=GPIO_BRR_BR7; if (j>0+full) { GPIOC->BSRR=GPIO_BSRR_BS6; } else { if (j<0+full-gist) { GPIOC->BRR=GPIO_BRR_BR6; } } } else { GPIOC->BRR=GPIO_BRR_BR1; } if ((num==3) || (num==6) || (num==9)) // { GPIOC->BRR=GPIO_BRR_BR6; if (j<4250-full) { GPIOC->BSRR=GPIO_BSRR_BS7; } else { if (j>4250-full+gist) { GPIOC->BRR=GPIO_BRR_BR7; } } } else { GPIOC->BRR=GPIO_BRR_BR3; } //     if ((num==2) || (num==5) || (num==8)) { if (j<js-gist*3) //       { GPIOC->BRR=GPIO_BRR_BR6; //   « » (    ) GPIOC->BSRR=GPIO_BSRR_BS7; //   « » } else { if (j>js-gist*2) { GPIOC->BRR=GPIO_BRR_BR7;   « » } }; if (j>js+gist*3) { GPIOC->BRR=GPIO_BRR_BR7; GPIOC->BSRR=GPIO_BSRR_BS6; } else { if (j<js+gist*2) { GPIOC->BRR=GPIO_BRR_BR6; } }; }; }; if ((x==max*15)) { if (((num==1) || (num==2) || (num==3) || (num==5) || (num==7) || (num==8) || (num==9))&&(inpok)) //    { GPIOC->BSRR=GPIO_BSRR_BS12; } else { GPIOC->BRR=GPIO_BRR_BR12; } x++; } else { x++; if (x>max*20+300000) { if (!inpok) { GPIOC->BRR=GPIO_BRR_BR2;//   } x=max*20+1; } } //   if (x%80000<40000) { if ((num%3==1) && (inpok) && (num<10)) { GPIOC->BSRR=GPIO_BSRR_BS1; } else { GPIOC->BRR=GPIO_BRR_BR1; } if ((num%3==0) && (inpok) && (num<10)) { GPIOC->BSRR=GPIO_BSRR_BS3; } else { GPIOC->BRR=GPIO_BRR_BR3; } } else { GPIOC->BRR=GPIO_BRR_BR1; GPIOC->BRR=GPIO_BRR_BR3; } if (sti==0) { do { ti=0; } while (ti>1); } }; return 0; }; //   TIM6_DAC void TIM6_DAC_IRQHandler(void) { ti++; TIM6->SR &= ~TIM_SR_UIF; //  UIF }
      
      









画像



画像



次のように機胜したす。







5. DACデゞタル-アナログコンバヌタヌを䜿甚しおサりンドを再生する



ADCはマスタリングされおいるため、DACを泚意せずに攟眮しないでください。 教育や嚯楜の目的で䜿甚する最も明癜な方法は、音を生成するように思えたす。 開発順序は叀兞的です。Webで既補のサンプルを芋぀けお実行し、「すごい」、コヌドを倉曎したす。

スピヌカヌをNPNトランゞスタのプラスずコレクタに接続したした。DACが抵抗を介しお出力されるレッグからの信号は、トランゞスタのベヌスに到達したす。 理論的には、スピヌカヌは極性が倉化する音の呚波数の電気信号で駆動されたすが、スピヌカヌには䞀方向にのみ電流を䟛絊したす。 2぀のトランゞスタに぀いお異なる回路を詊したしたが、音に倧きな違いは聞こえたせんでした。 おそらく、適切なスキヌムを芋぀けられなかったのでしょう。



最初の音は、 この䟋を䜿甚しお取埗されたした。



サンプルコヌド
 #include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" /* ,       DAC    */ const uint16_t sin[32] = { 2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647}; unsigned char i=0; int main(void) { /*    */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*   */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); /*   6 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); /*    */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); /*        */ TIM6->PSC = 0; TIM6->ARR = 500; TIM6->DIER |= TIM_DIER_UIE; //    TIM6->CR1 |= TIM_CR1_CEN; //  ! NVIC_EnableIRQ(TIM6_DAC_IRQn); // TIM6_DAC_IRQn  /*  DAC1 */ DAC->CR |= DAC_CR_EN1; /*   */ while (1) { } } /*    6 */ void TIM6_DAC_IRQHandler(void) { TIM6->SR &= ~TIM_SR_UIF; //  UIF DAC->DHR12R1=sin[i++]; //      if (i==32) i=0; //     32     }
      
      









プログラムコヌドに基づいお食品の呚波数を蚈算し、結果をチュヌナヌず比范するずよいでしょう。 プロセッサヌ呚波数24,000,000 Hz。 タむマヌTIM6-> PSCは、れロに達するずリセットされたす。 すべおのビヌト。 タむマヌTIM6-> ARRは500にカりントされたす。 割り蟌みは、501回目のリセットごずにトリガヌされたすTIM6-> PSC-この堎合、24 000 000 Hz / 1/ 501≈47 904 Hzです。 これは、将来のオヌディオ信号のサンプリング呚波数です 。 , - mp3 44 100 . , , — 16 12. , .



— , 32 sin. : 47 904 / 32 ≈ 1 497 . ( 5 ), 
 «!». F#6, , : 1 497,1 .



画像



12:


なぜなら , - . -, . , 5 , 10 . :

TIM6->PSC = 23; // 1 M

TIM6->ARR = 99; // PSC 23 ARR 99 100 (10 )

, , — 27,5 . , (440 , ), 画像 11 ( ). ( 12 n ).



: , Excel . , . . , (), . 2 400 . Excel, , :

  1. , 12 ( ).
  2. ( — 27,5 ) (# — +1 , — +2 , — +12 ).
  3. , 10 000 , 10 000 .
  4. .
  5. 0 4095, .




. 結果



 //  const uint16_t noteC[]={ 76,2216,2383,2547,2709,2865,3017,3162,3299,3428,3547,3657,3755,3842,3917, 3979,4028,4064,4086,4095,4090,4070,4038,3991,3932,3860,3775,3679,3572, 3455,3328,3193,3050,2900,2744,2584,2419,2253,2085,1917,1749,1584,1422, 1264,1111,965,826,695,574,462,361,271,194,129,76,38,12,1,3,19,49,92,149, 218,300,393,498,613,738,871,1013,1161,1316,1475,1639,1805,1973 };
      
      









 //   const uint16_t noteCd[]={ 72,2226,2402,2576,2746,2911,3069,3220,3361,3493,3614,3722,3818,3901,3970, 4024,4063,4087,4095,4088,4065,4027,3974,3907,3825,3730,3622,3503,3372, 3231,3081,2924,2759,2590,2416,2239,2061,1883,1706,1532,1362,1196,1038, 887,744,612,490,381,284,200,130,75,35,10,0,6,27,64,116,182,263,357,464, 583,713,853,1002,1159,1323,1492,1666,1842,2020 }; const uint16_t noteD[]={ 68,2236,2423,2607,2786,2959,3124,3280,3425,3559,3680,3787,3879,3955,4016, 4059,4086,4095,4087,4061,4018,3959,3883,3792,3686,3566,3432,3288,3132, 2968,2795,2617,2433,2246,2057,1869,1682,1498,1318,1145,980,823,677,543, 421,314,221,143,82,38,10,0,7,32,74,133,207,298,403,523,655,799,954,1118, 1291,1469,1652,1839,2028 }; const uint16_t noteDd[]={ 63,2247,2445,2639,2828,3009,3181,3342,3490,3625,3745,3849,3935,4003, 4053,4084,4095,4087,4059,4012,3946,3862,3761,3643,3510,3363,3204, 3034,2854,2666,2473,2275,2076,1876,1678,1483,1293,1111,938,775, 625,488,366,260,171,100,48,14,0,6,31,76,139,220,319,434,565,710, 868,1037,1215,1402,1594,1792,1991 }; //  const uint16_t noteE[]={ 60,2259,2469,2673,2872,3061,3239,3405,3556,3691,3809,3907,3986,4044,4080, 4095,4087,4058,4008,3936,3844,3733,3604,3458,3297,3122,2937,2741,2538, 2330,2119,1907,1697,1490,1289,1097,914,744,588,447,324,219,133,69,25, 3,3,24,68,133,218,323,446,586,742,912,1095,1287,1488,1694,1905 }; const uint16_t noteF[]={ 57,2272,2493,2709,2917,3115,3300,3470,3623,3756,3870,3961,4029,4074, 4094,4089,4060,4007,3930,3831,3710,3569,3410,3234,3044,2842,2631, 2413,2190,1965,1742,1522,1309,1104,911,731,567,421,295,189,106,47, 11,0,14,51,113,199,306,434,582,748,929,1123,1329,1543,1763,1987 }; const uint16_t noteFd[]={ 54,2285,2519,2747,2966,3172,3362,3536,3689,3820,3927,4008, 4063,4091,4092,4065,4010,3929,3823,3693,3540,3367,3177, 2971,2753,2526,2291,2054,1817,1582,1354,1135,929,738,564, 410,279,171,89,33,4,3,29,83,163,269,399,550,723,912,1118,1336,1563,1797,2034 }; const uint16_t noteG[]={ 51,2299,2547,2787,3016,3230,3426,3602,3754,3880,3978,4047,4086, 4094,4071,4017,3934,3822,3683,3519,3333,3127,2905,2670,2426,2176, 1924,1674,1430,1194,972,766,580,416,276,163,79,25,1,8,47,115,213, 338,490,665,861,1075,1303,1543,1791,2042 }; const uint16_t noteGd[]={ 48,2314,2576,2829,3068,3290,3492,3668,3817,3936,4023,4076, 4095,4079,4028,3944,3828,3681,3506,3307,3086,2848,2596, 2335,2069,1802,1540,1286,1045,821,618,440,288,167,78,22, 0,14,61,143,257,401,574,771,991,1228,1479,1739,2005 }; const uint16_t noteA[]={ 45,2330,2606,2872,3123,3353,3558,3734,3878,3987,4059,4092, 4087,4043,3961,3842,3689,3504,3292,3056,2801,2532,2253, 1970,1689,1415,1153,907,684,486,319,184,85,23,0,16,71, 163,292,454,646,865,1107,1366,1639,1919 }; const uint16_t noteAd[]={ 42,2346,2639,2918,3179,3416,3624,3798,3934,4030,4083,4093, 4059,3982,3864,3707,3514,3290,3039,2767,2480,2183,1883, 1587,1301,1031,782,561,371,218,103,30,1,15,72,172,313, 490,700,940,1203,1484,1777 }; const uint16_t noteH[]={ 40,2364,2673,2967,3238,3481,3690,3859,3985,4064,4095,4076, 4009,3894,3736,3536,3301,3036,2747,2441,2126,1809,1498,1199, 922,671,453,274,137,46,3,10,65,168,316,506,732,991,1274,1577,1890 }; const uint16_t noteP[]={ //   1,2048 };
      
      









, ( 1, 2, 4, 8 ..):



 uint16_t mnote(const uint16_t *pa,char octave) //         { int ii=0; do {ii=i;} while (ii!=i); ii=(octave*ii)%pa[0]; ii=*(pa+ii); return ii; }
      
      







i 100 :



 /*    6 */ void TIM6_DAC_IRQHandler(void) { i++; TIM6->SR &= ~TIM_SR_UIF; //  UIF }
      
      







, . , Nokia:



 uint16_t *melody[]={ noteE,noteP,noteG,noteP, noteA,noteA,noteP,noteE, noteP,noteG,noteP,noteAd, noteA,noteA,noteP,noteP, noteE,noteP,noteG,noteP, noteA,noteA,noteP,noteG, noteP,noteE,noteP,noteP, noteP,noteP,noteP,noteP };
      
      







, ?..



(), , :



コヌド
  uint16_t *melody2[]={ noteH,noteP,noteD,noteP, noteE,noteE,noteP,noteH, noteP,noteD,noteP,noteF, noteE,noteE,noteP,noteP, noteH,noteP,noteD,noteP, noteE,noteE,noteP,noteD, noteP,noteH,noteP,noteP, noteP,noteP,noteP,noteP }; uint16_t *melody3[]={ noteGd,noteP,noteH,noteP, noteCd,noteCd,noteP,noteGd, noteP,noteH,noteP,noteD, noteCd,noteCd,noteP,noteP, noteGd,noteP,noteH,noteP, noteCd,noteCd,noteP,noteH, noteP,noteGd,noteP,noteP, noteP,noteP,noteP,noteP };
      
      









( ). しかし 0 4095, . , , . 100 




.



 #include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" int i=0; uint16_t current=0; int loccurrent=0; uint16_t mnote(const uint16_t *pa,char octave) //         { int ii=0; do {ii=i;} while (ii!=i); ii=(octave*ii)%pa[0]; ii=*(pa+ii); return ii; } //      100 ,  0  4095 //  const uint16_t noteC[]={ 76,2216,2383,2547,2709,2865,3017,3162,3299,3428,3547,3657,3755,3842,3917,3979,4028,4064,4086,4095,4090,4070,4038,3991,3932,3860,3775,3679,3572,3455,3328,3193,3050,2900,2744,2584,2419,2253,2085,1917,1749,1584,1422,1264,1111,965,826,695,574,462,361,271,194,129,76,38,12,1,3,19,49,92,149,218,300,393,498,613,738,871,1013,1161,1316,1475,1639,1805,1973 }; //   const uint16_t noteCd[]={ 72,2226,2402,2576,2746,2911,3069,3220,3361,3493,3614,3722,3818,3901,3970,4024,4063,4087,4095,4088,4065,4027,3974,3907,3825,3730,3622,3503,3372,3231,3081,2924,2759,2590,2416,2239,2061,1883,1706,1532,1362,1196,1038,887,744,612,490,381,284,200,130,75,35,10,0,6,27,64,116,182,263,357,464,583,713,853,1002,1159,1323,1492,1666,1842,2020 }; const uint16_t noteD[]={ 68,2236,2423,2607,2786,2959,3124,3280,3425,3559,3680,3787,3879,3955,4016,4059,4086,4095,4087,4061,4018,3959,3883,3792,3686,3566,3432,3288,3132,2968,2795,2617,2433,2246,2057,1869,1682,1498,1318,1145,980,823,677,543,421,314,221,143,82,38,10,0,7,32,74,133,207,298,403,523,655,799,954,1118,1291,1469,1652,1839,2028 }; const uint16_t noteDd[]={ 63,2247,2445,2639,2828,3009,3181,3342,3490,3625,3745,3849,3935,4003,4053,4084,4095,4087,4059,4012,3946,3862,3761,3643,3510,3363,3204,3034,2854,2666,2473,2275,2076,1876,1678,1483,1293,1111,938,775,625,488,366,260,171,100,48,14,0,6,31,76,139,220,319,434,565,710,868,1037,1215,1402,1594,1792,1991 }; //  const uint16_t noteE[]={ 60,2259,2469,2673,2872,3061,3239,3405,3556,3691,3809,3907,3986,4044,4080,4095,4087,4058,4008,3936,3844,3733,3604,3458,3297,3122,2937,2741,2538,2330,2119,1907,1697,1490,1289,1097,914,744,588,447,324,219,133,69,25,3,3,24,68,133,218,323,446,586,742,912,1095,1287,1488,1694,1905 }; const uint16_t noteF[]={ 57,2272,2493,2709,2917,3115,3300,3470,3623,3756,3870,3961,4029,4074,4094,4089,4060,4007,3930,3831,3710,3569,3410,3234,3044,2842,2631,2413,2190,1965,1742,1522,1309,1104,911,731,567,421,295,189,106,47,11,0,14,51,113,199,306,434,582,748,929,1123,1329,1543,1763,1987 }; const uint16_t noteFd[]={ 54,2285,2519,2747,2966,3172,3362,3536,3689,3820,3927,4008,4063,4091,4092,4065,4010,3929,3823,3693,3540,3367,3177,2971,2753,2526,2291,2054,1817,1582,1354,1135,929,738,564,410,279,171,89,33,4,3,29,83,163,269,399,550,723,912,1118,1336,1563,1797,2034 }; const uint16_t noteG[]={ 51,2299,2547,2787,3016,3230,3426,3602,3754,3880,3978,4047,4086,4094,4071,4017,3934,3822,3683,3519,3333,3127,2905,2670,2426,2176,1924,1674,1430,1194,972,766,580,416,276,163,79,25,1,8,47,115,213,338,490,665,861,1075,1303,1543,1791,2042 }; const uint16_t noteGd[]={ 48,2314,2576,2829,3068,3290,3492,3668,3817,3936,4023,4076,4095,4079,4028,3944,3828,3681,3506,3307,3086,2848,2596,2335,2069,1802,1540,1286,1045,821,618,440,288,167,78,22,0,14,61,143,257,401,574,771,991,1228,1479,1739,2005 }; const uint16_t noteA[]={ 45,2330,2606,2872,3123,3353,3558,3734,3878,3987,4059,4092,4087,4043,3961,3842,3689,3504,3292,3056,2801,2532,2253,1970,1689,1415,1153,907,684,486,319,184,85,23,0,16,71,163,292,454,646,865,1107,1366,1639,1919 }; const uint16_t noteAd[]={ 42,2346,2639,2918,3179,3416,3624,3798,3934,4030,4083,4093,4059,3982,3864,3707,3514,3290,3039,2767,2480,2183,1883,1587,1301,1031,782,561,371,218,103,30,1,15,72,172,313,490,700,940,1203,1484,1777 }; const uint16_t noteH[]={ 40,2364,2673,2967,3238,3481,3690,3859,3985,4064,4095,4076,4009,3894,3736,3536,3301,3036,2747,2441,2126,1809,1498,1199,922,671,453,274,137,46,3,10,65,168,316,506,732,991,1274,1577,1890 }; const uint16_t noteP[]={ 1,2048 }; //,   uint16_t *melody[]={ noteE,noteP,noteG,noteP, noteA,noteA,noteP,noteE, noteP,noteG,noteP,noteAd, noteA,noteA,noteP,noteP, noteE,noteP,noteG,noteP, noteA,noteA,noteP,noteG, noteP,noteE,noteP,noteP, noteP,noteP,noteP,noteP }; //  uint16_t *melody2[]={ noteH,noteP,noteD,noteP, noteE,noteE,noteP,noteH, noteP,noteD,noteP,noteF, noteE,noteE,noteP,noteP, noteH,noteP,noteD,noteP, noteE,noteE,noteP,noteD, noteP,noteH,noteP,noteP, noteP,noteP,noteP,noteP }; //  uint16_t *melody3[]={ noteGd,noteP,noteH,noteP, noteCd,noteCd,noteP,noteGd, noteP,noteH,noteP,noteD, noteCd,noteCd,noteP,noteP, noteGd,noteP,noteH,noteP, noteCd,noteCd,noteP,noteH, noteP,noteGd,noteP,noteP, noteP,noteP,noteP,noteP }; int main(void) { GPIO_InitTypeDef PORT; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); PORT.GPIO_Pin = (GPIO_Pin_9 | GPIO_Pin_8); PORT.GPIO_Mode = GPIO_Mode_Out_PP; PORT.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC, &PORT); /*    */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /*   */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); /*   6 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); /*    */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM6->PSC = 23; // 24000-1  1000 TIM6->ARR = 99; // PSC 23  ARR 99   100  TIM6->DIER |= TIM_DIER_UIE; //    TIM6->CR1 |= TIM_CR1_CEN; //  ! NVIC_EnableIRQ(TIM6_DAC_IRQn); // TIM6_DAC_IRQn  /*  DAC1 */ DAC->CR |= DAC_CR_EN1; /*   */ while (1) { GPIOC->BRR=GPIO_BRR_BR8; GPIOC->BSRR=GPIO_BSRR_BS9; do { loccurrent=i; } while (i!=loccurrent); //  ,    GPIOC->BRR=GPIO_BRR_BR9; GPIOC->BSRR=GPIO_BSRR_BS8; current=(loccurrent/(2000))%32; //   ,  0  31. DAC->DHR12R1=(mnote(melody[current],1)+mnote(melody2[current],1)+mnote(melody[current],2)+mnote(melody2[current],2)+mnote(melody[current],4)+mnote(melody3[current],2))/6; } } /*    6 */ void TIM6_DAC_IRQHandler(void) { i++; TIM6->SR &= ~TIM_SR_UIF; //  UIF }
      
      









, - ? はい



13:


, , STM32VLDiscovery, . :

1. Youtube Aston Martin.

2. ( ) .

3. ( Audacity ).

4. . 24 . , 2 , 2-3 -. .

5. WAV-.

6. ( WAV 2 TEXT) — -, . , .

7. 0 4095 Excel. 60 000 Notepad++ Sublime Text, . Excel 30 , — CoIDE 


8. .



, over 9000 . :







, , , , , :







そのようなもの。



All Articles