本文主要记录和总结STM32F767IGT6配置CAN通讯,参考正点原子的HAL库相关例程。工程中的串口配置和printf重定向不在总结。
步骤1:时钟配置
步骤2:CAN配置
波特率是500k
步骤3:TIM3配置
定时器配置作用是在,定时器中断中每1ms接收CAN数据一次
步骤4:CAN.c函数过滤器配置
extern uint8_t CANRecFlag ; //CAN接收表示,完成 1
extern uint8_t CANRec_buff[8]; //CAN接受到的数据位
extern CAN_RxHeaderTypeDef CANRec_msg; //接收消息
CAN_TxHeaderTypeDef TxMessage; //发送消息
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 6;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_6TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
CAN_FilterTypeDef CAN1_FilerConf;
CAN1_FilerConf.FilterBank = 0; //过滤器0
CAN1_FilerConf.FilterMode = CAN_FILTERMODE_IDMASK;
CAN1_FilerConf.FilterScale = CAN_FILTERSCALE_32BIT;
CAN1_FilerConf.FilterIdHigh = 0X0000; //32位ID
CAN1_FilerConf.FilterIdLow = 0X0000;
CAN1_FilerConf.FilterMaskIdHigh = 0X0000; //32位MASK
CAN1_FilerConf.FilterMaskIdLow = 0X0000;
CAN1_FilerConf.FilterFIFOAssignment = CAN_FILTER_FIFO0;//过滤器0关联到FIFO0
CAN1_FilerConf.FilterActivation = ENABLE; //激活滤波器0
CAN1_FilerConf.SlaveStartFilterBank = 14;
if(HAL_CAN_ConfigFilter(&hcan1,&CAN1_FilerConf)!=HAL_OK)
{
Error_Handler();//滤波器初始化
}
if(HAL_CAN_Start(&hcan1)!=HAL_OK)
{
Error_Handler();//CAN打开
}
/* USER CODE END CAN1_Init 2 */
}
发送函数
/**
* @brief CAN 发送一组数据
* @note ID_IDE: 标准ID, 数据帧
* @param ID : 标准ID(11位)
* @param Msg : 数据指针,最大为8个字节.
* @param Len : 数据长度(最大为8)
* @retval
*/
uint8_t CAN_Send_Msg(uint32_t ID, uint8_t *Msg, uint8_t Len,uint32_t ID_IDE)
{
uint32_t TxMailbox = CAN_TX_MAILBOX0;
TxMessage.StdId = ID; /* 标准标识符 */
TxMessage.ExtId = ID; /* 扩展标识符(29位) */
/*表示CAN消息的标识符扩展位,用于指示标识符是标准标识符还是扩展标识符*/
TxMessage.IDE = ID_IDE; //CAN_ID_EXT ;CAN_ID_STD
TxMessage.RTR = CAN_RTR_DATA; /* 数据帧 */
TxMessage.DLC = Len;
if (HAL_CAN_AddTxMessage(&hcan1, &TxMessage, Msg, &TxMailbox) != HAL_OK) /* 发送消息 */
{
/* Transmission request Error */
Error_Handler();
}
return 0;
}
接收函数
/**
* @brief CAN 接收数据查询
* @retval 接收结果
* @arg 0 , 无数据被接收到;
* @arg 其他, 接收的数据长度
*/
uint8_t CAN_Recv_Msg(void)
{
if (HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) >=1) /* 没有接收到数据 */
{
if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &CANRec_msg, CANRec_buff) == HAL_OK) /* 读取数据 */
{
CANRecFlag = 1;
}
}
return CANRec_msg.DLC;
}
定时器初始化中打开定时器中断
在中断函数中添加接收函数
void TIM3_IRQHandler(void)
{
/* USER CODE BEGIN TIM3_IRQn 0 */
/* USER CODE END TIM3_IRQn 0 */
HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */
CAN_Recv_Msg();
/* USER CODE END TIM3_IRQn 1 */
}
main.c函数中进行处理
while (1)
{
if(CANRecFlag)
{
CANRecFlag = 0;
if(CANRec_msg.IDE == CAN_ID_EXT)
{
CAN_Send_Msg(CANRec_msg.ExtId,CANRec_buff,8,CAN_ID_EXT);
for(int i=0;i < 8;i++)
{
printf("CANRec_buff[%d]==%d \r\n",i,CANRec_buff[i]);
}
}
else if (CANRec_msg.IDE == CAN_ID_STD)
{
CAN_Send_Msg(CANRec_msg.StdId,CANRec_buff,8,CAN_ID_STD);
for(int i=0;i < 8;i++)
{
printf("CANRec_buff[%d]==%d \r\n",i,CANRec_buff[i]);
}
}
}
}