Как написать эффективные функции обратного вызова на Teensy 4.0?

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

Однако я чувствую, что мне нужно больше узнать об ограничениях функций обратного вызова во встроенных системах, таких как Teensy 4.0, которую я использую. Причина, по которой я спрашиваю, заключается в том, что - если я правильно информирован - std::function не рекомендуется использовать во встроенных системах из-за накладных расходов на память. Другая причина вопроса заключается в том, что функции, которые я хочу использовать для обратного вызова, могут привести к нарушению принципа сокращения функций обратного вызова.

Я просмотрел главу, посвященную принципам встроенного программирования, в книге Страуструпа «Программирование: принципы и практика использования C++». К сожалению, он не дает советов по функциям обратного вызова конкретно для встраиваемых систем.

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

, 👍0

Обсуждение

Я часто использую обратные вызовы во встроенных системах на гораздо менее функциональных микроконтроллерах, чем Cortex (328p f/ex). Накладные расходы на вызовы незначительны — вызов через указатель вместо прямого вызова. На этой странице есть [руководство по обратным вызовам в Teensy](https://github.com/TeensyUser/doc/wiki/Callbacks)., @JRobert

Должны ли ваши обратные вызовы переносить состояние (т. е. быть объектами-функторами, содержащими данные), или вы просто будете использовать голые функции (или лямбда-выражения без захвата)?, @Edgar Bonet

@EdgarBonet Сразу пришло в голову, что это в основном будут голые функции, но возможно, мне понадобятся и другие типы вариантов использования., @Erik


1 ответ


2

Я довольно интенсивно использовал обратные вызовы на Arduino Mega 2560, для управления сообщениями RS-485. На этой плате примерно в 8 раз меньше флэш-памяти и в 128 раз меньше оперативной памяти, чем у вашего Teensy. Однако, поскольку ядро AVR не поддерживает std::function, я использовал старую добрую идиому C для определения обратные вызовы:

void MyClass::register_callback(
        void (*callback)(some_type some_data, void *callback_data),
        void *callback_data);

Вызывающая сторона должна правильно упаковать все состояние, необходимое обратный вызов в struct и передайте указатель на эту struct в качестве последний аргумент register_callback(). Класс запишет как указатель функции и указатель void*. Когда ожидаемое событие случается, класс вызывает обратный вызов, передавая ему сохраненный void* как его последний аргумент. Затем обратный вызов приводит этот указатель к указателю на ожидаемую struct, и теперь она может получить доступ к нужному состоянию.

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

Если вас пугает стоимость std::function, я предлагаю вам реализовать простой пример обратного вызова, используя этот метод, а затем использовать std::function, и вы сравниваете использование памяти. Если стоимость std::function оказывается важным, вы всегда можете перейти к C способ. Я подозреваю, что с std::function все будет в порядке, и на самом деле это нечто большее. удобнее, чем обрабатывать указатель функции и состояние отдельно аргументы.

,

Интересно, я посмотрю. Спасибо за ваш ответ!, @Erik