Добрый день. Делаю устройство, которое читает данные по CAN шине (с автомобиля) и отображает на экране. Использую связку mcp2115 и mcp2551, схема аналогична https://www.sparkfun.com/products/10039 Для работы с mcp2515 использую библиотеку https://github.com/franksmicro/Arduino/tree/master/libraries/MCP2515 Схему собрал, к машине подключил, работает. Однако эта библиотека, как и многие другие аналоги не использует прерывания. У mcp2515 есть отдельная нога для прерываний. В шилде она соединена с Pin2 ардуины. Собственно вопрос, как использовать прерывание? Я сейчас не про "физическое" использование, это в datasheet-е описано. Мне нужно получать по CAN шине несколько параметров. Протокол обмена устроен так, что я отправляю в шину запрос с номером параметра, а оттуда получаю ответ. Те примеры, что я видел, работают "в лоб": в цикле loop отправляют запрос, ждут ответ. Если нужно получить 3 параметра, то собственно повторяют это еще 2 раза. Если параметров хотя бы штук 5, цикл loop становится достаточно медленным, приходится 5 раз ждать пока придет ответ. Я бы хотел сделать иначе. В цикле loop только отправлять запросы в шину, а по прерыванию из шины читать. Но для чтения из шины мне много чего сделать надо, в том числе с использованием SPI шины. Т.е. минимальная быстрая функция не получится. И можно ли вообще в прерывании использовать SPI? Изучая вопрос с использованием прерываний, видел такой варинат: в функции обработки прерывания происходит detachInterrupt, разрешение использования прерываний interrupts(), вся необходимая обработка, а потом опять attachInterrupt. Насколько это правильно? Можно ли использовать такой прием?
Можно переписать в библиотеке функцию (или добавить еще одну свою) boolean MCP2515::receiveCANMessage(CANMSG *msg, unsigned long timeout) так, чтобы она не ждала сообщение, а в случае его отсутствия на момент опроса сразу выходила. Тогда можно устроить быстрый опрос внутри loop() без ожидания и не связываться с перрываниями.
Можно, но у меня в loop() вывод на lcd экран через расширитель. Т.е. не очень быстро. Я сейчас примерно так и делаю - я добавил в библиотеку функцию проверки регистра CANINTF, т.е. наличия принятого сообщения. В loop() я шлю три запроса, и проверяю наличие принятого. Если есть - читаю. Ну и раз в 0.5 секунды вывожу на экран. Но вообще именно этих костылей и хотелось бы избежать. Сколько принятое сообщение висит в буфере? А если пришло еще 1, 2 или 10, а loop() еще не успел закончится (потому что идет отправка запросов или вывод на lcd)? На практике конечно не страшно, если несколько "ответов" пропадут. В реальном устройстве, мне даже запросы слать не надо, там "ответы" сами идут с заданной частотой, от 10Hz до 100Hz. Реальное отображение с такой частотой не нужно, обновляю данные раз в 0.2 - 0.5 секунды. Т.е. если даже несколько "ответов" не успею обработать, ничего страшного, их и так слишком много. Мой вопрос вообщем в том, как сделать правильно, а не чтоб просто работало.
С прерываниями, конечно, будет правильнее. Индикация все-таки дело вторичное... Отцеплять прерывание внутри обработчика не имеет смысла, т.к. пока вы из обработчика не вышли, новое прерывание не случится. На AVR есть возможность разрешить вложенные прерывания, но изначально они отключены.
Никогда не работал с этими модулями, но мысль для подумать подкину. Мысль самая общая, идею ухватите, думаю развить сможете Первое на мой взгляд что все делают и на чем сразу ошибаются так то "свалить все в одну кучу" на микроконтроллере, получение данных, вывод на LCD и еще управление чем-либо и тд и тп. Тут можно сделать следующие. Один микроконтроллер задействовать исключительно для отправки запросов и считывания данных и .... То есть, он занят лишь одним делом он или отправляет запросы и поучает ответы или если система шлет ответы сама, просто их читает. Далее есть два варианта 1. Считав ответ просто кладет в память и все, идет читать следующий, по запросу от другого МК быстро отдает эти данные не пытаясь считать их с шины повторно. 2. Сверяет новое значение со старым, если оно изменилось то самостоятельно пересылает данные на МК-слушатель ( тут реализуется очень хороший голливудский принцип " не звоните нам, мы сами вам позвоним" ака Паттерн: Слушатель). Это позволяет минимизировать общения между двумя МК. А МК-слушатель может тем временем выполнять массу полезной работы а не запрашивать вечно данные, так как будет знать что как только данные с момента последней передачи изменятся ему пришлют новые. Важно сделать четкий формат сообщений в котором этот МК будет отдавать данные, этот формат не должен зависеть от шин и прочего а просто логичный удобный ясный формат. Далее, второй МК, он к примеру отвечает за логику и представление данных, то есть он как раз работает с LCD и при необходимости производит некие расчеты если оно требуется. Что мы получаем в итоге, два модуля совершенно не зависимые друг от друга, модуль считывания данных скрывает любые заморочки в шинами и физическими проблемами, предоставляя четкий интерфейс, что позволит заменить его на любой другой не трогая модуль логики и представления. А модуль логики и представления так же скрывает все дела, можете к нему подключить что угодно лишь бы соблюдался требуемый протокол общения Вообще, нечто отдаленно подобное применяется в серьезных системах от которых требуется скорость, расширяемость и устойчивость. P.s. Я на данный разрабатываю систему контроля помещений, версия 1.0 (минимальная) которой если получится запилить что то путнее будет в будущем представлена на этом форуме с исходниками всем желающим. Там как раз таки реализуются подобные описанные выше идеи как на уровне ПО на самом оборудовании контроля так и на уровне системы в целом