STM32をレジスタで制御する②~デジタル入力~

こういうのってやる気があるうちに記事にするのが賢いんです。
てなわけで第二弾、GPIOの入力です。
といっても前回のデジタル出力とやることって、実はほぼ一緒なんですよね、サクッとやっちゃいましょう。

スイッチの状態でLEDの状態を切り替え

タクトスイッチだけ使って、デバッグモードでレジスタの状態を見るだけでもいいんですけど、面白くはないですよね。
視覚的に感じたいし、LEDも使いましょう。
今回は入力のほうだけ取り上げるので、コーディングの準備やLチカについては前回の記事を適宜参照してください。

GPIOの初期化

今回はPA0を出力(LED)、PA8を入力(タクトスイッチ)でいきます。
まずはポートAにクロックを供給してGPIOを使えるようにしましょう。

コードにするとこんな感じです。
前回とちょーっとだけコードが変わっただけですね。
(まだまだ簡単です…CAN通信とかをレジスタはちょっとやりたくねぇな。)

RCC -> AHBENR |= (1 << 17);

さ、そんなことは置いておいて入出力の設定をしましょう。

GPIOx_MODERレジスタは2ビットで各ピンの入出力設定を行います。
今回の場合、MODER0は"01"、MODER8は"00"にすればよさそうですね。
コードに起こすとこうなります。

GPIOA -> MODER |= (1 << 0);
GPIOA -> MODER &= (~(1 << 1));
GPIOA -> OSPEEDR = 0;
GPIOA -> MODER &= (~(1 << 16));
GPIOA -> MODER &= (~(1 << 17));

上の二行がPA0を出力に、下の二行がPA8を入力に設定する分です。
ついでにアウトプットの出力スピードも前回と同じようにコーディングしておきました。
※アウトプットの出力スピードについては、別の記事で実験した記事を上げようかなって考えています。しばしお待ちください。

スイッチの入力を読む

初期化がこの前の記事とほぼ同じだったのでサクッと終わりましたね。
ループ内のGPIO操作も特に難しいことはありません(割り込み?そんなの知らない)。

ピンの入力状態はこのGPIOx_IDRレジスタから読むことができます。
PA8がLOWのときはこのレジスタの8ビット目が0に、HIGHの時は1になります。
変数SW_stateにスイッチの状態を代入するコードはこんな感じで書けます。

uint8_t SW_state = ((GPIOA -> IDR & 1 << 8) >> 8);

ちょっとややこしいですね…。
もっとシンプルに書く方法があるかもしれないな…。
まず、
   GPIOA -> IDR & 1 << 8
で8ビット目だけのビットを取り出します。
それから右に8ビットシフトすることで、SW_stateには0、または1でスイッチの入力状態が保存されます。

さあ、あとはこの入力状態をPA0に出力してもらいましょう。

GPIOA -> ODR = SW_state;

はい、これだけです。
ここの代入演算子は、論理演算を用いた複合演算子ではなく、通常(?)の代入演算子を用いてください。
例えば論理和(|=)を用いた場合、

  • プログラム開始から入力がLOWの間は、PA0もLOW

  • 初めて入力がHIGHになったとき、PA0もHIGIになる

  • それ以降、入力状態にかかわらずPA0はHIGH

という動作になります。
まあこの動作が期待通りのプロジェクトはなかなかないでしょう。
さあ、これでプログラムは完成です。

まだタイマーだったりDMAだったり、シリアル通信だったりをレジスタ制御していないので、「あれ、レジスタ制御って案外できるのか?!」って勘違いしてしまいそうですね…。
このプログラムを動作させた様子です。
今回タクトスイッチはプルダウンにしているので、スイッチがオンの時に点灯、オフの時に消灯になります。
(例にもよって𝕏の投稿ですが、許してください。)

また、レジスタ制御の利点として、ポートの入力を一度に読んだり、出力を一度に設定できます。
いちいちdigitalReadだったり、HAL_GPIO_ReadPinを複数書く必要がないっていいですよね。(しかも若干の処理速度向上も期待できる)
PA0~7をタクトスイッチに、PA8~15をLEDに接続し、スイッチに対応するLEDを点灯させるプログラムもレジスタ制御ならサクッと書けます。

プログラムの詳細は省略します。
このプログラムを動作させたのが下の動画です。
めんどくさいビット演算をしなくても同時入力、同時出力の実装が可能なのはいいですよね。

まとめ

前回とほぼ同じような解説が多かったですね。
ちょっとロボカップサッカーの話になるのですが、Arduino(ATmega328pとかAtmega2560)を使用したロボットの場合、基本的な入出力をレジスタで制御するだけで、かなり処理速度が向上するんですよね。
ただSTM32などの32bitマイコンってレジスタ制御にしても、Arduinoより恩恵って薄そうな気がします。
まあでもラインセンサーだったりの入力の情報を1ピンずつ読む必要がないのは、アルゴリズム的にも有利な気がしますね。
そこらへんで今回は終わりです、おやすみなさい。


この記事が気に入ったらサポートをしてみませんか?