PROGCONT.RU

Вход Регистрация
О САЙТЕ ГЛАВНАЯ
 

STM32F CAN1 настройка и обмен данными с помощью SPL.

 В этой статье я опишу как настроить модуль CAN для самотестирования и полноценного обмена информации по шине, для этого я буду использовать реальные устройства в виде двух контроллеров один из которых STM32F103C8 на котором и будем экспериментировать. Устройства будут связаны между собой через трансивер( приемопередатчик) на микросхеме TJA1050, который был приобретён в виде готового модуля.
 Ниже схема подключение двух устройств.

нет рисунка

 Не много о принципе отправки и принятия данных, все это модуль CAN делает автоматически из за особенности интерфейса и для этого у него имеются специальные регистры которые называются почтовые ящики( mailbox). Для отправки данных по шине в один из трех почтовых ящиков записываются передаваемые данные, конфигурация сообщения и даётся команда на отправку, после того как шина освободится сообщение будет передано автоматически модулем CAN.
 Принимается данные тоже автоматически используя для этого специальные фильтра, если идентификатор сообщения соответствуют условию фильтра то оно сохраняется в один из двух буферов FIFO0 или FIFO1, прием данных тоже контролируется регистрами принимающих почтовых ящиков которых два, один на каждый буфер.


Примеры программ настройки и отправки данных.

 Первый пример используется для самопроверки работы модуля CAN1 выводы TX и RX которого будут соединены внутри контроллера с помощью режима CAN_Mode_Silent_LoopBack, так что во внешнем подключении нет необходимости. Программа работает просто CAN1 отправляет данные и сам же принимает через прерывание, для визуализации у меня к GPIOC вывод 13 подключен светодиод если все нормально то есть пришли данные, совпадает переданный идентификатор и два байта данных то светодиод должен мигать, для проверки можете изменить какой нибудь один из трех перечисленных параметров тогда светодиод не будет мигать.

#include "stm32f10x.h"
//Структура для отправки данных.
CanTxMsg TxMessage;
//Структура для принятых данных.
CanRxMsg RxMessage;
void Pause( uint32_t p);
int main(void){
RCC_DeInit();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef LED_pc13;
LED_pc13.GPIO_Mode= GPIO_Mode_Out_OD;
LED_pc13.GPIO_Pin= GPIO_Pin_13;
LED_pc13.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init( GPIOC, &LED_pc13);
//Объявляем структуру настройки CAN1 и заполняем её параметрами.
CAN_InitTypeDef CAN_InitStructure;
CAN_DeInit( CAN1);
CAN_StructInit( &CAN_InitStructure);
CAN_InitStructure.CAN_TTCM= DISABLE;//Отключён захват времени.
CAN_InitStructure.CAN_ABOM= DISABLE;//Не работает автоматическое отключение шины от ошибок.
CAN_InitStructure.CAN_AWUM= DISABLE;//Отключён автоматический выход из сна.
CAN_InitStructure.CAN_NART= DISABLE;//Работает автоматическая повторная отправка сообщений.
CAN_InitStructure.CAN_RFLM= DISABLE;//Буфера будут перезаписаны новыми сообщениями если переполнены.
CAN_InitStructure.CAN_TXFP= DISABLE;//Порядок отправки сообщений будет происходить по приоритетам идентификаторов.
CAN_InitStructure.CAN_Mode= CAN_Mode_Silent_LoopBack;//Режим самотестирования.
CAN_InitStructure.CAN_SJW= CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1= CAN_BS1_2tq;
CAN_InitStructure.CAN_BS2= CAN_BS2_3tq;
CAN_InitStructure.CAN_Prescaler= 48;
CAN_Init( CAN1, &CAN_InitStructure);
//Структура для настройки фильтра.
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber= 0;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh= 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow= 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= 0;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);
//Настройка прерывания в NVIC от приёма данных.
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init( &NVIC_InitStructure);
//Включаем прерывание от приема данных.
CAN_ITConfig( CAN1, CAN_IT_FMP0, ENABLE);
//Заполняем структуру для отправки сообщения данными .
TxMessage.StdId= 0x11;
TxMessage.RTR= CAN_RTR_DATA;
TxMessage.IDE= CAN_ID_STD;
TxMessage.DLC= 2;
TxMessage.Data[0]= 0xCA;
TxMessage.Data[1]= 0xFE;

