PascalでのARMプログラミング

一度、突然、完全に予期せず、戦争を宣言することなく、アイデアが浮上しました。 このため、STM32クリスタルの作成とプログラミングが必要でした。



しかし、問題は何ですか? stm32vldiscoveryは棚の上にあり、翼で待っていました。私はプログラミングを知っていて、しばしば「順序どおり」に書きます。 私は鉄の友達です。



まず、「何を書くべきか」という疑問が生じました。 多くのプログラミング環境がありますが、言語は「C」のみです。 オプションなし。 私は原則としてアセンブラーを考慮しません。 LEDを点滅させることもできますが、もっと複雑なものには多大な労力が必要です。



しかし、私はCを知りません! 一般的に。 私の人生はすべてPascal / Delphiのみで書きました。 言語を学ぶ? 40歳以上のときに言語を学ぼうとしたことがありますか? 仕事をするとき、家族、そして最低の空き時間。 心が若者ほど鋭くないとき。 そして、1つのプロジェクトのためにこれらすべてを始めることは、法律のために勉強し、次の家のパン屋への旅行のために車を買うことよりも意味がありません。



ソリューションは、MikroElektronikaの「mikroPascal PRO for ARM」で見つかりました。 正直に言うと、PICチップの人気のピーク時に「mikroPascal PRO for PIC」で既に働いていました。 印象はあまり良くありませんでした。 コンパイラは「奇妙な」ものであり、シェルも安定性と使いやすいインターフェイスに違いはありませんでした。



何年にわたって何が変化し、どの方向に変化したかを見るのはさらに興味深いものでした。



そして、手元にあるもの:



タスク:Cコードを1行も使わずにマイクロコントローラープログラミングをマスターする。



それでは始めましょう...



プロジェクトの作成は簡単です。 ファイル->新規->新規プロジェクト。



マイクロコントローラーのタイプを示します。 彼は、どの標準ライブラリを使用するかを尋ねます(デフォルト-すべて)。 出発します。 コンパイル中の「余分な」ライブラリは自動的にスローされます。



タイミングを設定することを忘れないでください。 疑わしい場合は、標準の「スキーム」のいずれかを使用してください。 これは、タイミングパラメータの設定セットです。



まず、LEDを試してみましょう。 燃やすように頼みましょう。 LEDはポートD12、D13、D14、およびD15にあります。

コード
プログラムMyProject1;
始める
   //出口ポートを初期化します
   GPIO_Digital_Output(@ GPIOD_BASE、_GPIO_PINMASK_12または_GPIO_PINMASK_13または_GPIO_PINMASK_14または_GPIO_PINMASK_15);
   //ライト
   SetBit(GPIOD_ODR、12);
   SetBit(GPIOD_ODR、13);
   SetBit(GPIOD_ODR、14);
   SetBit(GPIOD_ODR、15);

  本当はnopを行います。
終わり。




やめて! さて、これらのマイクロコントローラの使用経験のある膨大な数の人々が疑問を抱くでしょう。ポートクロッキングを含めるのはどこですか?!



非常に簡単: 入力ポートまたは出力ポートを初期化すると、クロッキングが自動的にオンになります。 信じられない-表示->統計->機能ツリー(私のお気に入り!)に行ってください。







コンパイラが「自動的に」行うことについて疑問がある場合は、確認してください。 点灯しているLEDを見ることは確かに素晴らしいことです。 しかし、退屈。 彼にまばたきをしてみましょう

コード
プログラムMyProject1;

始める
   //出口と入口にピンを設定します
   GPIO_Digital_Output(@ GPIOD_BASE、_GPIO_PINMASK_12または_GPIO_PINMASK_13または_GPIO_PINMASK_14または_GPIO_PINMASK_15);

  本当の始まり
       TestBit(GPIOD_ODR、12)の場合、ClearBit(GPIOD_ODR、12)の場合、SetBit(GPIOD_ODR、12)。
       Delay_1sec;
  終わり;
終わり。




ボードにボタンがあります。 起動しましょう。 ボタンを押すと、LEDが点灯します。 そして、リリースされると、彼らは外に出ます(ただし、予想外に!-冗談です)。 ボタンはA0にあります。 読み取りには、ボタン関数を使用します。 連絡先の跳ね返りを抑制し、ボタンのロジック(NCまたはNO)を考慮します。 原則として、ポートビットのステータスを「直接」簡単に読み取ることができますが、より読みやすくなっています。



コード
プログラムMyProject1;

