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****/
后续主函数直接调用库文件即可。
以上为测试数据记录,如果需要源代码可收藏加关注,博主可分享源文件