Напишем на ардуино программу, которая постоянно шлет в CAN пакет, состоящий из 4 байт, а также при получении сообщения извне (будем считать оно тоже состоит не более, чем из 4 байт) отображает его в Serial порт. Подключим необходимый файл к нашему скетчу и создадим переменную data - отправляемый пакет. Для замера времени создадим переменную t.
#include <VBCoreG4_arduino_system.h>
uint8_t data[4] = {222, 173, 190, 239}; //байты - DE AD BE EF
unsigned long t;
FDCAN_HandleTypeDef hfdcan1;// создаем переменную типа FDCAN_HandleTypeDef
CanFD canfd; //в классе CanFD реализованы функции can_init(), запускающая can,
// get_hfdcan(), возвращающая ссылку на структуру FDCAN_HandleTypeDef и
// create_header, создающая хидер для отправляемого сообщения
В setup() вызывем методы класса CanFD - can_init() , инициализирующую can и get_hfdcan(), возвращающую инициализированнную управляющую can-ом структуру типа FDCAN_HandleTypeDef
В основном цикле loop() ставим условие: если в очереди на отправку сообщения есть место, тогда создадим хидер отправляемого пакета. В классе CanFD для этого есть метод create_header(uint32_t ID), где ID - это ID сообщения. Для примера пусть у нас ID = 100 (0х64). Указываем длину сообщения и отправляем. Если пакет отправлен и все хорошо будем мигать светодиодиком.
if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != 0){
FDCAN_TxHeaderTypeDef TxHeader = create_header(100); //создаем хидер исходящего сообщения, 100 - ID сообщения, в hex 0х64
TxHeader.DataLength = FDCAN_DLC_BYTES_4; //количество байт в сообщении - 4
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, data) != HAL_OK){ Error_Handler(); }
else{digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));} //помигаем светодиодом, если все ок
}
Чтение пакетов из can происходит следующим образом: пока в очереди получаемых сообщений есть хотя бы одно, создаем хидер этого сообщения и массив, где будет лежать содержимое посылки. Если сообщение получено, выведем в Serial порт его ID, и само сообщение. Сейчас, для простоты, выведем первые 4 байта массива, считая, что больше отправлено не будет.
while(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) > 0 )
{
FDCAN_RxHeaderTypeDef Header; // хидер для входящего сообщения
uint8_t RxData[64]; // максимальная длина сообщения - 64 байта
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &Header, RxData) != HAL_OK){ Error_Handler(); }
else{ // напечатаем первые 4 байта входящего сообщения, если все ок. Пример отправки сообщения cansend can0 00000123#DEADBEEF
Serial.print("ID ");
Serial.print(Header.Identifier); // ID сообщения
Serial.print(" data: ");
Serial.print(RxData[0]);
Serial.print(" ");
Serial.print(RxData[1]);
Serial.print(" ");
Serial.print(RxData[2]);
Serial.print(" ");
Serial.print(RxData[3]);
Serial.println(" ");
}
Удобно, чтобы сообщения отправлялись с одной и той же частотой. Нам достаточно чтобы весь цикл выполнялся за 1 милисекунду. Поэтому в конце добавим задержку на все оставшееся время до 1 милисекунды. Весь листинг программы приведен ниже.
#include <VBCoreG4_arduino_system.h>
//в VBCoreG4_arduino_system.h пин PA5 определен как LED2
//запустить can c распберри - sudo ip link set can0 up txqueuelen 65535 type can bitrate 1000000 dbitrate 8000000 fd on
//отправить сообщение c распберри - cansend can0 00000123#DEADBEEF, ID всегда содержит 8 цифр
//прочитать все сообщения в can - candump can0
//прочитать сообщение can по его ID - candump can0,ID:7ff
//в libraries добавить библиотеку VBCoreG4_arduino_system
//функция can_init() запускает can
//функция get_hfdcan() возвращает переменную типа FDCAN_HandleTypeDef, без которой невозможно взаимодействие с can
//функция create_header(uint8_t ID) создает хидер для отправки сообщения, в нее нужно передать переменную типа uint8_t - ID сообщения
uint8_t data[4] = {222, 173, 190, 239}; //DE AD BE EF
unsigned long t;
FDCAN_HandleTypeDef hfdcan1; // создаем переменную типа FDCAN_HandleTypeDef
CanFD canfd;
void setup() {
Serial.begin(115200);
canfd.can_init(); // запускаем can
hfdcan1 = *(canfd.get_hfdcan());
}
void loop() {
t = micros(); //время в микросекундах
//------Отправка сообщения в can------
if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != 0){
FDCAN_TxHeaderTypeDef TxHeader = canfd.create_header(100); //создаем хидер исходящего сообщения, 100 - ID сообщения, в hex 0х64
TxHeader.DataLength = FDCAN_DLC_BYTES_4; //количество байт в сообщении - 4
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, data) != HAL_OK){ Error_Handler(); }
else{digitalWrite(LED2, !digitalRead(LED2));} //помигаем светодиодом, если все ок
}
// -------Получение сообщений из can-------
while(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) > 0 )
{
FDCAN_RxHeaderTypeDef Header; // хидер для входящего сообщения
uint8_t RxData[64]; // максимальная длина сообщения - 64 байта
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &Header, RxData) != HAL_OK){ Error_Handler(); }
else{ // напечатаем первые 4 байта входящего сообщения, если все ок. Пример отправки сообщения cansend can0 00000123#DEADBEEF
Serial.print("ID ");
Serial.print(Header.Identifier); // ID сообщения
Serial.print(" data: ");
Serial.print(RxData[0]);
Serial.print(" ");
Serial.print(RxData[1]);
Serial.print(" ");
Serial.print(RxData[2]);
Serial.print(" ");
Serial.print(RxData[3]);
Serial.println(" ");
}
}
delayMicroseconds(1000-(micros()-t)); //время выполнения программы 1 мс
}
Загрузите программу на плату. Проверить действительно ли все сообщения отправляются в can можно на Raspberry с помощью утилиты candump, а чтобы отправить сообщение воспользуйтесь утилитой cansend. О том как работают утилиты было расказано в предыдущей главе.