STM32F429 基于HAL库的双路CAN中断收发实例


/** \addtogroup can_group can通讯模块 */

/*@{*/

CAN_HandleTypeDef   CAN1_Handler;   //CAN1句柄
CAN_HandleTypeDef   CAN2_Handler;   //CAN1句柄

/**
* \brief     函数功能:CAN1初始化
*
* \param[in] tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1TQ~CAN_SJW_4TQ
* \param[in] tbs2:时间段2的时间单元.   范围:CAN_BS2_1TQ~CAN_BS2_8TQ;
* \param[in] tbs1:时间段1的时间单元.   范围:CAN_BS1_1TQ~CAN_BS1_16TQ
* \param[in] brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
*            波特率=Fpclk1/((tbs1+tbs2+1)*brp); 其中tbs1和tbs2我们只用关注标识符上标志的序号,例如CAN_BS2_1TQ,我们就认为tbs2=1来计算即可。
* \param[in] mode:CAN_MODE_NORMAL,普通模式;CAN_MODE_LOOPBACK,回环模式;
*            Fpclk1的时钟在初始化的时候设置为45M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_8tq,6,CAN_MODE_LOOPBACK);
*            则波特率为:45M/((6+8+1)*6)=500Kbps
* \return    0:   初始化成功
*            其他:初始化失败 
*/
uint8_t CAN1_Mode_Init(uint32_t tsjw,uint32_t tbs2,uint32_t tbs1,uint16_t brp,uint32_t mode) 
{
    CAN_FilterTypeDef  CAN1_FilerConf;
    
    CAN1_Handler.Instance=CAN1; 
    CAN1_Handler.Init.Prescaler=brp;    //分频系数(Fdiv)为brp+1
    CAN1_Handler.Init.Mode=mode;        //模式设置 
    CAN1_Handler.Init.SyncJumpWidth=tsjw;         //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    CAN1_Handler.Init.TimeSeg1=tbs1;         //tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    CAN1_Handler.Init.TimeSeg2=tbs2;         //tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    CAN1_Handler.Init.TimeTriggeredMode=DISABLE;     //非时间触发通信模式 
    CAN1_Handler.Init.AutoBusOff=DISABLE;     //软件自动离线管理
    CAN1_Handler.Init.AutoWakeUp=DISABLE;     //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    CAN1_Handler.Init.AutoRetransmission=DISABLE;      //禁止报文自动重传 
    CAN1_Handler.Init.ReceiveFifoLocked=DISABLE;     //报文不锁定,新的覆盖旧的 
    CAN1_Handler.Init.TransmitFifoPriority=DISABLE;     //优先级由报文标识符决定 
	
    if(HAL_CAN_Init(&CAN1_Handler)!=HAL_OK) return 1;   //初始化
    
    CAN1_FilerConf.FilterIdHigh=0X0000;     //32位ID
    CAN1_FilerConf.FilterIdLow=0X0000;
    CAN1_FilerConf.FilterMaskIdHigh=0X0000; //32位MASK
    CAN1_FilerConf.FilterMaskIdLow=0X0000;  
    CAN1_FilerConf.FilterFIFOAssignment=CAN_FILTER_FIFO0;//过滤器0关联到FIFO0
    CAN1_FilerConf.FilterBank=0;          //过滤器0
    CAN1_FilerConf.FilterMode=CAN_FILTERMODE_IDMASK;
    CAN1_FilerConf.FilterScale=CAN_FILTERSCALE_32BIT;
    CAN1_FilerConf.FilterActivation=ENABLE; //使能滤波器0
    CAN1_FilerConf.SlaveStartFilterBank=15;
	
    if(HAL_CAN_ConfigFilter(&CAN1_Handler,&CAN1_FilerConf)!=HAL_OK) return 2;//滤波器初始化
	
    return 0;
}

/**
* \brief     函数功能:CAN2初始化
*
* \param[in] tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1TQ~CAN_SJW_4TQ
* \param[in] tbs2:时间段2的时间单元.   范围:CAN_BS2_1TQ~CAN_BS2_8TQ;
* \param[in] tbs1:时间段1的时间单元.   范围:CAN_BS1_1TQ~CAN_BS1_16TQ
* \param[in] brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
*            波特率=Fpclk1/((tbs1+tbs2+1)*brp); 其中tbs1和tbs2我们只用关注标识符上标志的序号,例如CAN_BS2_1TQ,我们就认为tbs2=1来计算即可。
* \param[in] mode:CAN_MODE_NORMAL,普通模式;CAN_MODE_LOOPBACK,回环模式;
*            Fpclk1的时钟在初始化的时候设置为45M,如果设置CAN2_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_8tq,6,CAN_MODE_LOOPBACK);
*            则波特率为:45M/((6+8+1)*6)=500Kbps
* \return    0:   初始化成功
*            其他:初始化失败 
*/
uint8_t CAN2_Mode_Init(uint32_t tsjw,uint32_t tbs2,uint32_t tbs1,uint16_t brp,uint32_t mode)
{
    CAN_FilterTypeDef  CAN2_FilerConf;
    
    CAN2_Handler.Instance=CAN2; 
    CAN2_Handler.Init.Prescaler=brp;    //分频系数(Fdiv)为brp+1
    CAN2_Handler.Init.Mode=mode;        //模式设置 
    CAN2_Handler.Init.SyncJumpWidth=tsjw;         //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    CAN2_Handler.Init.TimeSeg1=tbs1;         //tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    CAN2_Handler.Init.TimeSeg2=tbs2;         //tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    CAN2_Handler.Init.TimeTriggeredMode=DISABLE;     //非时间触发通信模式 
    CAN2_Handler.Init.AutoBusOff=DISABLE;     //软件自动离线管理
    CAN2_Handler.Init.AutoWakeUp=DISABLE;     //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    CAN2_Handler.Init.AutoRetransmission=DISABLE;      //禁止报文自动重传 
    CAN2_Handler.Init.ReceiveFifoLocked=DISABLE;     //报文不锁定,新的覆盖旧的 
    CAN2_Handler.Init.TransmitFifoPriority=DISABLE;     //优先级由报文标识符决定 
	
    if(HAL_CAN_Init(&CAN2_Handler)!=HAL_OK) return 1;   //初始化
    
    CAN2_FilerConf.FilterIdHigh=0X0000;     //32位ID
    CAN2_FilerConf.FilterIdLow=0X0000;
    CAN2_FilerConf.FilterMaskIdHigh=0X0000; //32位MASK
    CAN2_FilerConf.FilterMaskIdLow=0X0000;  
    CAN2_FilerConf.FilterFIFOAssignment=CAN_FILTER_FIFO0;//过滤器0关联到FIFO0
    CAN2_FilerConf.FilterBank=15;          //过滤器14
    CAN2_FilerConf.FilterMode=CAN_FILTERMODE_IDMASK;
    CAN2_FilerConf.FilterScale=CAN_FILTERSCALE_32BIT;
    CAN2_FilerConf.FilterActivation=ENABLE; //激活滤波器0
    CAN2_FilerConf.SlaveStartFilterBank=15;
	
    if(HAL_CAN_ConfigFilter(&CAN2_Handler,&CAN2_FilerConf)!=HAL_OK) return 2;//滤波器初始化
	
    return 0;
}
/**
* \brief      函数功能:CAN底层驱动,引脚配置,时钟配置,中断配置
*
* \param[in]  hcan:CAN句柄
* \return   
*            
*/
static int CAN1_CLK_ENABLED=0;

void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
    GPIO_InitTypeDef GPIO_Initure;
    
	if(hcan->Instance == CAN1_Handler.Instance)
	{
		CAN1_CLK_ENABLED++;
		if(CAN1_CLK_ENABLED == 1)
		{
			__HAL_RCC_CAN1_CLK_ENABLE();                //使能CAN1时钟
		}
		
		__HAL_RCC_GPIOA_CLK_ENABLE();			    //开启GPIOA时钟
						
		GPIO_Initure.Pin=GPIO_PIN_11|GPIO_PIN_12;   //PA11,12
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //推挽复用
		GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;         //快速
		GPIO_Initure.Alternate=GPIO_AF9_CAN1;       //复用为CAN1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);         //初始化
		
#if CAN1_RX0_INT_ENABLE  	
		HAL_NVIC_SetPriority(CAN1_RX0_IRQn,1,0);    //抢占优先级1,子优先级0
		HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);          //使能中断
#endif	
	}
	
	if(hcan->Instance == CAN2_Handler.Instance)
	{
		
		__HAL_RCC_CAN2_CLK_ENABLE();                //使能CAN2时钟
		
		CAN1_CLK_ENABLED++;
		if(CAN1_CLK_ENABLED == 1)
		{
			__HAL_RCC_CAN1_CLK_ENABLE();                //使能CAN1时钟
		}
		
		__HAL_RCC_GPIOB_CLK_ENABLE();			    //开启GPIOB时钟
		
		GPIO_Initure.Pin=GPIO_PIN_12|GPIO_PIN_13;   //PB12,13
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //推挽复用
		GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;         //快速
		GPIO_Initure.Alternate=GPIO_AF9_CAN2;       //复用为CAN2
		HAL_GPIO_Init(GPIOB,&GPIO_Initure);         //初始化

#if CAN2_RX0_INT_ENABLE		
		HAL_NVIC_SetPriority(CAN2_RX0_IRQn,1,0);    //抢占优先级1,子优先级0
		HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);          //使能中断
#endif
}
	
    

}

#if CAN1_RX0_INT_ENABLE                         //使能RX0中断
/**
* \brief      函数功能:CAN1中断服务函数
*
* \return   
*            
*/
void CAN1_RX0_IRQHandler(void)
{
    HAL_CAN_IRQHandler(&CAN1_Handler);//此函数会调用CAN_Receive_IT()接收数据
}
#endif

#if CAN2_RX0_INT_ENABLE
/**
* \brief      函数功能:CAN2中断服务函数
*
* \return   
*            
*/
void CAN2_RX0_IRQHandler(void)
{
    HAL_CAN_IRQHandler(&CAN2_Handler);//此函数会调用CAN_Receive_IT()接收数据
}
#endif

#if CAN1_RX0_INT_ENABLE | CAN2_RX0_INT_ENABLE
/**
* \brief      函数功能:CAN中断回调函数
*             此函数会被CAN_Receive_IT()调用
* \param[in]  hcan:CAN句柄
* \return   
*            
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan)
{
    static CAN_RxHeaderTypeDef CAN_RX_HDR;
	CAN_MSG_TYPE CANA_RX_BUF;
	CAN_MSG_TYPE CANB_RX_BUF;
    // CAN1数据接收
    if (hcan->Instance == CAN1_Handler.Instance)
    {

		// 接收数据
		if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CANA_RX_BUF.data) == HAL_OK)		// 获得接收到的数据头和数据
		{	
			CANA_RX_BUF.id = CAN_RX_HDR.StdId;
			CanTasks(CANA_RX_BUF);
			//处理函数
			HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);					// 再次使能FIFO0接收中断
		}
    }

    // CAN2数据接收
    else if (hcan->Instance == CAN2_Handler.Instance)
    {
		// 接收数据
		if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CANB_RX_BUF.data) == HAL_OK)		// 获得接收到的数据头和数据
		{
			CANB_RX_BUF.id = CAN_RX_HDR.StdId;
			CanTasks(CANB_RX_BUF);
			//处理函数
			HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);					// 再次使能FIFO0接收中断
		}
    }
}
#endif	
/**
* \brief      函数功能:can1/can2发送一组数据(标准帧,数据帧)	
*
* \param[in]  buf:要发送的数据结构
* \return   返回值:0,成功;
*		    1,CANA发送失败
*           2,CANB发送失败         
*/

uint8_t CAN12_Transmit(CAN_MSG_TYPE buf)
{
    uint32_t txmailbox = 0;
    uint32_t offset = 0;
    CAN_TxHeaderTypeDef hdr;

    hdr.IDE = CAN_ID_STD;						// ID类型:标准帧
    hdr.RTR = CAN_RTR_DATA;						// 帧类型:数据帧
    hdr.StdId = buf.id;							// 标准帧ID,最大11位,也就是0x7FF
    hdr.TransmitGlobalTime = DISABLE;

    while (buf.len != 0)
    {
        hdr.DLC = buf.len > 8 ? 8 : buf.len;			// 数据长度
        if (HAL_CAN_AddTxMessage(&CAN1_Handler, &hdr, ((uint8_t *)buf.data) + offset, &txmailbox) != HAL_OK)
		{
            return 1;
		}
		if (HAL_CAN_AddTxMessage(&CAN2_Handler, &hdr, ((uint8_t *)buf.data) + offset, &txmailbox) != HAL_OK)
		{
            return 2;
		}
        offset += hdr.DLC;
        buf.len -= hdr.DLC;
    }
    return 0;
}
/**
* \brief      函数功能:CAN12启动
*
* \param[in]  
* \return             
*/
void CAN12_start(void)
{
	HAL_CAN_Start(&CAN1_Handler);
	HAL_CAN_Start(&CAN2_Handler);
	HAL_CAN_ActivateNotification(&CAN1_Handler, CAN_IT_RX_FIFO0_MSG_PENDING);	// 再次使能FIFO0接收中断	  
	HAL_CAN_ActivateNotification(&CAN2_Handler, CAN_IT_RX_FIFO0_MSG_PENDING);	// 再次使能FIFO0接收中断	
}

/*@}*/



#ifndef __CAN_H
#define __CAN_H
#include "sys.h"

typedef struct      /* CAN报文的结构体 */
{
    uint16_t id;        //CAN ID
    uint8_t data[8];    //CAN数据
	uint8_t len;        //CAN数据长度
}CAN_MSG_TYPE;

//CAN接收RX0中断使能
#define CAN1_RX0_INT_ENABLE	1		//0,不使能;1,使能.
#define CAN2_RX0_INT_ENABLE	1		//0,不使能;1,使能.

uint8_t CAN1_Mode_Init(uint32_t tsjw,uint32_t tbs2,uint32_t tbs1,uint16_t brp,uint32_t mode);//CAN1初始化
uint8_t CAN2_Mode_Init(uint32_t tsjw,uint32_t tbs2,uint32_t tbs1,uint16_t brp,uint32_t mode);//CAN2初始化
uint8_t CAN12_Transmit(CAN_MSG_TYPE buf);
void CAN12_start(void);
#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

予叶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值