С лучшим пониманием того, что вы пытаетесь сделать, приходят на ум лучшие решения.
Оказывается, вы не используете свой последовательный порт для отправки или получения последовательных данных.На самом деле вы подключаете переключатель к линии RX и переключаете его вручную с помощью механического переключателя, подавая высокий или низкий уровень в зависимости от положения переключателя.
Итак, вы пытаетесь эмулировать линию цифрового входа с линией RX вашего последовательного порта.Если вы посмотрите , как работает последовательный порт , вы увидите, что при отправке байта линия TX переключается с низкого уровня на высокий со скоростью передачи данных в бодах, но поверх данных вы должны учитыватьстартовые и стоповые биты.Итак, почему ваше решение работает (по крайней мере, иногда): это легко увидеть, если взглянуть на изображение области:
![scope capture TX line sending](https://i.stack.imgur.com/FI7SW.png)
Это скриншотлиния TX, отправляющая байт \x00
, измеренный между контактами 3 (TX) и 5 (GND) без бита четности.Как видите, шаг длится всего 7,5 мс (при скорости 1200 бод).То, что вы делаете со своим переключателем, - нечто подобное, но в идеале бесконечно долго (или до тех пор, пока вы не переключите свой переключатель обратно, что будет происходить через 7,5 мс, независимо от того, насколько быстро вы это сделаете).У меня нет переключателя, чтобы попытаться, но если я открываю терминал на своем порту и использую кабель для короткого замыкания линии RX на вывод 4 (на разъеме SUB-D9), иногда я получаю 0x00
байт, но в основномэто что-то ещеВы можете попробовать этот эксперимент самостоятельно с PuTTy или RealTerm и вашим переключателем, я думаю, вы получите лучшие результаты, но не всегда ожидаемый байт из-за отскакивания контактов.
Другой подход: Я уверен, что могут быть способы улучшить то, что у вас есть, например, снизить скорость передачи данных до 300 или 150 бит / с, проверить разрыв в строке или другие творческие идеи.
Но то, что вы пытаетесь сделать, больше похоже на чтение строки GPIO, и на самом деле последовательный порт имеет несколько цифровых линий, предназначенных (в старые времена) для управления потоком .
Чтобы использовать эти линии, вы должны подключить общий полюс на вашем коммутаторе к линии DSR (контакт 6 на SUB-D9), а полюсы NO и NC к линиям DTR (контакт 4) и RTS (контакт 7).).
Программная сторона будет на самом деле проще, чем чтение байтов: вам просто нужно активировать аппаратное управление потоком:
self.ser = serial.Serial()
self.ser.port='COM4'
self.ser.baudrate=1200 #Baud rate does not matter now
self.ser.timeout=0
self.ser.rtscts=True
self.ser.dsrdtr=True
self.ser.open()
Определите логические уровни для вашего коммутатора:
self.ser.setDTR(False) # We use DTR for low level state
self.ser.setRTS(True) # We use RTS for high level state
self.ser.open() # Open port after setting everything up, to avoid unkwnown states
И используйте ser.getDSR()
для проверки логического уровня строки DSR в вашем цикле:
def start_stop(self):
while True :
try:
switch_state = self.ser.getDSR()
if switch_state == False and self._cycRunning == True:
self.cycleStop()
print("Off")
elif switch_state == True and self._cycRunning == False:
self.cycleStart()
print("On")
except serial.SerialException as e:
print("Error")
Я определил вашу переменную self._cycRunning
как логическую (в коде инициализации вы определили ее какплавать, но это было, вероятно, опечатка).
Этот код работает без сбоев даже при использовании зачищенного провода в качестве переключателя.