LT3080実験用DC電源プロジェクト(9)PCB基板化

 LT30800を用いた安定化電源


画像だと文字が潰れているとおもうのでPDFを用意

試行錯誤の結果、ブレッドボードで組んだのが以下
  ジャンパーでごちゃっと!!これを一つ一つ、くみ上げてきた自分を誇らしく思う。
TFTの画面に、カラー表示。設定値などの変更は、ローターリーエンコーダーを利用。
リモート、ローカルでLEDの色も変わるように。


KiCadでレイアウト
3Dを確認すうとこんな感じ
JLCPCBに発注。少し最近は送料が高くなっている模様。といっては1.2$。で送料は大陸から送られてきて180円ぐらい。

ブレッドボードでは、328PBにブートローダーを焼き付けてあるので、USB経由で以下のプログラを書き込み。

#include <SPI.h>

// ===============================
// ピンアサイン
// ===============================
const int PIN_CS = PIN_PB2;
const int PIN_DAC_CS = PIN_PB1;
const int PIN_PMOS = PIN_PB0;

const int PIN_LED_R = PIN_PB7;
const int PIN_LED_G = PIN_PB6;
const int PIN_LED_B = PIN_PE1;

const int PIN_Encoder_A  = PIN_PD7;
const int PIN_Encoder_B  = PIN_PD6;
const int PIN_Encoder_SW = PIN_PD5;

// ===============================
// PowerState 構造体
// ===============================
struct PowerState {
    float setVoltage;        // 設定電圧[V]
    float setCurrentLimit;   // 電流制限[mA]
    bool outputEnabled;      // 出力 ON/OFF
    bool remoteMode;         // true=REMOTE, false=LOCAL
};

PowerState ps;

// ===============================
// SPI 設定
// ===============================
SPISettings dacSetting(1000000, MSBFIRST, SPI_MODE1);
SPISettings adcSetting(2000000, MSBFIRST, SPI_MODE0);

// ===============================
// DAC 出力関数
// ===============================
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);
}

// ===============================
// applyOutputState()
// ===============================
void applyOutputState() {

  // ---- 電圧設定(CH0) ----
  float v_dac = ps.outputEnabled ? (ps.setVoltage / 2.975f) : 0.0f;
  if (v_dac < 0.0f) v_dac = 0.0f;
  DACVset(0, v_dac);

  // ---- 電流制限(CH1) ----
  float limit_dac = 0.00344f * ps.setCurrentLimit - 0.032f;
  if (limit_dac < 0.0f) limit_dac = 0.0f;
  DACVset(1, limit_dac);
}

// ===============================
// UART Line Buffer
// ===============================
String lineBuffer = "";

// ===============================
// エンコーダーSW 長押し判定(1秒)
// ===============================
unsigned long swPressStart = 0;
bool swPrev = false;

void checkEncoderSwitch() {
    bool sw = (digitalRead(PIN_Encoder_SW) == LOW); // 押されたら LOW

    if (sw && !swPrev) {
        swPressStart = millis();
    }

    if (!sw && swPrev) {
        unsigned long pressTime = millis() - swPressStart;

        if (pressTime > 1000) {  // ★ 1秒以上 → LOCAL に強制遷移
            ps.remoteMode = false;
            Serial.println("MODE:LOCAL");
        }
    }

    swPrev = sw;
}

// ===============================
// setup()
// ===============================
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);

  pinMode(PIN_LED_R, OUTPUT);
  pinMode(PIN_LED_G, OUTPUT);
  pinMode(PIN_LED_B, OUTPUT);
  digitalWrite(PIN_LED_R, HIGH);
  digitalWrite(PIN_LED_G, HIGH);
  digitalWrite(PIN_LED_B, HIGH);

  pinMode(PIN_Encoder_SW, INPUT_PULLUP);

  SPI.begin();
  while (Serial.available()) Serial.read();

  // ---- PowerState 初期化 ----
  ps.setVoltage = 0.0f;
  ps.setCurrentLimit = 1000.0f;
  ps.outputEnabled = false;
  ps.remoteMode = true;  // PC が優先

  applyOutputState();
  digitalWrite(PIN_PMOS, HIGH);  // 起動時のみ必要
}

// ===============================
// loop()
// ===============================
void loop() {

  // ---- ローカルUI(SW長押し) ----
  checkEncoderSwitch();

  // ---- SCPI ----
  while (Serial.available()) {
    char c = Serial.read();

    if (c == '\r') continue;
    if (c == '\n') {
      lineBuffer.trim();
      if (lineBuffer.length() > 0) {
        processSCPI(lineBuffer);
      }
      lineBuffer = "";
    } else {
      lineBuffer += c;
    }
  }
}

