目录
一、概念
1、简述
2、CAN 的几种模式
二、实践
1、环回模式轮询通信
1.1 软件配置
1.2 代码编写
2、环回模式中断通信
2.1 软件配置
2.2 代码编写
一、概念
1、简述
STM32微控制器系列包含多个型号,其中一些型号集成了CAN(Controller Area Network)控制器,使其可以直接通过硬件接口实现CAN通信。CAN总线是一种多主总线,用于实时应用,例如在汽车、工业自动化和医疗设备中进行数据通信。
2、CAN 的几种模式
CAN(Controller Area Network)通信支持几种不同的操作模式,这些模式主要设计用于系统初始化、调试、故障检测和网络管理。
1. 正常模式(Normal Mode): 这是最常见的模式,在这种模式下,CAN节点可以发送和接收数据。所有的CAN功能都是可用的,节点可以参与总线上的数据交换,包括数据帧和远程帧的发送与接收。这是CAN总线在日常操作中最常用的模式。
2. 环回模式(Loopback Mode): 在环回模式下,节点发送的数据会被立即重定向回到同一节点的接收器。这意味着节点可以发送一个数据帧,并立即在同一节点上接收该帧,而不将其发送到总线上。这种模式主要用于测试CAN硬件和软件的正确性,因为它允许开发者检查发送的数据是否与接收的数据一致,而无需其他网络节点的参与。
3. 静默模式(Silent Mode): 在静默模式下,节点可以接收数据,但是不会向总线发送任何数据。这意味着即使在检测到总线上的数据帧或远程帧时,节点也不会进行应答或发送任何数据。静默模式通常用于监控网络活动,而不干扰网络通信。例如,在进行故障诊断时,工程师可能只想观察网络上的数据流,而不是影响它们。
4.静默环回模式(Silent Loopback Mode):它结合了静默模式和环回模式的特点,即节点既不会向总线发送数据,同时也会将发送的数据在内部进行环回,用于更细致的测试和调试目的。
二、实践
1、环回模式轮询通信
1.1 软件配置
1.2 代码编写
if(CAN_SetFilters()==HAL_OK)
{
printf("ID Filter: Only Odd IDs \r\n");
}
if(HAL_CAN_Start(&hcan1)==HAL_OK)
{
printf("CAN is start \r\n");
}
uint8_t msgID=1;
while (1)
{
//CAN_TestPoll(msgID++,CAN_RTR_DATA);//数据帧
//printf("\r\n \r\n");
HAL_Delay(2000);
CAN_TestPoll(msgID++,CAN_RTR_REMOTE);//遥控帧
printf("\r\n \r\n");
}
HAL_StatusTypeDef CAN_SetFilters()
{
CAN_FilterTypeDef canFilter;
canFilter.FilterBank=0;
canFilter.FilterMode=CAN_FILTERMODE_IDMASK;
canFilter.FilterScale=CAN_FILTERSCALE_32BIT;
canFilter.FilterIdHigh =0x0020;
canFilter.FilterIdLow = 0x0000;
canFilter.FilterMaskIdHigh = 0x0020;
canFilter.FilterMaskIdLow = 0x0000;
canFilter.FilterFIFOAssignment=CAN_FILTER_FIFO0;
canFilter.FilterActivation = CAN_FILTER_ENABLE;
canFilter.SlaveStartFilterBank = 14;
HAL_StatusTypeDef result = HAL_CAN_ConfigFilter(&hcan1, &canFilter);
return result;
}
void CAN_TestPoll(uint8_t msgID, uint8_t frameType)
{
uint8_t txData[8];
txData[0]=msgID;
txData[1]=msgID+11;
CAN_TxHeaderTypeDef TxHeader;
TxHeader.StdId=msgID;
TxHeader.RTR=frameType;
TxHeader.IDE=CAN_ID_STD;
TxHeader.DLC = 2;
TxHeader.TransmitGlobalTime =DISABLE;
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)<1){}
uint32_t TxMailbox;
if(HAL_CAN_AddTxMessage(&hcan1, &TxHeader, txData, &TxMailbox)!=HAL_OK)
{
printf("Send to mailbox error \r\n");
return ;
}
//uint8_t tempStr[30];
printf("Send MsgID= %d \r\n",msgID);
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=3){}
//轮询方式接收消息
HAL_Delay(1);
if(HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0)!=1)
{
printf("Message is not received \r\n");
return ;
}
printf("Message is received \r\n");
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];
if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData)==HAL_OK)
{
printf("StdID=%ld \r\n",RxHeader.StdId);
printf("RTR(0=Data,2=Remote)=%ld \r\n",RxHeader.RTR);
printf("IDE(0=Std,4=Ext)=%ld \r\n",RxHeader.IDE);
printf("DLC(Data Length)=%ld \r\n",RxHeader.DLC);
if(TxHeader.RTR == CAN_RTR_DATA)
{
printf("Data[0] = %d \r\n",RxData[0]);
printf("Data[1] = %d \r\n",RxData[1]);
}
}
}
2、环回模式中断通信
2.1 软件配置
2.2 代码编写
if(CAN_SetFilters()==HAL_OK)
{
printf("ID Filter: Only Odd IDs \r\n");
}
if(HAL_CAN_Start(&hcan1)==HAL_OK)
{
printf("CAN is start \r\n");
}
uint8_t msgID=1;
__HAL_CAN_ENABLE_IT(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);//使能接收中断
__HAL_CAN_ENABLE_IT(&hcan1,CAN_IT_RX_FIFO1_MSG_PENDING);
while (1)
{
CAN_SendMsg(msgID++,CAN_RTR_DATA);
HAL_Delay(1000);
printf("\r\n \r\n");
}
HAL_StatusTypeDef CAN_SetFilters()
{
CAN_FilterTypeDef canFilter;
//设置FIFO0的筛选器
canFilter.FilterBank=0;
canFilter.FilterMode=CAN_FILTERMODE_IDMASK;
canFilter.FilterScale=CAN_FILTERSCALE_32BIT;
canFilter.FilterIdHigh =0x0020;
canFilter.FilterIdLow = 0x0000;
canFilter.FilterMaskIdHigh = 0x0020;
canFilter.FilterMaskIdLow = 0x0000;
canFilter.FilterFIFOAssignment=CAN_FILTER_FIFO0;
canFilter.FilterActivation = CAN_FILTER_ENABLE;
canFilter.SlaveStartFilterBank = 14;
HAL_StatusTypeDef result = HAL_CAN_ConfigFilter(&hcan1, &canFilter);
if(result!=HAL_OK)
{
return result;
}
//设置FIFO1的筛选器
canFilter.FilterBank=1;
canFilter.FilterIdHigh =0x0000;
canFilter.FilterIdLow = 0x0000;
canFilter.FilterMaskIdHigh = 0x0000;
canFilter.FilterMaskIdLow = 0x0000;
canFilter.FilterFIFOAssignment=CAN_FILTER_FIFO1;
result = HAL_CAN_ConfigFilter(&hcan1, &canFilter);
return result;
}
void CAN_SendMsg(uint8_t msgID, uint8_t frameType)
{
CAN_TxHeaderTypeDef TxHeader;
TxHeader.StdId=msgID;
TxHeader.RTR=frameType;
TxHeader.IDE=CAN_ID_STD;
TxHeader.DLC = 4;
TxHeader.TransmitGlobalTime =DISABLE;
uint32_t random32bit;
HAL_RNG_GenerateRandomNumber(&hrng,&random32bit);
uint8_t txData[8];
txData[0]= random32bit & 0x000000FF;
txData[1]=(random32bit & 0x0000FF00)>>8;
txData[2]=(random32bit & 0x00FF0000)>>16;
txData[3]=(random32bit & 0xFF000000)>>24;
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)<1){}
printf("Send MsgID = %d \r\n",msgID);
uint32_t TxMailbox;
if(HAL_CAN_AddTxMessage(&hcan1, &TxHeader, txData, &TxMailbox)!=HAL_OK)
{
printf("Send to mailbox error \r\n");
return ;
}
}
void CAN_ReadMsg(uint32_t FIFO_num)
{
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];
if(FIFO_num == CAN_RX_FIFO0)
{
printf("Message received by FIFO0 \r\n");
if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData)!=HAL_OK)
{
printf("Read FIFO0 error \r\n");
return ;
}
}
else if(FIFO_num == CAN_RX_FIFO1)
{
printf("Message received by FIFO1 \r\n");
if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO1, &RxHeader, RxData)!=HAL_OK)
{
printf("Read FIFO1 error \r\n");
return ;
}
}
printf("StdID=%ld \r\n",RxHeader.StdId);
printf("RTR(0=Data,2=Remote)=%ld \r\n",RxHeader.RTR);
printf("IDE(0=Std,4=Ext)=%ld \r\n",RxHeader.IDE);
printf("DLC(Data Length)=%ld \r\n",RxHeader.DLC);
printf("Data = %02X %02X %02X %02X \r\n",RxData[0],RxData[1],RxData[2],RxData[3]);
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_ReadMsg(CAN_RX_FIFO0);
}
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_ReadMsg(CAN_RX_FIFO1);
}