Python PySerial с автоматической RTS через полудуплексную плату RS-485 с использованием Beaglebone Black Angstrom
Я пытаюсь использовать Beaglebone Black под управлением Angstrom (ядро 3.8) для связи с устройствами в полудуплексной сети RS-485 на 9600-N-8-1.
Я пытаюсь использовать плату RS-485 Breakout, похожую на эту: https://www.sparkfun.com/products/10124, за исключением того, что чип является MAX3485 http://www.maximintegrated.com/datasheet/index.mvp/id/1079. Я купил плату в сборе с контактами и клеммной колодкой. Мой друг протестировал его с помощью осциллографа и заявил, что плата RS-485 работает. На плате есть пять контактов, которые подключаются к BBB. 3-5 В (мощность), RX-I, TX-O, RTS и GND.
Я отключил поддержку HDMI на BBB, чтобы UART4_RTSn
а также UART4_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
Затем я нашел наложение для включения UART-4 с управлением RTS/CTS:
/*
* 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";
};
};
Скомпилировал и включил оверлей:
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
Подключил плату 485 к ББ вот так
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)
В Python я пытаюсь использовать последовательный порт, как это:
import serial
ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True)
ser.write(list_of_byte_dat)
Я знаю, что программа работает, потому что когда я использую конвертер USB в RS-485 на /dev/ttyUSB0
и установить rtscts=False
связь работает в обоих направлениях просто отлично. Но я не могу заставить коммуникацию работать правильно, используя плату RS-485.
У меня две проблемы с платой RS-485, обе связаны с RTS.
RTS на плате работает в обратном направлении так, как я ожидаю. Когда я подаю напряжение на вывод RTS платы rs485, светодиод RTS на плате гаснет и плата не передает. Когда я снимаю напряжение с контакта RTS, включается светодиод RTS и плата передает. Как изменить полярность контакта UART_RTSn на BBB?
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.
Это, кажется, плохое решение, но оно заставляет RTS на плате RS485 включаться в правильное время при отражении на
/dev/ttyO4
из командной строки.Как я могу изменить полярность
UART4_RTSn
закрепить или настроить аппаратную конфигурацию или изменить конфигурацию в pyserial?Это подводит меня ко второму вопросу
Как я уже говорил в задаче 1,
UART4_RTSn
Пин будет работать автоматически (но в обратном направлении) для меня при выводе значения на порт tty, например:echo -en '\x02\xFD\xCD......' > /dev/ttyO4
Это сделает
UART4_RTSn
светодиод мигает во время передачи данных. Если он настроен без упомянутого выше костяного сценария, он будет нормально включен и мигать во время передачи. Если я использую мой хак с бэкскриптом, он будет выключен и мигать во время передачи (что я и хочу). Однако это работает только при использовании echo из командной строки. Когда я использую Python и настраиваю последовательный портUART4_RTSn
Пин становится неактивным. Он не будет мигать во время передачи. Как только я сделаю заявление в python:ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True)
UART4_RTSn
штифт отключается и остается выключенным. Не мигает при отправке информации с использованиемser.write(stuff)
, В результате плата rs485 не включена для передачи. Как я могу получитьUART4_RTSn
пин для автоматической работы в pyserial? Я пытался установитьrtscts=False
и это не сработало.Я могу использовать
ser.setRTS(True)
или жеser.setRTS(False)
чтобы вручную переключать значение контакта, чтобы я знал, что я использую правильный контакт и что он распознается. Но я не хочу напрямую переключать контакт UART4_RTSn. Я хочу, чтобы он работал автоматически, когда последовательный порт передает данные, и он работает при использовании echo, но не в Python.
Любая помощь будет принята с благодарностью.
3 ответа
RTS обычно активный активный низкий сигнал, я подозреваю причину, по которой вы видите, что данные передаются с echo
является то, что он не использует RTS/CTS (оставляя его на высоком уровне) и поэтому может только передавать данные.
Согласно сообщению на http://www.raspberrypi.org/phpBB3/viewtopic.php?f=26&t=29408
Если вы включите аппаратное управление потоком (CRTSCTS в "man termios", или "stty crtscts -F /dev/ttyAMA0", или pySerial rtscts=True), то отправка будет происходить только после подтверждения CTS. RTS будет утвержден за исключением случаев, когда буфер ввода ядра заполнен. Входной буфер ядра составляет около одной страницы или 4 КБ, поэтому ваше приложение должно отстать в чтениях до того, как RTS действительно изменится.
Поэтому убедитесь, что CTS утверждается (тянется к земле) за пределами вашей доски. Однако я не думаю, что это даст вам правильный контроль над RTS, который вам нужен.
Итак, для вашего приложения вы должны отключить аппаратное управление потоком (rtscts=False
) и вручную управлять RTS с помощью setRTS(1)
перед записью и setRTS(0)
после этого.
Если вы все еще не видите, как данные поступают на устройство, попробуйте поменять местами провода A & B - маркировка A/B (разочаровывающе) не согласована на устройствах RS485. Лучше использовать D+/D- маркировку, если это возможно, в ваших собственных приложениях.
Используйте 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 = ...;
Вы можете использовать pnp транзистор / p канал Mosfet/ логический вентиль не - инвертор, как 7404
может быть, вам нужно очистить буфер записи после операции записи ser.write(....) ser.flush()