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는 샤프(SHARP, 현재는 Vishay 등에 승계)에서 나온 포토커플러로, 포토트랜지스터 출력이며 약 80–100 kbps 정도의 응답 속도를 가집니다. MIDI IN과 같은 31.25 kbps 신호에서는 충분히 동작하지만, 단종/구하기 어려운 경우가 있어 대체품을 찾게 됩니다.
→ PC900과 동일한 4핀 DIP 패키지, CTR 범위 유사.
→ 흔한 범용 포토커플러, 속도는 MIDI용으로 충분.
→ 국내외 유통량이 많음. CTR 넓고 속도는 약 50 kHz 수준으로 MIDI에 사용 가능.
아두이노 우노(UNO)로 PC900V(포토트랜지스터형 옵토커플러)를 단품 점검하고, 측정 결과를 I2C 20×4 LCD(2004)에 표시하는 예제입니다. Phase1(저속 ON/OFF 논리 확인)과 Phase2(1 kHz/5 kHz 토글 응답 통계)를 지원합니다.
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
테스트 결과를 LCD에 표시하려면 아래처럼 I2C LCD를 추가하세요. (주소 0x27 또는 0x3F)
UNO A4 (SDA) -------------------- LCD SDA UNO A5 (SCL) -------------------- LCD SCL UNO +5V ------------------------- LCD VCC UNO GND ------------------------- LCD GND
// 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); }