深入学习CAN总线技术的笔记

CAN学习笔记

硬件部分:

1、仅有 CAN_L 和 CAN_H 两条总线

2、显性电平为逻辑值0,隐性电平为逻辑值1

软件部分:
CAN的基本知识
(一)、CAN帧的种类

帧可以看做是用于传输信息的邮件单位,帧由段组成,段由二进制位组成

实验室主要用到数据帧

img

上图中灰体为显性电平0

名称 描述
帧起始 表示帧的开始,产生一个bit的显性电平。
仲裁段 表示帧的优先级, 由标识符(ID)和传送帧类型(RTR)组成。
控制端 表示数据的字节数,由6个bit构成
数据段 数据的具体内容,可发送0~8 个字节的数据。
CRC段 用于校验传输是否正确。
ACK段 表示确认是否正常接收。
帧结束 表示此帧结束。

△仲裁段:

ID为报文的名字,可通过CAN的过滤器筛选

RTR表示为数据帧还是远程帧(0表示数据帧)

△控制段:

IDE表示为标准格式还是扩展格式(0表示为标准格式)

DLC表示数据部分的长度,前面的r0、r1编程时不用管,默认为0(显性电平)即可

△数据段:

可以用来存放0~8个字节的数据

(二)CAN总线的传输速率

由APB1 peripheral clocks开始分频

(三)CAN总线的过滤机制

1、屏蔽位模式:报文ID符合目标ID的指定部分便允许通过(屏蔽码)

2、标识符列表模式:一模一样才能通过(与期望ID比较)

(四)CAN总线的发送和接收

1、CAN接收:FIFO相当于接收邮箱(开启接收中断0或1即开启FIFO0或FIFO1)

每个FIFO有三级深度,相当于可以储存3个CAN报文

2、CAN发送:通过发送邮箱Tx Mailboxes实现

​ 准备完成的CAN报文将被填入到空闲的发送邮箱中,等待上一个邮箱中存储的报文发送完成,之后进行发送。

(五)CAN在cubemx上配置

1、使能CAN

2、调与分频系数、时间片1、时间片2和SWJ(通常为1),调节至波特率与外设要求的一致

3、打开CAN接收和发送中断

CAN的代码编写

(六)CAN接收:过滤器组配置

参考函数:

/* 定义CAN过滤器寄存器位宽类型 */
typedef union
{
	__IO uint32_t value; //32位的value变量,存储一个寄存器的值,而下面的结构体是对其进行细分
	struct
	{
		uint8_t REV : 1; //< [0] :未使用,1bit
		uint8_t RTR : 1; //< [1] : RTR(数据帧或远程帧标志位),1bit
		uint8_t IDE : 1; //< [2] : IDE(标准帧或扩展帧标志位),1bit
		uint32_t EXID : 18; //< [21:3] : 存放扩展帧ID,18bits
		uint16_t STID : 11; //< [31:22]: 存放标准帧ID,11bits
	} Sub;
} CAN_FilterRegTypeDef;
/**
* @brief CAN过滤器配置(屏蔽位模式)若要使用列表模式,则可自行修改注释多余语句
* @parma _id:目标ID号,标准ID
* @parma _filter_num:当前配置的过滤器组号,0-27
* @return NULL
* @author Lingzi_Xie
* @note _id配置为全0时,表示全通
*/
void CAN_Filter_Config(uint32_t _id, uint16_t _filter_num)
{
	CAN_FilterTypeDef sFilterConfig;
	CAN_FilterRegTypeDef IDH = {0};
	CAN_FilterRegTypeDef IDL = {0}; 
	IDH.Sub.STID = (_id >> 16) & 0xFFFF; //把标准ID高16位放在寄存器1的STID域
	IDL.Sub.STID = (_id & 0xFFFF); //把标准ID低16位放在寄存器2的STID域
	/* 过滤器配置,参照HAL库CAN_FilterTypeDef的相关注释完成
	配置模式、位宽、ID、MaskID、关联FIFO、使
	能激活 */
	//加载过滤器配置
	if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
	{
		Error_Handler();
	}
}

