ちょっと電卓をやろうと思って

投稿日:

 Raspberry PiにAD変換ICをつないで遊んでいたわけであるが、ふと「3.3Vを12ビットでAD変換すると、結局1ティック何Vかいな」なぞと計算したくもなる。

 たまたまUNIXのコマンドラインにいたら、普通、


# echo 'scale=20;3.3/4096' | bc

……とかやると思うんだけど、ところが、Ruspberry Piには、「bc」がデフォルトでは入ってないのである。

 うーむ。bc入れとかなアカンがな、アンタ。世の中のUNIX爺ィがみんな怒りまっせ。

 と、いうわけで、


toshio@satoraspi:/var/www$ sudo apt-get install bc
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが新たにインストールされます:
  bc
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。
106 kB のアーカイブを取得する必要があります。
この操作後に追加で 257 kB のディスク容量が消費されます。
取得:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main bc armhf 1.06.95-2 [106 kB]
106 kB を 1秒 で取得しました (78.0 kB/s)
以前に未選択のパッケージ bc を選択しています。
(データベースを読み込んでいます ... 現在 79298 個のファイルとディレクトリがインストールされています。)
(.../bc_1.06.95-2_armhf.deb から) bc を展開しています...
menu のトリガを処理しています ...
install-info のトリガを処理しています ...
man-db のトリガを処理しています ...
bc (1.06.95-2) を設定しています ...
menu のトリガを処理しています ...
toshio@satoraspi:/var/www$

……とかやるんでしょうね。

 で、まことに平和な、オッサンがやりたい計算が可能になる。


toshio@satoraspi:/var/www$ echo 'scale=20;3.3/4096' | bc
.00080566406250000000
toshio@satoraspi:/var/www$

 1ティック0.81mVと思えば、まあ、間違いのないところであるようだ。

Raspberry Piで温度を測ろう

投稿日:

 以前、Arduinoのアナログ入力にサーミスタをつなぎ、温度計にして遊んだ最近はLCDディスプレイに温度を表示してみたり、なかなか面白い。

 一方、Raspberry PiはWebによくなじむ。ApacheもPHPも走る。

IMG_3317 それで、先週宮城大学小島研究室のサイトで公開しておられるADCアクセスのためのソースコードを拝借して遊んだが、これを使ってWeb温度計にしてみた。

 まず、ブレッドボードにAD変換ICのMCP3208と、サーミスタ、分圧用の抵抗1kΩを置き、適切に配線する。これには、以前Arduinoで遊ぶために買った「Seeedstudio Arduino Sidekick Basic Kit」に入っていたMF11-503Kというサーミスタをそのまま使う。

 それから、C++でこんなプログラムを書く。先週も書いたが、宮城大学小島研究室のサイトで公開しておられるコードは、Raspberry Pi 1では何の支障もなく動くが、Raspberry Pi 2 Model Bではそのままでは動かない。一部の型キャストなどを変更する必要がある。それについては先週のエントリで記してある。

//
//    tempMesure.cpp
//      佐藤俊夫
//      Sun Sep  6 13:57:53 JST 2015
//      サーミスタMF11-503Kと1kΩ抵抗を直列につなぎ、3.3Vを印加して、
//      その間から分圧をとって温度を測る。
//      宮城大学小島研究室でウェブ公開しておられるソースコードを拝借した。
//      コンパイル
//        cc -lm tempMesure.cpp raspSPI.o raspADC.o -o tempMesure
//
#include <stdio.h>
#include <math.h>
#include "raspADC.h"

#define ADC_CHIP  ADC_3208
float tempMesure(int srcVal);

int main() {
  ADC adc;

  adc.init("/dev/spidev0.1", ADC_CHIP);
  printf("%2.2f\n", tempMesure(adc.get(0)));
}

