简体   繁体   English

带有自动RTS的Python PySerial通过使用Beaglebone Black Angstrom的半双工RS-485分线板

[英]Python PySerial with Auto RTS through Half-Duplex RS-485 breakout board using Beaglebone Black Angstrom

I'm trying to use a Beaglebone Black running Angstrom (3.8 kernel) to communicate with devices on a half-duplex RS-485 network at 9600-N-8-1. 我正在尝试使用运行Angstrom(3.8内核)的Beaglebone Black与9600-N-8-1的半双工RS-485网络上的设备进行通信。

I'm trying to use an RS-485 Breakout board similar to this one: https://www.sparkfun.com/products/10124 , except the chip is a MAX3485 http://www.maximintegrated.com/datasheet/index.mvp/id/1079 . 我正在尝试使用与此类似的RS-485分线板: https ://www.sparkfun.com/products/10124,除了芯片是MAX3485 http://www.maximintegrated.com/datasheet/index .mvp / id / 1079 I bought the board pre-assembled with pins and a terminal strip. 我买了预装有针脚和端子条的电路板。 A friend of mine tested it with an oscilloscope and declared that the RS-485 board does work. 我的一位朋友用示波器对其进行了测试,并宣称RS-485板可以正常工作。 The board has five pins that connect to the BBB. 该板有五个引脚连接到BBB。 3-5V (Power), RX-I, TX-O, RTS, and GND. 3-5V(电源),RX-I,TX-O,RTS和GND。

I've disabled HDMI support on the BBB so that the UART4_RTSn and UART4_CTSn pins will be available. 我已禁用BBB上的HDMI支持,以便UART4_RTSnUART4_CTSn引脚可用。

    mkdir /mnt/boot
    mount /dev/mmcblk0p1 /mnt/boot
    nano /mnt/boot/uEnv.txt
    #change contents of uEnv.txt to the following:
    optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN 

Then I've found an overlay to enable UART-4 with RTS/CTS control: 然后我找到了一个覆盖层来启用带有RTS / CTS控制的UART-4:

            /*
     * Modified version of /lib/firmware/BB-UART4-00A0.dtbo to add RTS so we can reset Arduinos
     */
    /dts-v1/;
    /plugin/;

    / {
      compatible = "ti,beaglebone", "ti,beaglebone-black";
      part-number = "BB-UART4-RTS";
      version = "00A0";
      exclusive-use = "P9.13", "P9.11", "P9.15", "P8.33", "P8.35", "uart4";

      fragment@0 {
        target = <0xdeadbeef>;

        __overlay__ {


          pinmux_bb_uart4_pins {
            pinctrl-single,pins = <
              0x070 0x26   /* P9_11 = UART4_RXD = GPIO0_30,    MODE6 */
              0x074 0x06   /* P9_13 = UART4_TXD = GPIO0_31,    MODE6 */
              /* need to enable both RTS and CTS, if we only turn on RTS then driver gets confused */
              0x0D0 0x26   /* P8_35 = UART4_CTSN = lcd_data12, MODE6 */
              0x0D4 0x06   /* P8_33 = UART4_RTSN = lcd_data13, MODE6 */
              /* 0x040 0x0F   /* P9_15 = GPIO1_16 = GPIO48,       MODE7  failed attempt to put DTR on gpio */
            >;
            linux,phandle = <0x1>;
            phandle = <0x1>;
          };
        };
      };

      fragment@1 {
        target = <0xdeadbeef>;

        __overlay__ {
          status = "okay";
          pinctrl-names = "default";
          pinctrl-0 = <0x1>;
        };
      };

      __symbols__ {
        bb_uart4_pins = "/fragment@0/__overlay__/pinmux_bb_uart4_pins";
      };

      __fixups__ {
        am33xx_pinmux = "/fragment@0:target:0";
        uart5 = "/fragment@1:target:0"; /* Not a mistake: UART4 is named uart5 */
      };

      __local_fixups__ {
        fixup = "/fragment@1/__overlay__:pinctrl-0:0";
      };
    };

Compiled and Enabled the overlay: 编译并启用叠加层:

    cd /lib/firmware
    dtc -O dtb -o BB-UART4-RTS-00A0.dtbo -b 0 -@ BB-UART4-RTS-00A0.dts 
    echo BB-UART4-RTS:00A0  > /sys/devices/bone_capemgr.*/slots

