情報処理の講義でArduinoのレジスタを触り始めたのですが、解説が絶望的なのでクラスの誰か一人でも救済できたらいいなと思って書いた記事です。
前回のあらすじTL;DR
- レジスタ操作はただのC言語ゲーミング!!!!
- ただのdigitalWrite禁止縛り
- レジスタ変数を操作するとピンを操作できる
詳細はこちら
個別でピンを操作する
前回の
PORTD = 0B01000000;
を改善していきたいと思います。このプログラムはPD6をHIGHに設定するプログラムです。ピンの対応表は前回の記事にもあったこちらの表を参照してください。(DDRをPORTに置き換えてね)
しかしこのプログラム、一部問題があります。PD6以外は全てLOWになってしまいます。対して
digitalWrite(6, HIGH); //6番ピンはPD6
は6をHIGHにしますが6以外は操作しません。これを今回はポート操作で実現していきます。
ビット演算子
ここでビット演算子について復習します。FJT先生のディジタル回路でやったブール代数は理解してる前提で行きます。
&(論理積)
ここでXnはXのn bit目を表すものとします。
論理積はいわゆる掛け算です。元のデータがA、操作をBとした時に以下のように考えるとわかりやすいです。
- Bが1のところはAが引き継がれる
- Bが0のところは強制的に0になる
|(論理和)
論理和はいわゆる掛け算です。元のデータがA、操作をBとした時に以下のように考えるとわかりやすいです。
- Bが0のところはAが引き継がれる
- Bが1のところは強制的に1になる
ビット演算子を用いたレジスタの操作
0→1
「Bが1のところは強制的に1になる」という性質を使いたいので論理和を使います。
PORTD = PORTD | 0B01000000;
こうすると
- PD6以外はPORTDがそのまま引き継がれる
- PD6は強制的に1になる
となります。つまり
digitalWrite(6, HIGH); //6番ピンはPD6
と完全に同等です。
1→0
「Bが0のところは強制的に0になる」という性質を使いたいので論理積を使います。
PORTD = PORTD & 0B10111111;
こうすると
- PD6以外はPORTDがそのまま引き継がれる
- PD6は強制的に0になる
となります。つまり
digitalWrite(6, LOW); //6番ピンはPD6
と完全に同等です。
省略形
便利なので覚えておきましょう。
PORTD = PORTD | 0B01000000;
PORTD |= 0B01000000;
PORTD = PORTD & 0B10111111;
PORTD &= 0B10111111;
【発展】ド・モルガンの法則
原理を理解してしまえば、あとはブール代数ゲーなのでド・モルガンの法則を適用できます。
論理和
\begin{align}
C &= A + B \\
&= \overline{\overline{A}} + \overline{\overline{B}}\\
&= \overline{\overline{A} ・ \overline{B}}\\
\end{align}
論理積
\begin{align}
C &= A ・ B \\
&= \overline{\overline{A}} ・ \overline{\overline{B}}\\
&= \overline{\overline{A} + \overline{B}}\\
\end{align}
まぁそれはそうって感じですね。これを使ってさっきの式を書き換えると、
PORTD = PORTD | 0B01000000;
PORTD = ~(~PORTD & 0B10111111);
PORTD = PORTD & 0B10111111;
PORTD = ~(~PORTD | 0B01000000);
です。~
は反転の記号です。
まぁこれくらい覚えておけばEND先生に煽られることはないと思います。
ビットシフト
シフト演算子を思い出してください。これらはそれぞれ同様です。
PORTX |= 0B01000000;
PORTX |= 0B1 << 6;
PORTX &= 0B10111111;
PORTX &= ~(0B1 << 6);
補足すると、論理和の方は0B00000001
をシフトした後に反転しています。
チートシート
最悪これ覚えておけばおk
PORTX |= 0B01000000; // 0→1
PORTX |= 0B1 << 6; // 0→1
PORTX &= 0B10111111; // 1→0
PORTX &= ~(0B1 << 6);// 1→0
DDRXについても同様です。
おわりに
おわりです