STM32 CAN总线

STM32 CAN基础知识

CAN 波特率计算:

Fpclk1 / ( (CAN_BS1+CAN_BS2+1) * CAN_Prescaler)
pclk1 频率在 CubeMX Clock Configuration 中设置,其余三个在 CubeMX -> CAN1 -> Parameter Setting 中

CAN工作模式讲解
综合参考

一个简单的发送消息的程序

CubeMX 配置

在这里插入图片描述

main函数编辑

在 main 中添加

  /* USER CODE BEGIN 2 */
	HAL_CAN_Start(&hcan1);
	static uint32_t TxMailBox=0;
	uint8_t pData[8]={1,2,3,4,5,6,7,8};
	CAN_TxHeaderTypeDef Header;
	Header.StdId=2;
	Header.ExtId=3;
	Header.IDE=CAN_ID_STD;
	Header.RTR=CAN_RTR_DATA;
	Header.DLC=8;
  /* USER CODE END 2 */

在这里插入图片描述

在 while(1)中

我在D10接了一个灯

		HAL_CAN_AddTxMessage(&hcan1,&Header,pData,&TxMailBox);
		HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_10);
		HAL_Delay(1000);

在这里插入图片描述

发送消息

封装自己的消息发送函数

can.h 中声明
/* USER CODE BEGIN Prototypes */
uint8_t CANSendMsg(uint8_t* msg, uint8_t len, uint8_t std_can_id);
/* USER CODE END Prototypes */

在这里插入图片描述

can.c 中编写函数
/* USER CODE BEGIN 1 */
uint8_t CANSendMsg(uint8_t* msg, uint8_t len, uint8_t std_can_id)
{	
	uint32_t TxMailbox;
  CAN_TxHeaderTypeDef CAN_TxHeader;
  // 设置发送参数
  CAN_TxHeader.StdId = std_can_id;                 // 标准标识符(12bit)
  // CAN_TxHeader.ExtId = 0x00;                 // 扩展标识符(29bit)
  CAN_TxHeader.IDE = CAN_ID_STD;             // 使用标准帧
  CAN_TxHeader.RTR = CAN_RTR_DATA;           // 数据帧
  CAN_TxHeader.DLC = len;                    // 发送长度      
  CAN_TxHeader.TransmitGlobalTime = DISABLE;

  // 发送CAN消息
  if(HAL_CAN_AddTxMessage(&hcan1, &CAN_TxHeader, msg, &TxMailbox) != HAL_OK) 
  {
    return 1;
  }
//  while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3) 
//  {

//  }
  return 0;	

}
/* USER CODE END 1 */

在这里插入图片描述

main函数while中调用

测试代码只发送了前 5个 字节

		uint8_t msg[8]={0,1,2,3,4,5,6,7};
		uint8_t std_can_id = 3;
		CANSendMsg(msg, 5,std_can_id);

在这里插入图片描述

接收消息

STM32 过滤器配置

过滤模式介绍

CAN滤波器的主要作用是筛选CAN接收的数据,只有满足设定规则的数据才会被接收,否则会被过滤掉。
掩码模式:对报文ID的每一位可选择必须相同和不管它。
列表模式:只给出接收的ID,其它的一概不接收。

ID : 0xFED0; (1111111011010000)
屏蔽:0xFFE0;(1111111111100000)
那就是表示,接收端接受帧数据时,前11位的数值必须跟ID中定义的前11位一致,后面的5位数据忽略。不管是什么值都可以。也即是说屏蔽位中的数值:
0: 不关心,该位不用于比较;
1: 必须匹配,到来的标识符位必须与滤波器对应的标识符寄存器位相一致。

代码示例

can.c 中添加下面函数,在 can.h中声明。 设置筛选器,要在完成 CAN 初始化之后调用此函数。

void CAN_Config(void)
{
  CAN_FilterTypeDef  sFilterConfig;

  /* Configure the CAN Filter */
  sFilterConfig.FilterBank = 0;                      // 过滤器编号,使用一个CAN,则可选0-13;使用两个CAN可选0-27
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  // 过滤器模式,掩码模式或列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 过滤器位宽
  sFilterConfig.FilterIdHigh = 0x0000;               // 过滤器验证码ID高16位,0-0xFFFF
  sFilterConfig.FilterIdLow = 0x0000;                // 过滤器验证码ID低16位,0-0xFFFF
  sFilterConfig.FilterMaskIdHigh = 0x0000;           // 过滤器掩码ID高16位,0-0xFFFF
  sFilterConfig.FilterMaskIdLow = 0x0000;            // 过滤器掩码ID低16位,0-0xFFFF
  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // FIFOx,0或1
  sFilterConfig.FilterActivation = ENABLE;           // 使能过滤器
  sFilterConfig.SlaveStartFilterBank = 14;           // 从过滤器编号,0-27,对于单CAN实例该参数没有意义

  if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    /* Filter configuration Error */
  }

  /* Start the CAN peripheral */
  if (HAL_CAN_Start(&hcan) != HAL_OK)
  {
    /* Start Error */
  }

  /* Activate CAN RX notification */
  if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
    /* Notification Error */
  }
}

在这里插入图片描述
main.c
在这里插入图片描述

STM32 接收数据

接收部分只要开启了Rx中断,在CAN控制器收到消息时会调用RxFifo的回调函数,此时我们在这里读取数据并根据实际情况做相应的处理即可。
在这里插入图片描述

/*******************************************************************************
* Function Name  : HAL_CAN_RxFifo0MsgPendingCallback
* Description    : 消息接收回调函数
* Input          : hcan
* Output         : None
* Return         : None
****************************************************************************** */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{// 收到CAN数据会触发接收中断,进入该回调函数
  uint32_t i;
  uint8_t RxData[8];
  CAN_RxHeaderTypeDef CAN_RxHeader; 
  
  if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RxHeader, RxData) == HAL_OK)
  {
    // 串口打印接收结果
    printf("GetRxMessage, CANID:0x%0X, Data:", CAN_RxHeader.StdId);
    for(i = 0;i < CAN_RxHeader.DLC; i++)
    {
      printf("%02x ", RxData[i]);
    }
    // 把接收的数据用CAN再发回去
    CAN_Send_Msg(RxData, CAN_RxHeader.DLC);
  }
}

如果想把接收到的数据传出去,在上面函数中删除 RxData 定义,然后再函数外面定义成全局变量。
can.c

/* USER CODE BEGIN 0 */
uint8_t RxData[8];
/* USER CODE END 0 */

can.h

/* USER CODE BEGIN Private defines */
extern uint8_t RxData[8];
/* USER CODE END Private defines */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值