HAL库开发——CAN通信

1.1 定义接收过滤器类型定义结构体(CAN_FilterTypeDef)变量,配置包括                                 

使能过滤器

定义过滤器模式:编码模式/掩码模式

定义过滤ID

typedef struct
{
  uint32_t FilterIdHigh;          /*!过滤器验证码ID高16位,只能填0到0xFFFF 中间的数值 */

  uint32_t FilterIdLow;           /*!过滤器ID低16位,只能填0到0xFFFF 中间的数值*/

  uint32_t FilterMaskIdHigh;      /*!过滤器掩码ID高16位,只能填0到0xFFFF中间的数值 */

  uint32_t FilterMaskIdLow;       /*!过滤器掩码ID低16位,只能填0到0xFFFF中间的数值 */

  uint32_t FilterFIF(x)Assignment;  /*!将通过的报文放入哪个FIFOx中,填写FIFO(x) */

  uint32_t FilterBank;            /*!使用过滤器编号。使用一个CAN,则可选 0~13;使用两个CAN可选0~27 */

  uint32_t FilterMode;            /*!过滤器模式选择。掩码模式填写 CAN_FILTERMODE_IDMASK,列表模式填写 CAN_FILTERMODE_IDLIST */

  uint32_t FilterScale;           /*!过滤器位宽,32位是CAN_FILTERSCALE_32BIT,16位是CAN_FILTERSCALE_16BIT */

  uint32_t FilterActivation;      /*!是否使能过滤器,DISABLE 或 ENABLE */

  uint32_t SlaveStartFilterBank;  
} CAN_FilterTypeDef;

关于过滤器模式:由两个32位寄存器组成,通过配置两种位宽,两种模式,得到 四种过滤模式,总结如下

模式
16位列表        可包含四个列表成员
32位列表可包含两个列表成员
16位掩码可包含两组验证码+掩码
32位掩码可包含一组验证码+掩码

注意:FilterIdHigh、FilterIdLow、FilterMaskIdHigh、FilterMaskIdLow这四个成员不是它的名字那么简单,​ 他们的功能取决于使用的过滤器模式。若为列表模式,则不管是FilterId还是FilterMaskId都表示的是列表成员,列表1和列表2。​ 在32位过滤器中,一组High和Low检验同一个CAN ID(FilterIdHigh和FilterIdLow组成一组32位ID);16位过滤器,则可分别独立检验一个ID

1.1.1关于移位操作:

标准帧用16位过滤器表示:FilterIdHigh、FilterIdLow、FilterMaskIdLow、FilterMaskIdLow各可以表示一个列表成员。由于标准帧的ID是11位的,所以需要将其ID左移5位。标准帧用32位过滤器表示:FilterIdHigh、FilterIdLow共同表示一个ID,FilterMaskIdLow、FilterMaskIdLow共同表示一个ID。由于标准帧ID是11位的,故表示时其ID需左移5位存入High,且LOW = 0 | CAN_ID_STD (意思是将IDE位置为0)。扩展帧用32位过滤器表示:扩展帧的ID是29位的,所以将扩展帧ID先左移3位与32位按高位对齐,再右移16位并取低16位,存入High;将扩展帧ID左移3位与32位对齐,再取低16位存入Low。具体操作如下

CAN_FilterTypeDef sFilterConfig                                 //定义过滤器设置结构体变量
uint32_t StdId =0x321;				                            //一个标准CAN ID
uint32_t ExtId =0x1800f001;			                            //一个扩展CAN ID

sFilterConfig.FilterIdHigh = StdId<<5;			                //标准ID放入FilterIdHigh
sFilterConfig.FilterIdLow = 0|CAN_ID_STD;			            //标准ID,故设置IDE位为0

sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;       //扩展帧ID高16位放入                                                                           FilterMaskIdHigh
sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT;	//扩展帧ID高16位放入                                                                           FilterMaskIdLow,并设置                                                                     IDE位为1

1.2 配置CAN接收过滤器HAL_CAN_ConfigFilter

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)

功能:配置CAN过滤器
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,CAN配置结构体的指针
返回值:HAL状态

注意:即使不过滤任何报文,也要将过滤器使能(ENABLE),可以用在掩码模式下将所有位配置为0实现无过滤

    实例:
    CAN_FilterTypeDef can_filter_st;   //创建用于配置过滤器的FilterTypeDef类结构体
    can_filter_st.FilterActivation = ENABLE;     //使能过滤器
    can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式位掩码模式
    can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为32位
    can_filter_st.FilterIdHigh = 0x0000;      //设置ID
    can_filter_st.FilterIdLow = 0x0000;
    can_filter_st.FilterMaskIdHigh = 0x0000;
    can_filter_st.FilterMaskIdLow = 0x0000;
    can_filter_st.FilterBank = 0;    //过滤器编号
    can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0; //把接收到的报文放入到FIFO0邮箱中
    can_filter_st.SlaveStartFilterBank = 14; //为从属can选择开始的过滤库,对于单个CAN实例,这个参数没有意义,不考虑
    HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);//将配置好的结构体作为参数通过函数配置到CAN1的邮箱FIFO0的过滤器

2.开启CAN,HAL_CAN_Start

HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);

功能:开启CAN,一般在while函数前一开始就要打开
参数:CAN句柄指针,&hcan1 或 &hcan2
返回值:返回值:HAL状态

3.1定义发送报文定义结构体(CAN_TxHeaderTypeDef)

配置包括:报文ID,帧类型IDE+RTR,数据长度DLC

typedef struct
{
  uint32_t StdId;    /*!标准ID。参数值只能是 0 到 0x7FF(二进制的11位1) */

  uint32_t ExtId;    /*!扩展ID。参数值只能是 0 到 0x1FFFFFFF(二进制的29位1)*/
    //ExtId 与 StdId 这两个成员根据下面的 IDE 位配置,只有一个是有效的。

  uint32_t IDE;      /*!IDE。HAL库编程时,标准帧填写CAN_ID_STD,扩展帧填写CAN_ID_EXT */

  uint32_t RTR;      /*!RTR。HAL库编程时,数据帧填写CAN_RTR_DATA,遥控帧填写CAN_RTR_REMOTE */

  uint32_t DLC;      /*!DLC。数据长度,参数值只能是 0 到 8 */

  FunctionalState TransmitGlobalTime; /*!< Specifies whether the timestamp counter value captured on start
                          of frame transmission, is sent in DATA6 and DATA7 replacing pData[6] and pData[7].
                          @note: Time Triggered Communication Mode must be enabled.
                          @note: DLC must be programmed as 8 bytes, in order these 2 bytes are sent.
                          This parameter can be set to ENABLE or DISABLE. */

} CAN_TxHeaderTypeDef;

3.2 发送报文,HAL_CAN_AddTxMessage

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, 
CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);

功能:增加一个消息到第一个空闲的 Tx 邮箱,并且激活对应的传输请求

参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,发送报文定义结构体的指针
​ 第三个,数据帧数组的内容,长度不能超过定义的长度
​ 第四个,Tx邮箱,可填 (uint32_t*)CAN_TX_MAILBOX0 ,CAN_TX_MAILBOX1 , CAN_TX_MAILBOX3
返回值:HAL状态

注意:参数pTxMailbox是需要自己定义一个uint32_t的变量去传入,而非使用系统提供的发送邮箱宏定义。不然会进入硬件中断

4.1 定义接收报文定义结构体(CAN_RxHeaderTypeDef)

配置内容同上

typedef struct
{
  uint32_t StdId;   
  uint32_t ExtId;    
  uint32_t IDE;      
  uint32_t RTR;      
  uint32_t DLC;      
  uint32_t Timestamp; /*!< Specifies the timestamp counter value captured on start of frame reception. @note: Time Triggered Communication Mode must be enabled.This parameter must be a number between Min_Data = 0 and Max_Data = 0xFFFF. */

  uint32_t FilterMatchIndex; /*!< Specifies the index of matching acceptance filter element. This parameter must be a number between Min_Data = 0 and Max_Data = 0xFF. */

} CAN_RxHeaderTypeDef;

在中断回调中声明一个该类型结构体,不同配置,作为参数传递给getmessage函数

4.2接收报文

需要先开启中断HAL_CAN_ActivateNotification,第二个参数设置为CAN_IT_RX_FIFO0 _MSG_PENDING

HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs)

功能:使能中断
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,使能哪个中断,在stm32f4xx_HAL_Driver.h中,搜索Receive Interrupts可以查到各宏定义,作为接收端时开启相对应的FIFO邮箱的接受中断
返回值:HAL状态

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, 
uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])

功能:从Rx FIFO收取一个 CAN 帧
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2​
第二个,Rx FIFO,可填 CAN_RX_FIFO0, CAN_RX_FIFO1
​ 第三个,接收报文定义结构体的指针
​ 第四个,接受数据数组
返回值:HAL状态

