Table of Contents

PC900 optocoupler

기본 자료

PC900V 데이터시트 다음 그림의 출처: http://midi.teragonaudio.com/hardware/pc_intfc.htm

    (상단에서 본 모습, 핀1 표시 점 기준)

        ┌───────┐
 Anode  |1     6| Vcc (+5V)
Cathode |2     5| GND (Emitter)
    NC  |3     4| Vout (Collector)
        └───────┘

핀 기능 요약

PC900V Drop-in Replacement

PC900V는 샤프(SHARP, 현재는 Vishay 등에 승계)에서 나온 포토커플러로, 포토트랜지스터 출력이며 약 80–100 kbps 정도의 응답 속도를 가집니다. MIDI IN과 같은 31.25 kbps 신호에서는 충분히 동작하지만, 단종/구하기 어려운 경우가 있어 대체품을 찾게 됩니다.

1. 핀 호환 Drop-in 대체품

→ PC900과 동일한 4핀 DIP 패키지, CTR 범위 유사.

→ 흔한 범용 포토커플러, 속도는 MIDI용으로 충분.

→ 국내외 유통량이 많음. CTR 넓고 속도는 약 50 kHz 수준으로 MIDI에 사용 가능.

2. MIDI용으로 자주 쓰이는 대체품

3. 정리

Arduino UNO 기반 PC900V 옵토커플러 테스터 (I2C 2004 LCD 표시)

아두이노 우노(UNO)로 PC900V(포토트랜지스터형 옵토커플러)를 단품 점검하고, 측정 결과를 I2C 20×4 LCD(2004)에 표시하는 예제입니다. Phase1(저속 ON/OFF 논리 확인)과 Phase2(1 kHz/5 kHz 토글 응답 통계)를 지원합니다.

1. 준비물

2. 배선

D9로 PC900V의 LED를 구동하고, D2(INT0)로 포토트랜지스터 출력을 읽습니다. (I2C 20×4 LCD를 사용할 경우 A4/A5 배선 예시도 아래에 포함)

Arduino UNO                          PC900V (6pin DIP)
============                         ==================

 D9 (디지털 출력) -----[220Ω]----------> Pin1 (Anode, LED+)
 GND ---------------------------------> Pin2 (Cathode, LED-)

 +5V ---------------------------------> Pin6 (Vcc)
 GND ---------------------------------> Pin5 (Emitter, GND)

 D2 (디지털 입력, INT0) <------------+-- Pin4 (Collector, Output)
                                    |
                                   [RL = 1kΩ~2.2kΩ Pull-up]
                                    |
                                   +5V

요약:

(선택) I2C 20×4 LCD 연결 예시

테스트 결과를 LCD에 표시하려면 아래처럼 I2C LCD를 추가하세요. (주소 0x27 또는 0x3F)

UNO A4 (SDA) -------------------- LCD SDA
UNO A5 (SCL) -------------------- LCD SCL
UNO +5V ------------------------- LCD VCC
UNO GND ------------------------- LCD GND

3. 기대 동작

4. 스케치 (I2C 2004 LCD 표시)

// Arduino UNO + I2C 2004 LCD: PC900V Optocoupler Tester
// D9: drive(220Ω 통해 PC900V LED+), D2: sense(INT0, RL=1k~2.2kΩ로 +5V 풀업)
// LCD: 20x4 I2C (addr 0x27). 필요 시 0x3F 등으로 변경.
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 
#define LCD_ADDR 0x27
LiquidCrystal_I2C lcd(LCD_ADDR, 20, 4);
 
const uint8_t DRIVE_PIN = 9;   // Opto LED drive
const uint8_t SENSE_PIN = 2;   // Opto output sense (INT0)
 
volatile uint32_t edgeCount = 0;
volatile uint32_t lastEdgeUs = 0;
volatile uint8_t  lastState  = 0;
volatile uint32_t highMin = 0xFFFFFFFF, highMax = 0, highSum = 0, highCnt = 0;
volatile uint32_t lowMin  = 0xFFFFFFFF, lowMax  = 0, lowSum  = 0, lowCnt  = 0;
 
void onSenseEdge() {
  uint32_t now = micros();
  uint8_t state = digitalRead(SENSE_PIN); // HIGH=1, LOW=0
  uint32_t dt = now - lastEdgeUs;
 
  if (lastEdgeUs != 0) {
    if (state == LOW) {
      // 방금 HIGH->LOW: 직전 구간은 HIGH 구간 길이
      if (dt < highMin) highMin = dt;
      if (dt > highMax) highMax = dt;
      highSum += dt; highCnt++;
    } else {
      // 방금 LOW->HIGH: 직전 구간은 LOW 구간 길이
      if (dt < lowMin) lowMin = dt;
      if (dt > lowMax) lowMax = dt;
      lowSum += dt; lowCnt++;
    }
  }
  lastEdgeUs = now;
  lastState  = state;
  edgeCount++;
}
 
