-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3f19d81
Showing
2 changed files
with
123 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# BK Precision 1696 | ||
|
||
This is a Python library for communicating with the [BK Precision 1696][psup] | ||
power supply via its serial interface. You can control the supply's parameters | ||
and take voltage/current readings. | ||
|
||
For example: | ||
|
||
import psup | ||
with psup.Supply() as sup: | ||
sup.voltage(1.3) | ||
volts, amps = sup.reading() | ||
print '%f V, %f A' % (volts, amps) | ||
|
||
For more details, see [my blog post][blog] about a setup using this library to | ||
measure the dynamic power of a smartphone. | ||
|
||
[psup]: http://www.bkprecision.com/products/model/1696/programmable-dc-power-supply-1-20vdc-0-999a.html | ||
[blog]: http://www.cs.washington.edu/homes/asampson/blog/powermeasurement.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from __future__ import division | ||
import serial | ||
import glob | ||
import time | ||
import decimal | ||
|
||
def _str2num(num, factor=10): | ||
"""Takes a number in the supply's format, which always has one | ||
decimal place, and returns a decimal number reflecting it. | ||
""" | ||
return decimal.Decimal(num) / factor | ||
def _num2str(s, length=3, factor=10): | ||
"""Turns a number, which may be a decimal, integer, or float, | ||
and turns it into a supply-formatted string. | ||
""" | ||
dec = decimal.Decimal(s) | ||
return ('%0' + str(length) + 'i') % int(dec * factor) | ||
def _numfields(s, fields, factor=10): | ||
"""Generates numbers of the given lengths in the string. | ||
""" | ||
pos = 0 | ||
for field in fields: | ||
yield _str2num(s[pos:pos+field], factor) | ||
pos += field | ||
|
||
class Supply(object): | ||
def __init__(self, ident=None): | ||
if not ident: | ||
# Discover a device. | ||
devices = glob.glob('/dev/tty.PL*') # Mac OS X | ||
devices += glob.glob('/dev/ttyUSB*') # Linux | ||
ident = devices[0] | ||
self.ser = serial.Serial(ident, 9600, 8, 'N', 1) | ||
|
||
def command(self, code, param='', address='00'): | ||
# Put this communication in an isolated little transaction. | ||
self.ser.flushInput() | ||
self.ser.flushOutput() | ||
|
||
self.ser.write(code + address + param + "\r") | ||
self.ser.flush() | ||
|
||
out = None | ||
while True: | ||
# Read until CR. | ||
resp = '' | ||
while True: | ||
char = self.ser.read() | ||
resp += char | ||
if char == '\r': | ||
break | ||
|
||
if resp == 'OK\r': | ||
return out | ||
|
||
if out is not None: | ||
print 'received more than one line of output without OK!' | ||
return resp | ||
|
||
out = resp | ||
|
||
def start(self): | ||
self.command('SESS') | ||
def close(self): | ||
self.command('ENDS') | ||
def voltage(self, volts): | ||
self.command('VOLT', _num2str(volts)) | ||
def reading(self): | ||
resp = self.command('GETD') | ||
volts, amps = _numfields(resp, (4, 4), 1) | ||
return volts/100, amps/1000 | ||
def maxima(self): | ||
resp = self.command('GMAX') | ||
return tuple(_numfields(resp, (3, 3))) | ||
def settings(self): | ||
resp = self.command('GETS') | ||
return tuple(_numfields(resp, (3, 3))) | ||
def enable(self): | ||
"""Enable output.""" | ||
self.command('SOUT', '1') | ||
def disable(self): | ||
"""Enable output.""" | ||
self.command('SOUT', '0') | ||
|
||
# Context manager. | ||
def __enter__(self): | ||
self.start() | ||
return self | ||
def __exit__(self, exc_type, exc_value, traceback): | ||
self.close() | ||
|
||
# Just some tests to show it's working. | ||
if __name__ == '__main__': | ||
with Supply() as sup: | ||
time.sleep(0.5) | ||
sup.voltage(1.3) | ||
sup.enable() | ||
time.sleep(0.5) | ||
print 'Reading', sup.reading() | ||
print 'Maxima', sup.maxima() | ||
print 'Settings', sup.settings() | ||
sup.disable() | ||
print 'Disabled; reading', sup.reading() | ||
time.sleep(0.5) |