基于STM32F429和HAL库的CAN收发例程
1.CAN协议介绍
  CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串⾏通信
协议。在当前的汽车产业中,出于对安全性、舒适性、⽅便性、低公害、低成本的要求,各种
各样的电⼦控制系统被开发了出来。由于这些系统之间通信所⽤的数据类型及对可靠性的要求
不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、
stm32怎么使用printf“通过多个 LAN,进⾏⼤量数据的⾼速通信”的需要, 1986 年德国电⽓商博世公司开发出⾯
向汽车的 CAN 通信协议。此后, CAN 通过 ISO11898 及 ISO11519 进⾏了标准化,现在在欧
洲已是汽车⽹络的标准协议。
现在, CAN 的⾼性能和可靠性已被认同,并被⼴泛地应⽤于⼯业⾃动化、船舶、医疗设
备、⼯业设备等⽅⾯。现场总线是当今⾃动化领域技术发展的热点之⼀,被誉为⾃动化领域的
计算机局域⽹。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有
⼒的技术⽀持。
CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,
⼆者必居其⼀。发送⽅通过使总线电平发⽣变化,将消息发送给接收⽅。
2.Cube配置
  基本配置跳过,直接讲CAN的配置,只是收发的话,配好CAN的时钟加上开个接收中断就⾏了。CAN的时钟配置是挂载在APB1的时钟上的,可根据这⼀点来计算CAN总线的波特率,⽐如本例程的APB1是45MHz,则CAN总线的波特率为:45M/((9+5+1)*6)M=500KMz。
要注意的是F429的CAN数据线的GPIO⼝是在PA11和PA12,但Cube⾃动⽣成的不是这两个GPIO⼝。记得改⼀下GPIO⼝复⽤,软件要和硬件要匹配。
Cube⽣成的代码如下:
/* Includes ------------------------------------------------------------------*/
#include "can.h"
/* USER CODE BEGIN 0 */
/
* USER CODE END 0 */
CAN_HandleTypeDef hcan1;
/* CAN1 init function */
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 6;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_9TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_5TQ;
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();
}
}
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_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**CAN1 GPIO Configuration
PA11    ------> CAN1_RX
PA12    ------> CAN1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
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 */
}
}
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_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 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
3.Cube收发例程
  除了Cube的配置外,我们还要配置⼀个CAN_FilterTypeDef(CAN1滤波器)和⼀个CAN_TxHeaderTypeDef(CAN1发送消息句柄),然后