Hooked up the 485 board to the BB like this 像这样将485板连接到BB

    3-5V to P9_05 (VDD_5V)
    RX-I to P9_13 (UART4_TXD) 
    TX-O to P9_11 (UART4_RXD)
    RTS  to P8_33 (UART4_RTSn)
    GND  to P9_01 (DGND)

In python I'm trying to use the serial port like this: 在python我试图使用这样的串口:

    import serial
    ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True)
    ser.write(list_of_byte_dat)

I know the program works because when I use a USB to RS-485 converter on /dev/ttyUSB0 and set rtscts=False the communication works in both directions just fine. 我知道程序有效,因为当我在/dev/ttyUSB0上使用USB转RS-485转换器并设置rtscts=False ,通信在两个方向都可以正常工作。 But I can't get communication to work correctly using the RS-485 board. 但是我无法使用RS-485板正常工作。

I have two issues with the RS-485 board, both deal with RTS. 我有两个问题与RS-485板,都处理RTS。

  1. The RTS on the board works backwards from the way I expect it to. 电路板上的RTS从我期望的方式向后工作。 When I apply voltage on the RTS pin of the rs485 board the RTS led on the board goes off and the board will not transmit. 当我在rs485板的RTS引脚上施加电压时,电路板上的RTS指示灯熄灭,电路板不会发送。 When I remove voltage from the RTS pin the RTS led turns on and the board will transmit. 当我从RTS引脚移除电压时,RTS LED导通,电路板将发送。 How do I reverse the polarity of the UART_RTSn pin on the BBB? 如何反转BBB上UART_RTSn引脚的极性?

    Temporary solution: I've made a small bone script program that uses UART4_RTSn pin as input. It turns on a different GPIO when the UART4_RTSn pin is off and turns off that same GPIO pin when the UART4_RTSn pin is on. Then hooked up the RTS pin on the rs485 board to the GPIO pin instead of the UART4_RTSn pin.

    This seems to be a poor solution, but it does make the RTS on the RS485 board come on at the correct time when echoing to the /dev/ttyO4 from the command line. 这似乎是一个糟糕的解决方案,但它确实使RS485板上的RTS在/dev/ttyO4回显到/dev/ttyO4的正确时间出现。

    How can I change the polarity of the UART4_RTSn pin either by adjusting the hardware configuration or by changing the configuration in pyserial? 如何通过调整硬件配置或更改pyserial中的配置来更改UART4_RTSn引脚的极性?

    This brings me to the second issue 这让我想到了第二个问题

  2. As I stated in problem 1 the UART4_RTSn pin will work automatically (but backwards) for me when echoing a value to the tty port like this: 正如我在问题1中所述,当我向tty端口回显一个值时, UART4_RTSn引脚将自动(但向后)工作,如下所示:

     echo -en '\\x02\\xFD\\xCD......' > /dev/ttyO4 

    This will make the UART4_RTSn led blink while the data is being transmitted. 这将使UART4_RTSn在数据传输过程中闪烁。 If I have it setup without the bonescript mentioned above, then it will be on normally and blink off while transmitting. 如果我没有上面提到的bonescript进行设置,那么它将正常启动并在传输时闪烁。 If I use my bonescript hack then it will be off normally and blink on while transmitting (which is what I want). 如果我使用我的bonescript hack那么它会正常关闭并在传输时闪烁(这就是我想要的)。 However this only works when using echo from the command line. 但是,这仅在从命令行使用echo时才有效。 When I use python and setup the serial port the UART4_RTSn pin becomes inactive. 当我使用python并设置串口时, UART4_RTSn引脚变为无效。 It will not blink while transmitting. 传输时不会闪烁。 As soon as I make the statement in python: 一旦我在python中发表声明:

     ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True) 

    The UART4_RTSn pin shuts off and stays off. UART4_RTSn引脚关闭并保持关闭状态。 It does not blink when sending information using ser.write(stuff) . 使用ser.write(stuff)发送信息时不会闪烁。 As a result the rs485 board is not enabled for transmission. 因此,rs485板无法进行传输。 How do I get the UART4_RTSn pin to work automatically in pyserial? 如何让UART4_RTSn引脚在pyserial中自动工作? I've tried setting rtscts=False and it did not work. 我已经尝试设置rtscts=False ,但它不起作用。

    I am able to use ser.setRTS(True) or ser.setRTS(False) to manually toggle the pin value so I know I'm using the correct pin and that it is being recognized. 我能够使用ser.setRTS(True)ser.setRTS(False)来手动切换引脚值,因此我知道我正在使用正确的引脚并且它正在被识别。 But I don't want to toggle the UART4_RTSn pin directly. 但我不想直接切换UART4_RTSn引脚。 I want it to work automatically when the serial port is transmitting data and it does when using echo, but not in Python. 我希望它在串口传输数据时自动工作,而在使用echo时则自动工作,但在Python中则不行。

