Отправлять числа в arduino через последовательный порт с помощью python

У меня есть файл с номерами под названием fginputs.txt. Например, это может быть что-то вроде этого:

4958
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4958

Я хочу, чтобы Python отправлял каждое число в Arduino через последовательный порт. После получения каждого числа arduino должна распечатать номер подтверждения, указывающий, что он получил действительное число, а затем сохранить это число в динамическом массиве, потому что я мог бы создавать файлы большего размера. Когда номеров больше не останется, отправьте «-1», чтобы завершить передачу.

Вот мой код Arduino:

// сохранить несколько целых чисел без знака
uint16_t SIZE, *inputList, cont = 0;
boolean inputsReady = false;

void setup()
{
 // инициализируем последовательную связь со скоростью 9600 бит в секунду:
 Serial.begin(9600);
  
 //свободная память динамического массива
 free(inputList); 
 //счетчик полученных чисел начинается с 0
 cont = 0;
 //Это правда, когда больше нет чисел для приема, в то время как ложь
 inputsReady = false;
 setupInputList();
 }

/* If there's not enough space, resize the array by one unit and store the number 
   */
void growAndInsert(int currentSize, int newInt){
    if(currentSize > SIZE)
        inputList = (uint16_t *)realloc(inputList, (currentSize + 1)*sizeof(uint16_t));
    inputList[currentSize] = newInt;
}
/**
  init inputList with 100 blocks
 */
void setupInputList(){
  SIZE = 10;
  inputList = (uint16_t *)malloc(sizeof(uint16_t) * SIZE);
}

void clearBuffer(){
while(Serial.available() > 0)
    Serial.read();
}

/**
Listens in serial port for an integer that represents a new input and returns it.
If it doesn't get anything useful from serial, return 0
*/
  int getNewInputFromSerial(){
   if (Serial.available() > 0) {
    delay(100);
    // ищем следующее слово
    int cmd = Serial.parseInt();
    clearBuffer();

    if(cmd == 4958)
        Serial.write("4");
    else if(cmd == 4154)
        Serial.write("5");
    else
        Serial.write("0");
    return cmd;
   }
  return 0;

}

void loop()
{
     if(!inputsReady){
        int newInput = getNewInputFromSerial();
        if(newInput == 0)
            return;
        if(newInput != -1)
            growAndInsert(cont++, newInput);
        else{
            inputsReady = true;
            //иниттаймер();
        }
    }


}

и скрипт Python:

global arduino
PORT = '/dev/ttyACM0'
FILENAME = "fginputs.txt"
#Read file with inputs
with open(FILENAME) as f:
        content = f.readlines()
#init serial port
arduino = serial.Serial(PORT, 9600, timeout=1);
time.sleep(2);

#write
for input in content:
    arduino.flush()
    arduino.write(input)
    time.sleep(.1);
    resp = arduino.read();
    print "i got " + resp

#Finish transmission with -1
arduino.flush()
arduino.write("-1")
#done
arduino.close();

При первом запуске скрипта я получаю следующее:

i got 4
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 4

Это здорово. Но если я запущу его во второй раз, я получу следующее:

i got 0
i got 4
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0

Что ужасно неправильно, потому что файл не изменился. Я не знаю, что здесь происходит. Если я отключу и снова подключу USB-кабель, передача снова будет работать безупречно.

, 👍0


2 ответа


Лучший ответ:

3
// сохранить несколько целых чисел без знака
uint16_t SIZE, *inputList, cont = 0;
boolean inputsReady = false;

void setup()
{
 // инициализируем последовательную связь со скоростью 9600 бит в секунду:
 Serial.begin(9600);

 //свободная память динамического массива
 free(inputList); 

Вы освобождаете указатель NULL, который является неопределенной операцией и здесь не нужен, так как он никогда не выделялся.


  if (Serial.available() > 0) {
    delay(100);
    // ищем следующее слово
    int cmd = Serial.parseInt();
    clearBuffer();

Это приведет к потере данных, я не удивлен, что что-то пропало.

Прочитайте это: Как обрабатывать входящие последовательные данные без блокировки — вам нужно избавиться от задержки и clearBuffer() для начала.


Пример кода для чтения из Serial без блокировки и без использования delay:

// сколько последовательных данных мы ожидаем перед новой строкой
const unsigned int MAX_INPUT = 50;

void setup ()
  {
  Serial.begin (115200);
  } // конец настройки

// здесь для обработки входящих последовательных данных после получения терминатора
void process_data (const char * data)
  {
  // пока просто отображаем его
  // (но вы можете сравнить его с каким-то значением, преобразовать в целое число и т. д.)
  Serial.println (data);
  }  // конец process_data

void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\n':   // конец текста
      input_line [input_pos] = 0;  // завершающий нулевой байт

      // терминатор достигнут! обработать input_line здесь...
      process_data (input_line);

      // сброс буфера для следующего раза
      input_pos = 0;  
      break;

    case '\r':   // отменить возврат каретки
      break;

    default:
      // продолжаем добавлять, если не полный ... разрешить завершающий нулевой байт
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // конец переключателя

  } // конец процессаIncomingByte

void loop()
  {
  // если серийные данные доступны, обрабатываем их
  while (Serial.available () > 0)
    processIncomingByte (Serial.read ());

  // делаем здесь другие вещи, например, тестируем цифровой ввод (нажатие кнопок) ...

  }  // конец цикла

В моем примере в process_data вы должны вызвать atoi для преобразования входящей строки в int (или atol, если она собирается быть длиннее).

,

бесплатно(NULL) можно; per man malloc re void free(void *ptr), «Если ptr равен NULL, никакая операция не выполняется»., @James Waldby - jwpat7

Ах, ты прав. Тем не менее, бессмысленная вещь в настройке. Сообщение исправлено., @Nick Gammon


1

Вы можете посмотреть это.

Это программа на Python, которая записывает/воспроизводит нажатия клавиш через UNO.

Он уже реализует:

  • последовательная связь с проверкой ошибок
  • ACK: каждое сообщение имеет собственный идентификатор, поэтому вы можете отслеживать, что было потеряно, если что-то случится.
  • синхронизация, если питание Arduino включается после запуска программы python
,