//Зажигаем светодиод.
GPIO_SetBits( GPIOC, GPIO_Pin_13);
while (1){
Pause( 100000);
//Отправляем данные.
CAN_Transmit( CAN1, &TxMessage);
}
}

//Обработчик прерывания от принятия сообщения.
void USB_LP_CAN1_RX0_IRQHandler( void){
//Процедура очищения структуры для принятия сообщения от старых данных.
RxMessage.StdId= 0;
RxMessage.ExtId= 0;
RxMessage.IDE= 0;
RxMessage.DLC= 0;
RxMessage.Data[0]= 0;
RxMessage.Data[1]= 0;
RxMessage.Data[2]= 0;
RxMessage.Data[3]= 0;
RxMessage.Data[4]= 0;
RxMessage.Data[5]= 0;
RxMessage.Data[6]= 0;
RxMessage.Data[7]= 0;
//Читаем данные из FIFO0 в структуру сообщений.
CAN_Receive( CAN1, CAN_FIFO0, &RxMessage);
//Проверяем принятые данные, если совпадают с принятыми то гасим светодиод.
if((RxMessage.StdId== 0x11) && (RxMessage.Data[0]== 0xCA) && (RxMessage.Data[1]== 0xFE)){
GPIO_ResetBits( GPIOC, GPIO_Pin_13);
Pause( 100000);
GPIO_SetBits( GPIOC, GPIO_Pin_13);
}
}
void Pause( uint32_t p){ for( uint32_t i=p; i>0; i--);}


 Прежде чем перейти к следующему примеру давайте разберемся как работают: фильтры сообщений, масштаб и режим CAN_FilterMode_IdList( список идентификаторов) или CAN_FilterMode_IdMask( идентификатор+маска).
 Начнем с фильтра сообщений, единицы в маске говорят что должно точно соответствовать в идентификаторе сообщения и идентификаторе фильтра, нули в маске обозначает что значение битов идентификаторов не важно. Ниже рисунок с примерами, зеленый идентификатор будет принято, красный значит с таким идентификатором сообщение не будет принято.

нет рисунка


 Теперь масштабирование и режим работы фильтра или как он должен по настоящему называться банк, далее поймете почему.
 Каждый банк содержит два регистра по 32 бита, параметр структуры CAN_FilterScale определяет как будет распределена память этих регистров:
CAN_FilterScale_16bit-выделено по 16 бит для идентификаторов и масок, применимо для стандартных идентификаторов длиной 11 бит.
 Порядок в различных режимах:
CAN_FilterMode_IdMask-в CAN_FilterIdLow записывается первый идентификатор в CAN_FilterMaskIdLow его маску, в CAN_FilterIdHigh второй идентификатор и в CAN_FilterMaskIdHigh его маску;
CAN_FilterMode_IdList-в CAN_FilterIdLow, CAN_FilterMaskIdLow, CAN_FilterIdHigh и CAN_FilterMaskIdHigh можно записать четыре идентификатора, порядок будет как они перечислены.
CAN_FilterScale_32bit-выделено 32 бита для идентификаторов и масок, тут возможно применение как к стандартным идентификаторам так и расширенным которые длиной 29 бит.
 Порядок в различных режимах:
CAN_FilterMode_IdMask-в CAN_FilterIdHigh будет старшие биты идентификатора и в CAN_FilterIdLow младшие, в CAN_FilterMaskIdHigh старшие биты маски и в CAN_FilterMaskIdLow младшие, то есть получится только при этих условиях будет один банк один фильтр;
CAN_FilterMode_IdList-в CAN_FilterIdHigh и CAN_FilterIdLow записывается один идентификатор, в CAN_FilterMaskIdHigh и CAN_FilterMaskIdLow второй.

нет рисунка


 Фактически если у нас 14 банка( от 0 до 13) то можно применить для одного буфера( FIFO0 или FIFO1) максимально 28 фильтров идентификатор+маска или 56 фильтра идентификатора при шестнадцатибитном масштабировании, вот и получается что в одном банке может находится до четырех фильтров.
 Узнать номер фильтра который разрешил принять сообщение можно прочитав его в элементе структуры CanRxMsg FMI или как в примере RxMessage.FMI.
 Пример нумерация фильтров показано ниже на картинке.
 

нет рисунка


 Красным помечен банк фильтра который не разу не настраивался и не включен то есть состояние по умолчанию, синим менялось конфигурация банка но отключен, все остальные действующие. Для пояснения, если банк не разу не использовался и не включен то у него будет два фильтра с настройками по умолчанию то есть принадлежат FIFO0, CAN_FilterScale_16bit, CAN_FilterMode_IdMask которые тоже будут иметь свои позиции в нумерации, если банк был просто отключён то его фильтра также сохранят свои позиции в нумерации.
 Для банков фильтров имеется определенный порядок применения если используются одновременно настроенные как CAN_FilterMode_IdMask и CAN_FilterMode_IdList, первыми по порядку модуль CAN будет проверять банки в режиме CAN_FilterMode_IdList, когда они закончатся только тогда будут проверятся CAN_FilterMode_IdMask тоже по порядку.


Рабочий пример и примеры фильтров для сообщений.

 В примере ниже выполнена полная настройка CAN1 для работы в готовом устройстве, показана настройка выводов, фильтров, прием данных в FIFO0 и FIFO1, отправка данных. Для первого пуска я настроил программу в режим тестирования используется режим CAN_Mode_Silent_LoopBack и вставил в комментарии код для проверки принятых данных CAN1 через UART, который можете раскомментировать и проконтролировать прием данных через программу терминал.
 Программа работает следующим образом, в основном теле через паузу отправляются сообщения для отработки каждого фильтра и сохраняются в FIFO0 или FIFO1, если будете использовать UART то на экране программы терминала будут выводится номер фильтра, идентификатор и два байта информации.
 Если проверка работы CAN1 пройдет удачно, тогда можно подключить устройства по схеме которая выложена в начале статьи и переправить режим работы с CAN_Mode_Silent_LoopBack на CAN_Mode_Normal тогда CAN1 будет подключен к внешним выводам контроллера, и будет работать полный анализ ошибок связи в модуле.

