ゆるく楽しむプログラミング

Arduinoで抵抗判別機を作ってみる

ツールボックスに放り込まれた抵抗 … どれが何オームなのか分からない … (;´Д`)
カラーコード? そんなもん読めたら苦労しない。
※頻繁に使う 1KΩだけは見分けがつくようになってきた。



毎度テスターを引っ張り出すのも面倒なので抵抗を判別するツールを作ってみます。

抵抗判別機の原理

こんな風に直列に接続した抵抗のそれぞれに掛かる電圧を測定します。
V0:VxはR0:Rxに等しくなります。
R0の抵抗値が分かっている時、Rxの抵抗値は
Rx = Vx ÷ (5V ― Vx) × R0
となります。

ArduinoのAD変換ポートで電圧値を取り込むと
電源電圧 = 1023
グランド = 0
となりますのでR0の抵抗値が判明していてPoint2の入力値が分かれば
Rx = Point2の値 ÷ (Point1の値 - Point2の値) × R0
で計算できます。

Arduinoでは分解能が1024しかありませんので、判別できる抵抗の範囲と精度は基準にする抵抗の抵抗値に依存します。
私の場合は手持ちの抵抗が判別できれば良いので基準抵抗を3KΩにしました。
計測可能な範囲は100Ωから100KΩ位と思います。


ブレッドボードに組んでみる


表示に学校のチャイムで使ったのと同じ0.96インチOLED(SSD1306)を使用します。
基準になる抵抗はとりあえず3KΩとしました。

OLED(SSD1306)を使うためのライブラリ

今回は ozoled-oled-display-096-i2c-driver-library を使います。
ちょっと不具合があるのとフォントを書き換えるために OzOLED.cpp の一部を修正します。
該当箇所を置き換えてください。32行目あたりと443行目あたりです。


// This font be freely used without any restriction(It is placed in public domain)
const byte BasicFont[][8] PROGMEM = {
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00},
    {0x00,0x14,0x7F,0x14,0x7F,0x14,0x00,0x00},
    {0x00,0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00},
    {0x00,0x23,0x13,0x08,0x64,0x62,0x00,0x00},
    {0x00,0x36,0x49,0x55,0x22,0x50,0x00,0x00},
    {0x00,0x00,0x05,0x03,0x00,0x00,0x00,0x00},
    {0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00},
    {0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00},
//  {0x00,0x08,0x2A,0x1C,0x2A,0x08,0x00,0x00}, // *
    {8, 140, 146, 225, 1, 225, 146, 140,}, // Ω
    {0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00},
    {0x00,0xA0,0x60,0x00,0x00,0x00,0x00,0x00},


void OzOLED::init(){
    Wire.begin();
    
    // upgrade to 400KHz! (only use when your other i2c device support this speed)
    if (I2C_400KHZ){
        // save I2C bitrate (default 100Khz)
        byte twbrbackup = TWBR;
        TWBR = 12; 
        //TWBR = twbrbackup;
        //Serial.println(TWBR, DEC);
        //Serial.println(TWSR & 0x3, DEC);
    }
    
    setPowerOff();     //display off
    delay(10);
    setPowerOn();      //display on
    delay(10); 
    setNormalDisplay();  //default Set Normal Display
    setPageMode();    // default addressing mode
    clearDisplay();
    setCursorXY(0,0); 

    sendCommand(0x3C); sendCommand(0x00); sendCommand(0xC0); // 上下反転
    sendCommand(0x3C); sendCommand(0x00); sendCommand(0xA0); // 左右反転

    sendCommand(0x8d); // Charge Pump
    sendCommand(0x14); // 表示
}


抵抗判別機のスケッチ

標準抵抗は3KΩに設定
配線の抵抗や電源の揺れによる影響を回避するために分解能を10Ωに設定。
1KΩ以上の場合100Ω単位の表示にしています。
なので、あくまで抵抗の判別機であり抵抗値を測定するものではありません。
※精度が低すぎて抵抗値測定に使うのは厳しいかと思います。

-- RegisterCheck.ino --
 
#if defined(__AVR_ATtiny85__)
#include <TinyWireM.h>
#include <TinyOzOLED.h>
#else 
#include <Wire.h>
#include <OzOLED.h>
#endif
char dispStr[16] ;
char rDispStr[6] ;

#define RANGE 10
#define BASEREGISTER 3000.0
#define INRANGE ((1023. / BASEREGISTER ) * RANGE + 1)
#define ANALIZE_PIN A3
#define ANALIZE_PIN2 A2

void setup(){
  //initialze SEEED OLED display
  OzOled.init(); 

  OzOled.clearDisplay();
  OzOled.setCursorXY(1,0);
  OzOled.printString("--------------");
  OzOled.setCursorXY(1,1);
  OzOled.printString("Register Check");
  OzOled.setCursorXY(1,2);
  OzOled.printString("--------------");

  pinMode(ANALIZE_PIN, INPUT);
  pinMode(ANALIZE_PIN2, INPUT);
}

void loop() {
  int buttonStat = analogRead(ANALIZE_PIN) ;
  int buttonStat2 = analogRead(ANALIZE_PIN2) ;

  OzOled.setCursorXY(1,3);
  sprintf(dispStr,"P:%04d/V:%04d",buttonStat2,buttonStat) ;
  OzOled.printString(dispStr);

  rDispStr[0] = 0;
  unsigned long int r = 0;
  buttonStat = ((buttonStat+INRANGE-1) / INRANGE) * INRANGE ; 
  buttonStat2 = ((buttonStat2+INRANGE-1) / INRANGE) * INRANGE ; 
  r = (buttonStat * BASEREGISTER) /(buttonStat2 - buttonStat) ;
  r = ((r + (RANGE -1)) / RANGE) * RANGE;
  if (r >= 1000) {
    if (((r%1000)/100) == 0) {
      sprintf(rDispStr,"R: %d K*          ",r/1000) ;
    } else {
      sprintf(rDispStr,"R: %d.%d K*       ",r/1000,((r%1000)/100)) ;
    }
  } else {
    sprintf(rDispStr,  "R: %d *           ",r) ;
  }
  rDispStr[13] = 0 ;
  OzOled.setCursorXY(1,6);
  OzOled.printString(rDispStr);

  delay(1000) ;
}