1.代码配置
1.1外设配置
1.1.1 时钟配置
void Drv_RccConfig(void)
{
/**
系统时钟使能
APB1:低速总线
APB2:高速总线
*/
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/** GPIO 时钟使能 */
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOD);
/** 外设时钟使能 */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM15);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_FDCAN);
}
初始化RCC振荡器,选择内部高速总线
使能GPIOA,B,C,D.
使能对应的中断TIM16,TIM17时钟
使能FDCAN的时钟
1.1.2 引脚配置
void Drv_GpioConfig(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LL_GPIO_PIN_4| LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = GPIO_AF3_FDCAN1;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
注意对应的引脚,本例为PC4,PC5。
功能设置成复用推挽输出。复用功能设置成 GPIO_AF3_FDCAN1。
1.1.3 FDCAN初始化
void Drv_IntCan(void)
{
FDCAN_HandleTypeDef hcan1;
HAL_NVIC_SetPriority(TIM17_FDCAN_IT1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM17_FDCAN_IT1_IRQn);
//FDCAN_FilterTypeDef sFilterConfig;
hcan1.Instance = FDCAN1; ///<寄存器基地址
hcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; ///<时钟分配器 不分频
hcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; ///<经典模式
hcan1.Init.Mode = FDCAN_MODE_NORMAL; ///<正常模式
hcan1.Init.AutoRetransmission = DISABLE; ///<不启动自动重传模式
hcan1.Init.TransmitPause = DISABLE; ///<不启动传输暂停模式
hcan1.Init.ProtocolException = DISABLE; ///<不启动异常传输功能
/* 我使用的时钟频率
波特率:125K
BAUD=Freq/Clock Divider/Prescaler/(Seg1+Seg2+1)
125K=16M/1/4/(27+4+1) = 125K
*/
hcan1.Init.NominalPrescaler = 4;///<仲裁段时钟分频,传统CAN模式时只设置这一段即可
hcan1.Init.NominalSyncJumpWidth = 1; ///<仲裁段同步跳转段的宽度
hcan1.Init.NominalTimeSeg1 = 27; ///<仲裁段时间段1
hcan1.Init.NominalTimeSeg2 = 4 ; ///<仲裁段时间段2
hcan1.Init.DataPrescaler = 4; ///<数据段时钟分频,若工作于传统模式,不需要设置数据段参数
hcan1.Init.DataSyncJumpWidth = 1;
hcan1.Init.DataTimeSeg1 = 27;
hcan1.Init.DataTimeSeg2 = 4;
hcan1.Init.StdFiltersNbr = 1; ///<标准帧滤波器数量
hcan1.Init.ExtFiltersNbr = 5; ///<扩展帧滤波器数量
hcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;// 发送模式:先入先出
if (HAL_FDCAN_Init(&hcan1) != HAL_OK)
{
// Error_Handler();
}
}
上面是发送和接收需要最基础的配置。前面两行是使能中断。后面是配置一些模式,波特率,然后进行初始化。我的注释写的很详细。下面是接收需要配置的一些东西,比如滤波器等。
///<FDCAN滤波器结构定义
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0;
sFilterConfig.FilterID2 = 0;
if (HAL_FDCAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
//Error_Handler();
}
sFilterConfig.IdType = FDCAN_EXTENDED_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0;
sFilterConfig.FilterID2 = 0;
///进行一些初始化操作
if (HAL_FDCAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
//Error_Handler();
}
if (HAL_FDCAN_ConfigGlobalFilter(&hcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
//Error_Handler();
}
HAL_FDCAN_ConfigInterruptLines(&hcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, FDCAN_INTERRUPT_LINE1);
/* Activate Rx FIFO 0 new message notification */
if (HAL_FDCAN_ActivateNotification(&hcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
//Error_Handler();
}
if (HAL_FDCAN_ConfigTxDelayCompensation(&hcan1, 5, 0) != HAL_OK)
{
//Error_Handler();
}
if (HAL_FDCAN_EnableTxDelayCompensation(&hcan1) != HAL_OK)
{
//Error_Handler();
}
现在基本配置基本已经配置好了。
1.2 发送和接收
1.2.1 发送配置。
static void test()
{
FDCAN_TxHeaderTypeDef TxHeader;
static u8 s_u8TxData[8];
static u8 s_u8Flag = 0;
TxHeader.Identifier = 0x111;
//TxHeader.Identifier = 0x111;
TxHeader.IdType = FDCAN_EXTENDED_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader.MessageMarker = 0;
s_u8TxData[0] = 0x01;
s_u8TxData[1] = 0xF0;
s_u8TxData[2] = 0x16;
s_u8TxData[3] = 0x01;
s_u8TxData[4] = 0xFF;
s_u8TxData[5] = 0xFF;
s_u8TxData[6] = 0xFF;
s_u8TxData[7] = 0xFF;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hcan1, &TxHeader, s_u8TxData) != HAL_OK)
{
s_u8Flag = 1;
}
else
{
s_u8Flag = 0;
}
}
发送重点
hcan1->State 正常发送情况应该是busy
hcan1->ErrorCode 错误码是0
hcan1->LatestTxFifoQRequest 这个应该是在0,2,4来回跳。
1.2.2 接收配置
void TIM17_FDCAN_IT1_IRQHandler(void)
{
/* USER CODE BEGIN TIM17_FDCAN_IT1_IRQn 0 */
//FDCAN_HandleTypeDef hcan1;
HAL_FDCAN_IRQHandler(&hcan1);
}
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
static u8 s_u8Rxdata[8];
FDCAN_RxHeaderTypeDef Rx0Msg;
if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0)
{
/* Retrieve Rx messages from RX FIFO0 */
if (HAL_FDCAN_GetRxMessage(&hcan1, FDCAN_RX_FIFO0, &Rx0Msg, s_u8RxData) != HAL_OK)
{
//接收错误
;
}
else
{
;
}
}
}
只要可以进中断就基本没问题。 重点看自己配置的是FIFO0还是FIFO1