#include "stm32f10x.h"
//Структура для отправки данных.
CanTxMsg TxMessage;
//Структура для принятых данных.
CanRxMsg RxMessage;
//Функция очищения структуры для принятия сообщения.
void Cleaning_RxMessage( CanRxMsg* RxMessage_c);
void Pause( uint32_t p);
int main(void){
RCC_DeInit();
RCC_APB1PeriphClockCmd( RCC_APB1Periph_CAN1, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
/*Раскомментируйте для проверки через UART или удалите.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1| RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructureU;
GPIO_InitStructureU.GPIO_Pin= GPIO_Pin_9;
GPIO_InitStructureU.GPIO_Mode= GPIO_Mode_AF_PP;
GPIO_InitStructureU.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructureU);
GPIO_InitStructureU.GPIO_Pin= GPIO_Pin_10;
GPIO_InitStructureU.GPIO_Mode= GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOA, &GPIO_InitStructureU);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate= 115200;
USART_InitStructure.USART_WordLength= USART_WordLength_8b;
USART_InitStructure.USART_StopBits= USART_StopBits_1;
USART_InitStructure.USART_Parity= USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;
USART_Init( USART1, &USART_InitStructure);
USART_Cmd( USART1, ENABLE);
*/
//Настройка выводов CAN1.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11;//CAN1 RX pin.
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_12;//CAN1 TX pin.
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure);
//Объявляем структуру настройки CAN1 и заполняем её параметрами.
CAN_DeInit( CAN1);
CAN_InitTypeDef CAN_InitStructure;
CAN_StructInit( &CAN_InitStructure);
CAN_InitStructure.CAN_TTCM= DISABLE;
CAN_InitStructure.CAN_ABOM= DISABLE;
CAN_InitStructure.CAN_AWUM= DISABLE;
CAN_InitStructure.CAN_NART= DISABLE;
CAN_InitStructure.CAN_RFLM= DISABLE;
CAN_InitStructure.CAN_TXFP= DISABLE;
//Тест режим, для готового устройства CAN_Mode_Normal.
//CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;
CAN_InitStructure.CAN_Mode= CAN_Mode_Silent_LoopBack;
CAN_InitStructure.CAN_SJW= CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1= CAN_BS1_2tq;
CAN_InitStructure.CAN_BS2= CAN_BS2_3tq;
CAN_InitStructure.CAN_Prescaler= 48;
CAN_Init( CAN1, &CAN_InitStructure);
//Структура для настройки фильтра.
CAN_FilterInitTypeDef CAN_FilterInitStructure;
//Настройка фильтра 1, принимаются все идентификаторы которые меньше 15.
CAN_FilterInitStructure.CAN_FilterNumber= 1;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh= 0;
CAN_FilterInitStructure.CAN_FilterIdLow= 0;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 2032<<5;
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);
//Настройка фильтра 2, принимаются все идентификаторы которые больше 15 но не должно быть единиц в младших четырех битах.
CAN_FilterInitStructure.CAN_FilterNumber= 2;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh= 0;
CAN_FilterInitStructure.CAN_FilterIdLow= 0;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 15<<5;
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= CAN_FIFO1;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);
//Настройка прерывания NVIC от приёма данных в FIFO0.
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel= USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init( &NVIC_InitStructure);
//Настройка прерывания NVIC от приёма данных в FIFO1.
NVIC_InitStructure.NVIC_IRQChannel= CAN1_RX1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init( &NVIC_InitStructure);
//Включаем прерывание от приема данных в FIFO0 и FIFO1.
CAN_ITConfig( CAN1, CAN_IT_FMP0, ENABLE);
CAN_ITConfig( CAN1, CAN_IT_FMP1, ENABLE);
while (1){
//Заполняем структуру для отправки сообщения в буфер FIFO0.
TxMessage.StdId= 11;
TxMessage.RTR= CAN_RTR_DATA;
TxMessage.IDE= CAN_ID_STD;
TxMessage.DLC= 2;
TxMessage.Data[0]= 32;
TxMessage.Data[1]= 64;
//Отправляем данные.
CAN_Transmit( CAN1, &TxMessage);
Pause( 5000000);
//Заполняем структуру для отправки сообщения в буфер FIFO1.
TxMessage.StdId= 16;
TxMessage.RTR= CAN_RTR_DATA;
TxMessage.IDE= CAN_ID_STD;
TxMessage.DLC= 2;
TxMessage.Data[0]= 8;
TxMessage.Data[1]= 16;
//Отправляем данные.
CAN_Transmit( CAN1, &TxMessage);
Pause( 5000000);
}
}

