User Tools

Site Tools


nano_ardule_midi_controller:pc900v

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)
        └───────┘

핀 기능 요약

  • Pin 1 : LED Anode (+, DIN4에서 220Ω 직렬 후 연결)
  • Pin 2 : LED Cathode (–, DIN5와 연결)
  • Pin 3 : NC (사용 안 함)
  • Pin 4 : Collector (출력, 풀업 후 아두이노 RX로)
  • Pin 5 : Emitter (GND)
  • Pin 6 : Vcc (+5V)

PC900V Drop-in Replacement

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

1. 핀 호환 Drop-in 대체품

  • Vishay VO618A / VO615A

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

  • Toshiba TLP521

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

  • Everlight EL817

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

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

  • 6N138 / 6N137
    • 핀 배열은 다르지만 MIDI IN 회로 예제에서 가장 많이 사용됨.
    • 6N138: CTR 높으나 응답이 느려 강한 풀업 저항(220Ω 수준)을 요구.
    • 6N137: 더 빠른 디지털용, 내부 슈미트 트리거 내장 → TTL 레벨로 안정적.
  • HCPL-0500, HCPL-0630
    • 고속/저지연용. MIDI에는 다소 오버스펙이지만 안정적 동작.

3. 정리

  • 핀 배열 그대로 교체 가능한 부품: VO618A, TLP521, EL817 등 4핀 DIP 계열.
  • MIDI IN 전용으로는 6N138/6N137이 사실상 업계 표준.
  • 단순 교체가 목적이라면 VO618A 같은 4핀 DIP가 가장 무난.

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

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

1. 준비물

  • Arduino UNO 보드
  • PC900V (또는 EL817/TLP521 등 4핀 포토트랜지스터형 옵토커플러)
  • I2C 20×4 LCD 모듈 (주소 0x27 또는 0x3F)
  • 저항: 220Ω(LED 직렬), 1kΩ~2.2kΩ(출력 풀업/로드 RL)
  • 점퍼 케이블, 브레드보드

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

요약:

  • UNO D9 → 220Ω → PC900V Pin1 (LED+), Pin2은 GND.
  • UNO +5V → Pin6 (Vcc), UNO GND → Pin5 (Emitter).
  • PC900V Pin4 (Collector) → UNO D2 입력, 그리고 풀업저항(RL) 을 통해 +5V에 연결.
  • 필요 시 Pin4→(74HC14 1게이트)→D2 로 신호 정형 권장.
  • UNO의 0,1번 핀(RX/TX)은 USB 시리얼과 충돌하므로 사용하지 않습니다.

(선택) 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. 기대 동작

  • LED ON(=D9 HIGH) → 트랜지스터 ON → D2가 LOW
  • LED OFF(=D9 LOW) → 트랜지스터 OFF → D2가 HIGH
  • Phase2에서 1 kHz/5 kHz 토글에 대해 엣지 개수와 HIGH/LOW 평균 펄스폭이 반주기 근처면 정상

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

  • 라이브러리: LiquidCrystal_I2C (주소 기본 0x27, 필요 시 0x3F로 변경)
  • 시리얼 모니터(115200bps)는 선택 사항(디버깅용)
// 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. 운용 팁

  • RL(출력 풀업/로드)은 1k~2.2kΩ 권장(속도/전류 밸런스 양호). 4.7kΩ도 가능하나 에지가 둔해질 수 있음.
  • 파형이 불안정하면 74HC14(1게이트) 를 D2 앞에 추가.
  • Phase2에서 1 kHz/5 kHz 측정 시 평균 펄스폭이 반주기(500 µs/100 µs) 근처이고 엣지 카운트가 안정적이면 정상.
  • MIDI(31.25 kbps)는 비트 폭이 32 µs 수준으로, 본 테스트에서 5 kHz(100 µs 반주기)까지 안정적이면 기본 동작 마진은 충분한 편.

6. 문제 해결 체크리스트

  • D9→220Ω→PC900V Anode(+) / Cathode(−)→GND 배선 재확인
  • RL 값/배선 길이 확인(1k~2.2kΩ 권장)
  • GND 공통, 전원 5 V 안정성 확인
  • LCD 주소(0x27/0x3F) 확인 및 변경
  • (선택) 74HC14로 신호 정형 후 D2로 입력
nano_ardule_midi_controller/pc900v.txt · Last modified: by hyjeong