#%TITLE% par263.mac $Revision: 1.8 $
#%NAME%
# Princeton Applied Research Potentiostat/Galvanostat model 263A and
# model VersaStatII 2532
#%DESCRIPTION%
#%SETUP%
#%END%
#
#%HISTORY%
#$Log: par263.mac,v $
#Revision 1.8 2017/04/28 14:51:25 ohlsson
#Mostly refactoring and making sure the 1.8 is the new version for BM08
#
#Revision 1.7 2016/07/05 14:09:02 witsch
#Francesco Carla`s additions.
#
#Revision 1.6 2016/07/01 11:51:29 witsch
#Allow to use two optional counters for potential and instantaneous current.
#some formatting.
#
#Revision 1.5 2012/05/14 15:03:17 claustre
#added blmenu, better hwd handchecking at setup, pct macro
#
#Revision 1.4 2011/10/10 12:34:31 claustre
#Just removed a debug print in _par263_waitcurve()
#
#Revision 1.3 2011/08/30 15:02:44 claustre
#New version copied from ID32 and ID03
#
#Revision 1.1 2006/03/14 08:41:28 perez
#Add vertex support to initial revison done by EP
#
#
#%END%
global PAR263_MODE[]
global PAR263_ESET
global PAR263_PAR[]
PAR263_MODE["0"]= "Unknown"
PAR263_MODE["1"]= "Galvanostat"
PAR263_MODE["2"]= "Potentiostat"
#%IU% (msg, err)
def _par263_print(msg, err) '{
tty_cntl("md")
printf("PAR263 %s> ", err?"ERROR":"")
tty_cntl("me")
print msg
}'
#%UU% <gpib_addr> <potential_mne> <current_cnt>
#%MDESC% Global setup. The potential unit will be mV and the current unit
# will be A (use the scale factor in config to change the sign and the scale)
#
def par263setup '{
global PAR263_ADDR
global PAR263_ANS
global PAR263_EMOT
global PAR263_ICNT
global PAR263_ECNT
global PAR263_PCNT
global PAR263_IICNT
global PAR263_TMB
local st
if ( "$#" < 3 ) {
print "$0 <gpib_addr> <potential_mot_mne> <current_cnt_mne> [<potenial_cnt_mne> <instantaneous_current_cnt_mne>]"
exit
}
PAR263_ADDR= "$1"
PAR263_EMOT= "$2"
PAR263_ICNT= "$3"
PAR263_PCNT= "$4"
PAR263_IICNT= "$5"
st= 0
# --- check device on gpib
st= _par263_checkid()
if (!st) {
_par263_print(sprintf("No PAR 263A controller at address <%s>", PAR263_ADDR), 1)
return
} else {
_par263_print(sprintf("Using controller at address <%s>", PAR263_ADDR))
}
# --- set Data Delimiter charater used to parse answers
if (st) {
st= _par263_write("DD 44")
if (!st) _par263_print("Cannot set data delimiter", 1)
}
# --- set potentiostat mode
if (st) {
st= _par263_write("MODE 2")
if (!st) _par263_print("Cannot set mode to potentiostat", 1)
}
# --- check pseudos
if (st && motor_num(PAR263_EMOT)==-1) {
_par263_print(sprintf("<%s> is not a motor", PAR263_EMOT))
st= 0
}
if (st && cnt_num(PAR263_ICNT)==-1) {
_par263_print(sprintf("<%s> is not a counter", PAR263_ICNT))
st= 0
}
PAR263_PAR["setup"] = (st)?1:0
PAR263_PAR["autorange"]=0
# --- default timebase
if (whatis("PAR263_TMB") & 0x8000000) {
PAR263_TMB= 50000
}
blmenuadd("PAR263 Potentiostat control","","par263_body","_par263_")
par263on
setup_tail("par263")
}'
#%UU%
#%MDESC
# count with autorange on
def pct '{
PAR263_PAR["autorange"]=1
cdef("cleanup_once", "PAR263_PAR[\"autorange\"]=0;","par263")
ct $*
PAR263_PAR["autorange"]=0
}'
#%IU%
#%MDESC% body macro for blmenu
def par263_body(mode) '{
if (mode == 1) {
if (PAR263_PAR["on"]) par263off
else par263on
}
return ((PAR263_PAR["on"])?"On":"Off")
}'
#%UU%
#%MDESC%
def par263unsetup '{
par263off
}'
#%UU%
#%MDESC% Activates pseudo motor/counters
def par263on '{
# check if the setup is done
if (PAR263_PAR["setup"]) {
cdef("user_checkall", "_par263_checkall;", PAR263_EMOT, 0x01)
cdef("user_getpangles", "_par263_getpangles;", PAR263_EMOT, 0x01)
cdef("user_prepcount", "_par263_prepcount;", PAR263_ICNT, 0x02)
cdef("user_getcounts", "_par263_getIcounts;", PAR263_ICNT, 0x02)
cdef("user_getcounts", "_par263_getPcounts;", PAR263_PCNT, 0x02)
cdef("user_getcounts", "_par263_getinstantaneousIcounts;", PAR263_IICNT, 0x02)
cdef("user_countersrun","if (_par263_waitcurve()) return (1);", PAR263_ICNT, 0x02)
} else {
_par263_print("par263 not setup properly, called first par263setup !!", 1)
par263off
exit
}
PAR263_PAR["on"] = 1
}'
#%UU%
#%MDESC% De-activates pseudo motor/counters
def par263off '{
cdef("", "", PAR263_EMOT, "delete")
cdef("", "", PAR263_ICNT, "delete")
PAR263_PAR["on"] = 0
}'
#%UU% [<time_in_sec>]
#%MDESC% Test curve acquisition
def par263acq '{
local tps __s[] __n
__s[0]= "|\r"; __s[1]= "/\r"; __s[2]= "-\r"; __s[3]= "\\\r"
__n= 0
tps= $1?$1:1
_par263_print(sprintf("Starting curve for %.2f sec", tps))
if (!_par263_startcurve(tps)) {
_par263_print("Cannot start curve")
exit
}
_par263_print("Waiting curve to finish")
while (_par263_waitcurve()) {
printf(__s[__n++%4])
sleep(0.1)
}
_par263_print("Reading curve")
if (!_par263_readcurve()) {
_par263_print("Cannot read curve")
exit
}
print
par263report
}'
#%IU% (acquisition_time)
#%MDESC% Start curve acquisition
def _par263_startcurve(tps) '{
global PAR263_READ[]
global PAR263_RUN
local _np
PAR263_RUN= 0
# Set auto range on I and E (needed on VersaStatII because there is
# no front panel switch for that)
if (PAR263_PAR["autorange"]) {
if (!_par263_write("AR 3")) return (0)
#if (!_par263_write("AR 2")) return (0)
#if (!_par263_write("I/E -6")) return (0)
}
if (!_par263_write("FLT 1")) return (0)
if (!_par263_write(sprintf("TMB %d", PAR263_TMB))) return (0)
PAR263_READ["tmb"]= PAR263_TMB
_np= int(tps*1000000 / PAR263_READ["tmb"])
if (!_par263_write(sprintf("LP %d", _np))) return (0)
PAR263_READ["np"]= _np
if (!_par263_io("LP")) return (0)
if (PAR263_ANS!=_np) return (0)
sleep (0.1)
if (!_par263_write("NC")) return (0)
if (!_par263_write("TC")) return (0)
cdef("cleanup_once", "_par263_cleanup;", "_p263_")
PAR263_RUN= 1
return (1)
}'
#%IU% ()
#%MDESC% Return 1 if curve still in acquisition
def _par263_waitcurve() '{
local _ns _as _st
if (!_par263_io("MON")) {
_par263_print("Cannot get curve acquisition status", 1)
return (0)
}
else {
_ns= split(PAR263_ANS, _as, ",")
_st= int(_as[0])
PAR263_READ["lp"]= int(_as[2])
PAR263_RUN= _st
_par263_io(sprintf("DP %d",PAR263_READ["lp"]),0.1)
return (_st)
}
}'
#%IU% ()
#%MDESC% Stop a curve acquisition
def _par263_stopcurve() '{
if (!_par263_write("HC")) return (0)
if (!_par263_write("NC")) return (0)
PAR263_RUN= 0
return (1)
}'
#%IU% ()
#%MDESC% Read curve minimum, maximum, integral
def _par263_readcurve() '{
local _ns _as
if (!_par263_io("IMIN", 0.05)) return (0)
_ns= split(PAR263_ANS, _as, ",")
PAR263_READ["imin"]= int(_as[0])
PAR263_READ["vmin"]= int(_as[1]) * pow(10, int(_as[2]))
if (!_par263_io("IMAX", 0.05)) return (0)
_ns= split(PAR263_ANS, _as, ",")
PAR263_READ["imax"]= int(_as[0])
PAR263_READ["vmax"]= int(_as[1]) * pow(10, int(_as[2]))
if (!_par263_io("IINT", 0.05)) return (0)
_ns= split(PAR263_ANS, _as, ",")
PAR263_READ["int"]= int(_as[0]) * pow(10, int(_as[1]))
if (PAR263_READ["lp"])
PAR263_READ["avg"]= PAR263_READ["int"]/PAR263_READ["lp"]
else PAR263_READ["avg"]= 0.
return (1)
}'
#%UU%
#%MDESC% Report information on last curve acquired
def par263report '{
tty_cntl("md"); printf("Curve Parameters:\n"); tty_cntl("me")
printf(" - TimeBase = %d\n", PAR263_READ["tmb"])
printf(" - PointsRequested = %d\n", PAR263_READ["np"])
printf(" - PointsRead = %d\n", PAR263_READ["lp"])
tty_cntl("md"); printf("Curve results:\n"); tty_cntl("me")
printf(" - MINIMUM = %g (at point %d)\n",PAR263_READ["vmin"], PAR263_READ["imin"])
printf(" - MAXIMUM = %g (at point %d)\n",PAR263_READ["vmax"], PAR263_READ["imax"])
printf(" - INTEGRAL= %g\n", PAR263_READ["int"])
printf(" - AVERAGE = %g\n", PAR263_READ["avg"])
}'
#%UU% [<mode>]
#%MDESC% Without <mode>, report the current controller mode
#%BR% With <mode> specified, change the mode
#%BR% Possible modes are:
#%BR% (1) Galvanostat
#%BR% (2) Potentiostat
def par263mode '{
if (!$#) {
if (_par263_io("MODE")) {
_par263_print(sprintf("Mode is %s", PAR263_MODE[PAR263_ANS]))
}
}
else {
mode= int($1)
if (mode!=1 && mode!=2) {
print "PAR263 Modes can be:"
print "1- "PAR263_MODE[1]
print "2- "PAR263_MODE[2]
}
else {
_par263_write(sprintf("MODE %d", mode))
if (_par263_io("MODE")) {
_par263_print(sprintf("Mode is %s", PAR263_MODE[PAR263_ANS]))
}
}
}
}'
#%UU%
#%MDESC% Read 10 I samples and return average
def par263readI '{
local _ns _as _v
if (_par263_io("READI")) {
_ns= split(PAR263_ANS, _as, ",")
if (_ns!=2) {
_par263_print("Got wrong answer from controller", 1)
_par263_print(PAR263_ANS, 1)
}
else {
_v= _as[0] * pow(10, _as[1])
_par263_print(sprintf("Current = %g A", _v))
}
}
}'
#%UU%
#%MDESC% Read 10 E samples and return average
def par263readE '{
local _v
if (_par263_io("READE")) {
_v= int(PAR263_ANS)
_par263_print(sprintf("Potential = %g mV", _v))
}
}'
#%UU% [<set_potential>]
#%MDESC% Read/Write set potential (unit=mV)
def par263setE '{
local _v
if ($#!=1) {
if (_par263_io("SETE")) {
_par263_print(sprintf("Set Potential = %d mV", PAR263_ANS))
}
}
else {
_v= int($1)
if ((_v<-10000)||(_v>10000)) {
_par263_print("Range is -10000..10000 mV", 1)
}
else {
_par263_write(sprintf("SETE %d", _v))
}
}
}'
#%IU%
def _par263_checkall '{
if ((PAR263_ESET!=-99999) && \
(A[motor_num(PAR263_EMOT)]!=PAR263_ESET)) {
if (!_par263_write(sprintf("SETE %d", A[motor_num(PAR263_EMOT)])))
_par263_print("Cannot set potential", 1)
}
}'
#%IU%
def _par263_getpangles '{
if (_par263_io("SETE")) {
PAR263_ESET= int(PAR263_ANS)
A[motor_num(PAR263_EMOT)]= PAR263_ESET
}
else {
PAR263_ESET= -99999
}
}'
#%IU%
def _par263_getEcounts '{
local _v
if (_par263_io("READE")) {
_v= int(PAR263_ANS)
S[cnt_num(PAR263_ECNT)]= _v
}
else {
S[cnt_num(PAR263_ECNT)]= -9999
}
}'
#%IU%
def _par263_getPcounts '{
local _v
if (_par263_io("READE")) {
_v= int(PAR263_ANS)
S[cnt_num(PAR263_PCNT)]= _v
}
else {
S[cnt_num(PAR263_PCNT)]= -9999
}
}'
#%IU%
def _par263_getinstantaneousIcounts '{
local _v
if (_par263_io("READI")) {
local _ns _as _v
_ns= split(PAR263_ANS, _as, ",")
if (_ns!=2) {
_par263_print("Got wrong answer from controller", 1)
_par263_print(PAR263_ANS, 1)
}
else {
_v= _as[0] * pow(10, _as[1])
_par263_print(sprintf("Current = %g A", _v))
}
S[cnt_num(PAR263_IICNT)]= _v
}
else {
S[cnt_num(PAR263_IICNT)]= -9999
}
}'
#%IU%
def _par263_getIcounts '{
S[cnt_num(PAR263_ICNT)]= 0.
if (!PAR263_RUN) {
if (!_par263_readcurve())
_par263_print("Cannot read curve")
else S[cnt_num(PAR263_ICNT)]= PAR263_READ["avg"]*counter_par(cnt_num(PAR263_ICNT),"scale")
}
}'
#%IU%
def _par263_prepcount '{
global PAR263_RUN
PAR263_RUN= 0
if (!_par263_startcurve(COUNT_TIME))
_par263_print("Cannot start curve acquisition", 1)
else PAR263_RUN= 1
}'
#%IU%
def _par263_cleanup '{
if (!_par263_stopcurve())
_par263_print("Cannot stop curve acquisition", 1)
else _par263_print("Curve acquisition stopped")
}'
#%UU%
#%MDESC% Reset default controller parameters
def par263reset '{
gpib_cntl(PAR263_ADDR, "sdc")
}'
#%UU%
#%MDESC% Report error status on last command executed
def par263error '{
if (_par263_io("ERR")) {
if (PAR263_ANS)
_par263_print(sprintf("ERROR CODE = %d", PAR263_PAR))
else _par263_print("NO ERROR")
}
}'
#%UU% [<0|1>]
#%MDESC% Without argument: report cell status
#%BR% With argument: 0= set cell OFF
#%BR% 1= set cell ON
def par263cell '{
local _v
if ($#!=1) {
if (_par263_io("CELL")) {
_par263_print(sprintf("Cell Status = %s", PAR263_ANS==1?"ON":"OFF"))
}
}
else {
_v= int($1)
if (_v!=0 && _v!=1) {
_par263_print("Parameter should be 0 (OFF) or 1 (ON)", 1)
}
else {
_par263_write(sprintf("CELL %d", _v))
}
}
}'
#%UU% [<0|1>]
#%MDESC% Without argument, report dummy cell status
#%BR% With argument: 0= set dummy cell OFF
#%BR% 1= set dummy cell ON
def par263dummy '{
local _v
if ($#!=1) {
if (_par263_io("DUMMY")) {
_par263_print(sprintf("Dummy Cell = %s", PAR263_ANS==1?"ON":"OFF"))
}
}
else {
_v= int($1)
if (_v!=0 && _v!=1) {
_par263_print("Parameter should be 0 (OFF) or 1 (ON)", 1)
}
else {
_par263_write(sprintf("CELL %d", _v))
}
}
}'
#%IU% ()
def _par263_checkid() '{
gpib_par(PAR263_ADDR,"timeout", 20)
if (_par263_io("ID")) {
if ((PAR263_ANS=="2631") || (PAR263_ANS=="2532")) {
# for huge cycle with too many data to read the controller
# takes a while to return the data (e.g. 2000 pts takes
# 4sec.)
return (1)
}
}
return (0)
}'
#%IU% (cmd)
def _par263_write(cmd) '{
if (!gpib_put(PAR263_ADDR, cmd)) {
_par263_print(sprintf("cannot send <%s> on GPIB", cmd), 1)
return (0)
}
sleep(0.1)
return (1)
}'
#%IU% (cmd)
def _par263_io(cmd, slp) '{
if (_par263_write(cmd)) {
if (slp) sleep(slp)
return _par263_read(cmd)
}
else return (0)
}'
#%IU% ()
def _par263_read() '{
PAR263_ANS= gpib_get(PAR263_ADDR)
if (!length(PAR263_ANS)) {
_par263_print("no answer from controller", 1)
return (0)
}
return (1)
}'
#%UU%
#%MDESC% Interactive session
def par263talk '{
local ans cmd act
_par263_talkusage
while (1) {
ans= input("PAR263> ")
ans= __upper(ans)
act= substr(ans, 0, 1)
cmd= substr(ans, 3)
if (act=="W") {
_par263_write(cmd)
}
else if (act=="R") {
if (length(cmd)>1) {
_par263_write(cmd)
sleep(0.1)
}
_par263_read()
printf("PAR263> ")
tty_cntl("md"); print PAR263_ANS; tty_cntl("me")
}
else if (act=="Q") {
break
}
else {
_par263_talkusage
}
}
}'
def _par263_talkusage '{
print "USAGE: w <cmd> <pars> => Send <cmd> with all arguments <pars>"
print " r => Read answer"
print " r <cmd> <pars> => Send <cmd> and read answer"
print " q => Quit talk session"
print
}'
def __upper(str) '{
local _i _c _r
_r= ""
for (_i=1; _i<=length(str); _i++) {
_c= asc(substr(str, _i, 1))
_r= _r sprintf("%c", (_c>=0x60)?_c-0x20:_c)
}
return (_r)
}'
#%UU% init_pot down_pot up_pot slope ppsec
#%MDESC% Generate a single vertex from init_pot to down_pot, then up to
# up_pot and finally down to init_pot. All the potentials are in mV.
# The slope will be given in mV/sec. The parameter ppsec is the number
# of points per second
#
def par263vertex '{
local init_pot up_pot down_pot slope ppsec
local init_dac up_dac down_dac tmb
local mr mr_cmd cmd
local n1 n2 n3 points
if($# < 5) {
p "Usage: $0 init_pot down_pot up_pot slope ppsec [spp]"
p " potentials are in mV"
p " slope in mV/second"
p " spp stands for sample per point (NO EVERAGING)"
exit
}
# Set MODULATION RESOLUTION to 2.5muV per count
# mr = 0.0025 ; mr_cmd = 0
# Set MODULATION RESOLUTION to 25muV per count
# mr = 0.025 ; mr_cmd = 1
# Set MODULATION RESOLUTION to 250muV per count
mr = 0.250 ; mr_cmd = 2
init_pot = $1
down_pot = $2
up_pot = $3
slope = $4
ppsec = $5
spp = 1
if($#>5) { spp = $6 }
init_dac = int(init_pot/mr)
down_dac = int(down_pot/mr)
up_dac = int(up_pot/mr)
tmb = int(1000000/(ppsec*spp))
if((init_dac>8000) || (init_dac<-8000)) {
_par263_print( \
sprintf("init_dac %dmV out of range +/-%dmV",init_pot,8000*mr), 1)
exit
}
if((up_dac>8000) || (up_dac<-8000)) {
_par263_print(
sprintf("up_dac %dmV out of range +/-%dmV", up_pot, 8000 * mr), 1)
exit
}
if((down_dac>8000) || (down_dac<-8000)) {
_par263_print( \
sprintf("down_dac %dmV out of range +/-%dmV",down_pot,8000*mr), 1)
exit
}
if((slope>200) || (slope<1)) {
_par263_print(sprintf("slope %dmV/s out of range [1,200]",slope), 1)
exit
}
if((tmb>50000) || (tmb<400)) {
_par263_print(sprintf("ppsec %d out of range [20,2500]",ppsec), 1)
exit
}
# calculate the number of points of each slope
n1=int(fabs(down_pot - init_pot)*(ppsec/spp)/slope)
n2=int(fabs(up_pot - down_pot)*(ppsec/spp)/slope) + n1
n3=int(fabs(up_pot - init_pot)*(ppsec/spp)/slope) + n2
# arbitrary the number of points is fixed to 1020 but the program
# and this value may be adapted to slope implementation
points=n3
if(points>=3072) {
_par263_print( \
sprintf("too many points, decrease ppsec or increase slope",ppsec), 1)
_par263_print(sprintf("n1=%d n2=%d n3=%d\n",n1,n2,n3), 1)
exit
}
#
# Program coming from F.RENNER and tested with the DOS program
#
_par263_print(sprintf("Starting curve"))
# ??
_par263_write("27")
_par263_write("DCL")
_par263_write("FLT 65")
# Record I and E
_par263_write("SIE 3")
# Auto range off for I and E
_par263_write("AR 0")
# The destination CURVE is the 1st one
_par263_write("DCV 0")
_par263_write("PAM 0")
cmd=sprintf("S/P %d",spp)
_par263_print(cmd)
_par263_write(cmd)
# Ramp modulation on (INITIAL and VERTEX unit is in count and use need MR)
_par263_write("MM 1")
_par263_write("INTRP 1")
# Set CURRENT TO VOLTAGE CONVERTER to 1uA
_par263_write("I/E -6")
# Set MODULATION RESOLUTION to 250muV per count
cmd=sprintf("MR %d",mr_cmd)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("TMB %d",tmb)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("LP %d",points)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("INITIAL 0 %d",init_dac)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("VERTEX %d %d",n1,down_dac)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("VERTEX %d %d",n2,up_dac)
_par263_print(cmd)
_par263_write(cmd)
cmd=sprintf("VERTEX %d %d",n3,int_dac)
_par263_print(cmd)
_par263_write(cmd)
_par263_write("NC")
# Switch on the E on the CELL
_par263_write("CELL 1")
# Take curve i.e. starts producing E VERTEX
_par263_write("TC")
# Wait for the end of TC i.e. commands not treated
_par263_print("Waiting curve to finish")
while (_par263_waitcurve()) {
printf("Currently accessed point: %d\r",PAR263_READ["lp"])
sleep(0.1)
}
printf("Currently accessed point: %d\n",PAR263_READ["lp"])
# Switch off the E on the CELL
_par263_write("CELL 0")
# Display the I/E
_par263_print("Reading curves")
_par263vertex_plot(points)
}'
#
#%IU%
#%MDESC% Get from the VERSASTAT the contains of its CURVE buffers and plot them
# This macro expect I in the CURVE_0 and E in CURVE_1
#
def _par263vertex_plot(n) '{
local short array x[n]
local short array y[n]
local short array dat[2][n]
local f
local n_curve n_rd
if(n>3071) {
_par263_print(sprintf("%d higher than max 1024 allowed points",n), 1)
exit
}
# Get I values (i.e. y axis)
_par263_write(sprintf("BD 0 %d",n))
n_rd = gpib_get(PAR263_ADDR,dat[1])
if(n != n_rd) _par263_print("Error reading I values", 1);
# Get U values (i.e. x axis)
n_curve=1024*(int((n)/1024)+1)
_par263_write(sprintf("BD %d %d",n_curve,n))
n_rd = gpib_get(PAR263_ADDR,dat[0])
if(n != n_rd) _par263_print("Error reading U values", 1);
#
array_op("swap",dat)
# init plotting device
plot_cntl("filter1,open")
plot_cntl("erase")
plot_cntl("lines")
plot_range("auto","auto","auto","auto")
plot_move(0,0,sprintf("VERSASTAT I/E %d points",n))
array_plot(dat[0][1:n-1],dat[1][1:n-1])
f=getval("File name to dump I/E","voltagram.dat")
unix(sprintf("/bin/rm -f %s", f))
on(f);offt
print("#################################################\n# " date())
print("# I U")
array_dump(dat)
print("\n\n\n\n")
off(f);ont
close(f)
}'
################################################
### GALVANOSTAT MACROS (francesco 07/03/2013)###
################################################
###################################
# this macro is setting the current
def par263setI '{
local gal_cur1 galvcurr gal_ran
# added to avoid running command in the wrong mode
(_par263_io("MODE"))
if(PAR263_ANS==2) {_par263_print(sprintf("Wrong mode! command can not be executed, Mode is %s", PAR263_MODE[PAR263_ANS]))
return (0)
}
if($# != 1) {
p " Usage: set current in muA"
p " Maximum current: 100mA"
exit
}
gal_cur1 = $1
if((fabs(gal_cur1)>=0.02)) {gal_ran=-10;galvcurr=(gal_cur1*10000)}
if((fabs(gal_cur1)>=.2)) {gal_ran=-9; galvcurr=(gal_cur1*1000)}
if((fabs(gal_cur1)>=2)) {gal_ran=-8; galvcurr=(gal_cur1*100)}
if((fabs(gal_cur1)>=20)) {gal_ran=-7; galvcurr=(gal_cur1*10)}
if((fabs(gal_cur1)>=200)) {gal_ran=-6; galvcurr=(gal_cur1*1)}
if((fabs(gal_cur1)>=2000)) { gal_ran=-5; galvcurr=(gal_cur1*0.1)}
if((fabs(gal_cur1)>=20000)) {gal_ran=-4; galvcurr=(gal_cur1*0.01)}
if((fabs(gal_cur1)>=200000)) {p "maximum current 100mA"; exit}
cmd=sprintf("SETI %d %d",galvcurr,gal_ran)
_par263_write(cmd)
p cmd
}'
######################################
# this macro is for galvanostat setup
#%UU% <gpib_addr> <potential_cnt> <current_cnt>
#%MDESC% Global setup. The potential unit will be mV and the current unit
# will be mA (use the scale factor in config to change the sign and the scale)
#
def par263gsetup '{
global PAR263_ADDR
global PAR263_ANS
# global PAR263_EMOT
global PAR263_ICNT
global PAR263_ECNT
global PAR263_TMB
local st
if ($#!=3) {
print "$0 <gpib_addr> <current_cnt_mne> <potential_cnt_mne>"
exit
}
PAR263_ADDR= "$1"
PAR263_ICNT= "$2"
PAR263_ECNT= "$3"
st= 0
# --- check device on gpib
st= _par263_checkid()
if (!st)
_par263_print(sprintf("No PAR 263A controller at address <%s>", PAR263_ADDR), 1)
else _par263_print(sprintf("Using controller at address <%s>", PAR263_ADDR))
# --- set Data Delimiter charater used to parse answers
if (st) {
st= _par263_write("DD 44")
if (!st) _par263_print("Cannot set data delimiter", 1)
}
# --- set galvanostat mode
if (st) {
st= _par263_write("MODE 1")
if (!st) _par263_print("Cannot set mode to galvanostat", 1)
}
# --- check pseudos
# if (st && motor_num(PAR263_EMOT)==-1) {
# _par263_print(sprintf("<%s> is not a motor", PAR263_EMOT))
# st= 0
# }
if (st && cnt_num(PAR263_ICNT)==-1) {
_par263_print(sprintf("<%s> is not a counter", PAR263_ICNT))
st= 0
}
if (st && cnt_num(PAR263_ECNT)==-1) {
_par263_print(sprintf("<%s> is not a counter", PAR263_ECNT))
st= 0
}
PAR263_PAR["setup"] = (st)?1:0
PAR263_PAR["autorange"]=0
# --- default timebase
if (whatis("PAR263_TMB") & 0x8000000) {
PAR263_TMB= 50000
}
# blmenuadd("PAR263 Potentiostat control","","par263_body","_par263_")
par263gon
setup_tail("par263")
}'
#######################################
# added by francesco 07/03/2013
# activating pseudomotors/counters for galvanostat session. defines ECNT and ICNT
#%UU%
#%MDESC% Activates pseudo motor/counters
def par263gon '{
# check if the setup is done
if (PAR263_PAR["setup"]) {
cdef("user_prepcount", "_par263_prepcount;", PAR263_ICNT, 0x02)
cdef("user_getcounts", "_par263_getIcounts;", PAR263_ICNT, 0x02)
cdef("user_prepcount", "_par263_prepcount;", PAR263_ECNT, 0x02)
cdef("user_getcounts", "_par263_getEcounts;", PAR263_ECNT, 0x02)
cdef("user_countersrun", "if (_par263_waitcurve()) return (1);", PAR263_ICNT, 0x02)
cdef("user_countersrun", "if (_par263_waitcurve()) return (1);", PAR263_ECNT, 0x02)
} else {
_par263_print("par263 not setup properly, called first par263setup !!", 1)
par263off
exit
}
PAR263_PAR["on"] = 1
}'
########################################
# added by francesco 07/03/2013
# de-activating pseudomotors/counters for galvanostat session. defines ECNT and ICNT
# TO BE REMOVED: if executed after par263on erase the setup for galvanostat, use enable and disable instead.
#%UU%
#%MDESC% De-activates pseudo motor/counters in galvanostat
#def par263goff '{
# cdef("", "", PAR263_ECNT, "delete")
# cdef("", "", PAR263_ICNT, "delete")
# PAR263_PAR["on"] = 0
#}'
########################################
#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% E.Papillon
|