最近データ通信におけるクロックの役割について記事を読んで、「ああ、そういうことか」と理解したので、自分でもクロックを使ったデータ表現をやってみた。
一般的にクロックというと時計をイメージすると思うが、どちらかといえばメトロノームとか手拍子をイメージすると分かりやすい。
たとえば人間にとって「あーー」と「あーーー」と「あーーーーー」はどれも意味的には「あー」である。
私は何回「あ」と言ったでしょう?って聞かれても他人には答えられない。
「あーあーあー」といったのか「あああああ」と言ったのか、それは本人がイメージするリズム次第で変わってしまう。
さて、このことがコンピューターでは大いに問題になってくる。
なんせ電気信号のONとOFFでしか情報を表現できないので、オンオンオンオンオフオフオフオフと言ったのか、オーーーンオーーーフと言ったのかでは全然データの意味が違ってくる。
そこで使われるのが一定周期でON/OFFを繰り返すクロック。
クロックが1回「オン/オフ」する間を1ビットと解釈することで、正確にデータを読み解くことができる。
見た目:オーーーーンオフオーーンオーーフ
クロック:オンオフオンオフオンオフオンオフ
データ:オンオンオンオフオンオンオフオフ
実際にArduinoを使って、ASCIIコードでHelloと表示してみたのがこちら。
緑LEDがクロックで、赤LEDがデータである。
クロックに合わせて赤LEDを読み取ってメモすれば、一応人間でもデータを読み取ることができる。
(参考)ASCIIコード
www.ascii-code.com
コードは次のとおり。
const int CLOCK = 3; const int DATA = 4; void setup() { // put your setup code here, to run once: pinMode(CLOCK, OUTPUT); pinMode(DATA, OUTPUT); } void say(char x) { for(int i=7;i>=0;i--){ digitalWrite(DATA,x >> i & 1); digitalWrite(CLOCK,HIGH); delay(200); digitalWrite(CLOCK,LOW); delay(200); } } void loop() { // put your main code here, to run repeatedly: digitalWrite(CLOCK,LOW); digitalWrite(DATA,LOW); delay(5000); const char message[] = "Hello"; for(int i =0; i < strlen(message); i++ ) { digitalWrite(CLOCK,LOW); digitalWrite(DATA,LOW); delay(1000); say(message[i]); } }
メインループではmessageという文字型配列にセットしたHelloをfor文で一文字ずつ取り出してsay関数にパスしている。
say関数ではShift演算とANDマスクを使って1文字=8ビットから1ビットずつ取り出したものをデータLEDの出力としている。
シフトというのはずらすという意味で、たとえば01001000(文字H)を1ビット右シフトすると00100100となる。
左側の欠落した部分は0で埋められ、はみ出た部分は捨てられる。
これに00000001(数字の1の8ビット表現)をAND演算すると、各桁でAND演算が実施されるので右端以外は必然的に0、右端の1ビットは元データが1なら1、0なら0となる。こうやって右端のビットだけを取り出すことができる。
Arduinoでは1はHIGH(≒5V)、0がLOW(≒0V)となる為、データに応じてLEDが明滅する。
今回はsay関数のdelayを200としたけれど、分かりやすく500にすると、クロックのONが0.5秒、クロックのOFFが0.5秒、計1秒の間にデータを1ビット表現できる。1秒間に1クロックなので、1ヘルツである。
最近のCPUのクロック数は大体4ギガヘルツ前後なので、1秒間に4,000,000,000回ほどON/OFFを繰り返すことができるということかな。すげーなおい。
以上