始める
   //出口と入口にピンを設定します
   GPIO_Digital_Output(@ GPIOD_BASE、_GPIO_PINMASK_12または_GPIO_PINMASK_13または_GPIO_PINMASK_14または_GPIO_PINMASK_15);
   GPIO_Digital_Input(@ GPIOA_BASE、_GPIO_PINMASK_0);
  本当ながら
    ボタン(GPIOA_IDR、0、10、1)の場合、開始
       //ライト
       SetBit(GPIOD_ODR、12);
       SetBit(GPIOD_ODR、13);
       SetBit(GPIOD_ODR、14);
       SetBit(GPIOD_ODR、15);
    他の終わり
       //消す
       ClearBit(GPIOD_ODR、12);
       ClearBit(GPIOD_ODR、13);
       ClearBit(GPIOD_ODR、14);
       ClearBit(GPIOD_ODR、15);
    終わり;
終わり。




ループ内のダイレクトボタンポーリング? ボタンを常にチェックすることは常に可能とは限りません。 多くの場合、クリスタルはポーリングボタンよりも重要なことで忙しいです。 そして、プレスの瞬間を「逃す」ことができます。 イベントを処理する割り込みを生成するためにボタンを押すと、より正確になります。

コード
プログラムMyProject1;

プロシージャINT_EXTI0();  iv IVT_INT_EXTI0;  ics ICS_AUTO;
始める
   EXTI_PR:= $ FFFF;  //フラグをクリア
   TestBit(GPIOD_ODR、12)の場合、ClearBit(GPIOD_ODR、12)の場合、SetBit(GPIOD_ODR、12)。
終わり;

始める
   //結論を構成します
   GPIO_Digital_Output(@ GPIOD_BASE、_GPIO_PINMASK_12);
   GPIO_Digital_Input(@ GPIOA_BASE、_GPIO_PINMASK_0);

   EXTI_IMR:=%1; 希望する入力からの中断を許可する
   EXTI_FTSR:= $ FFFF; 到着割り込み0
  
   NVIC_IntEnable(IVT_INT_EXTI0);  //外部割り込みを有効にします
   EnableInterrupts();

  本当のこと;
終わり。






クリスタルには何がありますか? タイマー? PWMモードで遊んでみましょう。 結論は何ですか? 4番目のタイマーは、LEDに接続されているという結論に達します。 それで、私たちは何を待っていますか?

コード
プログラムMyProject1;
 var
  比率、tmp:単語;
始める
  比率:= PWM_TIM4_Init(25000);
   tmp:= 0;
   PWM_TIM4_Set_Duty(0、_PWM_NON_INVERTED、_PWM_CHANNEL1);
   PWM_TIM4_Start(_PWM_CHANNEL1、@ _GPIO_MODULE_TIM4_CH1_PD12);

  本当の始まり
     PWM_TIM4_Set_Duty(比率-tmp、_PWM_INVERTED、_PWM_CHANNEL1);
     Inc(tmp);
     tmp>比の場合、tmp:= 0;
     Delay_1ms;
  終わり;
終わり。






タイマーはPWMだけでなく使用できます。 手はタイマーを使用して定期的なアクションを実行するのに苦労します。 たとえば、タイマーを点滅させましょう。 タイマーが割り込みをプルし、割り込み自体がLEDを制御します。



これを行うには、タイマーレジスタに書き込むための係数を長く検討する必要があります。 そうでない場合は、メーカーのウェブサイトから無料のタイマー計算プログラムを使用してください。



初期データを入力して、完成したタイマーコードを取得します。 このようなもの:







コード
プログラムETXI;

プロシージャTimer2_interrupt();  iv IVT_INT_TIM2;
始める
   TIM2_SR.UIF:= 0;
   TestBit(GPIOD_ODR、12)の場合、ClearBit(GPIOD_ODR、12)の場合、SetBit(GPIOD_ODR、12)。
終わり;

プロシージャInitTimer2();
始める
   RCC_APB1ENR.TIM2EN:= 1;
   TIM2_CR1.CEN:= 0;
   TIM2_PSC:= 2239;
   TIM2_ARR:= 62499;
   NVIC_IntEnable(IVT_INT_TIM2);
   TIM2_DIER.UIE:= 1;
   TIM2_CR1.CEN:= 1;
終わり;

始める
   //終了するピンを設定します
   GPIO_Digital_Output(@ GPIOD_BASE、_GPIO_PINMASK_12);  // PORTDでデジタル出力を有効にします
   // // Timer2プリスケーラー:2239; プリロード= 62499; 実際の割り込み時間= 1
   InitTimer2();

   while(TRUE)do nop;  //無限ループ

終わり。




UART? 簡単です。 UART-USBアダプターを接続します。 たとえば、プロセッサの温度値を毎秒出力します。

