VBCores Docs
HomeGitHub
  • VBCores
  • Hardware
    • VBCore VB32G4
    • VB STM32 Programmer
    • BLDC motor driver 30A
    • DC motor driver 15A
    • Stepper motor driver 10A
    • Ethernet - CAN-FD
    • CAN-FD - Raspberry PI
      • Setting up CAN on Raspberry Pi
      • Troubleshooting
      • Работа с CAN FD через Python
    • PowerBoard 30A
    • SBus-HID
    • DC-DC 12V
    • USB 2.0-HUB
    • IMU BNO055
    • IMU BHI360
    • T-encoder
  • Software
    • Arduino IDE
      • Arduino IDE setup
      • Selecting MCU
      • Optional hardware preparation
      • Prepairing a sketch
      • Libraries
      • Examples
        • Все переписать нахрен
        • Работа с I2C
        • I2C detect
        • Датчик BNO055 / I2C
        • Датчик AS5047P / SPI
        • Датчик AS5600 / I2C
        • Работа с бесколлекторными двигателями
          • Simple FOC. Управление скоростью. Нахождение количества пар полюсов.
          • Simple FOC. Управление моментом
          • Чтение данных с датчика тока
        • Работа с коллекторным двигателем
          • Вращение DC мотором
          • Чтение угла по энкодеру. Управление DC мотором по углу
          • Чтение скорости вращения мотора по энкодеру
        • Работа с шаговым двигателем
          • Вращение шагового двигателя.
          • Контроль двигателя по интерфейсу SPI
    • STM32 CUBE IDE
      • Типовые настройки
      • Подсказки начинающим
        • Cube IDE для начинающих
        • Clock configuration
        • Таймеры - прерывания
        • Таймеры - ШИМ
        • Отладка программ
        • Коммуникации - FDCAN
        • Управление DC-мотором
        • Backup программы
  • Cyphal CAN
    • Cyphal CAN
    • PyCyphal
    • Yakut
    • Cyphal Arduino
      • Отправка и получение сообщений по cyphal
  • Работа с ROS
    • Установка Ubuntu, ROS и Arduino
    • ROS_LIB
    • Возможные ошибки
    • Примеры
      • Publisher. Hello World!
      • Publisher with Subscriber
      • Rotation by DC motor
  • Example projects
    • Motor-wheel upgrade
Powered by GitBook
On this page
  • Sending and receiving via classic CAN
  • Пример отправки и получения сообщения по CAN FD
  1. Software
  2. Arduino IDE
  3. Examples

Все переписать нахрен

Last updated 12 days ago

Sending and receiving via classic CAN

Let's write a sketch that sends a 4-byte frame over CAN while listening for incoming messages. If incoming message received successfully, we'll output it to the Serial port.

uint8_t data[4] - 4-byte long buffer for storing data to be transmited

CanFD - is a core class for CAN communication. It has the following methods:

  • init() - CAN initialization

  • write_default_params_classic() - метод, который запишет параметры по умолчанию для CAN FD (настроены два битрейта 500000 и 4000000 если вы будете использовать raspberry для чтения/записи в can fd, то при запуске интерфейса используйте команду sudo ip link set can0 up txqueuelen 65535 type can bitrate 500000 dbitrate 4000000 fd on. Подробно о том как работать с CAN на RPI написано в разделе VB Can FD Raspberry HAT)

  • write_default_params() - метод, который запишет параметры по умолчанию для обычного CAN( здесь по умолчанию настроен битрейт на 1000000. Запуск интерфейса на RPI: sudo ip link set can0 up txqueuelen 65535 type can bitrate 1000000)

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

  • apply_config() - метод, который применит записанные ранее методы для нашего экземпляра класса

  • default_start() - метод, который запускает FD CAN на модуле, он обязателен.

  • get_hfdcan() - сохраняет всю конфигурацию и возвращает указатель на структуру FDCAN_HandleTypeDef

#include <VBCoreG4_arduino_system.h>


uint8_t data[4] = {222, 173, 190, 239}; //DE AD BE EF
FDCAN_HandleTypeDef*  hfdcan1; // создаем указатель на переменную типа FDCAN_HandleTypeDef
CanFD* can;  //в классе CanFD реализованы функции init(), запускающая can, 
             // get_hfdcan(), возвращающая указатель на структуру FDCAN_HandleTypeDef и
             //write_default_params() - функ