// ===============================
// SCPI Command Processor
// ===============================
void processSCPI(String cmd) {

  cmd.trim();
  if (cmd.length() == 0) return;
  cmd.toUpperCase();

  // -------------------------
  // LOCAL 中に設定系コマンドが来たら REMOTE に戻す
  // -------------------------
  bool isSettingCmd =
      cmd.startsWith("VOLT") ||
      cmd.startsWith("CURR:LIM") ||
      cmd.startsWith("OUTP");

  if (!ps.remoteMode && isSettingCmd) {
      ps.remoteMode = true;
      Serial.println("MODE:REMOTE");
      // LOCAL → REMOTE に戻すだけで拒否しない
  }

  // -------------------------
  // *IDN?
  // -------------------------
  if (cmd == "*IDN?") {
    Serial.println("Arduino, Power Supply System, 1.3");
    return;
  }

  // -------------------------
  // VOLT <value>
  // -------------------------
  if (cmd.startsWith("VOLT")) {

    int spacePos = cmd.indexOf(' ');
    if (spacePos < 0) {
      Serial.println("ERR:SYNTAX");
      return;
    }

    float vout = cmd.substring(spacePos + 1).toFloat();
    ps.setVoltage = vout;

    applyOutputState();
    return;
  }

  // -------------------------
  // OUTP ON
  // -------------------------
  if (cmd == "OUTP ON") {
    ps.outputEnabled = true;
    applyOutputState();
    return;
  }

  // -------------------------
  // OUTP OFF
  // -------------------------
  if (cmd == "OUTP OFF") {
    ps.outputEnabled = false;
    applyOutputState();
    return;
  }

  // -------------------------
  // MEAS:VOLT?
  // -------------------------
  if (cmd == "MEAS:VOLT?") {

    uint16_t adc = readADS8341(0);
    float v = adcToVoltage(adc);

    v = v * 3.13f;  // 分圧補正
    Serial.println(v, 6);
    return;
  }

  // -------------------------
  // MEAS:CURR?
  // -------------------------
  if (cmd == "MEAS:CURR?") {

    uint16_t adc = readADS8341(3);
    float v = adcToVoltage(adc);

    float current_mA = (0.355 * v - 0.006) * 1000;
    if (current_mA < 0.0f) current_mA = 0.0f;

    Serial.println(current_mA, 6);
    return;
  }

  // -------------------------
  // CURR:LIM?
  // -------------------------
  if (cmd == "CURR:LIM?") {
    Serial.println(ps.setCurrentLimit, 3);
    return;
  }

  // -------------------------
  // CURR:LIM <value>
  // -------------------------
  if (cmd.startsWith("CURR:LIM")) {

    int spacePos = cmd.indexOf(' ');
    if (spacePos < 0) {
      Serial.println("ERR:SYNTAX");
      return;
    }

    float limit = cmd.substring(spacePos + 1).toFloat();
    ps.setCurrentLimit = limit;

    applyOutputState();
    return;
  }

  // -------------------------
  // LED / PMOS
  // -------------------------
  if (cmd == "PMOS ON") {
    ps.outputEnabled = true;
    applyOutputState();
    return;
  }

  if (cmd == "PMOS OFF") {
    ps.outputEnabled = false;
    applyOutputState();
    return;
  }

  if (cmd == "LEDR ON") { digitalWrite(PIN_LED_R, LOW); return; }
  if (cmd == "LEDR OFF"){ digitalWrite(PIN_LED_R, HIGH); return; }
  if (cmd == "LEDG ON") { digitalWrite(PIN_LED_G, LOW); return; }
  if (cmd == "LEDG OFF"){ digitalWrite(PIN_LED_G, HIGH); return; }
  if (cmd == "LEDB ON") { digitalWrite(PIN_LED_B, LOW); return; }
  if (cmd == "LEDB OFF"){ digitalWrite(PIN_LED_B, HIGH); return; }

  // -------------------------
  // Unknown command
  // -------------------------
  Serial.println("ERR:UNKNOWN COMMAND");
}



コメント

このブログの人気の投稿

【充電回路】TP4056(保護回路は電池側)

スーパーファミコン コントローラーの無線化プロジェクト:動作バージョン1

CH9329で日本語キーボード109で正しく表示する方法