見出し画像

【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通信は簡単~


最初に:この記事にあるラズベリーパイのプログラムには、
 ☆GASのデプロイID☆
と書かれた部分があります。

ここには、次の記事でご紹介するGASのプログラムのデプロイIDを記入してください。
https://note.com/prog_article5/n/n0452f2e6a6b5



つまり、このプログラムは、次の記事でご紹介するGASで作ったアプリをデプロイして初めて完成になります。

回路ができたら、タクトスイッチを押した場合のラズベリーパイ側のプログラム(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.51.5の場合は 2 と判断
  直前の判断と不一致(押し続け)なら無視
  URLに「?x=2」を追加してアクセス実施

elif 1.5 <= v and 2.5 > v:スイッチ3が押されたはず(約2V)
  Vの値が1.52.5の場合は 3 と判断
  直前の判断と不一致(押し続け)なら無視
  URLに「?x=3」を追加してアクセス実施

else:
  それ以外なら押されていないと判断して何もしない

以上で、ラズベリーパイ側の処理は終了です。

上記でアクセスしたURLにはGASのプログラムがデプロイされており、このプログラムを介して、Googleスプレッドシートに値が書き込まれます。


長くなってしまったので、ここで記事を切ります。

次回は、GAS側でのプログラムをご説明する予定です。




いいなと思ったら応援しよう!