Simple library for Keithley 2400 Source Measure Unit (SMU) control over RS-232/USB-serial
Project description
keithley2400
Simple, clean Python library for controlling the Keithley 2400 Source Measure Unit (SMU) over RS-232 / USB-serial.
Features
- Full V/I/R sourcing and measurement control via SCPI
- Pure-Python — no National Instruments VISA required
- Works natively on macOS (including Apple Silicon M1/M2/M3/M4), Linux, and Windows
- Statistical sampling with mean and standard deviation
- Generator-based voltage sweep (
sweep_iv) for IV curves - One-liner convenience function:
quick_iv_sweep() - Context manager support for safe resource cleanup
- Serial port discovery helper:
find_serial_port() - Automatic Keithley 2400 port discovery via
*IDN?probing whenresource=Noneor when a stale configured port fails
Installation
pip install keithley2400
Requirements
- Python 3.6+
pyvisa >= 1.11.0pyvisa-py >= 0.5.2pyserial >= 3.4
Hardware Setup
The Keithley 2400 communicates over RS-232 using a USB-serial adapter.
- Connect the USB-serial cable between the instrument's RS-232 port and your computer.
- Ensure the instrument's baud rate matches (factory default: 9600 baud, 8N1).
- Find your port:
from keithley2400 import find_serial_port
ports = find_serial_port()
# Example output: ['ASRL/dev/cu.usbserial-FTRTKC3X::INSTR']
Quick Start
1. Connect automatically (recommended)
from keithley2400 import Keithley2400
with Keithley2400(resource=None) as k: # auto-discovers by probing *IDN?
print(k.idn())
2. Find your serial port manually
from keithley2400 import find_serial_port
print(find_serial_port())
3. Run an IV Sweep (one-liner)
from keithley2400 import quick_iv_sweep
voltages = [v * 0.5 for v in range(0, 21)] # 0 to 10 V in 0.5 V steps
csv_file = quick_iv_sweep(
voltages=voltages,
out_csv="iv_curve.csv",
compliance_amps=0.01, # 10 mA current limit
stabilize_s=0.5, # wait 500 ms after each voltage step
n_samples=50, # average 50 readings per point
)
print(f"Saved: {csv_file}")
4. Full Manual Control
from keithley2400 import Keithley2400
# Using context manager (automatically turns output off and closes on exit)
with Keithley2400(resource="ASRL/dev/cu.usbserial-FTRTKC3X::INSTR") as k:
print(k.idn())
k.set_source_v(5.0)
k.set_current_compliance(0.01) # 10 mA limit
k.configure_measure_vi()
k.output_on()
v, i = k.read_v_i()
print(f"V={v:.4f} V I={i:.6e} A")
# Statistical sampling
stats = k.sample_stats(param="I", n=100, delay_s=0.01, stabilize_s=0.5)
print(f"I mean={stats['mean']:.6e} A stdev={stats['stdev']:.2e} A")
5. Resistance Measurement
from keithley2400 import Keithley2400
with Keithley2400() as k:
# 2-wire resistance
k.configure_measure_ohms(method="2W")
k.set_ohms_source_current(1e-3) # 1 mA test current
k.output_on()
r = k.read_r(mode="ohms")
print(f"R = {r:.2f} Ohm")
6. Custom IV Sweep with Generator
from keithley2400 import Keithley2400
import csv
voltages = [round(v * 0.1, 2) for v in range(0, 101)] # 0 to 10 V
with Keithley2400() as k:
k.output_on()
with open("iv_data.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["V_set", "I_mean_A", "I_stdev_A"])
for v, i_mean, i_stdev in k.sweep_iv(voltages, compliance_amps=0.05):
writer.writerow([v, i_mean, i_stdev])
print(f"V={v:.2f} I={i_mean:.4e} A")
API Reference
Keithley2400 Class
__init__(resource, backend="@py", settings=None)
Open connection to the instrument.
| Parameter | Type | Default | Description |
|---|---|---|---|
resource |
str or None | None |
PyVISA resource string. None or "auto" triggers auto-discovery by probing serial ports with *IDN?. |
backend |
str | "@py" |
PyVISA backend ("@py" = pyvisa-py, no NI-VISA needed) |
settings |
SerialSettings | None | RS-232 parameters (default: 9600 8N1) |
Output Control
| Method | Description |
|---|---|
output_on() |
Enable source output |
output_off() |
Disable source output |
Source Configuration
| Method | Description |
|---|---|
set_source_v(volts) |
Source a voltage |
set_source_i(amps) |
Source a current |
set_current_compliance(amps) |
Set current limit (when sourcing V) |
set_voltage_compliance(volts) |
Set voltage limit (when sourcing I) |
Measurement Configuration
| Method | Description |
|---|---|
configure_measure_vi(auto_range=True) |
Measure V and I simultaneously |
configure_measure_ohms(method="2W") |
Resistance measurement (2W or 4W) |
set_current_range(amps) |
Manual current measurement range |
Readings
| Method | Returns | Description |
|---|---|---|
read_v_i() |
(float, float) |
Voltage and current |
read_v() |
float |
Voltage only |
read_i() |
float |
Current only |
read_r(mode="calc") |
float |
Resistance (R=V/I or instrument ohms) |
Statistical Sampling
| Method | Returns | Description |
|---|---|---|
sample_stats(param, n=50, delay_s=0.01, stabilize_s=0.0) |
dict |
Mean and stdev over N readings |
Returns: {"mean": float, "stdev": float, "n": float}
IV Sweep
| Method | Returns | Description |
|---|---|---|
sweep_iv(voltages, ...) |
Iterator[(V, I_mean, I_stdev)] |
Voltage sweep generator |
Utilities
| Method | Returns | Description |
|---|---|---|
idn() |
str |
Instrument identification string |
get_error() |
str |
Error queue query |
close() |
— | Close VISA session |
SerialSettings Dataclass
| Field | Default | Description |
|---|---|---|
baud_rate |
9600 |
Communication speed |
data_bits |
8 |
Data bits per character |
parity |
none |
Parity check |
stop_bits |
one |
Stop bits |
terminator |
"\r" |
Line terminator (CR confirmed working) |
timeout_ms |
5000 |
Read timeout in milliseconds |
Convenience Functions
find_serial_port(backend="@py") -> list
List all detected USB-serial ports.
find_keithley_resource(backend="@py", settings=None, verbose=True) -> Optional[str]
Probe detected serial ports with *IDN? and return the first one that identifies as a Keithley 2400.
quick_iv_sweep(voltages, out_csv=None, resource=..., ...) -> Optional[str]
One-liner: connect → sweep → save CSV → disconnect. Returns the CSV path.
CSV Output Format
voltage_V,current_mean_A,current_stdev_A,n_samples
0.0,+1.234567e-09,2.345e-11,50
0.5,+5.678901e-09,3.456e-11,50
1.0,+1.234567e-08,4.567e-11,50
...
Notes
- Always call
output_off()beforeclose()(the context manager does this automatically) FORM:ELEM VOLT,CURRis set ininitialize()— this makesread_v_i()parsing deterministic- If you switch to
configure_measure_ohms(), FORM:ELEM changes to RES; callconfigure_measure_vi()again to switch back - If a configured serial port goes stale,
Keithley2400(..., auto_discover=True)will scan candidate serial ports and accept only one whose*IDN?response looks like a Keithley 2400 - The
@pybackend works without a NI-VISA installation — fully compatible with Apple Silicon
License
MIT License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keithley2400-0.1.1.tar.gz.
File metadata
- Download URL: keithley2400-0.1.1.tar.gz
- Upload date:
- Size: 11.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6dde8eff445fa10dd1e8ce7d2395608b01ee376d1b839857db0bdc3ed2e760e1
|
|
| MD5 |
cb156170d72ae31190a569452ba88401
|
|
| BLAKE2b-256 |
fd035d3c72ace042c89e44373a382a066b827d9c3f00122ab08d48cbf7dd5af4
|
File details
Details for the file keithley2400-0.1.1-py3-none-any.whl.
File metadata
- Download URL: keithley2400-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7f975591bff794fb82960dba6b1f2b8dc79da55fef0160189b9201cbbe07d16
|
|
| MD5 |
483fbacf63875941679f5555896d4f95
|
|
| BLAKE2b-256 |
e7343fd75f96f48dda6d6ccd2ea8c28e4434bc672ada166631fb9b84cc17b80c
|