ArduinoをPC制御して0-10Vを出力 その3 電圧が一定しない?
昨日の続き。Arduino+MCP4922+LM358でPC制御できる0-10V電源(6系統)を作っています。ハードウェアとArduinoのスケッチが出来たので、動作確認してみます。シリアルモニタで1A_4095と送れば、フルパワー(MCP4922で5V、増幅して10V)が出るはず。なんですが、実際やってみると4095送ってもMCP4922で4.4Vにしかなりません。デュアル 12ビット DAコンバータ シリアル (SPI / マイクロワイヤ) 14ピン PDIP 1袋 (2個入) MCP4922-E/Pこれは、私の環境ではMCP4922の基準電圧(Vref)に4.4Vしかかかってないからです。MCP4922のVrefはArduinoの5V出力から取っていますが、これは様々な理由で電圧が落ちるらしい。なので、別途5V電源を用意してVrefに使えばいいのですが、正直面倒くさい。【送料無料】安定化電源 AC 100-240V to DC 5V コンバーター スイッチング電源 直流電源変換器 短絡・過負荷・過電圧保護機能 アルミ製 サイズ:5A 25W上限ぎりぎりの5V近い電圧が必要ならそれも仕方ないですが、余裕があるならArduinoで電源電圧(Vcc)を読んで補正してやれば(落ちる分を見越して大き目の電圧を出力指示すれば)それで済みます。Arduinoに直接Vcc電圧を取得するコマンドはないですが、うまくコードを書けば配線不要で読めるらしい。http://radiopench.blog96.fc2.com/blog-entry-490.html上記を参考に改変したArdinoスケッチがこれ。送るのは4095までの整数値ではなく、0~5Vまでの電圧そのものを送出することにしました。ついでにコマンドを拡充し、Rを送出するとVccの電圧を返すようにしました。--------#include "pins_arduino.h"#include <SPI.h>#define LDAC 9 // ラッチ動作出力ピン#define MCP1 4 // MCP1選択ピン#define MCP2 3 // MCP2選択ピン#define MCP3 2 // MCP3選択ピンconst int Vin_PIN = A0;void setup() { Serial.begin(9600); // 制御するピンは全て出力に設定する pinMode(LDAC,OUTPUT) ; pinMode(MCP1,OUTPUT) ; pinMode(MCP2,OUTPUT) ; pinMode(MCP3,OUTPUT) ; //最初はすべてhighにする digitalWrite(MCP1,HIGH) ; digitalWrite(MCP2,HIGH) ; digitalWrite(MCP3,HIGH) ; // SPIの初期化処理を行う SPI.begin() ; // SPIを行う為の初期化 SPI.setBitOrder(MSBFIRST) ; // ビットオーダー SPI.setClockDivider(SPI_CLOCK_DIV8) ;// クロック(CLK)をシステムクロックの1/8で使用(16MHz/8) SPI.setDataMode(SPI_MODE0) ; // クロック極性0(LOW) クロック位相0 //電源電圧測定 pinMode(14, OUTPUT);}void loop() { //シリアルポートを読んで有効な文字があったら while(Serial.available()>0){ String cmds = Serial.readStringUntil('\n'); String MCPnumber = cmds.substring(0,1); String MCPport=cmds.substring(1,2); float vValue = cmds.substring(3).toFloat(); float Vcc = cpuVcc(); // 電源電圧測定 int iValue = vValue / Vcc * 4095; //電圧を整数値に変換 if(iValue>4096) {iValue=4095;} //上限を4095でクリップ //CSを選択 if(MCPnumber =="R"){ Serial.println(Vcc,2); // シリアルポートにVccを書き出す delay(200); break; }else if(MCPnumber =="1"){ digitalWrite(MCP1,LOW) ; }else if(MCPnumber =="2"){ digitalWrite(MCP2,LOW) ; }else if(MCPnumber =="3"){ digitalWrite(MCP3,LOW) ; } //ポートを選択 int PortOfset; if(MCPport =="A"){ PortOfset=B00110000; }else if(MCPport =="B"){ PortOfset=B10110000; } //出力 digitalWrite(LDAC,HIGH) ; //LDACを上げる SPI.transfer(((iValue >> 8) & 0x0F) | PortOfset) ; // Highバイト(0x30=OUTA/BUFなし/1x/シャットダウンなし) SPI.transfer(iValue & 0xff) ; // Lowバイトの出力 上位バイトを消す //CSを戻す digitalWrite(MCP1,HIGH) ; digitalWrite(MCP2,HIGH) ; digitalWrite(MCP3,HIGH) ; // ラッチ信号を出す(出力指示) digitalWrite(LDAC,LOW) ; }}float cpuVcc(){ // 電源電圧(AVCC)測定関数 Vref=AVcc, input=internal1.1V long sum=0; ADMUX = 0x4E; // ADC Multiplexer Select Reg. ADCSRA |= ( 1