5

I asked this question on the Engineering StackExchange and someone said it might be more appropriate here.


I want to interface an old Shimadzu spectrophotometer (Model UV-1601, manual here) through its RS-232C port, which is described in the manual in Fig. 12.2:

RS-232C cable for UV-1601 (IBM)

I want to use a USB Type C connection on my laptop, so I bought this adapter from StarTech, with the following pinout diagram:

RS-232 DB9 male pinout

Next, I used PySerial to try and communicate with the instrument. That's when things started to become difficult for me. The manual of the spectrophotometer gives the details of the serial transmission parameters:

Transmission parameters

The manual also describes an example protocol (although the code is in BASIC) to change the instrument wavelength:

Protocol

In this protocol:

  • ENQ is 05 in hexadecimal
  • ACK is 06 in hexadecimal
  • EOT is 04 in hexadecimal
  • NUL is 00 in hexadecimal
  • w, 6, and 0 are interpreted as ascii caracters (for example 'w' is 77 in hexadecimal

In Python, I have a short program that opens the serial communications:

import serial
device = serial.Serial(port='COM4', baudrate=9600, bytesize=serial.SEVENBITS, parity=serial.PARITY_ODD, stopbits=serial.STOPBITS_ONE, timeout=.1)

Then, I use this line to send the ENQ signal:

device.write(b'\x05')

Now here comes the trouble. If I try to read the ACK byte with:

device.read()

It returns an empty byte:

b''

If I try to send the rest of the command it won't work. If I send the ENQ, and straight after send the command:

device.write(b'\x77\x36\x30\x30\x30\x00')

I hear the device moving the slit to the new position, but the screen of the instrument isn't updated until I send an ACK signal. Also, I cannot send another command until I send that same ACK signal.

My main problem is that I can't output the instrument data.

I want to focus on this small example to make sure everything is right first.

The BASIC program described in the manual is as follows:

100 'UV-1601 PC Control Program
110 DIMBUF$(32)
120 ENQ $ =CHR $ (&H5) : EOT $ =CHR $ (&H4) : ESC $ =CHR $ (&H1B)
130 NUL $ =CHR $ (&H0) : ACK $ =CHR $ (&H6) : NAK $ =CHR $ (&H15)
140 '
150 ' GO TO A
160 OPEN "COM1: 071NN" AS#1
170 FOR 1=0 TO 99: NEXT
180 PRINT #1,ENQ $;
190 IF INPUT $ (1,#1)< >ACK $ THEN 170
200 FOR 1=0 TO 99: NEXT
210 PRINT #l,"w6000" +NUL$;
220 IF INPUT $ (1, #1)< >ACK $ THEN BEEP : PRINT #1, ESC $;: GOTO 250
230 IF INPUTS (1, #1)< >EOT$ THEN BEEP: PRINT#1, ESC $;: GOTO 250
240 PRINT #1, ACK $; -o
250 CLOSE #1 O
260 END 

Does anyone know why I can't seem to read the bytes from the instrument? Is it because of my RS-232C to USB C adapter, or is it related to PySerial?

EDIT: this is the cable I ended up making (this is the same wiring as suggested by @jonathanjo but with a female connector on the left-hand side to the USB adaptor and male connector on the right-hand side to the instrument)

enter image description here

With this cable, I could read the data from the spectro, but oddly enough, changing the wavelength still doesn't work as expected, but I guess I will live with that problem.

For those interested, this is a repository where I store my Python code for this instrument.

Thank you all :)

Omnistic
  • 53
  • 5
  • 2
    So what is the question? Just because it is an electronic device, it does not mean writing a Python program to communicate with it has anything to do with electronics, it's just usage of an electrical device and thus off-topic. Likely just how the device responds and when, so pyserial timing with the device is important. – Justme Apr 24 '23 at 14:02
  • 2
    OK, so have you made sure the pin 7 on device is ground, and have you built a custom cable that matches the pinout? – Justme Apr 24 '23 at 14:42
  • 1
    @jonathanjo The handshake links are irrelevant if you are making the PC program and choose to not use handshaking pins so you don't have to fake them. – Justme Apr 24 '23 at 15:05
  • @Justme pin 7 is not GND on a DB9 connector; pin 5 is GND. – Andy aka Apr 24 '23 at 15:06
  • @justme -- my mistake, I read the diagram wrongly, deleted my comments. – jonathanjo Apr 24 '23 at 15:18
  • @Andyaka Shimadzu has used multiple pinouts and checked from another source different products have used different pinouts, including pins #7 and #9 for GND. On this product, it could be that manual is correct and it really is pin #7, as the connector gender won't match direct M/F cable connection or F/F null modem cable connection to a standard PC. It just says the interface is a standard RS-232C, and that does not define a 9-pin connector, so the product does not have to use same pinout as PC. – Justme Apr 24 '23 at 18:09

1 Answers1

5

Note that your device has non-standard wiring, as pointed out in comments, and in particular the signal ground. You'll have to ensure you have the three wires connected between your device and your PC as shown. The connections inside the PC connector (DTR to DSR and CTS to DTS) are optional and ideally should omitted if you ensure your program doesn't require them.)

At least one problem, the empty bstring, is caused by the timeout in your open call:

import serial
device = serial.Serial(port='COM4',
    baudrate=9600,
    bytesize=serial.SEVENBITS,
    parity=serial.PARITY_ODD,
    stopbits=serial.STOPBITS_ONE,
    timeout=.1)

The 0.1 second timeout is evidently shorter than needed, and so read returns an empty string. You could just try making it longer, or putting a loop around.

From the manual for the serial module:

read(size=1)

  • Parameters: size – Number of bytes to read.
  • Returns: Bytes read from the port.
  • Return type: bytes

Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read.

You'll need to have some kind of polling or much longer timeouts in order to get your data. You might find, with a slow-responding mechanical machine, that you can just put appropriate delays in various places.

You might also have some need of flush to ensure the bytes are sent.


Edit: The following is the minimal cabling requirement as I understand it, and you need to make a little adaptor from two D-type 9-way sockets.

enter image description here

jonathanjo
  • 12,049
  • 3
  • 27
  • 60
  • Thank you for your answer. I will try the timeout asap. However, regarding the wiring. I think I misunderstood something. Are DTR, GND, and DSR all connected together? Or is it DTR and DSR together only (and the wire goes over the GND wire)? – Omnistic Apr 25 '23 at 10:47
  • @Omnistic I'll draw what I think is correct. – jonathanjo Apr 25 '23 at 11:05
  • @Omnistic "Are DTR, GND, and DSR all connected together?" **No** "Or is it DTR and DSR together only (and the wire goes over the GND wire)" **YES**. – jonathanjo Apr 25 '23 at 11:49
  • jonathanjo one more question, when you say "omit" you mean I don't need to do this connection? Or is "omit" referring to a connection onto the same connector? – Omnistic Apr 25 '23 at 20:41
  • "omit"="do not connect". You only need three wires, drawn red, green, grey. – jonathanjo Apr 25 '23 at 21:40
  • Increased timeout to 5. Didn't improve the situation. Made the cable but on the spectro the connector is female. So, I made a male and female one (I have a picture if someone needs). Then, I could read the bytes. There's still a minor problem. The example still doesn't work. After I send ENQ, I read ACK and ESC, and when I change the wavelength it doesn't work. If I send ENQ and change the wavelength without reading its ok. Reading data from the spectro works now (second example in manual)! We can say I'm sorted. But still curious why it does that. Any idea? Thanks a lot for your help. – Omnistic Apr 26 '23 at 16:16
  • Yes, can I see the picture of your adaptor? (I really couldn't see whether the connector on the back of the was male or female.) – jonathanjo Apr 26 '23 at 16:18
  • I've edited my post with a picture of the connector, thanks a lot for your help again :) – Omnistic May 15 '23 at 13:28