Нетривиальный пример кода для bxCAN i/f на STM32?
Я использую периферийную библиотеку STM для настройки и использования шины CAN. Проблема в том, что я должен поставить задержку между пакетами Tx, или я начинаю отбрасывать пакеты. Включение циклов чтения и т. Д., Похоже, не имеет никакого эффекта. У кого-нибудь есть рабочий пример, который не включает добавление задержки магического числа?
3 ответа
Это не относится к CAN или STM32, но на самом деле касается контроля того, как часто что-то происходит в микроконтроллере.
Есть несколько способов решить эту проблему:
1) Используйте таймер
Установите таймер так, чтобы он генерировал прерывание со скоростью, которую вы хотите передать. (т. е. каждые 10 мс) Используйте прерывание для запуска вашего кода передачи. Обратите внимание, что ваша подпрограмма обработки прерываний должна быть максимально короткой; он может просто установить флаг "go", который проверяется вашим основным циклом, когда он установлен, очистить флаг, передать, а затем подождать, пока он не будет установлен снова.
2) Используйте операционную систему реального времени, такую как FreeRTOS
ОСРВ обычно работает аналогично методу таймера, описанному выше, но абстрагирует детали и делает это надежным способом. Вы можете создать несколько задач, которые работают по разным графикам, если вам нужно. Например, вам может потребоваться передавать данные каждые 10 мс, но обновлять индикацию только каждые 200 мс.
Я использую STM32 + HAL + FreeRTOS
Вам нужно поставить magiC# delay, что означает, что вы израсходовали весь 3x почтовый ящик. Итак, вам нужна очередь для хранения дополнительных данных. Вот как я решаю проблему
У меня была задача, которая принимает следующие события
- Передача выполнена IRQ
- Запрос на передачу
Задача имела следующую структуру
- Состояние "занято" / "незанято" 3 почтовых ящиков
- Локальная очередь, содержащая данные для передачи
По запросу передачи поместите данные в локальную очередь и вызовите передачу ()
- После завершения передачи IRQ, пометьте соответствующий почтовый ящик как свободный и вызовите передачу ()
- Псевдокод передачи ()
- Если нет бесплатного почтового ящика, просто верни
- Найдите свободный почтовый ящик [n], отметьте почтовый ящик [n] как занятый и выполните передачу с ним
Посмотрите внимательно на возвращаемое значение SPL CAN_Transmit():
- @retval Номер почтового ящика, который используется для передачи или CAN_TxStatus_NoMailBox, если нет пустого почтового ящика.
Таким образом, вы можете выполнить некоторую проверку:
uint8_t retry_count = RETRY_COUNT;
while(retry_count && CAN_Transmit(CAN1, &TxMessage) == CAN_TxStatus_NoMailBox)
{
// <-- still you could delay here
retry_count--;
}
или просто
while(CAN_Transmit(CAN1, &TxMessage) == CAN_TxStatus_NoMailBox);