就可以启动CAN,使能CAN中断,⾄于CAN_RxHeaderTypeDef(CAN1接收消息句柄)只⽤定义不⽤配置。CAN_TxHeaderTypeDef hCAN1_TxHeader; //CAN1发送消息
CAN_RxHeaderTypeDef hCAN1_RxHeader; //CAN1接收消息
CAN_FilterTypeDef hCAN1_Filter; //CAN1滤波器
/*******************************************************************************
* Function Name  : vApp_CAN_TxHeader_Init
* Description    : 初始化发送帧头句柄
* Input          : pHeader 发送帧头指针
StdId 标识符
ExtId 扩展标识符
IDE 0:标准帧 1:拓展帧
RTR 0:数据帧 1:远程帧
DLC 数据长度
* Output        : None
* Return        : None
****************************************************************************** */
void vApp_CAN_TxHeader_Init(CAN_TxHeaderTypeDef    * pHeader,
uint32_t                            StdId,
uint32_t                            ExtId,
uint32_t                            IDE,
uint32_t                            RTR,
uint32_t                            DLC)
{
pHeader->StdId    = StdId;    //11位标准标识符
pHeader->ExtId    = ExtId;    //29位扩展标识符
pHeader->IDE        = IDE;        //1位        0:标准帧 1:拓展帧
pHeader->RTR        = RTR;      //1位  0:数据帧 1:远程帧
pHeader->DLC        = DLC;        //4位发送的数据的长度
pHeader->TransmitGlobalTime    =    ENABLE;
}    /*******************************************************************************
* Function Name  : vApp_CAN_Filter_Init
* Description    : 初始化滤波器
* Input          : pFilter 滤波器句柄,初始化全部值
IdHigh,
IdLow,
MaskIdHigh,
MaskIdLow,
FIFOAssignment,
Bank,
Mode,
Scale,
Activation,
SlaveStartFilterBank
* Output        : None
* Return        : None
****************************************************************************** */
void vApp_CAN_Filter_Init(CAN_FilterTypeDef * pFilter,
uint32_t IdHigh,
uint32_t IdLow,
uint32_t MaskIdHigh,
uint32_t MaskIdLow,
uint32_t FIFOAssignment,
uint32_t Bank,
uint32_t Mode,
uint32_t Scale,
uint32_t Activation,
uint32_t SlaveStartFilterBank)
{
pFilter->FilterIdHigh                = 0;
pFilter->FilterIdLow                  = 0;
pFilter->FilterMaskIdHigh        =    0;
pFilter->FilterMaskIdLow            =    0;
pFilter->FilterFIFOAssignment = CAN_FILTER_FIFO0;
pFilter->FilterBank                    = 0;
pFilter->FilterMode                    = CAN_FILTERMODE_IDMASK;
pFilter->FilterScale                    = CAN_FILTERSCALE_32BIT;
pFilter->FilterActivation        = ENABLE;
pFilter->SlaveStartFilterBank = 0;
}
/*******************************************************************************
* Function Name : vApp_User_CAN_Configuration
* Description : 初始化CAN(⽤户修改)
* Input : None
* Output : None
* Return : None
****************************************************************************** */
void vApp_User_CAN_Configuration(void)
{
/*----------------- CAN初始化配置 --------------------------*/
vApp_CAN_Configuration(&hCAN1_TxHeader, &hCAN1_Filter,
/* TxHeader 句柄配置 */
/* StdId ExtId IDE RTR DLC */
0x12, 0, CAN_ID_STD, CAN_RTR_DATA, 8,
/* Filter 句柄配置 */
/* IdHigh IdLow MaskIdHigh MaskIdLow FIFOAssignment Bank Mode Scale Activation SlaveStartFilterBank */
0, 0, 0, 0, CAN_FILTER_FIFO0, 0, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, ENABLE, 0);
}
/*******************************************************************************
* Function Name  : vApp_CAN_Configuration
* Description    : CAN初始化配置,配置发送帧头,配置滤波器
* Input          : (...)
* Output        : None
* Return        : None
****************************************************************************** */
void vApp_CAN_Configuration(CAN_TxHeaderTypeDef    * pTxHeader,
CAN_FilterTypeDef    * pFilter,
uint32_t                            StdId,
uint32_t                            ExtId,
uint32_t                            IDE,
uint32_t                            RTR,
uint32_t                            DLC,
uint32_t                            IdHigh,
uint32_t                            IdLow,
uint32_t                            MaskIdHigh,
uint32_t                            MaskIdLow,
uint32_t                            FIFOAssignment,
uint32_t                            Bank,
uint32_t                            Mode,
uint32_t                            Scale,
uint32_t                            Activation,
uint32_t                            SlaveStartFilterBank)
{
/*-1- 初始化TxHeader句柄 ----------------------------------------*/
vApp_CAN_TxHeader_Init(pTxHeader, StdId, ExtId, IDE, RTR, DLC);
/
*-2- 初始化滤波器句柄 ------------------------------------------*/
vApp_CAN_Filter_Init(pFilter, IdHigh, IdLow, MaskIdHigh, MaskIdLow, FIFOAssignment, Bank, Mode, Scale, Activation, SlaveStartFilterBank);    HAL_CAN_ConfigFilter(&hcan1, pFilter);
/*-3- 启动CAN ---------------------------------------------------*/
while(HAL_CAN_Start(&hcan1) != HAL_OK )
{
printf("\nCAN_Start Failed!!");
HAL_Delay(100);
}
printf("\nCAN_Start Success!!");
/*-4- 使能中断通知 ----------------------------------------------*/
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
}
发送的只⽤调⽤HAL库的HAL_CAN_AddTxMessage函数就⾏了
/*******************************************************************************
* Function Name : vApp_User_CAN1_TxMessage
* Description : 使⽤CAN1发送数据
* Input : None
* Output : None
* Return : None
****************************************************************************** */
void vApp_User_CAN1_TxMessage(uint8_t aTxData[], uint8_t DLC)
{
vApp_CAN_TxMessage(&hcan1, &hCAN1_TxHeader, aTxData, DLC);
}
/*******************************************************************************
* Function Name  : vApp_CAN_TxMessage
* Description    : 邮箱发送数据
* Input          : hcan
pTxHeader 发送帧头
aData 数据段

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。