STM32 CAN通讯配置

简介

CAN通信帧共分为数据帧、远程帧、错误帧、过载帧和帧间隔,本文这里以数据帧为例。

注:显性电平对应逻辑0,CAN_H和CAN_L之差为2.5V左右。而隐性电平对应逻辑1,CAN_H和CAN_L之差为0V, 数据帧有标准帧和扩张帧两种格式,一个11位,一个29位

标准帧和扩张帧两种格式区别:

  • 扩展帧的仲裁域有29位,可以出现2^29中报文,且在数据链路上是有间隙的(对操作者透明),帧ID的范围是0000 0000-1FFF FFFF。(PS:目的就是构造29位的CAN ID,可以实现更加庞大的ID群)
  • 标准帧的仲裁域是连续的11位,可以出现2^11种报文,也就是帧ID的范围是000-7FF;
  • 标准帧和扩张帧的控制帧中的DLC(数据长度)完全相同,但保留位不同,标准帧为IDE、R0,扩展帧为R1、R0,必须以显性电平发送(由数据链路层操作)

注意:这里的帧ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级(帧ID值越小,优先级越高,最小是0x00000000)

CAN协议特点:

1、多主控制。
2、系统柔软性。
3、通讯速度快,通讯距离远。
4、具有错误检测、错误通知、错误恢复功能。
5、故障封闭功能。
6、连接节点多。

CAN总线具有自动仲裁功能,这样就提高了总线的利用率。

CAN总线没有被发送出去的隐性信号,会由CAN控制器后续发送出去。这里牵涉到CAN总线优先级的问题,后续进一步讲述。
当然,CAN相比485具有明显优势,主要原因还是在于CAN控制器。

CAN直接通过TX连接对方的RX引脚,单向传输可以,双向传输就不行,因为CAN控制器会实时监测发送出去的信号是否正确。也就是说TX要与RX信号一致才行,否则CAN控制器认为你发送失败。

CAN总线收发,中断方式接收配置

平台:STM32F103RB
STM32CUBEMX V5.3


配置CAN

CAN的波特率最大为1Mbps。

波特率计算方法:时钟主频 / 分频 / (tq1 + tq2 + swj)

以500K的波特率配置为例
stm32f103的CAN的时钟主频是36M,分9频就是4M,在除以(5 + 2 + 1)得到500K的波特率。
注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。

在这里插入图片描述
在这里插入图片描述

CAN之数据帧格式

在这里插入图片描述

代码部分

CAN初始化

CAN_HandleTypeDef hcan1;
CAN_FilterTypeDef sFilterConfig;

//CAN初始化:

/* CAN init function */
void MX_CAN_Init(void)
{
	hcan1.Instance = CAN1;
	hcan1.Init.Prescaler = 9;
	hcan1.Init.Mode = CAN_MODE_LOOPBACK;					// 回环模式,测试用。
	hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
	hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
	hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
	hcan1.Init.TimeTriggeredMode = DISABLE;					// 时间触发通信模式禁能
	hcan1.Init.AutoBusOff = DISABLE;						// 软件自动离线管理禁能
	hcan1.Init.AutoWakeUp = DISABLE;						// 睡眠模式自动唤醒禁能
	hcan1.Init.AutoRetransmission = DISABLE;				// 报文自动重传禁能
	hcan1.Init.ReceiveFifoLocked = DISABLE;					// 报文锁定禁能,新报文覆盖旧报文
	hcan1.Init.TransmitFifoPriority = ENABLE;				// 使能优先级由报文标识符决定
	if (HAL_CAN_Init(&hcan1) != HAL_OK)
	{
		Error_Handler();
	}

	sFilterConfig.FilterBank = 0;									// 使用过滤器0
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;				// 屏蔽位模式
	sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;				// 32位宽
	sFilterConfig.FilterIdHigh = 0x0000;							// ID高十六位
	sFilterConfig.FilterIdLow = 0x0000;								// ID低十六位
	sFilterConfig.FilterMaskIdHigh = 0x0000;						// ID掩码高十六位
	sFilterConfig.FilterMaskIdLow = 0x0000;							// ID掩码低十六位
	sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;				// 过滤器0关联到FIFO0
	sFilterConfig.FilterActivation = ENABLE;						// 激活过滤器0
	sFilterConfig.SlaveStartFilterBank = 14;
	if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
	{
		Error_Handler();
	}

	if (HAL_CAN_Start(&hcan1) != HAL_OK)
	{
		Error_Handler();
	}

	if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)		// 使能FIFO0数据中断接收
	{
		Error_Handler();
	}
}

覆写接收中断回调函数

(注意:上面的配置我们使用的式FIFO0,所以要覆写FIFO0的中断回调函数):

void can_msg_info(CAN_RxHeaderTypeDef* hdr, const void* data)
{
	printf("IDE     : %s\r\n",
			hdr->IDE == CAN_ID_STD ? "CAN_ID_STD" : "CAN_ID_EXT");
	printf("RTR     : %s\r\n",
			hdr->RTR == CAN_RTR_DATA ? "CAN_RTR_DATA" : "CAN_RTR_REMOTE");
	printf("DLC     : %ld\r\n", hdr->DLC);
	printf("StdId   : 0x%X\r\n", hdr->StdId);
	printf("ExtId   : 0x%X\r\n", hdr->ExtId);
	printf("Data    : %s\r\n", (char *) data);
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if (hcan->Instance == hcan1.Instance)
	{
		uint8_t buf[8];
		CAN_RxHeaderTypeDef CAN_RX_HDR;
		if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, buf)			// 获得接收到的数据头和数据
				== HAL_OK)
		{
			can_msg_info(&CAN_RX_HDR, buf);
			HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);	// 再次使能FIFO0接收中断
		}
	}
}

