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");
}
コメント
コメントを投稿