愛知工業大学 工学部 電気学科電子情報工学専攻 3年次生 樋口 陽輝
樋口陽輝(ひぐちはるき)
愛知工業大学 工学部 電気学科 電子情報工学専攻
岐阜工業高校 電子工学科
ディジタル回路設計, アナログ回路設計, Web開発, 組込みシステム開発, 電気工学, 通信工学
本講座は, 高校「情報I」の内容や, 中学数学で扱う累乗(指数)の内容が登場します. 学術的に見るとかなり難しいですが, 本日は理解することよりも, 電子回路を組み立て, 動かすことを楽しんで取り組んでいただけると幸いです.
人とコンピューターは数字の数え方が違う!? 10進数と2進数について解説
1 + 1 を計算させよう! 半加算器の作成
もっと大きな数を計算させよう! 全加算器の作成
本当に足し算電卓として使えることを確かめてみよう!
1+11+11+1が10なわけ無いじゃん(笑) って思いますよね? もちろん「いち たす いち は じゅう」なら間違いですね. でも, 見かたを変えると正しくもなります. まずはその数字の見かたを知りましょう.
例えば,
みなさんは無意識にこのように数を見ているはずです. 100+30+5だから135 もう少し分解すると,
1×100+3×10+5×1=1351 \times 100 + 3 \times 10 + 5 \times 1 = 135 1×100+3×10+5×1=135
これをもっと分解すると, こうとも見ることができます.
100の位1×10×10=10010の位3×10=301の位5×1=5\begin{aligned} 100\text{の位}\quad & 1 \times 10 \times 10 = 100 \\ 10\text{の位}\quad & 3 \times 10 = 30 \\ 1\text{の位}\quad & 5 \times 1= 5 \end{aligned} 100の位10の位1の位1×10×10=1003×10=305×1=5
このように, 1の位, 10の位, 100の位, ・・・
と数を表す方法を 10進数 といいます.
ですが, コンピューターはこの10進数を使うことができません.
(「電卓もスマホも普通に計算できるじゃん!」 って思った方へ
実は普通に計算できているように見えているだけで, 私たちには見えないところでコンピューターが頑張ってくれています.)
さっきの135という数字, コンピューターの中ではこうなっています.
1000011110000111 10000111
いっせん万ひゃくじゅういち...??? なにが起こったのか, わけが分かりません
私たちの使う 10進数では, 0 1 2 3 4 5 6 7 8 9 の数字と, ×10\times 10×10 (◯の位)で数を表しました.
一方, コンピューターの中では 2進数 を使って数を表します. この2進数では, 0 と 1 だけで数を表します. 仕組みを知れば簡単です. 一緒に2進数について知っていきましょう.
10進数では,このように数を数えました.
100の位1×10×10=10010の位3×10=301の位5×1=5\begin{aligned} 100\text{の位}\quad & 1 \times 10 \times 10 = 100 \\ 10\text{の位}\quad & 3 \times 10 = 30 \\ 1\text{の位}\quad & 5 \times 1 = 5 \end{aligned} 100の位10の位1の位1×10×10=1003×10=305×1=5
ここで, 100の位というのは 10×1010 \times 1010×10 の位です. 例えば, 9+19 + 19+1 では, 0 ~ 9 の数字だけで 答えを表すことができないので, 1×10+0×11 \times 10 + 0 \times 11×10+0×1 という形で10を表現します. 2進数も同じように数を表現します.
10000111 (135)を先ほどと同じように書き表すとこんな感じになります.
128の位1×2×2×2×2×2×2×2=12864の位0×2×2×2×2×2×2=032の位0×2×2×2×2×2=016の位0×2×2×2×2=08の位0×2×2×2=04の位1×2×2=42の位1×2=21の位1×1=1\begin{aligned} 128\text{の位}\quad & 1 \times 2 \times 2 \times 2\times 2\times 2\times 2 \times 2 = 128 \\ 64\text{の位}\quad & 0 \times 2 \times 2 \times 2 \times 2 \times 2 \times 2 = 0 \\ 32\text{の位}\quad & 0 \times 2 \times 2 \times 2 \times 2 \times 2 = 0 \\ 16\text{の位}\quad & 0 \times 2 \times 2 \times 2 \times 2= 0 \\ 8\text{の位}\quad & 0 \times 2 \times 2 \times 2 = 0 \\ 4\text{の位}\quad & 1 \times 2 \times 2 = 4 \\ 2\text{の位}\quad & 1 \times 2 = 2 \\ 1\text{の位}\quad & 1 \times 1 = 1 \end{aligned} 128の位64の位32の位16の位8の位4の位2の位1の位1×2×2×2×2×2×2×2=1280×2×2×2×2×2×2=00×2×2×2×2×2=00×2×2×2×2=00×2×2×2=01×2×2=41×2=21×1=1
2進数の練習
0=000008=0100016=1000024=110001=000019=0100117=1000125=110012=0001010=0101018=1001026=110103=0001111=0101119=1001127=110114=0010012=0110020=1010028=111005=0010113=0110121=1010129=111016=0011014=0111022=1011030=111107=0011115=0111123=1011131=11111\begin{aligned} 0 &= 00000 \quad 8 &= 01000 \quad 16 &= 10000 \quad 24 &= 11000\\ 1 &= 00001 \quad 9 &= 01001 \quad 17 &= 10001 \quad 25 &= 11001\\ 2 &= 00010 \quad 10 &= 01010 \quad 18 &= 10010 \quad 26 &= 11010\\ 3 &= 00011 \quad 11 &= 01011 \quad 19 &= 10011 \quad 27 &= 11011\\ 4 &= 00100 \quad 12 &= 01100 \quad 20 &= 10100 \quad 28 &= 11100\\ 5 &= 00101 \quad 13 &= 01101 \quad 21 &= 10101 \quad 29 &= 11101\\ 6 &= 00110 \quad 14 &= 01110 \quad 22 &= 10110 \quad 30 &= 11110\\ 7 &= 00111 \quad 15 &= 01111 \quad 23 &= 10111 \quad 31 &= 11111\\ \end{aligned} 01234567=000008=000019=0001010=0001111=0010012=0010113=0011014=0011115=0100016=0100117=0101018=0101119=0110020=0110121=0111022=0111123=1000024=1000125=1001026=1001127=1010028=1010129=1011030=1011131=11000=11001=11010=11011=11100=11101=11110=11111
2進数の数の数え方の雰囲気は分かりましたか?
普通10までしか数えられないのに...!?
実際に数えてみましょう
右手の手のひらを自分に向けて数えます. 1で指を立たせて, 0は閉じましょう.
大きい数はこうなります. 時間がある時に1ずつ足して確かめてみてください. (左手) 親指→人差し指→中指→薬指→小指→ (右手) 小→薬→中→人→親
1=00000∣0000132=00001∣000002=00000∣0001064=00010∣000004=00000∣00100128=00100∣000008=00000∣01000256=01000∣0000016=00000∣10000512=10000∣00000\begin{aligned} 1 &= 00000|00001 \quad 32 &= 00001|00000 \\ 2 &= 00000|00010 \quad 64 &= 00010|00000 \\ 4 &= 00000|00100 \quad 128 &= 00100|00000 \\ 8 &= 00000|01000 \quad 256 &= 01000|00000 \\ 16 &= 00000|10000 \quad 512 &= 10000|00000 \\ \end{aligned} 124816=00000∣0000132=00000∣0001064=00000∣00100128=00000∣01000256=00000∣10000512=00001∣00000=00010∣00000=00100∣00000=01000∣00000=10000∣00000
512+256+128+64+32+16+8+4+2+8+1=1023512+256+128+64+32+16+8+4+2+8+1= 1023 512+256+128+64+32+16+8+4+2+8+1=1023
↓↓ ↓
1023=11111∣111111023 = 11111|11111 1023=11111∣11111
普通の足し算の筆算と同じように計算できます.
まずは 1+11+11+1 から
101+0110\begin{array}{ccc} & \scriptsize{1} &\\ & 0 & 1 \\ + & 0 & 1 \\ \hline & 1 & 0 \end{array} +1001110
1+1=101+1=101+1=10 ですね! 2進数で10は2なので, 計算内容は正しいことが分かります. (10→2+0=210 → 2 + 0 = 210→2+0=2)
続いて 3+103 + 103+10
10011+10101101\begin{array}{ccccc} & & \scriptsize{1} &\\ & 0 & 0 & 1 & 1 \\ + & 1 & 0 & 1 & 0 \\ \hline & 1 & 1 & 0 & 1 \end{array} +0111001110101
11+1010=110111+1010 = 110111+1010=1101 2進数で1101は13なので正しいことが分かります. (1101→8+4+0+1=131101 → 8 + 4 + 0 + 1 = 131101→8+4+0+1=13)
22+14=?22+14 = ?22+14=?
10進数と2進数の対応表
22は10110, 14は1110でした. 10110+1110を計算します.
111110110+01110100100\begin{array}{ccccccc} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & & \\ & & 1 & 0 & 1 & 1 & 0 \\ + & & 0 & 1 & 1 & 1 & 0 \\ \hline & 1 & 0 & 0 & 1 & 0 & 0 \\ \end{array} +11110010101111110000
10110+1110=10010010110 + 1110 = 10010010110+1110=100100 100100→32+0+0+4+0+0=36100100 → 32 + 0 + 0 + 4 + 0 + 0 = 36100100→32+0+0+4+0+0=36 こちらの計算結果も正しいですね! これで2進数の計算方法はマスターできました!
コンピューターが2進数を使って数を表現していて, 2進数を使って計算することが 分かりました!ですが, なぜこんな面倒なことをするのでしょう???
今回の講座のゴールは大きな数の足し算を実現する, 計算機を作ることです. もう少し簡単に言うと, 足し算だけができる電卓(足し算電卓)を作ることです. 電卓を作るには全加算器という部品を作る必要があります. さらに, 全加算器を作るためには半加算器という部品を作る必要があります. これからみなさんには, 手順に従って全加算器を作ってもらいます! そして, みなさんが作った全加算器を組み合わせて, 足し算電卓を作ります.
ようやく電子回路の出番です. まずはお手元の部品を確認しましょう. 取り扱いにあたり怪我をする可能性が高いと講師が判断した部品は, あらかじめブレッドボードに挿された状態になっています. 抜き差しをしないようお願いします.
7セグメントLEDは, あらかじめブレッドボードに挿してあります.
ロジックICは, あらかじめブレッドボードに挿してあります.
画像で線が引かれている部分は電気の道(回路)が繋がっています.
試しに画像のように部品を刺してみましょう. LEDは, 足が長いほうが上, 短いほうが下です! 抵抗は青い方に繋がっています.
このとき, 電気の流れはこのようになっています. 電気の流れを追っていったとき, 乾電池の+からーに帰ってきています. 電気の道で円が作れていれば, 電気が流れます. だからLEDが光るんですね.
2進数でいう 1 ケタの足し算は
0+0=000+1=011+0=011+1=10\begin{aligned} 0 + 0 = 00 \quad \\ 0 + 1 = 01 \quad \\ 1 + 0 = 01 \quad \\ 1 + 1 = 10 \quad \end{aligned} 0+0=000+1=011+0=011+1=10
となります. コンピューターにこのような計算をさせる回路(計算機)を作ってみましょう.
計算結果の1ケタ目に注目します. 0+0または1+10+0または1+10+0または1+1 のときに0, 0+1または1+00+1または1+00+1または1+0 のときに1となっています. 計算結果の2ケタ目に注目します. 1+11+11+1 のときのみ1, それ以外は0となっています. 2つの入力に対して, このような出力が得られる回路を作ります.
このような計算をさせるには, 「論理演算」 をする必要があります.
具体的には 「AND」「XOR」というものを使います.
1ケタ目をXORが計算し, 繰り上がりのケタをANDが計算します.
何を言っているのかさっぱりだと思うので, 表と具体例を使って説明します.
エックスオアまたはエクスクルーシブオアと呼びます. 「排他的論理和」という論理演算を行います.
1+11 + 11+1 をしたときに1ケタ目は繰り上がりによって0になることと, 0+0=00+0=00+0=0 が表現できています. 実際に回路を作って確認してみましょう.
画像と同じようにブレッドボードに部品を挿してみてください.
拡大
スイッチを右にスライドさせると オン になります. どちらかのスイッチをオンにしたときはLEDが光って, 両方のスイッチをオンにしたときにはLEDが光らなければ正しくできています!
黒い四角はコンピューターの一種で, これを「ロジックIC」といいます. 先ほど電気や情報の世界では オンを 1, オフを 0 と表現すると説明しました. スイッチがオンであれば電気が流れます. これが 1 , スイッチがオフであれば電気は流れません. これが 0 ということです. そして, ロジックICに電気を流していれば入力が 1, ロジックICが電気を流していれば出力が 1 と表現します. 出力が 1のときはLEDに電気が流れてLEDが光るといった具合で回路は動作します.
ロジックICの中はこんな構造をしています.
14番(左上)は電源の+極を接続 7番(右下)は電源のー極を接続 今回は 1番に 入力2 2番に 入力1 3番に LED を接続しています
接続図で流れを追ってみます.
左オフ, 右オフの場合
左オン, 右オフの場合
左オフ, 右オンの場合
左オン, 右オンの場合
アンドと呼びます. 「論理積」という論理演算を行います.
1+11 + 11+1 をしたときのみ, 2ケタ目が繰り上がりによって 1 になることが表現できています. 実際に回路を作って確認してみましょう.
LEDと抵抗, 配線を追加します. 画像のように部品を挿してください.
両方のスイッチをオンにしたときだけ左のLEDが光れば正しくできています!
接続図でも確認してみましょう.
入出力関係を表にまとめるとこうなります. これを「真理値表」といいます. そして, 右にに2進数の1ケタの計算を示します.
おや? 左と右が一致していますね. どうやらこの回路で1+11+11+1までの計算ができるようです.
実は動作確認のついでに1+11+11+1までの足し算を行う回路を作ってもらっていました. 左のLEDが繰り上がりのケタ(2の位), 右のLEDが1の位の数を表しています. これで, 0+0=00,0+1=01,1+0=01,1+1=100 + 0 = 00 , 0 + 1 = 01 , 1 + 0 = 01 , 1 + 1 = 100+0=00,0+1=01,1+0=01,1+1=10 を計算させることができました. この状態だと計算ができているという感じがしないので, のちほど2進数を10進数に変換する回路を紹介します.
現在の回路をシンプルな接続図で表したものがこちらです.
無事 1+11 + 11+1 を計算する回路を作ることができました! この回路こそが先ほど紹介した「半加算器」です.
半加算器では 入力1 と 入力2 の足し算をするだけで計算をすることができました. しかし, 2ケタの計算をするときはどうでしょうか. 例えば, 3+33 + 33+3 (11+1111 + 1111+11) を計算してみます.
11011+011110\begin{array}{ccccc} & \scriptsize{1} & \scriptsize{1} &\\ & 0 & 1 & 1 \\ + & 0 & 1 & 1 \\ \hline & 1 & 1 & 0 \end{array} +10011111110
このとき, 計算結果の2ケタ目に注目しましょう. このケタの計算は, 1+11 + 11+1 ではなく, 1ケタ目の繰り上がりによって 1+1+11 + 1 + 11+1+1 を計算していますね? この計算をするのが全加算器です.
全加算器はこのように作ります. 先ほど作った半加算器とOR(次のスライドで解説)を組み合わせると作れます.
難しいので, 理解しなくて大丈夫です.
オアと呼びます. 「論理和」という論理演算を行います.
1+11 + 11+1ではまだ使いませんが, あとで使う論理演算もあるので, ついでに確認します.どちらか一方に 1 が入力されていれば 1 を出力する演算です. 実際に回路を作って確認してみましょう.
まずこの状態にしてからLEDに配線を繋げると良いです.
両方のスイッチがオフのときだけ左端のLEDが消えれば正しくできています!
続いて, 全加算器を作ります. 画像のように部品を刺しましょう. さっき作った半加算器は後で使うのでそのまま残しておきます.
見づらいので, 長い配線を抜いた状態を載せます. 茶色は長さが少し合っていないですが, I(アイ)の行に無理やり挿してください.
左上, 右上, 左下のスイッチを使います. 下右は使いません.
入力1(1ケタ目)がが右上, 入力2(2ケタ目)が左上, 入力3(桁上げ入力)が左下です.
左の画像は, いま手元にある回路の接続図です. 表のようにスイッチのオン・オフを切り替えて, 表と同じ出力の結果が得られるか確認しましょう.
XOR, AND, ORを使って, 半加算器と全加算器を作ることができました. 半加算器と全加算器を1個ずつ組み合わせると, 2ケタの足し算ができるようになります.
このように組み合わせます.
画像と同じ用に部品を刺しましょう. 今回は変わるところが少ないです.
23と24の銀を外し, 23と26をオレンジで繋ぎます. 長い黄色で下の17と上の43を繋ぎます.
入力2の2ケタ目が左上, 入力1の2ケタ目が左下, 入力2の1ケタ目が右上, 入力1の1ケタ目が右下です.
画像と同じ入力と出力の関係であることを確認しましょう.
2ケタ(11+11=11011 + 11 = 11011+11=110まで)の足し算ができる回路を作りました. 実は全加算器を作ることができたなら, あとは全加算器を増やすだけで 計算できるケタを大きくすることができます.
例えば,4ケタの足し算の回路を作ったときの図はこんな感じです.
1011+11111011+11111011+1111 を計算させると, このような流れで110101101011010 が出力されます.
ということで, 大きな数の計算をしてみましょう. 今日の講座には21人が参加しています. 全加算器が21個と, 半加算器1つを使えば22ケタ+22ケタまでの計算をさせることができます.
一人ひとりが持っている回路だけでは, 「コンピューターが計算してくれている!」という感じがしませんが,
みなさんの作った全加算器を全部つなげると
4194303+4194303=83886064194303 + 4194303 = 8388606 4194303+4194303=8388606
までの足し算をすることができます!
実際に繋いで, 本当に計算ができることを確かめてみましょう.
大きな数の計算結果を表示するための回路を作ってきました. これに各桁の計算結果を入力することで, 計算結果が正しいことを確かめます.
全加算器の回路に戻します. その後, 左下のスイッチを外してください.
出力2を他の人のブレッドボードの下7番に接続し, 出力1を表示用回路の入力に接続します.
ここでは計算例として, 3595117+1797558=53926753595117+1797558=53926753595117+1797558=5392675を計算させてみます. 2進数で計算するとこうなります.
111111111111111111111101101101101101101101+011011011011011011011010100100100100100100011\begin{array}{cccccccccccccccccccccccc} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & \scriptsize{1} & & & \\ & & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 \\ + & & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 & 1 & 1 & 0 \\ \hline & 1 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 & 1 & 1 \end{array} +111100111110101100111110101100111110101100111110101100111110101100111110101100110011101
現在, 計算結果をLEDを使って2進数で表しています. 4つ目のICと7セグメントLEDを使って, 10進数の数で表示できるようにします.
まずは, 11+11までを計算できる回路に繋げ直しましょう.
続いて, ICと7セグメントLEDに抵抗と配線を追加します. まずはLEDと抵抗, 長い線を取り外してください.
抵抗を50から59に
抵抗を51から62に
抵抗を52から63に
抵抗を57から60に
赤色を上の53から下の56に
赤色を上の54から下の57に
赤色を上の55から下の58に
抵抗を56から62に
抵抗を58から59に
配線は画像の通り(他に7本あります)
17から54に, 19から48に, 36から49に接続します. 電源を接続し, 0から6が表示されることを確認してみてください.
接続図はこのようになっています.
実は, 大学では一度もこのブレッドボードを触ったことはありません. 実物を使って回路を作る代わりに, 「VHDL」というハードウェア記述言語で回路を設計し, 「FPGA」というものに書き込んで, 設計した回路の動作を確認します.
これが大学の実験で使っているFPGAボードです. 大学や仕事での研究や設計では, 実際に回路を作っていると, 時間がかかる, 一人でしか作業ができない等で大変なので, FPGA(回路の構造をプログラムできるデバイス)を用います. [出典: AMD - Digilent Nexys A7]
みなさんがよく耳にする, プログラミング言語とは異なります. すごく簡単に言うと, 設計したい回路に対して 「入力に対してどのような出力をするのか」 を, プログラミングのように書きます.
講座の最初に作った半加算器をそのままVHDLで書くとこんな感じです. 解説はしないですが, 「こんな感じのことやってるんだなぁ」と思ってください.
library IEEE; use IEEE.std_logic_1164.ALL; use IEEE.numeric_std_unsigned.ALL; entity half_adder is port ( A : in std_ulogic; B : in std_ulogic; S : out std_ulogic; C : out std_ulogic; ); end half_adder; architecture RTL of half_adder is S <= A xor B; C <= A and B; end RTL;
これで講座は以上になります. お疲れ様でした! いかがだったでしょうか. 最初にお話した通り, 理解するには難しい内容だったと思いますが, ブレッドボードでの回路作成を通して, 電子や情報の楽しさやおもしろさを感じてもらえたなら嬉しく思います. 今回の講座を通して電子工作に興味を持ってもらえた場合, ネットで調べると電子工作に関する色んなサイトが出てきますので, ぜひ参考にしてください. 色んな回路を作るには, 今回使ったLEDやロジックIC以外の部品が必要になりますが, そのほとんどはこのお店に売っていますよというのを紹介しておきます. (今回の部品もここで注文しています.) →秋月電子通商
データシート(特性表)より, ICの出力する電圧 VCC=4.5VV_{CC}=4.5VVCC=4.5V, LEDの電圧降下VF=2.1VV_F=2.1VVF=2.1V, LEDの定格電流IF=0.02AI_F=0.02AIF=0.02Aであるので, オームの法則より,
R=V/I=(4.5−2.1)/0.02=120ΩR = V/I = (4.5-2.1)/0.02 = 120Ω R=V/I=(4.5−2.1)/0.02=120Ω
7セグメントLEDの電圧降下VF=1.8VV_F=1.8VVF=1.8V, 定格電流IF=0.02AI_F=0.02AIF=0.02A 同じ120Ω抵抗を使った場合
I=V/R=(4.5−1.8)/120=0.0225AI = V/R = (4.5-1.8)/120 = 0.0225A I=V/R=(4.5−1.8)/120=0.0225A
定格より少し大きいが, 問題無い程度.
constexpr uint8_t PIN_A = 6; constexpr uint8_t PIN_D = 7; constexpr uint8_t PIN_C = 8; constexpr uint8_t PIN_B = 9; constexpr uint8_t PIN_DATA = 10; constexpr uint8_t PIN_SL = 11; constexpr uint8_t PIN_CLK = 12; constexpr uint8_t PIN_8TH_DIGIT = 14; constexpr uint8_t PIN_7TH_DIGIT = 15; constexpr uint8_t PIN_6TH_DIGIT = 16; constexpr uint8_t PIN_5TH_DIGIT = 17; constexpr uint8_t PIN_4TH_DIGIT = 18; constexpr uint8_t PIN_3RD_DIGIT = 19; constexpr uint8_t PIN_2ND_DIGIT = 20; constexpr uint8_t PIN_1ST_DIGIT = 21; constexpr uint8_t digit_pins[8] = { PIN_1ST_DIGIT, PIN_2ND_DIGIT, PIN_3RD_DIGIT, PIN_4TH_DIGIT, PIN_5TH_DIGIT, PIN_6TH_DIGIT, PIN_7TH_DIGIT, PIN_8TH_DIGIT }; constexpr uint8_t length = 24; // 入力ビット数 constexpr uint8_t segments_length = 8; // 7セグの表示桁数 struct segments { uint8_t segment[8]; // 配列の長さはsegments_length と同値 };
void setup() { pinMode(PIN_A, OUTPUT); pinMode(PIN_D, OUTPUT); pinMode(PIN_C, OUTPUT); pinMode(PIN_B, OUTPUT); pinMode(PIN_DATA, INPUT); pinMode(PIN_SL, OUTPUT); pinMode(PIN_CLK, OUTPUT); pinMode(PIN_8TH_DIGIT, OUTPUT); pinMode(PIN_7TH_DIGIT, OUTPUT); pinMode(PIN_6TH_DIGIT, OUTPUT); pinMode(PIN_5TH_DIGIT, OUTPUT); pinMode(PIN_4TH_DIGIT, OUTPUT); pinMode(PIN_3RD_DIGIT, OUTPUT); pinMode(PIN_2ND_DIGIT, OUTPUT); pinMode(PIN_1ST_DIGIT, OUTPUT); digitalWrite(PIN_SL, HIGH); } // クロック立ち上げ void clk_rising() { digitalWrite(PIN_CLK, HIGH); delayMicroseconds(1); digitalWrite(PIN_CLK, LOW); }
uint32_t read_data() { uint32_t val = 0; digitalWrite(PIN_SL, LOW); delayMicroseconds(1); digitalWrite(PIN_SL, HIGH); for (uint8_t i = 0; i < length; i++) { val <<= 1; // 1bit左シフト val = val | digitalRead(PIN_DATA); // 現在の入力をLSBに代入 clk_rising(); } return val; } uint8_t digits10(uint32_t val) { if (val == 0) { return 1; } uint8_t cnt = 0; while (val > 0)
{ val /= 10; cnt++; } if (cnt > segments_length) { cnt = segments_length; } return cnt; } segments pullout_digit(uint32_t val, uint8_t digits_length) { segments result = {}; uint8_t least_digit; for (uint8_t i = 0; i < digits_length; i++) { // 1桁目を抜き出す least_digit = val % 10; result.segment[i] = least_digit; val = val / 10; // 位を下げる } return result; }
void display(const segments &digits, uint8_t digits_length) { uint8_t number; uint8_t illuminate_digits; for (uint8_t i = 0; i < digits_length; i++) { number = digits.segment[i]; digitalWrite(PIN_A, (number & 0b0001) ? HIGH : LOW); digitalWrite(PIN_B, (number & 0b0010) ? HIGH : LOW); digitalWrite(PIN_C, (number & 0b0100) ? HIGH : LOW); digitalWrite(PIN_D, (number & 0b1000) ? HIGH : LOW); illuminate_digits = digit_pins[i]; digitalWrite(illuminate_digits, HIGH); delayMicroseconds(100); digitalWrite(illuminate_digits, LOW); digitalWrite(PIN_A, LOW); digitalWrite(PIN_B, LOW); digitalWrite(PIN_C, LOW); digitalWrite(PIN_D, LOW); digitalWrite(illuminate_digits, LOW); } for (uint8_t i = digits_length; i < segments_length; i++) { delayMicroseconds(100); } }
void loop() { uint32_t input_bits = 0; segments output_digits; uint8_t digits_length; input_bits = read_data(); digits_length = digits10(input_bits); output_digits = pullout_digit(input_bits, digits_length); display(output_digits, digits_length); }
GitHubリンク (コードはここに置かれています.)