float tempMesure(int srcVal){
  const float B = 4350.0, Ta = 25.0, Rt0 = 50000.0;  //  MF11-503Kスペックシート記載
  const float K = 273.15;  //  熱力学温度の定数
  const float v0 = 3.3, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 4096;  //  アナログ入力の分解能
  float vt = 0.0, rt = 0.0;

  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;
  return(1.0 / (log(rt / Rt0) / B + 1.0 / (Ta + K)) - K);
}

 これは単に、サーミスタで計った現在の温度を標準出力に書くだけだ。

 これを「popen();」で開けば、PHPで読める。簡単である。

<html>
 <head>
  <meta name="Editor" content="vim">
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  <link rel="icon" href="favicon.ico" type="image/x-icon" />
  <link rel="Shortcut Icon" type="image/x-icon" href="favicon.ico" />
  <title>PHPで温度計</title>
  <meta http-equiv="Keyword" content="佐藤俊夫, 佐藤, 俊夫, SATOTOSHIO, SatoToshio, sato, toshio, Raspberry Pi, Raspberry Pi 2 Model B">
 </head>
 <body bgcolor="#888888">
<body>
  <center>
  <h1><img src="raspberry_pi.png" width="50px" align="middle"/>Raspberry Pi + PHPで温度計</h1>
  <hr>
  </center>
<?
ini_set( 'display_errors', 1 );
$process = popen("sudo /home/toshio/SPI_ADC/tempMesure", "r");
$temp = fgets($process);
?>
<center>
<table border=1 width="120px">
<tr> <th>0</th><th>10</th> <th>20</th> <th>30</th> <th>40</th> <th>50</th> <th>60</th></tr>
<tr><td colspan = 7>
<table>
<tr>
<td bgcolor="red" width="<?print $temp * 2?>px"><?print $temp?>℃</td&t;</tr></table>
</tr>
</table>
</td></tr></tr></table>
</center>
</body>
</html>

raspberry_tempMesure
 テーブルの幅を温度計のアルコール柱に見立てて、赤い帯で表すようにしてみた。


 Arduinoでも同じようなことはできるが、Arduinoで難しいのは、こういうふうに、無駄に画像を配置したり、少し分量の多いHTMLを書いたりすることだ。だが、こんなことはRaspberry Piには造作もなくできてしまう。

 反面、Arduinoはアナログ入力が直接可能だが、Raspberry Piで同じことをしようとすると、アナログ入力にAD変換ICを準備し、これとの通信にもいろいろと研究の上で取り組む必要がある。簡単で刺激的な目的のために少しプロトタイピングをしてみようと考えている多くのクリエイターがなしうるところではない。

 入門書籍「Raspberry Piをはじめよう」にもそうしたことが少し書かれてある。

Raspberry Pi 2 Model B に WiFi、AD変換ICでアナログ入力

投稿日:
とりあえず無線LANにする

 Raspberry Pi、線がダラダラつながっているのは面倒くさいから、メインのifをWiFiにしてみたい。たまたま、Raspberry Piと相性がいいと言われるUSBのWiFiアダプタ「PLANEX GW-USNano2」というのをかなり前から持っている。

 USBポートにとりあえずこれを挿入し、

# lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 2019:ab2a PLANEX GW-USNano2 802.11n Wireless Adapter [Realtek RTL8188CUS]

……もう、サクッとプラグアンドプレイの一発認識である。

# ifconfig
eth0      Link encap:イーサネット  ハードウェアアドレス b8:27:eb:45:1d:d0
          inetアドレス:192.168.1.105 ブロードキャスト:192.168.1.255  マスク:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:498 エラー:0 損失:1 オーバラン:0 フレーム:0
          TXパケット:253 エラー:0 損失:0 オーバラン:0 キャリア:0
      衝突(Collisions):0 TXキュー長:1000
          RXバイト:46665 (45.5 KiB)  TXバイト:34011 (33.2 KiB)

lo        Link encap:ローカルループバック
          inetアドレス:127.0.0.1 マスク:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:8 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:8 エラー:0 損失:0 オーバラン:0 キャリア:0
      衝突(Collisions):0 TXキュー長:0
          RXバイト:1104 (1.0 KiB)  TXバイト:1104 (1.0 KiB)

