STM32F105之双CAN通讯(TD341SCANH)

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO国际标准化的串行通信协议。

在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需要。目前有着许多行业应用着CAN通讯,其中被广泛地应用行业有自动化、船舶、医疗设备、工业设备等。

今天博主就给大家讲讲主要的CAN通讯的硬件设计及代码的编写,博主选用的CAN芯片为金升阳CAN通讯模块TD341SCANH,此款芯片性能稳定可靠。以下是通讯电路图及芯片实物图,供大家参考:


对于MCU,选用携带双CAN通道的单片机STM32F105R8T6,,因为网上大多基本上都是单独的CAN通讯,没有双CAN通讯,所以博主来分享一波,其中PA11、PA12为CAN0通道引脚,PB12、PB13为CAN1通道引脚。
CAN.c文件里面把引脚初始化,然后决定扩展帧及标准帧的类别,最后去去设置波特率及过滤接收ID:

/**
  ******************************************************************************
  * File Name          : CAN.c
  * Description        : This file provides code for the configuration
  *                      of the CAN instances.
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2021 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "can.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;

uint8_t Rx1_data[8];
uint8_t Rx2_data[8];

/* CAN1 init function */
void MX_CAN1_Init(void)   //波特率=Fpclk1/((CAN_BS1_4TQ+1+CAN_BS2_4TQ+1+1)*brp);
{

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 16;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_4TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

}
/* CAN2 init function */
void MX_CAN2_Init(void)
{

  hcan2.Instance = CAN2;
  hcan2.Init.Prescaler = 16;
  hcan2.Init.Mode = CAN_MODE_NORMAL;
  hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan2.Init.TimeSeg1 = CAN_BS1_4TQ;
  hcan2.Init.TimeSeg2 = CAN_BS2_4TQ;
  hcan2.Init.TimeTriggeredMode = DISABLE;
  hcan2.Init.AutoBusOff = DISABLE;
  hcan2.Init.AutoWakeUp = DISABLE;
  hcan2.Init.AutoRetransmission = DISABLE;
  hcan2.Init.ReceiveFifoLocked = DISABLE;
  hcan2.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan2) != HAL_OK)
  {
    Error_Handler();
  }

}

static uint32_t HAL_RCC_CAN1_CLK_ENABLED=0;

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* CAN1 clock enable */
    HAL_RCC_CAN1_CLK_ENABLED++;
    if(HAL_RCC_CAN1_CLK_ENABLED==1){
      __HAL_RCC_CAN1_CLK_ENABLE();
    }
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**CAN1 GPIO Configuration    
    PA11     ------> CAN1_RX
    PA12     ------> CAN1_TX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspInit 1 */

  /* USER CODE END CAN1_MspInit 1 */
  }
  else if(canHandle->Instance==CAN2)
  {
  /* USER CODE BEGIN CAN2_MspInit 0 */

  /* USER CODE END CAN2_MspInit 0 */
    /* CAN2 clock enable */
    __HAL_RCC_CAN2_CLK_ENABLE();
    HAL_RCC_CAN1_CLK_ENABLED++;
    if(HAL_RCC_CAN1_CLK_ENABLED==1){
      __HAL_RCC_CAN1_CLK_ENABLE();
    }
  
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**CAN2 GPIO Configuration    
    PB12     ------> CAN2_RX
    PB13     ------> CAN2_TX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* CAN2 interrupt Init */
    HAL_NVIC_SetPriority(CAN2_RX1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN2_RX1_IRQn);
  /* USER CODE BEGIN CAN2_MspInit 1 */

  /* USER CODE END CAN2_MspInit 1 */
  }
}

