Неблокируемый класс HardwareSerial (часть 2)

Обещанное продолжение…

Сегодня узнал, что 21.05.2012 вышла новая версия Arduino IDE 1.0.1.
Это событие подтолкнуло меня прочитать arduino.cc/en/Main/ReleaseNotes, где я обнаружил следующее:
* Serial transmission is now asynchronous — that is, calls to Serial.print(), etc. add data to an outgoing buffer which is transmitted in the background. Also, the Serial.flush() command has been repurposed to wait for outgoing data to be transmitted, rather than dropping received incoming data.

Причем, это, оказывается, было заявлено еще в ARDUINO 1.0 — 2011.11.30
Решил посмотреть, что же там изменилось.
Сравнил исходники. 1.0.1 и 1.0
Обнаружились два отличия.

1.
Было
struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile int head;
  volatile int tail;
};

Стало
struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile unsigned int head;
  volatile unsigned int tail;
};


2. Добавлено
HardwareSerial::operator bool() {
	return true;
}


Первое изменение понятно, хотя оно ни на что принципиально не влияет.
Второе — непонятно :(

Но меня, собственно, озадачило сообщение в changelog об асинхронной передаче (раньше не смотрел).
Так вот, это не совсем правда!
Асинхронная передача будет только в том случая, если в буфере есть свободное место.
// If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (i == _tx_buffer->tail)
    ;

А если он заполнен, то каждый последующий символ будет записан в буфер с ожиданием.
В первой части я писал: “Начал выяснять, и обнаружил, что класс HardwareSerial при выводе данных в COM порт переходит в состояние ожидания опустошения буфера обмена.“
Так вот это тоже неправда, точнее не совсем правда. :)

Разберемся…
1. Если написать
Serial.print(“12345678901234567890”);
то первые #define SERIAL_BUFFER_SIZE 16 символов попадут в буфер сразу, а остальный 4 попадут в цикл ожидания освобождения передающего буфера, и мы в итоге нарываемся на задержку исполнения кода за командой Serial.print();
2. Функция print очень “тяжелая”, поскольку она обладает достаточно большим функционалом. Работает она через stream.
Выдержка из Print.cpp
size_t Print::print(char c)
{
return write(c);
}
На каждый символ дергаем поток для записи одного символа. Это универсально, но жутко медленно.
Поэтому я добавил в свой класс несколько методов для прямой записи в буфер передачи.
size_t send(uint8_t);
size_t send(const uint8_t *buffer, size_t size);
size_t send(const char *str) { return send((const uint8_t *)str, strlen(str)); }
size_t sendNumber(unsigned long n, uint8_t base);
size_t sendNumber(long n, uint8_t base);


Для контроля заполнения передающего буфера добавлен метод
virtual int tx_available(void);

В неблокирующем режиме, программист должен сам контролировать заполнение передающего буфера, иначе получим искажение передаваемых данных.

После прилизывания кода и исправления одной ощибки получилось то, что находиться на code.google.com
code.google.com/p/nb-hardware-serial/downloads/list

Итак ChangeLog.
1. [*] Transmission bug fixed.
2. [*] New example for demonstration(change bloking/nonbloking mode on fly)
3 .[+] size_t send(uint8_t); (Direct write into TX buffer)
4 .[+] size_t send(const uint8_t *buffer, size_t size); (Direct write into TX buffer)
5 .[+] size_t send(const char *str) (Direct write into TX buffer)
6. [+] size_t sendNumber(unsigned long n, uint8_t base); (Direct write into TX buffer)
7. [+] size_t sendNumber(long n, uint8_t base); (Direct write into TX buffer)

ToDo (пока руки не дошли)
size_t sendBin(uint8_t); (Direct write serialised bin data into TX buffer)
size_t sendBin(uint16_t); (Direct write serialised bin data into TX buffer)

Сейчас библиотека уже в стабильном состоянии. Так что ее смело можно использовать в своих проектах.

Новый пример достаточно простой и понятный.
Переключение bloking/unbloking mode производится при передаче пробела/непробела :).
При работе через встроенный в Arduino IDE serial monitor отключите передачу CR и LF.

Если у кого появятся пожелания или замечания — пишите.


2012-05-23

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.