wlan0     Link encap:イーサネット  ハードウェアアドレス 00:22:cf:97:fe:b9
          inetアドレス:192.168.1.107 ブロードキャスト:192.168.1.255  マスク:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:506 エラー:0 損失:169 オーバラン:0 フレーム:0
          TXパケット:25 エラー:0 損失:0 オーバラン:0 キャリア:0
      衝突(Collisions):0 TXキュー長:1000
          RXバイト:128714 (125.6 KiB)  TXバイト:4541 (4.4 KiB)

 これも、もう、イッパツ。

 で、# shutdown -i0 -g0 -y、LANケーブル抜いて電源を入れなおす。

 サクッとつながる。ケーブルがだらだらつながっていたのが減って、これはとてもいいなあ。

USBのWiFiアダプタが快調に作動している様子
IMG_3308

アナログ入力をしてみる

 さて、今度はいろいろといじってみよう。

 Raspberry PiとArduinoにはいろいろと違いがある。その違い認識は世間ではもうとうの昔に確定済みであるようだが、私はその無視できない一つが「アナログ入力のあるなしではないだろうか?」と思い至っている。

 Arduinoはシンプルで扱いやすいにもかかわらず、10ビットのアナログ入力が6個もあり、これは意外と使い応えがある。抵抗やポテンショメータ、サーミスタ、CDSセル、音声など、実にいろいろなものをつなぐことができるのだ。

 だが、Raspberry Piにはアナログ入力は、ない。

 アナログ入力をしたければ、手段の一つに「Arduinoをつなぐ」というのがある。Arduinoを持っているなら、これは良い手段だが、なんだか無駄が大きい。

 もう一つが、「A/D変換器をつなぐ」ということだ。A/D変換IC、つまり「ADC」は、百何十円~数百円だから安い。合理的である。

 これについて解説しておられるサイトはたくさんある。それを参考にさせていただき、早速秋葉原へ行って2種類ばかりICを買い込む。

 これは、マイクロチップ・テクノロジー社製の「MCP3008-I/P」。8チャンネル10ビット、千石電商で320円。

MCP3008-I/P
IMG_3309

 コッチは、同じくマイクロチップ・テクノロジー社の「MCP3208-CI/P」。こちらも8チャンネルだが、幅は12ビット。秋月電子でソケット付き、データシート付きで320円。

MCP3208-CI/P
IMG_3310

 ついでにこの前壊したTLC5940NTも二つ買い込む。これも390円。

TLC5940NT
IMG_3311

 で、まずはMCP3208から試してみよう。

 Raspberry PiとICは、SPI通信でつなぐ。そのため、まず、Raspberry PiでSPI通信を行う要領を知る必要がある。

 Raspberry Piの場合は、SPIのモジュールをインストールしたり、ブラックリストから外すなどの着意が必要であったようだが、Raspberry Pi 2 の場合は、どうやらそのような操作は必要がなく、「# raspi-config」でAdvancedの中からSPIを選び、enableにすればよい。

 lsmodで確認し、次のように「spi_bcm2835」というモジュールが入っていればSPIが使える。

$ lsmod
Module                  Size  Used by
cfg80211              420690  0
rfkill                 16659  1 cfg80211
snd_bcm2835            19769  0
snd_pcm                74825  1 snd_bcm2835
snd_seq                53561  0
snd_seq_device          3650  1 snd_seq
snd_timer              18157  2 snd_pcm,snd_seq
snd                    52116  5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
8192cu                528485  0
spi_bcm2835             7100  0
i2c_bcm2708             5014  0
uio_pdrv_genirq         2966  0
uio                     8235  1 uio_pdrv_genirq

 さっそくブレッドボードにMCP3208を配置し宮城大学のサイトの記事にあるコードを使わせてもらったのだが、これがそのままでは動かず、ハマッた、ハマッた……。