​ 之后调用 HAL_CAN_Start(&hcan); 使能CAN外设。

△FilterMode:过滤器模式,分列表模式(CAN_FILTERMODE_IDLIST)和掩码模式(CAN_FILTERMODE_IDMASK

列表模式下,scale为32时,每个过滤器的列表只能写入两个报文ID,若scale为16时,每个过滤器的列表最多可写入4个CAN ID;而掩码模式则无需担心容量,完全取决于屏蔽码。

32位宽的列表模式下,FilterIdHigh与FilterIdLow一起用来存放一个CAN ID,FilterMaskIdHigh与FilterMaskIdLow用来存放另一个CAN ID,不再表示其字面所示的mask含义;16位宽的列表模式下,FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow这4个16位变量都是用来存储一个标准CAN ID;32位掩码模式下,CAN_FxR1(FilterIdHigh与FilterIdLow)用做32位宽的验证码,而CAN_FxR2(FilterMaskIdHigh与FilterMaskIdLow)则用作32位宽的屏蔽码。

△FilterScale:位宽(CAN_FILTERSCALE_32BITCAN_FILTERSCALE_16BIT

△FilterFIFOAssignment:FIFO的名称(0或1U)

△FilterNumber:过滤器编号,一共有0~27号过滤器

△FilterActivation:使能 ENABLE 即可

△BankNumber:单CAN设备通常设为14,无需理会;双CAN设备则填开启的过滤器编号

	关于过滤器的ID配置,使用标准数据帧通信时:

1、想配置成全通,则32位的屏蔽位模式下,ID和MaskID直接全0就行;
2、想配置成过滤特定ID,则32位的屏蔽位模式下,ID和MaskID都配置成目标ID就行啦;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhvtpHUO-1668156680313)(D:\Temp\WeChat Files\26f95c41a6d1a7d3001729c1359cedf.png)]

(七)CAN接收:中断回调函数编写

​ 报文存入FIFO后会触发CAN外设的Pending中断,故程序可通过配置此中断的 回调函数实现对报文的取出:

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
{
	//CAN数据接收
	if (canHandle->Instance == CAN1)
	{
		CAN_RxHeaderTypeDef RxHeader;  //接受句柄
        //获得接收到的数据头和数据
		if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &RxHeader, packet.payload) == HAL_OK)
		{
			//判断接收到的报文ID号,并作出对应的解包处理
			if(packet.hdr.StdId == 0x205)
			{
				/* 解包处理 */
			}
		}
	}
}

(八)CAN发送:发送报文的配置

​ 对于发送报文,我们需要先准备好发送报文的头部(ID、RTR、IDE和DLC等配置)和数据部分, 后直接调用 HAL_CAN_AddTxMessage() 即可,下面给出两种报文发送函数的写法

/**
* @brief Send an communication frame by CAN.
* @param hcan :CAN bus used to send.
* @param ID :ID of frame.
* @param *pData:Data to send.(pData可以换成函数内的局部变量)
* @param Len :Length of data.(通常取8)
* @return CAN_SUCCESS: Operation success.
* @return CAN_LINE_BUSY:CAN line busy.
* @要调的参数需要手动添加
*/
uint8_t CANx_SendData(uint16_t ID,uint8_t *pData,uint16_t Len)
{
	static CAN_TxHeaderTypeDef Tx_Header;
	uint32_t used_mailbox;
	/* 发送报文的Header配置,参照HAL库CAN_TxHeaderTypeDef的相关注释完成
	Header配置ID、RTR、IDE、DLC
	若发送标准格式的报文,则扩展ID填充全0即可;扩展格式同理 */
    
    //对发送的数据进行打包处理
    
	if(HAL_CAN_AddTxMessage(&hcanx,&Tx_Header,pData,&used_mailbox)!= HAL_OK)
	{
		return CAN_LINE_BUSY;
	}
	else{}
	return CAN_SUCCESS;
}