FDCAN_TxHeaderTypeDef TxHeader; // хидер сообщения, которое будет отправляться

В setup() вызывем функцию SystemClock_Config() - она обязательна для настройки тактирования, методы класса CanFD - init() , инициализирующую can, методы для записи и подтверждения настроек, функцию, запускающую CAN FD и get_hfdcan(), возвращающую инициализированнную управляющую can-ом структуру типа FDCAN_HandleTypeDef. Также укажем в хидере нашего сообщения его ID, размер и тип ID сообщения - он может быть расширенным, а может стандартным.

Если тип ID расширенный, то ID 0x64 будет выглядеть: 00000064, если стандартный: 064. Мы советуем использовать расширенный.

void setup() {
  Serial.begin(115200);
  pinMode(LED2, OUTPUT);
  /* Настройка FD CAN  */
  SystemClock_Config();  // Настройка тактирования
  can = new CanFD();  // Создаем управляющий класс
  can->init();  // Инициализация CAN
  can->write_default_params_classic();  // Записываем дефолтные параметры для classic CAN
  can->apply_config();  // Применяем их
  can->default_start();  // Запуск FDCAN модуля
  hfdcan1 = can->get_hfdcan();  // Сохраняем конфиг
  
  TxHeader.Identifier = 0x64;
  TxHeader.DataLength = FDCAN_DLC_BYTES_4; // длина сообщения 4 байта
  TxHeader.IdType = FDCAN_EXTENDED_ID; // тип ID расширенный
}

В основном цикле loop() ставим условие: если в очереди на отправку сообщения есть место, тогда отправляем сообщение. Если пакет отправлен и все хорошо будем мигать светодиодиком.

//------Отправка сообщения в can------
  if (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan1) != 0){
    
    if (HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, &TxHeader, data) != HAL_OK){ Error_Handler(); } 
    else{digitalWrite(LED2, !digitalRead(LED2));} //помигаем светодиодом, если все ок
  }

Чтение пакетов из can происходит следующим образом: пока в очереди получаемых сообщений есть хотя бы одно, создаем хидер этого сообщения и массив, где будет лежать содержимое посылки. Если сообщение получено, выведем в Serial порт его ID, и само сообщение. Сейчас, для простоты, выведем первые 4 байта массива, считая, что больше отправлено не будет.

// -------Получение сообщений из can-------
  while(HAL_FDCAN_GetRxFifoFillLevel(hfdcan1, FDCAN_RX_FIFO0) > 0 )
    {
      FDCAN_RxHeaderTypeDef Header;  // хидер для входящего сообщения
      uint8_t RxData[4]; // максимальная длина сообщения - 64 байта 
      if (HAL_FDCAN_GetRxMessage(hfdcan1, FDCAN_RX_FIFO0, &Header, RxData) != HAL_OK){ Serial.println("error"); 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("  ");
    }
    }
  delay(100);

В конце цикла добавили задержку в 100 милисекунд.

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

Пример отправки и получения сообщения по CAN FD

В целом код будет отличаться только настройками в setup() (названиями вызываемых функций):

  Serial.begin(115200);
  pinMode(LED2, OUTPUT);
  /* Настройка FD CAN
  */
  SystemClock_Config();  // Настройка тактирования
  canfd = new CanFD();  // Создаем управляющий класс
  canfd->init(); // Инициализация CAN
  canfd->write_default_params();  // Записываем дефолтные параметры для FDCAN (500000 nominal / 4000000 data)
  canfd->apply_config();  // Применяем их
  hfdcan1 = canfd->get_hfdcan();  // Сохраняем конфиг
  canfd->default_start();
 

  TxHeader.Identifier = 0x68;
  TxHeader.DataLength = FDCAN_DLC_BYTES_4;
  TxHeader.IdType = FDCAN_EXTENDED_ID;

Загрузите программу на плату. Проверить действительно ли все сообщения отправляются в can можно на Raspberry с помощью утилиты candump, а чтобы отправить сообщение воспользуйтесь утилитой cansend. О том как работают утилиты было расказано в .

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

главе Работа с CAN на Raspberry
здесь
Коммуникации-FDCAN
3KB
example_recv_send_can_classic.ino
3KB
example_recv_send_canfd.ino