Хобрук: Ваш путь к мастерству в программировании

Как заблокировать, пока WiringPi не закончит отправку последовательных данных (UART)?

Описание устройства (для контекста пропустите его, если вам не нравится электроника):

Для простого устройства связь осуществляется через полудуплексный UART (TX и RX находятся на одном и том же проводе) следующим образом:

  • Один контакт (режим записи) указывает, отправляет или принимает UART (1: TX, 0: RX)
  • Один вывод записывает в провод (TX).
  • Один вывод считывается с провода (RX).

Когда write-mode находится в режиме TX (запись), контакт RX находится в высоком импедансе, а TX - в режиме передачи. Пока write-mode находится в режиме приема (чтения), TXpin находится в режиме высокого импеданса и RX принимает.

Это просто для контекста, я не жду здесь электронных вопросов / ответов.

Пример WiringPI:

Для этого у меня есть следующий образец:

#include <wiringPi.h>
#include <wiringSerial.h>

int main()
{
    wiringPiSetup ();
    auto fd = serialOpen ("/dev/ttyAMA0", 115200);
    
    pinMode(0, OUTPUT);
    
    for(size_t i=0; i<10; ++i)
    {
        digitalWrite(0, HIGH);
        serialPutchar(fd, '\x55');
        digitalWrite(0, LOW);
        delay(1000);
    }

    serialClose(fd);
}

С помощью осциллографа я ясно вижу, что вывод write-mode сбрасывается до того, как UART завершит отправку данных.

Очевидно, я попытался добавить некоторую задержку или пустой цикл для настройки, но это ненадежно для времен мкс (из-за обычной точности таймеров в ОС).

Вопрос:

Как синхронизировать, чтобы вывод write-mode сбрасывался сразу после отправки байта UART? (Не более чем примерно через 150 мкс).


  • Я не вижу причины, по которой это помечено как c ++? Похоже на простой код c для меня. 08.09.2020
  • На самом деле это не стандартный C (auto не используется в семантике C с неявным int, а как ключевое слово C ++ 11). Важно, чтобы оба языка соответствовали вопросу. 08.09.2020
  • Использование C ++ 11 auto во встроенных системах просто опасно. Сомнительно использовать его практически в любом контексте. 08.09.2020
  • В любом случае, какой есть режим записи? Используйте аппаратное квитирование RTS / CTS, эти вещи стандартизированы уже лет 60 ... А как насчет земли сигнала? Подключение рашпиля с батарейным питанием к стационарному ПК не будет работать без сигнального заземления. 08.09.2020
  • @AdrianMaire Ой, не волнуйся. Я все равно упускал из виду ключевое слово auto. Но это сделало бы тег c IMO недействительным. Не следует злоупотреблять языковыми тегами для обращения к более широкой аудитории. 08.09.2020
  • @ πάνταῥεῖ Языковые теги принимаются, когда используются для указания языка, используемого для конкретной задачи или библиотеки (meta.stackoverflow.com/a/ 364198/903651). Также известно, что wiringPi доступен, например, в Python, но этот ответ не подходит, однако подходят как C, так и C++ в любой из их версий (например, c ++ 20). 08.09.2020
  • @ πάνταῥεῖ Это не C, int main() недопустимо в C, но в C ++. 08.09.2020
  • @AdrianMaire auto - это C и C ++, но они имеют разные значения. В C auto - это спецификатор класса хранилища, и в основном это означает в стеке. В C ++ это означает, что компилятор должен решить, какой тип правильный. В этом случае это будет int в C и C ++. 08.09.2020
  • @ 12431234123412341234123 Как бы то ни было, это незначительное беспокойство по поводу вопроса. Я проголосую за него, и меня устраивает пометка как есть. 08.09.2020
  • Честно говоря, я ожидал (возможно, ошибочно), что wiringPi будет обеспечивать более оптимальный (более простой и близкий к электронному) доступ к BCM2835, чем стандартный буферизованный posix write () / read (). Моя первая попытка заключалась в том, чтобы реализовать доступ к регистрам с нуля, но это неприятно, потому что требует глубокого изучения оборудования. До некоторой степени это было возможно, но для доступа к UART я хотел попробовать эту библиотеку. 08.09.2020

Ответы:


1

Я вижу 2 способа реализовать это:

1. Я не могу сейчас это проверить, но, похоже, вы могли бы использовать

 void serialFlush (int fd) ;

Согласно документам, это отбрасывает все полученные или ожидающие отправки данные с данного устройства, см. http://wiringpi.com/reference/serial-library/

(Изменить: после перечитывания этого предложения становится ясно, что оно действительно сбрасывает и записываемые данные, поэтому этот параметр отключен ...)

  1. Использование tcdrain () (https://linux.die.net/man/3/tcdrain), где вы передаете fd, возвращаемый serialOpen()
08.09.2020
  • Действительно, serialFlush не блокирует, а просто очищает буфер. 08.09.2020
  • tcdrain выглядит многообещающе (протестирую и приму / прокомментирую) 08.09.2020
  • Это работает, но определенно не соответствует требованиям по времени, это примерно то же самое, что и при использовании таймеров / планирования. 09.09.2020
  • Это прискорбно ... Сможете ли вы использовать контакты RTS (GPIO17) / CTS (GPIO16) порта UART, или вам придется придерживаться обычного GPIO? Если контакты RTS / CTS доступны, вы также можете попробовать включить hw hadshaking (в конце концов, это именно для такого рода сценариев использования ...) 10.09.2020
  • Хорошая идея, я попробую. 11.09.2020
  • RTS / CTS больше связаны со статусом UART (например, занят / доступен), чем с состоянием передачи / приема. Я, наконец, реализовал это поведение аппаратно с перезапускаемым таймером 555, равным 0,1 мс (но это не по теме для SO, поэтому я не помещаю здесь ответ). 05.10.2020

  • 2

    Установите блокировку для файлового дескриптора.

    Как восстановить работу файлового дескриптора в режим блокировки можно найти во многих местах. Вы можете использовать код из этого ответа и сделать:

    set_blocking_mode(fd, 1);
    serialPutchar(fd, '\x55');
    

    После этого write () внутри serialPutchar будет заблокирован . Обратите внимание, что fd открывается с помощью O_NONBLOCK в serialOpen ().

    08.09.2020
  • Не могли бы вы привести рабочий пример? Я не могу найти ни set_blocking_mode, ни блокирующего аргумента для serialOpen 08.09.2020
  • Связанный ответ содержит полную реализацию функции set_blocking_mode. neither blocking argument to serialOpen нет аргумента блокировки, seralOpen не позволяет указать режим. Could you put a working example? stackoverflow.com/questions/ 914463 / 08.09.2020
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..