void resetStats() {
  noInterrupts();
  edgeCount = 0;
  lastEdgeUs = 0;
  lastState  = digitalRead(SENSE_PIN);
  highMin = lowMin = 0xFFFFFFFF;
  highMax = lowMax = 0;
  highSum = lowSum = 0;
  highCnt = lowCnt = 0;
  interrupts();
}
 
void lcdHeader(const char* phase) {
  lcd.clear();
  lcd.setCursor(0,0); lcd.print("Opto Tester (UNO)");
  lcd.setCursor(0,1); lcd.print(phase);
}
 
void showPhase1(bool ledOn, int senseVal) {
  lcd.setCursor(0,2);
  lcd.print("LED:");
  lcd.print(ledOn ? "ON " : "OFF");
  lcd.print("  SENSE:");
  lcd.print(senseVal ? "HIGH" : "LOW ");
  lcd.setCursor(0,3);
  lcd.print("Expect ON->LOW, OFF->HIGH ");
}
 
void showPhase2Stats(uint32_t freqHz,
                     uint32_t edges,
                     uint32_t hMin, uint32_t hMax, uint32_t hAvg,
                     uint32_t lMin, uint32_t lMax, uint32_t lAvg) {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Phase2 @");
  lcd.print(freqHz);
  lcd.print("Hz  Edg:");
  lcd.print(edges);
 
  lcd.setCursor(0,1);
  lcd.print("HIGH us min/"); lcd.print(hMin);
  lcd.print(" max/");       lcd.print(hMax);
 
  lcd.setCursor(0,2);
  lcd.print("HIGH avg:");   lcd.print(hAvg); lcd.print("    ");
 
  lcd.setCursor(0,3);
  lcd.print("LOW  avg:");   lcd.print(lAvg); lcd.print("    ");
}
 
void phase1_basicToggle(uint16_t ms = 500, uint8_t repeats = 6) {
  lcdHeader("Phase1: Slow Toggle");
  for (uint8_t i=0; i<repeats; ++i) {
    digitalWrite(DRIVE_PIN, HIGH);
    delay(ms);
    showPhase1(true, digitalRead(SENSE_PIN));
 
    digitalWrite(DRIVE_PIN, LOW);
    delay(ms);
    showPhase1(false, digitalRead(SENSE_PIN));
  }
}
 
void phase2_edgeStats(uint32_t freqHz = 1000, uint32_t durationMs = 2000) {
  uint32_t halfPeriodUs = 1000000UL / (2 * freqHz);
  resetStats();
 
  uint32_t start = millis();
  bool level = false;
 
  while (millis() - start < durationMs) {
    level = !level;
    digitalWrite(DRIVE_PIN, level ? HIGH : LOW);
    delayMicroseconds(halfPeriodUs);
  }
 
  digitalWrite(DRIVE_PIN, LOW);
  delay(10);
 
  noInterrupts();
  uint32_t ec   = edgeCount;
  uint32_t hMin = (highCnt ? highMin : 0);
  uint32_t hMax = (highCnt ? highMax : 0);
  uint32_t hAvg = (highCnt ? (highSum / highCnt) : 0);
  uint32_t lMin = (lowCnt  ? lowMin  : 0);
  uint32_t lMax = (lowCnt  ? lowMax  : 0);
  uint32_t lAvg = (lowCnt  ? (lowSum / lowCnt) : 0);
  interrupts();
 
  showPhase2Stats(freqHz, ec, hMin, hMax, hAvg, lMin, lMax, lAvg);
}
 
void setup() {
  pinMode(DRIVE_PIN, OUTPUT);
  digitalWrite(DRIVE_PIN, LOW);
 
  pinMode(SENSE_PIN, INPUT);            // 외부 RL(1k~2.2kΩ) 권장
  attachInterrupt(digitalPinToInterrupt(SENSE_PIN), onSenseEdge, CHANGE);
 
  lcd.init();
  lcd.backlight();
 
  Serial.begin(115200); // 선택 사항(디버깅)
  Serial.println(F("== PC900V Optocoupler Tester (UNO + I2C 2004) =="));
}
 
void loop() {
  phase1_basicToggle(500, 6);     // Phase1: 느린 ON/OFF로 논리 확인
  phase2_edgeStats(1000, 2000);   // Phase2: 1 kHz 2초 측정
  delay(1500);
  phase2_edgeStats(5000, 2000);   // Phase2: 5 kHz 2초 측정(여유 확인)
  delay(3000);
}

5. 운용 팁

6. 문제 해결 체크리스트