Any help would be greatly appreciated. 任何帮助将不胜感激。

RTS is normally an active low signal, I suspect the reason that you see data being transmitted with echo is that it is not using RTS/CTS (leaving it high) and so is only able to transmit data. RTS通常是一个低电平有效信号,我怀疑你看到数据与echo传输的原因是它没有使用RTS / CTS(保持高电平),因此只能传输数据。

According to a post on http://www.raspberrypi.org/phpBB3/viewtopic.php?f=26&t=29408 根据http://www.raspberrypi.org/phpBB3/viewtopic.php?f=26&t=29408上的帖子

If you enable hardware flow control (CRTSCTS in "man termios", or "stty crtscts -F /dev/ttyAMA0", or pySerial rtscts=True), then sending will take place only when CTS is asserted. 如果启用硬件流控制(“man termios”中的CRTSCTS,或“stty crtscts -F / dev / ttyAMA0”或pySerial rtscts = True),则仅在CTS置位时才会发送。 RTS will be asserted except when the kernel input buffer is full. 除非内核输入缓冲区已满,否则将断言RTS。 The kernel input buffer is about one page or 4KB, so your application has to get well behind with its reads before RTS actually changes. 内核输入缓冲区大约是一页或4KB,因此在RTS实际更改之前,您的应用程序必须远远落后于它的读取。

So check that CTS is being asserted (pulled to ground) outside of your board. 因此,检查CTS是否在电路板外部断言(拉到地)。 However I don't think this will give you the right control over RTS that you need. 但是我不认为这会让你对你需要的RTS有正确的控制权。

So, for your application you should disable hardware flow control ( rtscts=False ) and manually control RTS with setRTS(1) before a write and setRTS(0) afterwards. 因此,对于您的应用程序,您应该禁用硬件流控制( rtscts=False )并在写入之前使用setRTS(1)手动控制RTS,然后再使用setRTS(0)

If you are still not seeing data get through to the device, try swapping the A & B wires - A/B labelling is (frustratingly) not consistent across RS485 devices. 如果您仍未看到数据通过设备,请尝试更换A和B线 - A / B标签(令人沮丧地)在RS485设备上不一致。 It is better to use D+/D- labelling if possible in your own applications. 如果可能,最好在您自己的应用程序中使用D + / D-标记。

Use ioctl to change the logic level... 使用ioctl来改变逻辑电平......

98         struct serial_rs485 rs485conf;
 99 
100         /* Enable RS485 mode: */
101         rs485conf.flags |= SER_RS485_ENABLED;
102 
103         /* Set logical level for RTS pin equal to 1 when sending: */
104         rs485conf.flags |= SER_RS485_RTS_ON_SEND;
105         /* or, set logical level for RTS pin equal to 0 when sending: */
106         rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
107 
108         /* Set logical level for RTS pin equal to 1 after sending: */
109         rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
110         /* or, set logical level for RTS pin equal to 0 after sending: */
111         rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
112 
113         /* Set rts delay before send, if needed: */
114         rs485conf.delay_rts_before_send = ...;
  1. you can use pnp transistor/ p channel mosfet/ logic gate not - inverter like 7404 你可以使用pnp晶体管/ p沟道mosfet /逻辑门不 - 像7404这样的逆变器

  2. maybe you have to flush write buffer after write operation ser.write(....) ser.flush() 也许你必须在写操作ser.write(....)ser.flush()之后刷写写缓冲区

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM