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. CSS3 04. 伸缩布局、设置主轴,侧轴方向、主/侧轴对齐方式、 伸缩比例、元素换行、换行控制、覆盖父元素的align-items;控制子元素顺序、web字体、突变字体

    CSS3 在布局方面做了非常大的改进,对块级元素的布局排列变得十分灵活,适应性非常强,其强大的伸缩性,在响应式开发中可以发挥极大的作用.(兼容性不好) 必要元素: 指定一个盒子为伸缩盒子 displa ...

  2. 你不得不知道的HashMap面试连环炮

    为什么用HashMap? 简述一下Map类继承关系? 解决哈希冲突的方法? 为什么HashMap线程不安全? resize机制? HashMap的工作原理是什么? 有什么方法可以减少碰撞? HashM ...

  3. Mysql 用户root密码重置

    Asterisk安装完成之后,接手新的Asterisk系统后不清楚Mysql的root账号密码. 重新重置mysql的root密码的方式 先查看mysql的版本号. 我的测试环境下的mysql版本为5 ...

  4. math库的使用

    math库简介 math库是Python提供的内置数学内函数库,因为复数类型常用于科学计算,一般计算并不常用,因此math库不支持复数类型,仅支持整数和浮点数运算,math库一共提供4个数学常数和44 ...

  5. sql 增删改列名

    添加列:alter table table_name add new_column data_type [interality_codition] ALTER TABLE dbo.tb newColu ...

  6. Winform应用程序简介

    1.winform应用程序是一种智能客户端技术,我们可以使用winform应用程序帮助我们获得信息或传输信息等. WPF技术——XAML美化界面. 2.  F4快速属性 (1)Name:在后台要获得前 ...

  7. 解决python -m pip install --upgrade pip 升级不成功问题

    1.使用命令出现. You are , however version is available. You should consider upgrading via the 'python -m p ...

  8. FBCTF平台安装

    一言难尽 = =开始不知道FBCTF只能安装在Ubuntu,在本地搭建半天好不容易弄起了PHP环境,打开错误,后来才知道只能在Ubuntu 14.04 LTS下安装= = FBCTF是Facebook ...

  9. ADC0832

    #include <reg51.h> #include "ADC0832.c" code uchar seven_seg[]={0xc0, 0xf9, 0xa4, 0x ...

  10. IO流——递归(输出所有文件)

    package pers.zbb.File; import java.io.File; public class FileDemo { public static void main(String[] ...