PCからのコマンドを受け取って、それで動作するようにしたい訳だが、コマンドはオリジナルでもよく、つまり”hoge 1.0"とシリアルで受け取ったら電圧を1.0Vにするとか。
LT3080ですが、最低電流を0.5mAは流さないと電圧が出力されません。そこで、マイナス電源を用意して、そこに向かって定電流ダイオードで常に2mAの電流が流れるようにしている。
これはちゃんとゼロボルト付近まで電圧を制御できる点ではよいアプローチ。しかし注意が必要で、前段のLT3080に電流を流せる状態にない時には、設定電圧をゼロにしていても、電流を引き出す事がでいないので出力電圧がマイナスに引き込まれてマイナス電位を出力してしまいます。
#include <SPI.h>
const int PIN_CS = PIN_PB2;
const int PIN_DAC_CS = PIN_PB1;
const int PIN_PMOS = PIN_PB0;
// DAC8555 用設定
SPISettings dacSetting(1000000, MSBFIRST, SPI_MODE1);
// ADS8341 用設定
SPISettings adcSetting(2000000, MSBFIRST, SPI_MODE0);
// 出力電圧ON/OFF 状態
bool outputEnabled =false;
//出力電圧設定値
float outputVoltage= 0.0;
//電流制限値を保持する変数
float currentLimit_mA = 1000.0f; // デフォルト 1000mA
// ===== DAC8555 =====
void DACVset(uint8_t chan, float Vsetadc) {
const float Vdacref = 3.300;
uint16_t DataInt = (uint16_t)(Vsetadc / Vdacref * 65535.0);
uint8_t cmd;
switch (chan) {
case 0: cmd = 0b00010000; break; // A
case 1: cmd = 0b00010010; break; // B
case 2: cmd = 0b00010100; break; // C
case 3: cmd = 0b00010110; break; // D
default: cmd = 0b00010000; break;
}
uint8_t msb = (DataInt >> 8) & 0xFF;
uint8_t lsb = DataInt & 0xFF;
digitalWrite(PIN_DAC_CS, LOW);
SPI.beginTransaction(dacSetting);
SPI.transfer(cmd);
SPI.transfer(msb);
SPI.transfer(lsb);
SPI.endTransaction();
digitalWrite(PIN_DAC_CS, HIGH);
}
// ===== ADC Utility =====
float adcToVoltage(uint16_t code) {
const float Vref = 3.300f;
return (float)code * (Vref / 65535.0f);
}
uint16_t readADS8341(uint8_t channel) {
const uint8_t muxTable[4] = {
0b10010111, // CH0
0b11010111, // CH1
0b10100111, // CH2
0b11100111 // CH3
};
channel &= 0x03;
uint32_t sum = 0;
SPI.beginTransaction(adcSetting);
for (int i = 0; i < 100; i++) {
uint8_t ctrl = muxTable[channel];
digitalWrite(PIN_CS, LOW);
SPI.transfer(ctrl);
uint8_t b0 = SPI.transfer(0x00);
uint8_t b1 = SPI.transfer(0x00);
uint8_t b2 = SPI.transfer(0x00);
digitalWrite(PIN_CS, HIGH);
uint32_t raw = ((uint32_t)b0 << 16) | ((uint32_t)b1 << 8) | b2;
uint16_t value = (raw >> 7) & 0xFFFF;
sum += value;
}
SPI.endTransaction();
return (uint16_t)(sum / 100);
}
// ===== UART Line Buffer =====
String lineBuffer = "";
void setup() {
Serial.begin(38400);
delay(300);
Serial.println("READY");
pinMode(PIN_CS, OUTPUT);
digitalWrite(PIN_CS, HIGH);
pinMode(PIN_DAC_CS, OUTPUT);
digitalWrite(PIN_DAC_CS, HIGH);
pinMode(PIN_PMOS, OUTPUT);
digitalWrite(PIN_PMOS, HIGH);
SPI.begin();
while (Serial.available()) Serial.read();
outputEnabled=false;
outputVoltage= 0.0;
DACVset(0, 0.0); // ★ 出力は 0V に
DACVset(1, 3.0); // CCは電流を流せる状態に
DACVset(2, 0.0); // 未使用
DACVset(3, 0.0); // 未使用
delay(10);
digitalWrite(PIN_PMOS, LOW); //PMOSを操作して、出力3.3Vをコンバーターに-3.3Vを生成
}
void loop() {
while (Serial.available()) {
char c = Serial.read();
if (c == '\r') continue; // ★ CR を無視する
if (c == '\n') {
lineBuffer.trim();
if (lineBuffer.length() > 0) {
processSCPI(lineBuffer);
}
lineBuffer = "";
} else {
lineBuffer += c;
}
}
}
// ===== SCPI Command Processor =====
void processSCPI(String cmd) {
// ★ ECHO: を削除し、受信文字列そのまま返す
//Serial.println(cmd);
cmd.trim();
if (cmd.length() == 0) return; // ★ 空行は無視
cmd.toUpperCase();
// -------------------------
// *IDN?
// -------------------------
if (cmd == "*IDN?") {
Serial.println("Arduino, Power Supply System, 1.2");
return;
}
// -------------------------
// VOLT <value>
// CH1 の実電圧を指定する
// -------------------------
if (cmd.startsWith("VOLT")) {
int spacePos = cmd.indexOf(' ');
if (spacePos < 0) {
Serial.println("ERR:SYNTAX");
return;
}
// ★ 出したい実電圧
float vout = cmd.substring(spacePos + 1).toFloat();
// ★ CH1 のみ制御(index = 0)
int ch_index = 0;
// ★ 設定値を記録(実電圧)
outputVoltage = vout;
// ★ 出力が ON のときだけ DAC に反映
if (outputEnabled) {
// 実電圧 → DAC 指示値(2.975 倍補正)
float v_dac = vout / 2.975f;
// 0V 以下はクリップ
if (v_dac < 0.0f) v_dac = 0.0f;
DACVset(ch_index, v_dac);
}
return;
}
// -------------------------
// OUTP ON
// CH1 の出力を ON にする
// -------------------------
if (cmd == "OUTP ON") {
int ch_index = 0; // CH1 固定
outputEnabled = true;
// 記録していた電圧に復帰
DACVset(ch_index, outputVoltage);
return;
}
// -------------------------
// OUTP OFF
// CH1 の出力を OFF にする
// -------------------------
if (cmd == "OUTP OFF") {
int ch_index = 0; // CH1 固定
outputEnabled = false;
// 出力をゼロに。
DACVset(ch_index, 0.0);
return;
}
// -------------------------
// MEAS:VOLT?
// CH1 の電圧を返す(実際に出力されている電圧を計測)
// -------------------------
if (cmd == "MEAS:VOLT?") {
int ch = 0; // CH1 固定
uint16_t adc = readADS8341(ch);
float v = adcToVoltage(adc);
// ★ CH1 は分圧されているので補正
v = v * 3.13f; // CSV から求めた補正係数
Serial.println(v, 6);
return;
}
// -------------------------
// MEAS:CURR?
//1Ωの抵抗に実際に流れている電流出力されている電流値
// -------------------------
if (cmd == "MEAS:CURR?") {
// CH2 の ADC を読む
uint16_t adc = readADS8341(3); // CH4 = index 3
float v = adcToVoltage(adc); // 差動アンプ出力電圧
// ★ 電流[mA] に変換(CSV から求めた補正式)
float current_mA = (0.355*v-0.006)*1000;//単位は[mA]
// 負値は 0 にクリップ
if (current_mA < 0.0f) current_mA = 0.0f;
Serial.println(current_mA, 6);
return;
}
// -------------------------
// CURR:LIM?
// -------------------------
if (cmd == "CURR:LIM?") {
Serial.println(currentLimit_mA, 3);
return;
}
// -------------------------
// CURR:LIM <value>
// -------------------------
if (cmd.startsWith("CURR:LIM")) {
int spacePos = cmd.indexOf(' ');
if (spacePos < 0) {
Serial.println("ERR:SYNTAX");
return;
}
// ★ 制限したい電流値
float set_currentLimit_mA = cmd.substring(spacePos + 1).toFloat();
// ★ CH2 のみ制御(index = 1)
int ch_index = 1;
// ★ 設定値を記録
currentLimit_mA = set_currentLimit_mA;
float dac_limit_voltage = 0.00344f * currentLimit_mA - 0.032f;
DACVset(1, dac_limit_voltage);
return;
}
if (cmd.startsWith("PMOS ON")) {
digitalWrite(PIN_PMOS, LOW);
return;
}
if (cmd.startsWith("PMOS OFF")) {
digitalWrite(PIN_PMOS, HIGH);
return;
}
// -------------------------
// Unknown command
// -------------------------
Serial.println("ERR:UNKNOWN COMMAND");
}
コメント
コメントを投稿