hex.pp.ua

Использование CAN в STM8

Controller Area Network на STM8




Вместе с компилятором Raisonance и средой разработки Ride7 поставляется библиотека периферийных устройств для STM8S. У меня она находится по адресу:

"C:\Program Files\Raisonance\Ride\Examples\STM8\ST_Libraries\STM8A-S_StdPeriph_Lib-v2.0.0\Libraries\STM8S_StdPeriph_Driver"

Так вот там есть файл stm8s_can.c, а в нём всё необходимое для работы с CAN. Напомню, что такое CAN. Это такая последовательная пакетная широковещательная сеть, по-английски назыавется Controller Area Network. В сети передаются маленькие пакеты, максимум 8 байт. У них есть идентификаторы, длиной 11 бит (стандартные) или 29 бит (расширенные). Я рассматриваю только вариант, где используются стандартные идентификаторы.

Кроме того, пакеты бывают двух видов — обычный пакет, и запрос на передачу. Запрос это такой пакет, где выставлен бит RTR (remote transmission request).

Настройка

Чтобы работать с CAN, микроконтроллер должен брать частоту из внешнего кварца. Иначе модуль CAN не работает. Поэтому ставим кварц, настраиваем STM8 на работу от внешнего кварца, как описано здесь. В конец функции Init_CPU() добавляем настройку предделителя CAN:

CLK_CANConfig( CLK_CANDIVIDER_1 );

Выводы процессора CAN_TX и CAN_RX нужно настроить на вывод и ввод.

  // CAN_TX
  GPIO_Init( GPIOG, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST );
  // CAN_RX
  GPIO_Init( GPIOG, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT );

Внизу будет ссылка на проект с описываемыми в этой статье исходниками для отладочной платы Reva v3.3. Я использую вот такую дочернюю плату STM8S208RB. В ней, чтобы заработал CAN, нужно организовать внешнюю частоту. Для этого на дочернюю плату можно проводком завести частоту 12 МГц, которая берётся с платы Reva (найдёте на плате пин, который соответствующим образом маркирован). Куда его заводить? На дочерней плате есть шесть «дырок» в левой части, как раз под установку кварца. Проводок можно воткнуть в правую нижнюю дырку, и всё заработает. У меня работает такая схема.

Ещё, на этой плате есть CAN Transiever. Чтобы работал CAN, нужно ещё и его включить. Делается это одной так:

  // Configure the CAN transceiver in active mode
  GPIO_Init( GPIOE, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST );

Инициализация

Дальше идёт инициализация модуля CAN. Полный исходный код смотрите в проекте, ссылка на которой расположена в конце статьи. Здесь покажу только основные строчки, на которые надо обратить внимание.

Параметры, влияющие на частоту передачи в шине CAN:

Параметры ниже подобраны мной для частоты передачи 25 КГц, в то время как частота микроконтроллера 12 МГц (а предделитель CAN равен 1, т.е. те же 12 МГц). Если эти параметры изменятся, то и следующие строчки тоже придётся менять, подбирать параметры заново.

Вычисляется это так:

QUANTA = (1 + BitSeg1 + BitSeg2)
CAN_FRQ = CPU_FRQ / (Presc * QUANTA)

Допустим, хотим частоту CAN 25 КГц, и частота процессора 12 МГц.

25000 = 12000000 / (Presc * QUANTA)

Надо подобрать такую (Presc * QUANTA), чтобы при делении 12 МГц на это число, получалась частота CAN 25 КГц. При вычислении QUANTA нужно иметь в виду, что BitSeg1 может быть в пределах от 1 до 16, а BitSeg2 в пределах от 1 до 8. QUANTA должна получиться в диапазоне от 8 до 25. В нашем случае (Presc * QUANTA) равно 480.

Допустим, выбрали BitSeg1 равным 7, а BitSeg2 равным 2. Тогда QUANTA = (1 + 7 + 2) = 10. Теперь узнаем значение предделителя. (Presc * QUANTA) должно равняться 480. Значит Presc равен 48.

Получаем такие строчки инициализации:

  // 25 КГц
  
  CAN_SynJumpWidth = CAN_SynJumpWidth_1TimeQuantum;
  CAN_BitSeg1 = CAN_BitSeg1_7TimeQuantum;
  CAN_BitSeg2 = CAN_BitSeg2_2TimeQuantum;
  CAN_Prescaler = 48;

Фильтры

Теперь о фильтрах. Фильтры нужны для того, чтобы микроконтроллер не тратил процессорное время на обработку всех приходящих по шине сообщений. Ведь их может быть довольно много, а микроконтроллер должен обрабатывать только какие-то конкретные сообщения с известными ему идентификаторами. Остальные надо фильтровать.

