此次测试是基于正点原子STM32精英版,芯片为STM32F103ZET6
基于HAL库的配置
预分频后为单位时间。Time for one bit 为时间段1和时间段2再加单位时间。时间段1和时间段2为单位时间的整数倍。在上图中为4+4+1倍,即9倍。图片中配置为2000ns,即波特率为500Kbps。
若是想要中断接收数据,还需要打开中断。完成后生成代码即可
CAN过滤器
过滤器是需要自己配置的,而且不配置过滤器CAN不能正常接收数据。
HAL_StatusTypeDef CAN_Filter_Init(CAN_HandleTypeDef *h_can)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 2; //chenal 0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //标识符屏蔽位模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽为单个32位
sFilterConfig.FilterIdHigh = 0xB000; //标识符寄存器
sFilterConfig.FilterIdLow = 0xC400; //标识符寄存器
//MASK bit 0 means don't care,bit 0 means match
sFilterConfig.FilterMaskIdHigh = 0xFE1F; //屏蔽寄存器 //只存在于标识符屏蔽位模式中,在标识符列表模式中为标识符寄存器
sFilterConfig.FilterMaskIdLow = 0xFE1F; //屏蔽寄存器
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //FIFO0的中断和FIFO1的中断是不一样的,这里是把接收到的报文放入到FIFO0中
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; //enable filter
sFilterConfig.SlaveStartFilterBank = 0; //为从属can选择开始的过滤库,对于单个CAN实例,这个参数没有意义
if (HAL_CAN_ConfigFilter(h_can, &sFilterConfig) != HAL_OK)
{
Error_Handler();
return HAL_ERROR;
}
//regist RX_IT
if (HAL_CAN_ActivateNotification(h_can, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) //注册CAN_IT_RX_FIFO0_MSG_PENDING 对应的回调函数原型
{
Error_Handler();
return HAL_ERROR;
}
return HAL_OK;
}
CAN过滤器说明
下图截于STM32的参考手册,对配置过滤器非常重要。
typedef struct
{
__IO uint32_t FR1; //标识符屏蔽位模式中标识符寄存器,配置ID
__IO uint32_t FR2; //标识符屏蔽位模式中屏蔽寄存器
}CAN_FilterRegister_TypeDef; //标识符列表模式中为2个标识符寄存器,配置ID
标识符屏蔽位模式:FxR0为标识符匹配值,FxR1为屏蔽码。若FxR1中某一位为1,FxR0中相应的位必须与收到的帧的标识符中的相应位吻合才能通过过滤器。FxR1中为0的位表示FxR0的相应位可不必与收到的帧进行匹配。
例如:标识符寄存器的bit15=0,屏蔽位寄存器的bit15=1,那么接受的Message里面的标识符的bit15必须为0才可能被硬件接受。如果屏蔽位寄存器的bit15=0,Message里面的标识符的bit15无论为什么值,bit15都能匹配通过。当bit0~bit31都能通过时。此Message就会被硬件接受。
标识符列表模式:FR1和FR2都是要匹配的标识符,收到的帧的标识符必须与其中一个吻合才能通过过滤。
例如:现在设置为0x602和0x601,那么只有ID为0x602和0x601时才会通过过滤器
所有过滤器是并联的,一个报文只要通过了一个过滤器就算是有效的
CAN_FxR1与CAN_FxR2寄存器分别被拆成两段,CAN_FxR1寄存器的高16位对应着代码中的FilterIdHigh,低16位对应着FilterIdLow,而CAN_FxR2寄存器的高16位对应着FilterMaskIdHigh,低16位对应着FilterMaskIdLow。
32位屏蔽位模式下:1个过滤器。FR2指定需要关心哪些位,FR1指定这些位的标准值
32位列表模式下:2个过滤器,FR1指定过滤器0的标准值,FR2指定过滤器1的标准值
16位屏蔽位模式下:2个过滤器。FR1高位配置过滤器0标准值,低位配置给过滤器1的标准值。FR2高位配置过滤器0关心的位,低位配置给过滤器1的关心的位。
16位列表模式下:4个过滤器。FR1低位配置过滤器0,高位配置过滤器1。FR2配置过滤器2和过滤器3
IDE=0为标准ID,IDE=1为扩展ID。
RTR=0代表数据帧,RTR=1代表远程帧。
MASK设置屏蔽码,ID设置标准值。
中断接收
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) //回调函数
HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0, &RxMessage, RxData); //可以读取CAN数据(RxMessage 的定义:CAN_RxHeaderTypeDef RxMessage;)
发送数据
CAN发送数据的函数是要自己写的
uint8_t HAL_CAN_SendTxMessage(CAN_TxHeaderTypeDef TxHeader,uint32_t std_id, uint8_t aData[],uint16_t lengh)
{
uint32_t TxMailBox;
uint8_t FreeTxMailBoxNum;
TxHeader.StdId = std_id;//ID
TxHeader.DLC = lengh;//数据长度
TxHeader.IDE = CAN_ID_STD; //扩展帧/标准帧
TxHeader.RTR = CAN_RTR_DATA;//远程帧/数据帧
TxHeader.TransmitGlobalTime = DISABLE;
while(0 == FreeTxMailBoxNum)
{
FreeTxMailBoxNum = HAL_CAN_GetTxMailboxesFreeLevel(&hcan);//查看空闲邮箱数量
}
if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, aData, &TxMailBox) != HAL_OK)//判断是否发送成功
{
/* Transmission request Error */
Error_Handler();
}
return 1;
}