今回ラズパイPicoに取り付けてMicroPythonで制御してみるのは、ソフトウエアで抵抗値を設定できる可変抵抗、デジタルポテンショメータです。MicroChip社製MCP4018であります。ソフトで制御できるというと回路をいじらないでも何かいろいろ出来そうで嬉しい気もします。まあ使い道にもよりますが。
※「MicroPython的午睡」投稿順 Indexはこちら
アイキャッチ画像にデジタルポテンショメータ MCP4018 の「近影」掲げました。ともかく小さいです。ピンの先端まで含めても 2mm x 2mm ほどです。半田付け不得意の私としては、DIP化ボードに半田付けするだけでほぼほぼ限界に達しています。
可変抵抗器といいつつ、デジタル制御です。I2Cによって抵抗値を制御します。128段階に調整可能です。フルレンジの抵抗値はメーカオプションでいろいろあるようですが、今回購入の品はフルレンジ10kΩ品です。計算上は、ほぼ1ステップ78Ωくらいで抵抗値をプログラムできるっと。なお当然ですが、内部に論理回路、メモリなども入った立派なICなので電源、グランドが必要です。チップの詳細については、MicroChip社の以下のページからどうぞ。
mcp4018 7-Bit Single Digital POT in SC70 w/I2C
また、購入は例によって秋月通商殿からです。以下が通販サイトへのリンクです。
デジタルポテンショメータ 10kΩ128タップ MCP4018T-103E/LT (4個入)
今回のテスト回路
今回は大したことはしてません(何時も大したことはしてないじゃないか。)ただデバイスに通電し、I2Cでプログラムしてみて、抵抗値が変わっているようだと測定できればよろしい、と。これに使った回路が以下です。
ラズパイPicoから設定値をI2C経由で送り込み、抵抗値の変化をA-W間の電位差の変化として計測するだけのもの。
ブレッドボード上に組み立てた実際の回路がこちら。なお、MCP4018はSOT363用のDIP化ボードの上に半田づけしました。半田付けも限界なら、マーキングの読み取りも限界。老眼の目でルーペで必死にマーキングを見、そして1番ピンのマークを確認。このサイズは辛い。手半田するようなチップじゃないからショウガナイ、ノージンジャー。
テスト用のMicroPythonスクリプト
ラズパイPico用のMicroPythonは、RP2040搭載のハードウエアI2Cは勿論、ソフトウエアI2Cもサポートしています。以前の記事ではさんざんお世話になっているものです。しかし今回は、ソフトウエアI2Cにほぼ相当のクラスを自前で作成してテストしています。その心は、MCP4018にソフトウエアRESETをかけて「ノウン」な状態にするために、1の9連送というシーケンスが必要であったため。
既存のハード、ソフトI2Cのメソッドでどうしたらできるのかよく分からなかったので、自前でコードしてしまいました。車輪の再発見というやつぞなもし。
import time, machine class fullSoftMCP4018: def __init__(self, sdaPin=2, sclPin=3): self.sdaPin = sdaPin self.sclPin = sclPin self.sda = machine.Pin(sdaPin, machine.Pin.OUT) self.scl = machine.Pin(sclPin, machine.Pin.OUT) self.scl.value(1) self.sda.value(1) self.MCP4018ADR = [0, 1, 0, 1, 1, 1, 1] def halfCYC(self): time.sleep_us(5) def startBIT(self): self.sda.value(0) self.halfCYC() self.scl.value(0) self.halfCYC() def dataBIT(self, dat): self.sda.value(dat) self.halfCYC() self.scl.value(1) self.halfCYC() self.scl.value(0) def ackBIT(self): self.sda = machine.Pin(self.sdaPin, machine.Pin.IN) self.halfCYC() self.scl.value(1) self.halfCYC() ack = self.sda.value() self.scl.value(0) self.sda = machine.Pin(self.sdaPin, machine.Pin.OUT) self.halfCYC() return ack def stopBIT(self): self.scl.value(1) self.halfCYC() self.sda.value(1) self.halfCYC() def softResetMCP4018(self): self.startBIT() for i in range(9): self.dataBIT(1) self.scl.value(1) self.halfCYC() self.stopBIT() def dataWrite(self, arg): self.startBIT() for v in self.MCP4018ADR: self.dataBIT(v) self.dataBIT(0) #Write adrAck = self.ackBIT() for i in range(8): if (arg & 0x80) != 0: self.dataBIT(1) else: self.dataBIT(0) arg <<= 1 datAck = self.ackBIT() self.stopBIT() return (adrAck, datAck) def sweepRangeUI(): global mcp4018 for res in range(0x80): print("RES: {0:02x}".format(res)) tpl = mcp4018.dataWrite(res) print("adrACK: {0} datACK: {1}".format(tpl[0], tpl[1])) time.sleep(2.0) def sweepRangeFast(): global mcp4018 for res in range(0x80): tpl = mcp4018.dataWrite(res) time.sleep_ms(1) def main(): global mcp4018 mcp4018 = fullSoftMCP4018(2, 3) mcp4018.softResetMCP4018() while(1): #sweepRangeUI() sweepRangeFast() if __name__ == "__main__": main()
なお、テストの本体は以下の関数です。
-
- sweepRangeUI() 人間用に設定値を画面に書き出しながら2秒毎に変化させる
- sweepRangeFast() オシロ用に設定値を1ms毎に変化させる
以下の実機上での動作確認は sweepRangeFast()によります。
実機動作確認
以下のオシロ画面の青色のC2のノコギリ波的な波形がポテンショメータ両端に現れた電位差です。右のMeasurements結果により最大で約3Vの電位差が確認できます。使用したMCP4018のフルレンジが10kΩ、外付け抵抗が1kΩ、与えた電圧が3.3Vです。10:1で分圧して3.0Vですな。またミニマム1.66mVくらいが見えてますが、外付け1kΩから推定するにプログラムで抵抗値最小としても端子間には0.6Ωくらいが見えておる、と。
ノコギリ波形の一部を拡大してみました。予想通り、階段状です。計算上は1ステップ23mVくらいになる筈ですが、そんな感じだな(いい加減な。)
デバイスそのものの動作はOK。MicroChip社のデータシートをみると「ありがち」な応用例がいろいろ書いてあります。次回はその辺をやってみますか。しかしそれにしても、デジタル電源をそのまま与えているので、ノイズがヤバイ感じです。静かな「定電流源」欲しいな。どっかでやったか、気のせいか?