【GASでIoT】自由にボタンを割り付ける(その3)~ボタンのワンプッシュでデータをWEB上に送り込む~
下記にある前の記事では、ラズベリーパイとADコンバータとの間で通信する方法をご紹介しました、今回の記事では、リアルなボタンが3つある「かんたんキーボード」を用意して、このボタンを押す事で、Googleスプレッドシートに入力する方法をご紹介します。
なお、以下のサイトを参考にさせて頂きました。ここに感謝しつつご紹介します。
ボタンを3つ並べた「かんたんキーボード」を作る
抵抗を直列につなぎ、タクトスイッチを3つならべた分圧抵抗器をつくり、電圧の読み出しのADコンバータを1つ配置すれば、とても簡単なキーボードになります。
称して「かんたんキーボード」。
このキーボードは、3つのボタンを押下すると、ボタンに割り当てられた数(1、2、3)をGoogleスプレッドシートに直接記入する、という機能を持っています。
つまりボタン一発でGoogleスプレッドシートに記録できるというデバイスです!
「かんたんキーボード」の回路を作る
回路の配線は下図を参考にしてください。
配線で気をつけるのは、タクトスイッチ(タクタイルスイッチ)の向きです。
タクトスイッチは、以下の様に足が出ている面(向き合うピンは互いに導通しています)が上下を向く様にします。この向きでであれば、隣り合う経路(破線)同士は通常は分離し、スイッチの押下時のみ導通する様になります。
もし横向けにしてしまうと、(足が内部で導通しているため)スイッチの状態によらず、常に破線部の経路は導通(ショート)している状態になり、スイッチとして機能しなくなります。
使用する部品は以下になります。
抵抗:5、10、15kΩ 各1ケ。近い値であれば多少ずれていても問題ありません。また、15kΩを10kΩ+5kΩに直列につなぎにして代用するなど、足して近い値になる複数の抵抗の直列つなぎで代用してもかまいません・
タクトスイッチ:3ケ
ADコンバータ:MCP3204 1ケ
配線部品とラズベリーパイ
回路図としては以下の様になります。
スイッチを押した場合の計算上の電圧は以下の様になります。
スイッチ1を閉じる 電圧=0V
スイッチ2を閉じる 電圧=約1V
スイッチ3を閉じる 電圧=約2V
以上で、回路の用意ができました。続いて、ラズベリーパイ側のプログラムを書きます。
ラズベリーパイ側のプログラム ~関数xfer2()を使えば、SPI通信は簡単~
回路ができたら、タクトスイッチを押した場合のラズベリーパイ側のプログラム(python)に以下のプログラムを書きましょう。
#必要なモジュールをインポート
import spidev #SPI通信用のモジュールをインポート
import time #時間制御用のモジュールをインポート
import sys #sysモジュールをインポート
#---WEBにリクエストを投じるためのモジュール
import requests
#電源電圧
Vref = 3.3
#SPI通信を行うための準備
spi = spidev.SpiDev() #インスタンスを生成
spi.open(0, 0) #CE0を指定, #port 0,cs 0
spi.max_speed_hz = 1000000 #転送速度 1MHz
#押下スイッチを区分するフラグ
flag="x"
#連続押下を防ぐフラグ
flag2="x"
#連続して値を読み込む
while True:
try:
adc = spi.xfer2([0x06,0x00,0x00])
data = ((adc[1] & 0x0f) << 8) | adc[2]
v= Vref*data/4096
if 0.5>v:
flag="1"
if flag != flag2:
print('1')
#---URLにアクセス
r = requests.get("https://script.google.com/macros/s/☆GASのデプロイID☆/exec?x=" + flag)
elif 0.5<=v and v<1.5:
flag="2"
if flag != flag2:
print('2')
#---URLにアクセス
r = requests.get("https://script.google.com/macros/s/☆GASのデプロイID☆/exec?x=" + flag)
elif 1.5 <= v and 2.5 > v:
flag="3"
if flag != flag2:
print('3')
#---URLにアクセス
r = requests.get("https://script.google.com/macros/s/☆GASのデプロイID☆/exec?x=" + flag)
else:
flag="x"
flag2=flag
time.sleep(0.2) #0.5秒間待つ
except KeyboardInterrupt:
#Ctrl+Cキーが押された
spi.close() #SPI通信を終了
sys.exit() #プログラム終了
プログラムの内容説明をします。
import spidev
冒頭にある上記のコードによって、SPI通信に関するモジュールが使用できる様になります。
spi.open(0, 0) #CE0を指定, #port 0,cs 0
最初の引数:対象デバイスを読み出すピン(CE0ピンなら1を指定)
次の引数:単独のデバイスなら0を指定
adc = spi.xfer2([0x06,0x00,0x00])
一番肝心な部分です。SPIのデータ通信は、xfer2()関数を使えば1行で送信・受信ともに処理できます。
まず、xfer2()にある3つある引数についてです。
これらは、MOSI(マスターアウト・スレーブイン)ピンからデバイスに向けて送り出される信号を意味します。(0x~とあるのは信号の並びを16進数で表した意味です)
最初の信号「0x06」は、ビットになおすと、「0000 0110」ですが、これは以下を表しています。
ADコンバータでCH0(チャンネル0)を使っている場合の具体的な信号は、以下を参照して、DIFFが「1」、D2が「0」を当てはめています。(xは何でもいいのですが、意味の無い信号はすべて0とした方が解りやすいです)
次の信号「0x00」は、ビットになおすと、「0000 0000」ですが、これは以下を表しています。
ADコンバータでCH0(チャンネル0)を使っている場合の具体的な信号は、上記の表を参照して、D1、D0ともに「0」を割り当てます。
あとは全て0の信号となります。
ここで再掲します。
adc = spi.xfer2([0x06,0x00,0x00])
xfer2()関数からの返り値は 変数abc(ADコンバータの意味です)で受けていますが、この返り値は、デバイスからMISO(マスターイン・スレーブアウト)ピンを介してデバイスから返される信号を意味します。
この返り値は、続く以下のコードで有意の部分を抽出しています。
data = ((adc[1] & 0x0f) << 8) | adc[2]
まず、コードには書いてないのですが、最初の8ビット abc[0] は意味の無いデータなので使用していません。
次の8ビット abc[1]は、以下の信号となっています。
この信号に0000 1111 (16進数では 0x0f)を掛ける(&記号)と以下のビットを得ます。
0、0、0、0、B11、B10、B9、B8
続いて8ビットシフト(<<8記号で、つまり8桁左移動)させて、以下のビットを得ます。(新しく4桁増えますが、ここは0で埋まります)
B11、B10、B9、B8、0、0、0、0 、0、0、0、0
最後に、この結果に、3番目の8ビット信号 abc[2] を足し合わせ(|記号)ます。なお、abc[2]は、以下のデータを含んでいます。
結果は、以下のビットとなります。
B11、B10、B9、B8、B7、B6、B5、B4、B3、B2、B1、B0
v= Vref*data/4096
続く上記のコードで、実際の電圧値に変換しています。(dataに入ったつまり2進数が、何気に10進数として扱えている事に驚きます)
これは、data値x1ポイント当たりの電圧値(基準電圧÷12ビット)という意味です。
この後、得られた電圧値に応じて、「URL」に「?X=〇(〇はスイッチの番号)」を加えてWEBにアクセスしています。
if 0.5>v: スイッチ1が押されたはず(約0V)
Vの値が0.5に満たない場合は 1 と判断
直前の判断と不一致(押し続け)なら無視
URLに「?x=1」を追加してアクセス実施
elif 0.5<=v and v<1.5: スイッチ2が押されたはず(約1V)
Vの値が0.5~1.5の場合は 2 と判断
直前の判断と不一致(押し続け)なら無視
URLに「?x=2」を追加してアクセス実施
elif 1.5 <= v and 2.5 > v:スイッチ3が押されたはず(約2V)
Vの値が1.5~2.5の場合は 3 と判断
直前の判断と不一致(押し続け)なら無視
URLに「?x=3」を追加してアクセス実施
else:
それ以外なら押されていないと判断して何もしない
以上で、ラズベリーパイ側の処理は終了です。
上記でアクセスしたURLにはGASのプログラムがデプロイされており、このプログラムを介して、Googleスプレッドシートに値が書き込まれます。
長くなってしまったので、ここで記事を切ります。
次回は、GAS側でのプログラムをご説明する予定です。