MCP3008,3208を使ってみる SPIデバイスの使用

ADコンバータであるMCP3XXXを使う下準備

違いは3008は10ビット(1024) 3208は12ビット(4096)

3208は10ビットの読み出しも可能



1.RaspberyPiでSPIの使用を有効に
 Menu>>設定>>RaspberryPiの設定>>インターフェース>>SPI
 を有効

2.パッケージをインストール
 python-spidev と python-dev (python)
 python3-spidev と python3-dev(python3)
 
 python2用とpython3用の2種類
  
 sudo apt-get install python-spidev python-dev
 sudo apt-get install python3-spidev python3-dev



3.使い方は
 import spidev
 
 spidev.SpiDev() で初期化
 spi.open(bus,device) でオープン device= CE0   1=CE1
 spi.close() で終わり


4.ソース 3008(10ビット)と3208(12ビット)
----------------------------------------------------------
!/usr/bin/env python
# -*- coding:utf-8 -*-
#sudo apt-get install python-spidev
import time
import sys
import spidev

spi = spidev.SpiDev()
spi.open(0,0)


def readadc(adcnum):
    r = spi.xfer2([1, 8 + adcnum << 4, 0])
    adcout = ((r[1] & 3) << 8) + r[2]
    return adcout

def readadc12(adcnum):
    if adcnum > 7 or adcnum < 0:    
        return -1
    r = spi.xfer2([4 | 2 | (adcnum >> 2), (adcnum & 3) << 6, 0])
    adcout = ((r[1] & 15) << 8) + r[2]
    return adcout

def convertVolts(data):
    volts = (data * 3.3) / 1023
    #volts = round(volts,4)
    return volts

def convertVolts12(data):
    volts = (data * 3.3) / 4095
    #volts = round(volts,4)
    return volts
def convertTemp(volts):
    #temp = (100 * volts) - 50.0
    temp = volts * 100
    temp = round(temp,4)
    return temp

if __name__ == '__main__':
    try:
        while True:
            data = readadc(1)
            print("adc10bit  : {:8} ".format(data))
            volts = convertVolts(data)
            temp = convertTemp(volts)
            print("volts10bit: {:8.2f}".format(volts))
            print("temp10bit : {:8.2f}".format(temp))

            data = readadc12(1)
            print("adc12bit  : {:8} ".format(data))
            volts = convertVolts12(data)
            temp = convertTemp(volts)
            print("volts12bit: {:8.2f}".format(volts))
            print("temp 12bit: {:8.2f}".format(temp))
           

            time.sleep(3)
    except KeyboardInterrupt:
        spi.close()
        sys.exit(0)

----------------------------------------------------------

4.1、ビット操作
 AD変換をする以上、ビット操作は必須である。
 

    r = spi.xfer2([4 | 2 | (adcnum >> 2), (adcnum & 3) << 6, 0])
    adcout = ((r[1] & 15) << 8) + r[2]

 3208は
 [000001Dd2 ,d1d2xxxxxx,xxxxxxxx]
 でデータを渡して
 [????????,???Nb11b10b9b8,b7b6b5b4b3b2b1b0]でデータが
 帰ってくる

4.2.送信データの説明
 d2d1d0 =チャネルのビット表示 0=000,1=001、7=111
  ・di[0]=[000001Dd2]  
       00000100 
       00000010
       0000000D2
      でor
       0000011d2を送信。。。。
   
 ・di[1]=[D1D2xxxxxx]
  チャンネルと00000011をandで上位8ビットをマスク
  6ビット左シフト
  [D1D2000000]をセット
 
  ・di[2]=[,xxxxxxxx]
    [00000000]をセット

4.3。受信データの説明(データシート参照)
 r[1]の上位4ビットをマスクする つまりビット操作のANDで
 15=00001111でビット操作
 r[1] = [0000b11b10b9b8]
    これを8ビット左シフトしてr[2]と連結すると
    [0000b11b10b9b8b7b6b5b4b3b2b1b0]と目出度くデータ取得



4.4volts = (data * 3.3) / 4095
 データシートを見ると4096が正解のようである


 
5.MCP3208をライブラリ化して利用
(日経リナックスの9月号を引用)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import spidev
class Mcp3208():
    def __init__(self, bus=0, device=0, vref=3.3):
        self.spi = spidev.SpiDev()  # spi初期化
        self.bus = bus
        self.device = device
        self.vref = vref
    def __read(self, ch):
        v = self.spi.xfer2([4 | 2 | (ch >> 2), (ch & 0x03) << 6, 0])
        value = ((v[1] & 0x0f) << 8) | v[2]
        return value
    def raw(self, ch):
        self.spi.open(self.bus, self.device)  # デバイス使用開始
        value = self.__read(ch)  # デバイスから値を取得
        self.spi.close()  # デバイス使用終了
        return value
    def get(self, ch):
        self.spi.open(self.bus, self.device)  # デバイス使用開始
        value = self.__read(ch)  # デバイスから値を取得
        result = (value * self.vref / 4096.0)
        self.spi.close()  # デバイス使用終了
        return result
-------------------------------------------------------------------------
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import adc
import math
import time
import sys
def main():
    bus = 0
    device = 0
    vref = 3.3
    mcp3208 = adc.Mcp3208(bus, device, vref)
    # 温度の測定
    channel = 0
    result = mcp3208.get(channel)
    t = result * 100
    print("lm35dz:{:8.2f}".format(t))
 
if __name__ == "__main__":
    try:
      while True:
         main()
         time.sleep(1)
    except KeyboardInterrupt:
         sys.exit(0)    

おまけ
spidevを使わない方法もあるようでして
詳細はgoogle先生で「Mp3208 python 」で検索
シリアル通信を手組すれば良いわけですが、
データシートを見ながら解析するとSPI通信の中身が
よく理解できる。
これはこれでトラブルがあった時に原因を追及しやすい

カテゴリー iot