Pull to refresh

Comments 16

Столько кода, показал бы хоть готовое изделие с видео подтверждением

Есть варианты и попроще, наберите в. Гугле: расширители портов

например PCF8575 обеспечивает 16 дополнительных линий ввода\вывода.

hc165 банально гораздо дешевле и проще дополнительно наращивать битность порта.

Извините, но у вас какая-то дурацкая архитектура вышла. Очереди в принципе нужны, чтобы организовать FIFO-обработку, а блокирующие очереди еще для того, чтобы один поток ждал, пока от другого что-то придет. Было бы логично, если бы таска кнопок выполняла свою низкоуровневю логику и выдавала в очередь события типа "кнопка 1 нажата", "повтороное нажатие кнопки 5". У вас же каждый тик таска выплевывает в очередь внутренне состояние всех кнопок, и в итоге от очереди нет никакого толку; порядок элементов в очереди не важен, и таска-читатель не ждет событий, т.к. они все равно идут непрерывным потоком. Код в главной такске вышел такой же, как если бы состояние кнопок хранилось в массиве, к которому имеют доступ обе таски (только потокобезопасный).

Поэтому тут и от двух тасок нет особой пользы, проще и дешевле было бы в главной таске вызывать фцнкцию вроде "update_buttons_states()" и дальше делать то, что и сейчас. Не было бы накладных расходов на переключание между тасками и на копирование памяти в очередь и из нее.

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

Это выглядит как неправильный выбор инструмента и попытка натянуть его на задачу. Очередь с несколькими слушателями работает, когда слушатели равноправны и нужно доставить элемент только одному. Традиционный пример - пул потоков-воркеров, которые берут задачи из очереди. Если одно событие должно уходить нескольким слушателям, и они еще и выбирают, какие кому нужны, то тогда лучше взять другой паттерн, publish-subscribe там, или observer. Или просто сделать состояние кнопок доступным на чтение всем желающим.

И да, это все уже изобретено до нас, например, есть бибилотека ETL (embedded template library), там есть и observer, и message router, и миллион других готовых велосипедов.

Было бы логично, если бы таска кнопок выполняла свою низкоуровневою логику и выдавала в очередь события типа "кнопка 1 нажата", "повторное нажатие кнопки 5". 

 и в итоге от очереди нет никакого толку; порядок элементов в очереди не важен, и таска-читатель не ждет событий, т.к. они все равно идут непрерывным потоком.

Согласен, так будет намного лучше. Это несложно исправить.

Если одно событие должно уходить нескольким слушателям, и они еще и выбирают, какие кому нужны, то тогда лучше взять другой паттерн

Например, есть бибилотека ETL (embedded template library), там есть и observer, и message router, и миллион других готовых велосипедов.

Спасибо, буду изучать и редактировать. Пока закреплю Ваш комментарий

Искал серебро, а нашёл золото. На удивление, в интернете мало информации про модель данных "1 источник - много приёмников" для встраиваемых RTOS, в частности для FreeRTOS. А задача-то типовая: пример. АЦП считывает сигнал, который должен быть обработан: а) ПИД-регулятором. б) Записан в лог. в) Выведен на дисплей. То есть, источник данных один, а приёмников много, и они "спят", пока нет новых данных. Я для этого обычно использовал GlobalEvent и TaskNotification - очереди в данном случае избыточны. Но библиотека ETL очень понравилась, спасибо большое за ссылку. Может, ещё что-то хорошее подскажете на эту тему?

Спасибо за коментарий! Ну вроде бы похожий функционал еще обеспечивает Qt for MCUs со стандартными для qt сигналами и слотами. Но оно требуют довольно толстых микроконтроллеров, ориентировано в основном на UI, и навязывает структуру проекта, системы сборки и т.п. Я сам не пользовался.

А обработка дребезга контактов ?

А в прерывании не проще?

Если сходите по ссылке на описание библиотеки EncButton, то увидите там в одном из пунктов:

  • Программное подавление дребезга

portYELD() переводит задачу в состояние ожидания?

Посылать события от кнопок в очередь довольно странное решение.
Очереди в RTOS нужны чтобы согласовать процессы с непостоянными циклами. Такое очень редко случается и требует серьезного анализа глубины очереди.

Если события от кнопок требуют очереди, то явно что-то не то с задачей приемником этих событий. Встраиваемая система это же текстовый редактор. Не среагировала вовремя на кнопку, значит игнорим кнопку, потому что уже поздно. Очередь здесь не нужна и даже может вызвать неприятные сюрпризы с поздней отработкой уже неактуальных команд.

Потом библиотека для энкодера весьма рискованно выполнена. Реакция на сигналы энкодера по прерываниям могут нарушить риалтайм и привести к деградации производительности и неточности, когда будет сильный дребезг. А у дешевых энкодеров ужасающий дребезг.

библиотека для энкодера весьма рискованно выполнена

Вы про какую именно библиотеку - EncButton? Если да, то в ней заложены разные способы отработки энкодеров, с разной точностью, в том числе есть обработка и очень плохих энкодеров без RC-обвесок. Можно обрабатывать как в прерываниях, так и без них.

Мне кажется, любая эффективная клавиатура в МК должна использовать прерывания. А не занимать время циклическим опросом

В клавиатурах обычно больше кнопок, чем остается у МК на работу с ней, так что применяются разные техники мультиплексирования, как в статье. Как в таких случаях реализовывать прерывания?

Ну у МК есть регистр с восемью портами. Любое изменение состояние этого порта (или изменение состояние по маске) вызывает прерывание.

Другое дело если есть матричная клавиатура. там необходимо динамическое сканирование состояния кнопок.

Если делать клавиатуру на специализированных микросхемах типа PCF8575, то там отдельная нога выдающее прерывание. А если учесть, что можно посадить 8 штук PCF на одну I2C шину с разными адресами, получается что можно расширить систему ввода/вывода до 128 портов с минимальным количеством задействованных портом МК.

Тут все зависит от задач, конечно. Но лично мне больше нравится решение с FreeRTOS, когда задача обработки ввода блокируется семафором, а обработчик прерывания с этого ввода семафор освобождает.

Эт зависит насколько комплексную работы выполняет дивайс.
В обычном универсальном ПЛК прерываний от разных источников бывает несколько десятков, а детерминизм должен быть гарантированным и жёстким. И тогда вы не можете себе позволить зависеть детерминизму от каких-то спорадических прерываний от клавиатуры.
Детерминизма добиваются тем что опрашивают клавиатуру в строго заданные интервалы времени.
Вообще метод разделения времени повсеместно используется в RTOS для обеспечения жёсткости реакции.

Sign up to leave a comment.

Articles