コード
プログラムMyProject1;  var uart_tx:string [20];  tmp:整数;  tmp1:実数;  UART2_Init(9600)を開始します。  // UARTを9600 bps ADC1_Init()で構成します;  Delay_ms(100);  //安定化を期待UART TSVREFE_bit:= 1;  UART2_Write_Text( 'Hello!');  UART2_Write(13);  UART2_Write(10);  while(TRUE)do begin tmp:= ADC1_Read(16);  //温度データを読み取りますtmp1:=(3300 * tmp)/ 4095;  // mVを再計算します。 計算に基づいて:3.3 V = 4096; tmp1:=((tmp1-760)/2.5)+25;  //度単位でカウントします。  V25 = 0.76VS = 2.5mV / C FloatToStr(tmp1、uart_tx);  uart_tx:= 'T:' + uart_tx + 'C';  UART2_Write_Text(uart_tx);  UART2_Write(13);  UART2_Write(10);  Delay_ms(1000); 終わり; 終わり。 




起動します...ケース温度-27C。 これは、部屋23Cにあるにもかかわらずです。 原則として、奇妙なことは何もありません。 メーカー自身がこのセンサーを使用して絶対温度を測定することはお勧めしませんが、温度の上昇/下降を測定するためだけに使用します。 温度センサーの出力電圧はチップごとにシフトし、シフトは45度に達することがあります。



やめて! GPIOの初期化を忘れましたか? そして、もう1つの「独自の」機能があります。「ピンで」動作するモジュールを初期化すると、ピンは自動的に初期化されます。 疑問? [表示]-> [統計]-> [機能ツリー](お気に入り)に移動します。







ご覧のとおり、結論は自動的に代替モードに転送され、それらのクロックがオンになります。



そして最後に-USBにアクセスします。 最も簡単なこと。 受信したメッセージを単に返すHIDデバイスを作成しましょう。

コード
プログラムHID_Read_Write_Polling;

 var cnt、kk:バイト。

 var readbuff:バイトの配列[64]。
 var writebuff:バイトの配列[64]。

始める
   HID_Enable(@ readbuff、@ writebuff);
   TRUEしながら
    始める
       USB_Polling_Proc();  //このルーチンを定期的に呼び出します
       kk:= HID_Read();
       if(kk <> 0)then
      始める
         cntの場合:= 0〜63 do
           writebuff [cnt]:= readbuff [cnt];
         HID_Write(@ writebuff、64);
      終わり;
    終わり;
終わり。




または、割り込みを使用した同様のアクション:



コード
プログラムHID_Read_Write;

 var cnt:バイト;

 var readbuff:バイトの配列[64]。
 var writebuff:バイトの配列[64]。

手順USB1Interrupt();  iv IVT_INT_OTG_FS;
始める
    USB_Interrupt_Proc();
終わり;

始める
   HID_Enable(@ readbuff、@ writebuff);
   TRUEしながら
    始める
       while(HID_Read()= 0)do
         ;
       cntの場合:= 0〜63 do
         writebuff [cnt]:= readbuff [cnt];
       while(HID_Write(@ writebuff、64)= 0)do
         ;
    終わり;
終わり。




このプログラム(および標準のUSBライブラリを使用するプログラム)が正常に機能するには、USBdsc.mpasファイルを生成する必要があります。 このデバイスのUSBパラメーターが含まれています。 「ツール」メニューからユーティリティ「HID Terminel」があります。 このユーティリティを使用すると、サンプルや簡単なアプリケーションを実行するのに十分な正しいファイルを生成できます。 さらに複雑な場合は、USBバスの説明をご覧ください。 そして、ファイルを編集します。 幸いなことに、彼には寛大なコメントが寄せられています。







このユーティリティを使用して、例の動作を確認します。







もちろん、今ではコードの「非効率性」について多くの不満があります。 しかし、見てください-USB HIDを使用したかなり「重い」例では、フラッシュの1.7%と動作メモリの1.2%を使用します。







そして少し余談。



この「魔法の」機構はすべて、クロックシステムが適切に構成されている場合にのみ機能します。 絶対に正しいコードが「だまされ」始めると、外部インターフェイスは「消え」始め、USBインターフェイス接続は「デバイスID要求エラー」というメッセージを生成します。プロジェクト設定を開き、クロックを再度チェックします。







これはすべて、Cの知識がマイクロコントローラーの効果的なプログラミングの前提条件ではないことを示しています。 また、標準ライブラリの存在により、トレーニングを受けていない人々の入場閾値が大幅に低下します。 この場合、コードは非常にコンパクトで読みやすいです。



プログラミング環境の詳細な説明は、別の記事に記載されます。



PS:実際、私はC(C ++)を知っています。 コードを自由に読んで理解します。 しかし、この言語でプログラムを書くことは私にとって「不快」です。 脳はパスカルのようなコードで自動的に出力を発行します。



All Articles