CA发送函数:

uint8_t CAN_Transmit(const void* buf, uint32_t len)
{
	uint32_t txmailbox = 0;
	uint32_t offset = 0;
	CAN_TxHeaderTypeDef hdr;

	hdr.IDE = CAN_ID_STD;				// 帧ID:标准帧
	hdr.RTR = CAN_RTR_DATA;				// 帧类型:数据帧
	hdr.StdId = 0x12;					// 标准帧ID,最大11位,也就是0x7FF
	hdr.ExtId = 0x12;					// 扩展帧ID,最大29位,也就是0x1FFF
	hdr.TransmitGlobalTime = DISABLE;

	while(len != 0)
	{
		hdr.DLC = len > 8 ? 8 : len;		// 数据长度
		if(HAL_CAN_AddTxMessage(&hcan1, &hdr, ((uint8_t *)buf) + offset, &txmailbox) != HAL_OK)
			return 1;
		offset += hdr.DLC;
		len -= hdr.DLC;
	}
	return 0;
}

附注:stm32cubemx can配置参数详解:

配置参数

参数意思
Prescaler预分频,即位时序提到的APB1 peripheral clocks继续分一次频
Time Quantum最小时间单位Tq,自动计算出来的,不需要填写
Time Quanta in Bit Segment 1PBS1段长度
Time Quanta in Bit Segment 2PBS2段长度
ReSynchronization Jump Width重同步跳跃宽度,即位时序提到的SJW
Time Triggered Communication Mode是否使能时间触发
Automatic Bus-Off Management是否使能自动离线管理
Automatic Wake-Up Modet是否使能自动唤醒
Qutomatic Retransmission是否使能自动重传
Receive Fifo Locked Mode是否使能锁定FIFO
Transmit Fifo Priority配置报文优先级的判断方法
Oprating Mode操作模式
  1. 这些参数也可以在can.c中自行修改
  2. 中断(NVIC)设置,根据需要设置,一般勾上CAN1 RX0 Interrupt

8.1.2 协议层

位时序

意义:为了实现正确的总线电平采样,确保通讯正常。最小单位是Tq(Time Quantum),一个完整位由8~25个Tq组成
组成:SS段、PTS 段、PBS1段、PBS2段

段名意义作用
SS(1Tq)同步段补偿物理延时,是传播时间、收发器延时之和的两倍
PTS(1~8Tq)传播时间段补偿变压阶段误差
PBS1(1~8Tq)相位缓冲段1使总线各节点同步
PBS2(2~8Tq)相位缓冲段2补偿边沿阶段误差
SJW(1~4Tq)再同步补偿宽度补偿时钟频率偏差、传输延迟等

例如
在这里插入图片描述

通讯波特率的计算:CAN使用的时钟线是APB1 peripheral clocks(假设是APC),即一般是SYSCLK的四分频。而CAN通讯还要对此进行预分频(假设是Prescaler),则一个Tq为 Prescaler / APC(单位s)。而一个数据位占(SS+PTS+PBS1+PBS2+SJW)个Tq。则一秒可以传输的位数就是1 T q ∗ 一 个 位 得 T q 数 \frac{1}{Tq一个位得Tq数}Tq∗一个位得Tq数1
例如:在时钟树查得APB1 peripheral clocks是45MHz,预分频为5,则一个Tq为 4 45 M H z = 111.1111 … ( n s ) \frac{4}{45MHz}=111.1111\dots(ns)45MHz4=111.1111…(ns) ,上图中有19个Tq,则此时波特率为1 19 ∗ 111.11 ∗ 1 0 − 9 ≈ 473689 ( b p s ) \frac{1}{19
111.11*10^{-9}}\approx473689(bps)19∗111.11∗10−91≈473689(bps)

  • 4
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
STM32是一种高性能的32位微控制器,具有广泛的应用领域。其中,CAN(Controller Area Network)通讯STM32最常用的通信协议之一。下面是关于STM32 CAN通讯例程的一些介绍。 STM32 CAN通讯例程是一种用于实现CAN通讯功能的开发示例。该例程提供了一套完整的CAN通讯工作流程,包括初始化CAN模块、配置CAN通讯参数、发送CAN帧和接收CAN帧等。 在使用STM32 CAN通讯例程之前,首先需要在STM32开发板上连接CAN总线,以实现外部设备和STM32的通信。然后,需要通过调用相应的函数来初始化CAN模块,并设置通讯参数,如波特率、过滤器和模式等。 一旦CAN模块初始化完毕,就可以使用相应的函数来发送和接收CAN帧。发送CAN帧需要将数据打包为CAN帧的格式,并使用相应的标识符将其发送到总线上。接收CAN帧需要使用相应的函数持续监听总线上的数据,并将接收到的数据解析为可用的格式。 在进行CAN通讯时,还可以使用中断或DMA来处理接收和发送数据。中断可以实现数据的实时处理和异步通知,而DMA可以实现高速的数据传输,提高系统性能。 STM32 CAN通讯例程具有广泛的应用场景,如汽车电子系统、工业自动化控制和智能家居等。通过学习和理解STM32 CAN通讯例程,开发者可以更好地使用STM32的CAN通讯功能,实现各种实际应用的需求。 总之,STM32 CAN通讯例程提供了一套方便易用的开发示例,帮助开发者快速上手并实现CAN通讯功能。通过学习该例程,开发者可以扩展STM32的应用范围,实现更多有趣和实用的功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路过的小熊~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值