/**
 * @brief  发送标准ID的数据帧
 * @param  hcan     CAN的句柄
 * @param  ID       数据帧ID
 * @param  pData    数组指针
 * @param  Len      字节数0~8(通常取8)
 * @要调的参数需要手动添加
 */
uint8_t CANx_SendStdData(uint16_t ID,uint16_t Len)
{
    static CAN_TxHeaderTypeDef   Tx_Header;
    uint8_t pData[8];
    
	Tx_Header.StdId=ID;
	Tx_Header.ExtId=0;
	Tx_Header.IDE=CAN_ID_STD;
	Tx_Header.RTR=CAN_RTR_DATA;
	Tx_Header.DLC=Len;
    
    //对发送的数据进行打包处理
    
        /*找到空的发送邮箱,把数据发送出去*/
	if(HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX0) != HAL_OK) //
	{
		if(HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX1) != HAL_OK)
		{
			HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX2);
         }
     }
}

/**
 * @brief  发送扩展ID的数据帧
 * @param  hcan     CAN的句柄
 * @param  ID       数据帧ID
 * @param  pData    数组指针
 * @param  Len      数据长度0~8(通常取8)
 * @要调的参数需要手动添加
 */
 uint8_t CANx_SendExtData(uint32_t ID,uint8_t *pData,uint16_t Len)
{
	static CAN_TxHeaderTypeDef   Tx_Header;
	uint8_t pData[8];
     
	Tx_Header.StdId=0;
	Tx_Header.ExtId=ID;
	Tx_Header.IDE=CAN_ID_EXT;
 	Tx_Header.RTR=CAN_RTR_DATA;
	Tx_Header.DLC=Len;
     
     //对发送的数据进行打包处理
     
        /*找到空的发送邮箱,把数据发送出去*/
	if(HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX0) != HAL_OK) //
	{
		if(HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX1) != HAL_OK)
		{
			HAL_CAN_AddTxMessage(&hcanx, &Tx_Header, pData, (uint32_t*)CAN_TX_MAILBOX2);
		}
     }
}


扩展:CAN的仲裁机制

△在CAN总线中,只要有一个CAN设备发出了显性电平,那么整条总线均表现为显性电平。

△CAN设备在进行报文发送时,会同时监听总线上的状态( 回读机制 ,通过收发器的Rx引脚回传 读取到的状态到控制器)。

△若在发送仲裁段时,本设备对比到其发出的二进制位和总线上当前的二进制位 不一致 ,说明此时 有 优先级更高(由第一条机制可知显然显性电平(二进制位1)优先级高于为0的) 的CAN设备在发送报文,则本设备停止报文发送( 退出竞争 )。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pMfARZxo-1668156680313)(C:\Users\殇之哈士奇\AppData\Roaming\Typora\typora-user-images\image-20211005165626885.png)]

	上图中ID 25处Node_A的显性电平覆盖了Node_B的隐性电平,则Node_B暂时停止发送报文,而Node_A仲裁胜出可以继续发送(优先级更高)

器的Rx引脚回传 读取到的状态到控制器)。

△若在发送仲裁段时,本设备对比到其发出的二进制位和总线上当前的二进制位 不一致 ,说明此时 有 优先级更高(由第一条机制可知显然显性电平(二进制位1)优先级高于为0的) 的CAN设备在发送报文,则本设备停止报文发送( 退出竞争 )。

[外链图片转存中…(img-pMfARZxo-1668156680313)]

	上图中ID 25处Node_A的显性电平覆盖了Node_B的隐性电平,则Node_B暂时停止发送报文,而Node_A仲裁胜出可以继续发送(优先级更高)
物联沃分享整理
物联沃-IOTWORD物联网 » 深入学习CAN总线技术的笔记

发表评论