5. 接收中断回调函数HAL_CAN_RxFifo0MsgPendingCallback

每当CAN完成一帧数据的接收时,即当CAN控制器接收到一个消息并存放在FIFO邮箱中时,就会触发一次CAN接收中断处理函数,接收中断函数完成一些寄存器的处理之后会调用CAN接收中断回调函数。                                                                         

一般在函数里面定义接收报文定义结构体(CAN_RxHeaderTypeDef)结构体变量,并用接收函数HAL_CAN_GetRxMessage接收

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)(根据使用0可能替换成1)

功能:接收回调函数,CAN回调后进行的操作。一般在此接收数据
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2​
返回值:void

6.函数实例

可以分别集成为四个函数

启动函数:启动CAN+使能中断

过滤器配置函数:定义过滤器结构体+配置CAN接收过滤器

发送函数:定义发送报文定义结构体+发送报文至邮箱

回调接收函数:在回调函数中定义接收报文结构体+接收邮箱内报文

启动函数:

void CAN_Start(CAN_HandleTypeDef *hcan)
{
    HAL_CAN_Start(&hcan);
    HAL_CAN_ActivateNotification(&hcan ,CAN_IT_RX_FIFO0_MSG_PENDING);
}

过滤器配置函数:

/**
 * @brief  16位列表模式过滤器配置
 * @param  hcan   CAN的句柄
 * @param  StdId1~StdId4  4个标准ID
 */
	CAN_FilterTypeDef can_filter;   //创建用于配置过滤器的FilterTypeDef类结构体
    can_filter_st.FilterActivation = CAN_FILTER_ENABLE;     //使能过滤器
    can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式为掩码模式
    can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为32位
    can_filter_st.FilterIdHigh = 0x0000;      //设置ID
    can_filter_st.FilterIdLow = 0x0000;
    can_filter_st.FilterMaskIdHigh = 0x0000;  //掩码模式下1为考虑为忽略,全为0即可以接收所有报文
    can_filter_st.FilterMaskIdLow = 0x0000;
    can_filter_st.FilterBank = 0;    //过滤器编码0~27
    can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0; //设置为FIFO0邮箱的过滤器
    can_filter_st.SlaveStartFilterBank = 14; //为从属can选择初始的过滤库,对于单个CAN实例,这个参数没有意义,不用考虑
    HAL_CAN_ConfigFilter(&hcan, &can_filter_st);//将配置好的结构体作为参数通过函数配置到CAN1的邮箱FIFO0的过滤器

发送函数:

    uint8_t TX_data[8];   //创建用于存放所发送数据的数组
	uint32_t mailbox;     //作为SendMessage的参数,返回数据存放的邮箱
	static CAN_TxHeaderTypeDef   Tx_Header; //创建发送报文结构体
	
	Tx_Header.StdId=0x12345678;        //标准帧ID
	Tx_Header.ExtId=0;                   //扩展帧ID,由于IDE配置为标准帧,故EXTID无效
	Tx_Header.IDE=CAN_ID_STD;            //帧类型——标准帧
	Tx_Header.RTR=CAN_RTR_DATA;           //帧类型——数据帧
	Tx_Header.DLC=8;                        //长度——8位
    HAL_CAN_AddTxMessage(&hcan, &Tx_Header, TX_data, &mailbox) //选择1个空置的发送邮箱,请求发送,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,其状态变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空置邮箱。
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
		CAN_RxHeaderTypeDef RxHeader;  //接受句柄	
	  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, Rx_data); //接收数据存放到指定邮箱
}

回调+接收函数:

/**
 * @brief  CAN FIFO0的中断回调函数,在里面完成数据的接收
 * @param  hcan     CAN的句柄
 */
 
 uint8_t date_CAN1[8];//设为全局变量,用于接收CAN1数据
 uint8_t date_CAN2[8];//设为全局变量,用于接收CAN2数据
 
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance ==CAN1)
	{
	  CAN_RxHeaderTypeDef RxHeader;  //创建接收报文结构体,只声明不配置
	  HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, date_CAN1); //接收,CAN邮箱为0
	  return ;
	}
	else if(hcan->Instance == CAN2)
	{
	  CAN_RxHeaderTypeDef RxHeader;  //创建接收报文结构体,只声明不配置
	  HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &RxHeader, date_CAN2); //接收,CAN邮箱为0
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值