ブレッドボードの状況
IMG_3312

 何か、Raspberry PiとRaspberry Pi 2 で、ioctrlに渡すデータ長に違いでもあるらしく、かなり試行錯誤した末、このようになった。

 宮城大学のサイトにあった元のコード(“raspSPI.cpp”内)

//  sendRecN: Nバイトデータの送信と受信(2048バイトまで)
void SPI::sendRecN (unsigned char *send, unsigned char *rec, int n)
{
    //  setup a block
    struct spi_ioc_transfer tr[1];
    tr[0].tx_buf = (unsigned int) send;
    tr[0].rx_buf = (unsigned int) rec;
    tr[0].len    = n;
    tr[0].speed_hz      = clock;
    tr[0].delay_usecs   = SPI_DELAY;
    tr[0].bits_per_word = SPI_BITS;
    tr[0].cs_change     = 0;
    //  send this byte
    int ret = ioctl(fd, SPI_IOC_MESSAGE(1), tr);
    if (ret < 0) {
        printf("error: cannot send spi message (SPI::sendRecN)\n");
        exit(-1);
    }
}

 Raspberry Pi model Bで動くように少し変更したコード(tr[]の個数と、tr[0]に渡す値のキャストを「int」から「unsigned long」に変更している)

//  sendRecN: Nバイトデータの送信と受信(2048バイトまで)
void SPI::sendRecN (unsigned char *send, unsigned char *rec, int n)
{
    //  setup a block
    struct spi_ioc_transfer tr[3];
    tr[0].tx_buf = (unsigned long) send;
    tr[0].rx_buf = (unsigned long) rec;
    tr[0].len    = n;
    tr[0].speed_hz      = clock;
    tr[0].delay_usecs   = SPI_DELAY;
    tr[0].bits_per_word = SPI_BITS;
    tr[0].cs_change     = 0;
    //  send this byte
    int ret = ioctl(fd, SPI_IOC_MESSAGE(1), tr);
    if (ret < 0) {
        printf("error: cannot send spi message (SPI::sendRecN)\n");
        exit(-1);
    }
}

(作動させた画面の様子)

  1132   867   827   829   833   838   877  2670
  1090   829   787   787   792   797   845  2668
  1028   768   725   721   724   732   796  2671
   929   678   631   623   625   636   737  2669
   791   534   471   444   429   435   572  2667
   408   172    94    54    29    53   281  2668
    84     0     0     0     0     0   111  2666
     0     0     0     0     0     0    20  2671
     0     0     0     0     0     0     0  2670
     0     0     0     0     0     0     0  2668
    19    29    34    39    41    36    27  2670
    87    93   101   110   114   107    81  2670
   173   173   183   195   201   186   146  2671
   274   276   300   327   347   339   276  2667
   614   609   650   692   727   698   552  2668
   948   901   907   902   911   916   741  2672
  1102   916   878   886   894   899   854  2670
  1160   888   865   868   873   878   913  2671
  1137   872   832   833   838   843   903  2665
  1093   830   788   787   792   796   869  2668
  1027   767   723   717   721   727   815  2669
   938   685   638   631   632   643   748  2669
   821   566   504   482   467   474   603  2665
   447   206   128    89    62    85   303  2669
   107     0     0     0     0     0   123  2670
     0     0     0     0     0     0    32  2669
     0     0     0     0     0     0     0  2667
     0     0     0     0     0     0     0  2670
    14    23    29    34    37    32    29  2669
    81    86    94   102   104    98    80  2665
   170   167   177   186   191   174   141  2671
   267   267   290   314   333   323   263  2668
   598   593   631   669   702   672   536  2670
   936   888   908   904   913   914   723  2669
  1098   917   876   888   894   899   840  2668
  1157   895   864   869   875   878   904  2668
  1138   873   834   835   841   844   902  2667

 7番ピンにポテンショメータをつなぎ、残りのピンは解放してあるので、乱雑な値が出ている。