Приведу один возможный пример фильтрации: 8-битный режим фильтрации по списку идентификаторов. Фильтрация в этом режиме возможна по битам 3-10 стандартного идентификатора. В следующем коде у идентификатора 0x5FC сдвигом отбрасываются три младших бита. Не смотрите на то, что другие переменные содержат в названии «mask». В этом режиме все они содержат биты идентификаторов, а не маски. Названы они так для того, чтобы можно было просто и незатейливо использовать их же для другого режима, где эти маски есть.

        
    CAN_FilterNumber = 0;
    CAN_FilterActivation = ENABLE;
    CAN_FilterMode = CAN_FilterMode_IdList;
    CAN_FilterScale = CAN_FilterScale_8Bit;

    CAN_FilterID1     = (0x5FC >> 3);
    CAN_FilterIDMask1 = 0;
    CAN_FilterID2     = 0;
    CAN_FilterIDMask2 = 0;
    CAN_FilterID3     = 0;
    CAN_FilterIDMask3 = 0;
    CAN_FilterID4     = 0;
    CAN_FilterIDMask4 = 0;

Таким образом, пропускаются только сообщения с идентификатором 0x5FC, и те, которые отличаются от него тремя младшими битами. Все остальные сообщения не пропускаются. Добавлять другие разрешённые идентификаторы следует в остальные CAN_FilterID*.

Отправка сообщений

Отправляются сообщения так: формируется пакет и отправляется, что тут ещё скажешь? Я использую такую функцию:

CAN_TxStatus_TypeDef CAN_Send(u16 uId, bool uRtr, u8 uLen, const void* const pData)
{
  CAN_TxStatus_TypeDef TxStatus;  
  CAN_TransmitMailBox_TypeDef TransmitMailbox;  
  u16 uSendLimit;
    
  if (!uRtr)
  {
    if (0 == uLen || uLen > 8 || NULL == pData) return CAN_TxStatus_Failed;
  }
  
  TransmitMailbox = CAN_Transmit(uId, CAN_Id_Standard, 
    uRtr ? CAN_RTR_Remote : CAN_RTR_Data, uLen, (u8*)pData);
    
  uSendLimit = 0xFFF; // Ограничение, чтобы не зависнуть на передаче
  do
  {
    TxStatus = CAN_TransmitStatus(TransmitMailbox); 
  } while (TxStatus != CAN_TxStatus_Ok && uSendLimit--);
  
  if (TxStatus != CAN_TxStatus_Ok)
  {
    printf("CAN: передача сообщения не удалась и отменена.\r\n");
    CAN_CancelTransmit(TransmitMailbox);
  } else
  {
    printf("CAN: Успешная передача сообщения.\r\n");
  }

  return TxStatus;
}

Получение сообщений

Принимаются сообщения в прерывании CAN. Прерывание будет наступать только по приходу сообщений, которые успешно преодолели фильтр. Прерывание выголядит так:

void CAN_RX_IRQHandler(void) interrupt 8
{
  u8 i;
  
  CAN_Receive();
  
  CanMsgIn.id = CAN_GetReceivedId();
  CanMsgIn.rtr = CAN_GetReceivedRTR();
  CanMsgIn.len = CAN_GetReceivedDLC();
  for (i = 0; i < CanMsgIn.len; i++)
  {
    CanMsgIn.dat[i] = CAN_GetReceivedData(i);  
  }  
  
  CAN_PrintMsg();
}

Дальше у меня тут вызывается CAN_PrintMsg(), которая просто выводит пришедшее сообщение на UART.

void CAN_PrintMsg(void)
{
  u8 i;
    
  if (!CanMsgIn.rtr)
  {
    printf("ИД: %04X\tДлина: %d\tRTR: %d\tДанные:", CanMsgIn.id, 
      (int)CanMsgIn.len, (int)CanMsgIn.rtr ? 1 : 0);
    for (i = 0; i < CanMsgIn.len; i++)
    {
      printf(" %02X", (int)CanMsgIn.dat[i]);
    }
  } 
    else
  {
    printf("ИД: %04X\tДлина: %d\tRTR: %d\t", CanMsgIn.id, 
      (int)CanMsgIn.len, (int)CanMsgIn.rtr ? 1 : 0);
    printf("(Запрос сообщения)");
  }
  printf("\r\n");
}

Проект

Скачать пример работы с CAN для STM8S: stm8-can.zip (189 Кб).

система комментирования CACKLE

Автор: амдф
Дата: 26.10.2012


Разделы сайта
Главная
Блог
Native API
NTFS и ReFS
Микроконтроллеры
Справочник NTDLL
Коды NTSTATUS
Разное

Избранное
NTFS Stream Explorer
Native Shell
Тенгвар

Остальное
nvpnhcknn (архив)
English pages
Контакты

Ленты atom
Лента Atom сайта Лента Atom блога



При копировании материалов хорошим тоном будет указание авторства и ссылка на сайт.