1.CAN协议介绍

  CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信
协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种
各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求
不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、
“通过多个 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 = ;
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 = {};
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, , );
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 = ;
pFilter->FilterIdLow = ;
pFilter->FilterMaskIdHigh = ;
pFilter->FilterMaskIdLow = ;
pFilter->FilterFIFOAssignment = CAN_FILTER_FIFO0;
pFilter->FilterBank = ;
pFilter->FilterMode = CAN_FILTERMODE_IDMASK;
pFilter->FilterScale = CAN_FILTERSCALE_32BIT;
pFilter->FilterActivation = ENABLE;
pFilter->SlaveStartFilterBank = ;
}

/*******************************************************************************
* 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();
}
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 数据段
DLC 数据段长度
* Output : None
* Return : None
****************************************************************************** */
void vApp_CAN_TxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef * pTxHeader, uint8_t aData[], uint8_t DLC)
{
uint32_t Tx_MailBox;
/*-1- 配置数据段长度 ----------------------------------------*/
pTxHeader->DLC = DLC;
/*-2- 发送aData ---------------------------------------------*/
while(HAL_CAN_AddTxMessage(hcan, pTxHeader, aData, &Tx_MailBox) != HAL_OK)
{
printf("TxMsg Failed!!");
HAL_Delay();
}
printf("\nSend Tx Message Success!!Tx_Mail:%d", Tx_MailBox); }

接收是用中断回调函数void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)来接收信息,这个是个HAL库里的弱函数,要自己重写。

/*******************************************************************************
* Function Name : HAL_CAN_RxFifo0MsgPendingCallback
* Description : 消息接收回调函数
* Input : hcan
* Output : None
* Return : None
****************************************************************************** */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t aRxData[], i; if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &hCAN1_RxHeader, aRxData) == HAL_OK)
{
printf("\nGet Rx Message Success!!\nData:");
for(i=; i<; i++)
printf("%d", aRxData[i]);
}
}

4.测试

  本次测试用的CAN分析仪是周立功的CANalyst-II,上位机是CANTest,下面介绍一下怎么用。根据上面计算的波特率,设置为500K,然后点最后的一栏

  单片机主函数程序如下:

int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t key;
uint8_t TxData[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
/* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */
SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
vApp_User_CAN_Configuration();
// KEY_Init(); //初始化按键
/* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{
vApp_User_CAN1_TxMessage(TxData, );
/* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

测试结果如下:

发送:

接收:

  

基于STM32F429和HAL库的CAN收发例程的更多相关文章

  1. 分享一个简单易用的软件定时器模块(MultiTimer)——基于keil+stm32f103zet+hal库(裸机实现)

    公众号上看到一个比较好的一个github项目:https://github.com/0x1abin/MultiTimer 今天看了看,简单的,就移植了- 且看文档的说明, ============== ...

  2. 【GMT43智能液晶模块】基于HAL库的SDRAM和LCD驱动例程(MDK工程&CubeMX工程)

    说明: 1.该工程基于HAL库实现动态存储器SDRAM驱动以及液晶控制器LCD驱动. 2.工程通过STM32CubeMX(Version 4.22.0)配置生成,可直接打开进行配置. 3.KEIL M ...

  3. 【书籍连载】《STM32 HAL 库开发实战指南—基于F7》-第一章

    从今天起,每天开始连载一章<STM32 HAL 库开发实战指南—基于F7>.欢迎各位阅读.点评.学习. 第1章  如何使用本书 1.1  本书的参考资料 本书参考资料为:<STM32 ...

  4. STM32F072从零配置工程-基于HAL库的串口UART中断配置

    先上一个采用串口直接传输的Demo: 此处的思路是完全采用HAL库来实现的,核心是运用HAL_UART_Transmit_IT和HAL_UART_Receive_IT两个函数来实现的,可以作为一个De ...

  5. 新建基于STM32F103ZET6的工程-HAL库版本

    1.STM32F103ZET6简介 STM32F103ZET6的FLASH容量为512K,64K的SRAM.按照STM32芯片的容量产品划分,STM32F103ZET6属于大容量的芯片. 2.下载HA ...

  6. STM32 HAL 库实现乒乓缓存加空闲中断的串口 DMA 收发机制,轻松跑上 2M 波特率

    前言 直接储存器访问(Direct Memory Access,DMA),允许一些设备独立地访问数据,而不需要经过 CPU 介入处理.因此在访问大量数据时,使用 DMA 可以节约可观的 CPU 处理时 ...

  7. STM32基于HAL库通过DMA读写SDIO

    通过STM32CUBEMX生成DMA读写sdio的工程,再读写过程中总会卡死在DMA中断等待读写完成的while中,最终发现while等待的标志在SDIO的中断里置位的,而SDIO中断优先级如果小于或 ...

  8. STM32串口接收中断——基于HAL库

    写在前面 最近需要使用一款STM32L4系列的芯片进行开发,需要学习使用HAL库.在进行串口中断使用的时候遇到了一些小麻烦,写下解决方案供大家参考. 1.UART相关的头文件引用错误 由于本人直接使用 ...

  9. 基于HAL库的STM32的DSP库详解(附FFT应用)

    1 . 建立工程,生成代码时选择包含所有库.   2. 打开 option for target 选择 Target 标签,在code generatio中,将floating point hardw ...

随机推荐

  1. Django-下载安装-配置-创建django项目-三板斧简单使用

    目录 Django 简介 使用 django 的注意事项 计算机名不能有中文 Django版本问题 django下载安装 在命令行下载安装 在pycharm图形界面下载安装 检验是否安装成功 创建Dj ...

  2. Mybatis系列(一)入门

    Mybatis系列(一)入门 mybatis简介 MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结 ...

  3. Caused by: java.net.UnknownHostException

    项目中使用某一组件,启动失败Caused by: java.net.UnknownHostException: xxxCentOS6.3: xxxCentOS6.3 解析不到xxxCentOS6.3. ...

  4. Mysql使用SSL连接

    最近项目中用到了SSL连接,记录一下,环境为windows10,Mysql版本为5.6 查看是否支持 SSL 首先在 MySQL 上执行如下命令, 查询是否 MySQL 支持 SSL: mysql&g ...

  5. 零基础一年拿下BAT三家offer

    背景 1.本人本科一本双非垫底的那种,硕士211.本硕电子通信,完全0基础,转行一年. 2.研一上第一学期上课+外派到老师合作公司写MATLAB.去年4月开始学习Java. 起步 1.实话说,刚决定转 ...

  6. [币严区块链]ETH搭建节点区块数据同步的三种模式:full、fast、light

    ETH  全节点Archive(归档)模式数据量增长图 上述图表可通过链接查看:https://etherscan.io/chartsync/chainarchive 通过上表,可以看到截止2019年 ...

  7. hbase 修复 hbase hbck

    hbase hbck 新版本的 hbck 可以修复各种错误,修复选项是: (1)-fix,向下兼容用,被-fixAssignments替代 (2)-fixAssignments,用于修复region ...

  8. java语言的开发环境

    1.Java  EE和Java  SE Java SE(Java  Platform Standard Edition)标准版:是在java基础阶段主要学习的内容,该技术是java的最核心技术,适合小 ...

  9. .Net Standard(.Net Core)实现获取配置信息

    一.前言 在.Net Framework框架有专门获取webconfig配置的方法供我们使用,但是在.Net Core或者.Net Standard中没有可以直接使用的方法来获取配置文件信息,下面就来 ...

  10. C#下载http/https的pdf、excel等文件(非在线打开,绕开插件)

    非本服务器文件,如PDF,excel等,下载一般是通过href=‘远程文件的http或者https’的方式下载,但是如果浏览器已经有PDF插件了,则用href不是下载,而是在线打开了,影响体验,所以远 ...