pySerial зависает после чтения 3 раза

Мы программируем картинку и диагностировали, что если мы отправим данные на последовательный порт, когда он пытается отправить данные нам, программа заблокируется (и наш код Python, и гипертерминал вылетят при тестировании). Он работал в гипертерминале и вводил его медленно (> 0,5 секунды между ударами) и вылетал при ударе по клавиатуре. Итак, что мы сделали, так это ввели time.sleep, который длиннее 0,5 секунды, но он все еще не работает.

Вот наш тестовый код.

import serial
import time

ser = serial.Serial("COM1")
ser.baudrate=2400

while 1:
    for i in range(23):
        ser.write(0x41)       
        time.sleep(.5)
        print("ok")

    rec = ser.read()
    rec2 = ser.read()
    rec3 = ser.read()
    print(rec)
    print(rec2)
    print(rec3)

    for i in range(23):
        data = ser.read()
        print(data)
        print("ok")
    time.sleep(5)

наша функция получения данных. Раньше мы отправляли "ok" каждый раз, когда он получал char (именно так мы знаем, что он зависает после 3 итераций). Мы вынесли его из цикла, чтобы увидеть, является ли это причиной проблемы, и это не так. Он вообще не отправляет «ОК» с этим кодом.

unsigned char receiveData(unsigned char *rxData, int length){
  // 1. Flag bit, RCIF, will be set when reception is complete and an interrupt will be generated if enable bit, RCIE, was set.
 char send[3] = "ok";

 int index = 0;

 if(rxData==(void*)0 || rxInitialized==FALSE) return FAILURE;
 while(index<length){
  while(PIR1bits.RCIF==0);       
  rxData[index]= RCREG;
  Delay1KTCYx(5);
  index++;
 }
    configureTransmission();
    sendData(send,3);

  // 2. Read the RCSTA register to get the 9th bit (if enabled) and   determine if any error occurred during reception.
  // 3. Read the 8-bit received data by reading the RCREG register.
  // 4. If any error occurred, clear the error by clearing enable bit   CREN.
 return SUCCESS;
}

person Ender    schedule 18.11.2010    source источник
comment
Вероятно, самый важный вопрос здесь: это настоящий коммуникационный порт или USB->последовательный ключ? Если это ключ, то какой марки и модели?   -  person synthesizerpatel    schedule 19.11.2010
comment
Какая картинка? Потому что, если это PIC16F87XA или аналогичный, эта функция receiveData неверна — флаг RCIF устанавливается, когда приемный буфер заполнен, и сбрасывается, когда RCREG пуст, т.е. читать.   -  person detly    schedule 19.11.2010
comment
Подождите, я неправильно прочитал код. Я подумаю еще.   -  person detly    schedule 19.11.2010


Ответы (2)


(Этот ответ предполагает, что вы используете PIC16, на что указывают названия определенных регистров.)

Короче говоря, это похоже на переполнение буфера в сочетании с ошибкой в ​​​​этом цикле в receiveData. Тот факт, что он зависает после отправки трех символов в короткой последовательности, может быть объяснен стр. 117 руководства:

Два байта данных могут быть получены и переданы в RCREG FIFO, а третий байт должен начать сдвиг в регистр RSR.

Это объяснило бы магическое число три.

Проходя код PIC, рассмотрите следующий сценарий (просто пример). Первый раз:

// One character already in RCREG - RCIF set
while(PIR1bits.RCIF==0);
// Reads ONE character - RCIF clear
rxData[index]= RCREG;
// While waiting here, two more characters are received - RCIF set
Delay1KTCYx(5);
index++;

Второй раз:

// RCIF set from before
while(PIR1bits.RCIF==0);
// Reads ONE character - RCIF STILL set, ONE character remains in UART FIFO!
rxData[index]= RCREG;
// While waiting here, three more characters are received
// RCIF set, RCREG fills up and the third character is discarded!
Delay1KTCYx(5);
index++;

Теперь остальная часть цикла будет продолжать чтение из RCREG до index == length, но, поскольку некоторые символы были отброшены, когда UART FIFO был заполнен, вы никогда не доберетесь туда и зависнете!

Что еще более вероятно, так это то, что вы получаете символы еще до того, как доберетесь до этой функции, поэтому UART FIFO заполнится еще до того, как вы туда доберетесь.

Есть несколько способов обойти это.

  1. Сделайте это в прерывании, чтобы немного быстрее перемещать входящие символы в буфер.
  2. Используйте цикл для чтения из RCREG: while(RCIF) rxData[index]= RCREG;, чтобы убедиться, что вы очищаете буфер при чтении из буфера UART, но это не остановит переполнение за пределами этой функции или во время этой задержки.
  3. Проверьте флаг OERR — если он установлен, предположите, что произошло что-то плохое, и начните сначала.
  4. Имейте стоп-символ или начальный символ (например, конец строки, знак препинания и т. д.), который сообщает вам, когда действительная команда запускается или останавливается. Если вы получаете два начальных символа без стоп-символа или какую-либо другую запутанную комбинацию, предположите, что вы в плохом состоянии, и начните сначала.

Дополнительный совет: вы можете сойти с ума, пытаясь учесть и компенсировать каждый пропущенный символ или проблему, подобную этой, в вашем коде PIC, но в конечном итоге это просто еще одна ошибка связи. Приоритетами в коде PIC должны быть: быстрое восстановление после ошибок и не зависание. Обнаружение ошибок и разумное восстановление должны обрабатываться клиентским кодом, где это намного проще.

person detly    schedule 19.11.2010

Используются ли для связи от PIC линии RTS/CTS последовательного порта? Вероятно, PIC ожидает какого-то управления потоком, а вы слишком быстро отправляете ему данные без какого-либо управления потоком. Ознакомьтесь с ограничениями PIC и при необходимости откройте порт с помощью управление потоком включено.

person whatnick    schedule 18.11.2010