//Обработчик прерывания от принятия сообщения в FIFO0.
void USB_LP_CAN1_RX0_IRQHandler(void){
//Очищаем структуру куда будем читать данные.
Cleaning_RxMessage( &RxMessage);
//Читаем данные из FIFO0 в структуру сообщений.
CAN_Receive( CAN1, CAN_FIFO0, &RxMessage);
//Вынимаем из структуры номер банка фильтра, идентификатор сообщения и два байта данных.
uint8_t bank_mes= RxMessage.FMI/2;
uint8_t id_mes= RxMessage.StdId;
uint8_t data1_mes= RxMessage.Data[0];
uint8_t data2_mes= RxMessage.Data[1];
/*Раскомментируйте для проверки через UART или удалите.
USART_SendData( USART1, bank_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, id_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, data1_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, data2_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
*/
}
//Обработчик прерывания от принятия сообщения в FIFO1.
void CAN1_RX1_IRQHandler( void){
//Очищаем структуру куда будем читать данные.
Cleaning_RxMessage( &RxMessage);
//Читаем данные из FIFO1 в структуру сообщений.
CAN_Receive( CAN1, CAN_FIFO1, &RxMessage);
//Вынимаем из структуры номер банка фильтра, идентификатор сообщения и два байта данных.
uint8_t bank_mes= RxMessage.FMI;
uint8_t id_mes= RxMessage.StdId;
uint8_t data1_mes= RxMessage.Data[0];
uint8_t data2_mes= RxMessage.Data[1];
/*Раскомментируйте для проверки через UART или удалите.
USART_SendData( USART1, bank_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, id_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, data1_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
USART_SendData( USART1, data2_mes);
while(!USART_GetFlagStatus( USART1, USART_FLAG_TXE));
*/
}
void Cleaning_RxMessage( CanRxMsg* RxMessage_c){
RxMessage_c->StdId= 0;
RxMessage_c->ExtId= 0;
RxMessage_c->IDE= 0;
RxMessage_c->DLC= 0;
RxMessage_c->FMI= 0;
RxMessage_c->Data[0]= 0;
RxMessage_c->Data[1]= 0;
RxMessage_c->Data[2]= 0;
RxMessage_c->Data[3]= 0;
RxMessage_c->Data[4]= 0;
RxMessage_c->Data[5]= 0;
RxMessage_c->Data[6]= 0;
RxMessage_c->Data[7]= 0;
}
void Pause( uint32_t p){ for( uint32_t i=p; i>0; i--);}


 Для наглядности привожу примеры настройки различных фильтров сообщений.

/* Структура для настройки банка 0 с четырьмя фильтрами для принятия по идентификатору.
Порядок фильтров: 0- CAN_FilterIdLow, 1- CAN_FilterMaskIdLow, 2- CAN_FilterIdHigh, 3- CAN_FilterMaskIdHigh.*/

CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber= 0;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_16bit;
CAN_FilterInitStructure.CAN_FilterIdLow= 0<<5;//Принять ID 0.
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 1<<5; //Принять ID 1.
CAN_FilterInitStructure.CAN_FilterIdHigh= 2<<5; //Принять ID 2.
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 3<<5; //Принять ID 3.
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);

/*Структура для настройки банка 1 двумя фильтрами с использованием маски.
Порядок фильтров: 0- CAN_FilterIdLow и CAN_FilterMaskIdLow, 1- CAN_FilterIdHigh и CAN_FilterMaskIdHigh.*/

CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber= 1;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_16bit;
CAN_FilterInitStructure.CAN_FilterIdLow= 0<<5; //Принять ID 0.
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 2047<<5;
CAN_FilterInitStructure.CAN_FilterIdHigh= 1<<5; //Принять ID 1.
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 2047<<5;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);

/*Структура для настройки банка 2 с двумя фильтрами для принятия по идентификатору.*/
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber= 2;
CAN_FilterInitStructure.CAN_FilterMode= CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale= CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh= 0<<5; ;//Принять ID 0.
CAN_FilterInitStructure.CAN_FilterIdLow= 0;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 1<<5; ;//Принять ID 1.
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment= CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation= ENABLE;
CAN_FilterInit( &CAN_FilterInitStructure);
Статья №41 Дата:01/04/2019

Комментарии.