void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
{

  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspDeInit 0 */

  /* USER CODE END CAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    HAL_RCC_CAN1_CLK_ENABLED--;
    if(HAL_RCC_CAN1_CLK_ENABLED==0){
      __HAL_RCC_CAN1_CLK_DISABLE();
    }
  
    /**CAN1 GPIO Configuration    
    PA11     ------> CAN1_RX
    PA12     ------> CAN1_TX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

    /* CAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspDeInit 1 */

  /* USER CODE END CAN1_MspDeInit 1 */
  }
  else if(canHandle->Instance==CAN2)
  {
  /* USER CODE BEGIN CAN2_MspDeInit 0 */

  /* USER CODE END CAN2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CAN2_CLK_DISABLE();
    HAL_RCC_CAN1_CLK_ENABLED--;
    if(HAL_RCC_CAN1_CLK_ENABLED==0){
      __HAL_RCC_CAN1_CLK_DISABLE();
    }
  
    /**CAN2 GPIO Configuration    
    PB12     ------> CAN2_RX
    PB13     ------> CAN2_TX 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_13);

    /* CAN2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
  /* USER CODE BEGIN CAN2_MspDeInit 1 */

  /* USER CODE END CAN2_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */

void  CAN_FilterInit(CAN_HandleTypeDef *hcan1)//CAN1 中断0
{
	
		CAN_FilterTypeDef  CAN_FilterInitStructure;
   	CAN_FilterInitStructure.FilterMode=CAN_FILTERMODE_IDMASK; 	//掩码模式
  	CAN_FilterInitStructure.FilterScale=CAN_FILTERSCALE_32BIT; //32位 
	
		CAN_FilterInitStructure.FilterIdHigh=0x000<<5;//32位ID	
		CAN_FilterInitStructure.FilterIdLow=0x0000;
		CAN_FilterInitStructure.FilterMaskIdHigh=0xf0e0;//32位MAS 
	 	CAN_FilterInitStructure.FilterMaskIdLow=0x0000;

		CAN_FilterInitStructure.FilterBank=0;//过滤器号0
  	CAN_FilterInitStructure.FilterFIFOAssignment=CAN_RX_FIFO0;//用FIFO接收信息
		CAN_FilterInitStructure.FilterActivation=ENABLE; //激活过滤器0
	
		CAN_FilterInitStructure.SlaveStartFilterBank=14;	//仅双机通讯有效
	
	if(HAL_CAN_ConfigFilter(hcan1,&CAN_FilterInitStructure)!=HAL_OK)
		Error_Handler();
	
	if(HAL_CAN_ActivateNotification(hcan1,CAN_IT_RX_FIFO0_MSG_PENDING)!=HAL_OK)
		Error_Handler();
	
	if(HAL_CAN_Start(hcan1)!=HAL_OK)
		Error_Handler();
	
}


void  CAN_FilterInit2(CAN_HandleTypeDef *hcan2)//CAN2中断1
{
	
		CAN_FilterTypeDef  CAN_FilterInitStructure;
	  CAN_FilterInitStructure.FilterBank=0;
   	CAN_FilterInitStructure.FilterMode=CAN_FILTERMODE_IDMASK; 	//掩码模式
	
  	CAN_FilterInitStructure.FilterScale=CAN_FILTERSCALE_32BIT; //32位 
	
		CAN_FilterInitStructure.FilterIdHigh=0x04<<5;//32位ID	
		CAN_FilterInitStructure.FilterIdLow=0x0000;
		CAN_FilterInitStructure.FilterMaskIdHigh=0xf0e0; //32位MAS 0xffff;32位MAS 
	 	CAN_FilterInitStructure.FilterMaskIdLow=0x0000;
	
		CAN_FilterInitStructure.FilterBank=14;//过滤器号14   		//针对STM32F105R8T6,g过滤器号设置为大于13才能通讯
  	CAN_FilterInitStructure.FilterFIFOAssignment=CAN_RX_FIFO1;//用FIF1接收信息
		CAN_FilterInitStructure.FilterActivation=ENABLE; //激活过滤器14
	
		CAN_FilterInitStructure.SlaveStartFilterBank=14;	//仅双机通讯有效
	
	if(HAL_CAN_ConfigFilter(hcan2,&CAN_FilterInitStructure)!=HAL_OK)
		Error_Handler();
	
	if(HAL_CAN_ActivateNotification(hcan2,CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
		Error_Handler();
	
	if(HAL_CAN_Start(hcan2)!=HAL_OK)
		Error_Handler();
	
}

//接收函数1
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1)//接收中断CAN1 中断0
{
		CAN_RxHeaderTypeDef rx_header;
		
		HAL_CAN_GetRxMessage(hcan1,CAN_RX_FIFO0,&rx_header,Rx1_data);//调用内部CAN接收函数
    HAL_CAN_ActivateNotification(hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);		//接收中断  
	  CAN_Send_Msg_1(hcan1,Rx1_data,8,0x613);
}


//接收函数2
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan2)//CAN2 接收中断1
{
		CAN_RxHeaderTypeDef rx_header_2;
		
		HAL_CAN_GetRxMessage(hcan2,CAN_RX_FIFO1,&rx_header_2,Rx2_data);//调用内部CAN接收函数
    HAL_CAN_ActivateNotification(hcan2,CAN_IT_RX_FIFO1_MSG_PENDING);		//接收中断完成 	
}


//发送函数1
void CAN_Send_Msg_1(CAN_HandleTypeDef *hcan1,uint8_t *msg,uint8_t len,uint16_t id)//发送中断CAN1 中断0
{
	
		CAN_TxHeaderTypeDef tx_header;
		uint32_t TxMailBox;
		
		tx_header.ExtId = id;			    //扩展帧ID->ExtId  标准帧->Stdid
		tx_header.IDE = CAN_ID_EXT;		//使用扩展帧
		tx_header.RTR = CAN_RTR_DATA;	//使用数据帧
		tx_header.DLC = len;			//数据长度
		
		HAL_CAN_AddTxMessage(hcan1,&tx_header,msg,&TxMailBox);//CAN发送函数
	
}

//发送函数2
void CAN_Send_Msg_2(CAN_HandleTypeDef *hcan2,uint8_t *msg,uint8_t len,uint16_t id)//can2发送
{
	
		CAN_TxHeaderTypeDef tx_header;
		uint32_t TxMailBox;
		
		tx_header.StdId = id;			
		tx_header.IDE = CAN_ID_STD;		//使用标准帧
		tx_header.RTR = CAN_RTR_DATA;	//使用数据帧
		tx_header.DLC = len;			//数据长度
		
		HAL_CAN_AddTxMessage(hcan2,&tx_header,msg,&TxMailBox);//CAN发送函数
	
	
}

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

CAN.h文件:

/**
  ******************************************************************************
  * File Name          : CAN.h
  * Description        : This file provides code for the configuration
  *                      of the CAN instances.
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2021 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __can_H
#define __can_H
#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
	 
#include "usart.h"
	 
/* USER CODE END Includes */
extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;
extern uint8_t Rx1_data[8];
extern uint8_t Rx2_data[8];
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_CAN1_Init(void);
void MX_CAN2_Init(void);

/* USER CODE BEGIN Prototypes */

void CAN_FilterInit(CAN_HandleTypeDef *hcan);//接收过滤器1初始化
void  CAN_FilterInit2(CAN_HandleTypeDef *hcan2);//接收过滤器2初始化

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1);//接收函数FIFO
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan2);//接收函数FIFO1
//void  HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan1);
void CAN_Send_Msg_1(CAN_HandleTypeDef *hcan1,uint8_t *msg,uint8_t len,uint16_t id);//发送函数1

void CAN_Send_Msg_2(CAN_HandleTypeDef *hcan2,uint8_t *msg,uint8_t len,uint16_t id);//发送函数2

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ can_H */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

后续主函数直接调用库文件即可。

以上为测试数据记录,如果需要源代码可收藏加关注,博主可分享源文件

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值