STM32-CAN总线通信文档

合集下载

stm32 can iap原理

stm32 can iap原理

stm32 can iap原理STM32是一款广泛应用于嵌入式系统开发的微控制器,其中的CAN (Controller Area Network)接口是一种常用的通信协议,用于在不同的设备之间进行数据传输。

而IAP(In-Application Programming)则是一种在设备中实现程序的在线更新的技术。

本文将介绍STM32中的CAN IAP原理,从而帮助读者更好地理解和应用这一技术。

CAN IAP原理的核心思想是通过CAN总线将新的程序代码传输到目标设备,并在设备中进行更新。

这种更新方式具有很高的灵活性和可靠性,能够使设备在不中断正常工作的情况下完成程序的更新。

下面将分别介绍CAN和IAP的基本原理,以及二者结合的实现方法。

我们来了解一下CAN接口。

CAN是一种串行通信协议,常用于工业控制系统和汽车电子领域。

它具有高速、可靠的特点,能够在多个节点之间进行数据传输。

在STM32中,CAN接口由硬件模块实现,可以通过编程配置其参数,如波特率、滤波器等。

CAN总线上的设备可以作为发送方或接收方,通过标识符来标识自己发送的数据。

通过CAN总线,设备之间可以实现快速的数据交换和通信。

我们来了解一下IAP技术。

IAP是一种在线更新程序的技术,能够在设备中更新程序代码,而无需将设备连接到计算机或使用外部编程器。

在STM32中,IAP技术可以通过修改存储器中的程序代码来实现程序的更新。

通过IAP技术,我们可以在设备中加载新的程序代码,实现功能的升级或修复bug等操作。

将CAN和IAP结合起来,就可以实现CAN IAP技术。

具体实现的步骤如下:1. 首先,需要将新的程序代码打包成BIN文件,并将其发送到目标设备。

可以通过计算机上的CAN工具或其他CAN设备发送程序代码。

2. 目标设备接收到BIN文件后,将其保存在存储器中的指定位置。

可以使用STM32提供的存储器编程接口来实现数据的写入。

3. 在存储器中保存了新的程序代码后,需要进行程序的更新。

STM32_CAN总线使用说明

STM32_CAN总线使用说明

CAN_FilterInit(&CAN_FilterInitStructure);
5.打开 CAN 接收中断
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
6.编辑发送数据(标识符模式和扩展模式)
TxMessage.StdId=0x10; TxMessage.RTR=CAN_RTR_DATA; TxMessage.IDE=CAN_ID_STD;//(标识符模式)// CAN_ID_EXT (扩展标识符模式) TxMessage.DLC=8; TxMessage.Data[0] =0x01; TxMessage.Data[1] =0x01; TxMessage.Data[2] =0x01; TxMessage.Data[3] =0x01; TxMessage.Data[4] =0x01; TxMessage.Data[5] =0x01; TxMessage.Data[6] =0x01; TxMessage.Data[7] =0x01; CAN_Transmit(CAN1, &TxMessage);
CAN_InitStructure.CAN_AWUM=DISABLE;
CAN_InitStructure.CAN_NART=DISABLE;
CAN_InitStructure.CAN_RFLM=DISABLE;
CAN_InitStructure.CAN_TXFP=DISABLE;
//总线断开后自动修复;
RxMessage.Data[2]=0x00; RxMessage.Data[3]=0x00; RxMessage.Data[4]=0x00; RxMessage.Data[5]=0x00; RxMessage.Data[6]=0x00; RxMessage.Data[7]=0x00; CAN_Receive(CAN1, CAN_FIFO0, &RxMessage); if(RxMessage.IDE==CAN_ID_STD) {

STM32的CAN总线接收与发送

STM32的CAN总线接收与发送
过滤器的模式的设置: 通过设置 CAN_FM0R 的 FBMx 位,可以配置过滤器组为标识符列表模式或屏蔽位模式。 为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。 为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。 应用程序不用的过滤器组,应该保持在禁用状态。
过滤器优先级规则: 位宽为 32 位的过滤器,优先级高于位宽为 16 位的过滤器; 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式; 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高。
if(sent == TRUE)
continue;
sent = TRUE;
data ++;
if(data > 'z')
data = '0';
CAN_TxData(data);
}
else
//按键放开
{
GPIO_ResetBits(GPIO_LED, GPIO_LD1);
sent = FALSE;
}
} }
接收邮箱(FIFO) 在接收到一个报文后,软件就可以访问接收 FIFO 的输出邮箱来读取它。一旦软件处理了报文(如把它读出来), 软件就应该对 CAN_RFxR 寄存器的 R中断 bxCAN 占用 4 个专用的中断向量。通过设置 CAN 中断允许寄存器 CAN_IER ,每个中断源都可以单独允许和禁 用。 (1) 发送中断可由下列事件产生: ─ 发送邮箱 0 变为空,CAN_TSR 寄存器的 RQCP0 位被置 1。 ─ 发送邮箱 1 变为空,CAN_TSR 寄存器的 RQCP1 位被置 1。 ─ 发送邮箱 2 变为空,CAN_TSR 寄存器的 RQCP2 位被置 1。 (2) FIFO0 中断可由下列事件产生: ─ FIFO0 接收到一个新报文,CAN_RF0R 寄存器的 FMP0 位不再是‘00’。 ─ FIFO0 变为满的情况,CAN_RF0R 寄存器的 FULL0 位被置 1。 ─ FIFO0 发生溢出的情况,CAN_RF0R 寄存器的 FOVR0 位被置 1。 (3) FIFO1 中断可由下列事件产生: ─ FIFO1 接收到一个新报文,CAN_RF1R 寄存器的 FMP1 位不再是‘00’。 ─ FIFO1 变为满的情况,CAN_RF1R 寄存器的 FULL1 位被置 1。

stm32扩展6路can

stm32扩展6路can

STM32扩展6路CAN简介STM32是一款由STMicroelectronics公司推出的32位ARM Cortex-M系列微控制器。

它具有高性能、低功耗和丰富的外设资源,被广泛应用于各种嵌入式系统中。

其中,CAN(Controller Area Network)是一种常用的通信协议,用于在嵌入式系统中实现设备之间的高速通信。

本文将介绍如何通过扩展6路CAN来进一步增强STM32的通信能力。

我们将详细介绍扩展6路CAN的硬件连接和软件配置,以及如何在STM32上编写代码实现CAN通信。

硬件连接在扩展6路CAN之前,首先需要确认所选的STM32开发板是否支持CAN功能。

如果不支持,可以考虑更换支持CAN功能的开发板。

扩展6路CAN需要使用外部CAN模块来实现。

常用的外部CAN模块有MCP2515和SN65HVD232,它们可以通过SPI或UART接口与STM32连接。

具体的硬件连接方式取决于所选的外部CAN模块和STM32开发板的引脚分配。

通常,外部CAN模块的连接方式如下:1.将外部CAN模块的VCC引脚连接到STM32开发板的3.3V电源引脚。

2.将外部CAN模块的GND引脚连接到STM32开发板的地引脚。

3.将外部CAN模块的CS引脚(如果有)连接到STM32开发板的某个GPIO引脚,用于片选信号。

4.将外部CAN模块的SCK引脚连接到STM32开发板的SPI时钟引脚。

5.将外部CAN模块的MISO引脚连接到STM32开发板的SPI MISO引脚。

6.将外部CAN模块的MOSI引脚连接到STM32开发板的SPI MOSI引脚。

7.将外部CAN模块的INT引脚(如果有)连接到STM32开发板的某个GPIO引脚,用于中断信号。

请注意,具体的硬件连接方式可能因外部CAN模块和STM32开发板的型号而异。

在进行硬件连接之前,请务必仔细查阅外部CAN模块和STM32开发板的引脚定义和连接方式。

软件配置在进行软件配置之前,需要确保已经安装了适用于STM32的开发环境,例如Keil MDK或STM32CubeIDE。

STM32_CAN总线使用说明

STM32_CAN总线使用说明
STM32F103***的 CAN 总线使用说明
1. 配置 CAN 时钟、映射、IO 口
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
7.查询是否发送完成
i = 0; while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFFF)) //与 2.0 库有异;判断发送数据成功 {
i++; } if(CAN_TransmitStatus(CAN1, TransmitMailbox) == CANTXPENDING) //表示数据正在 发送中。
CAN_FilterInit(&CAN_FilterInitStructure);
5.打开 CAN 接收中断
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
6.编辑发送数据(标识符模式和扩展模式)
TxMessage.StdId=0x10; TxMessage.RTR=CAN_RTR_DATA; TxMessage.IDE=CAN_ID_STD;//(标识符模式)// CAN_ID_EXT (扩展标识符模式) TxMessage.DLC=8; TxMessage.Data[0] =0x01; TxMessage.Data[1] =0x01; TxMessage.Data[2] =0x01; TxMessage.Data[3] =0x01; TxMessage.Data[4] =0x01; TxMessage.Data[5] =0x01; TxMessage.Data[6] =0x01; TxMessage.Data[7] =0x01; CAN_Transmit(CAN1, &TxMessage);

stm32 canopen 例子

stm32 canopen 例子

stm32 canopen 例子摘要:1.引言2.STM32微控制器简介3.CANopen协议简介4.STM32 CANopen例子概述5.硬件设计6.软件设计7.总结正文:1.引言随着工业自动化和物联网技术的不断发展,嵌入式系统在各领域得到了广泛应用。

其中,STM32系列微控制器凭借出色的性能和低功耗特点,成为了嵌入式领域的热门选择。

CANopen协议作为一种基于CAN总线的通信协议,具有良好的实时性和可靠性,在工业自动化领域有着广泛的应用。

本文将介绍一个基于STM32的CANopen例子,以供参考。

2.STM32微控制器简介STM32系列微控制器是意法半导体公司推出的一款基于ARM Cortex-M 内核的32位闪存微控制器。

它具有高性能、低功耗、多功能、易扩展等特点,广泛应用于嵌入式系统领域。

3.CANopen协议简介CANopen协议是基于CAN总线的通信协议,由德国的Robert Bosch GmbH公司开发。

它是一种用于实时控制的开放式串行通信协议,具有多主控制结构、高可靠性、实时性好等特点。

CANopen协议在工业自动化领域得到了广泛应用,特别是在工业控制器和现场设备之间的通信。

4.STM32 CANopen例子概述本文将以一个简单的STM32 CANopen例子为例,介绍如何实现基于STM32的CANopen通信。

该例子采用STM32F103C8T6微控制器,具备两个CAN通道,分别用于发送和接收数据。

硬件方面,通过扩展CAN收发器及相关的外围器件,实现CANopen通信;软件方面,编写相应的程序实现CANopen协议的帧传输、数据处理等功能。

5.硬件设计硬件设计主要包括微控制器、CAN收发器、外围器件等的选型和连接。

首先,选用STM32F103C8T6微控制器作为核心控制器,通过SPI接口与CAN 收发器(如TJA1020)进行通信。

其次,根据需要选择其他外围器件,如电源模块、晶振模块、复位模块等。

stm32常见通信方式(TTL、RS232、RS485、CAN)总结

stm32常见通信方式(TTL、RS232、RS485、CAN)总结

stm32常见通信方式(TTL、RS232、RS485、CAN)总结
一、TTL电平:全双工(逻辑1: 2.4V--5V 逻辑0: 0V--0.5V)
1、硬件框图如下,TTL用于两个MCU间通信
2、‘0’和‘1’表示
二、RS-232电平:全双工(逻辑1:-15V--5V 逻辑0:+3V--+15V)
1、硬件框图如下,TTL用于MCU与PC机之间通信需要加电平转换芯片
2、‘0’和‘1’表示
三、RS-485:半双工、(逻辑1:+2V--+6V 逻辑0:-6V---2V)这里的电平指AB 两线间的电压差
1、硬件框图如下
2、‘0’和‘1’表示
四、CAN总线:逻辑1:-1.5V--0V 逻辑0:+1.5V--+3V)这里的电平指CAN_High、CAN_Low 两线间的电压差
1、硬件框图如下
2、‘0’和‘1’表示
以上总结:
1、从单片机软件编程角度来说,RS23
2、RS-485最终结果都是转换为TTL电平方式与单片机通信(CAN收发器把差分信号转化为TTL-->CAN控制器(MCU))。

其目的都是提高通信质量,提高抗干扰能力。

2、TTL、RS232是逻辑电平信号。

RS-485、CAN为差分信号。

五、I2C
5.1 I2C物理层
5.2 I2C协议层
5.3 数据的起始信号与停止信号
5.4数据有效性
I2C 协议在SCL 高电平时对SDA 信号采样,SCL 低电平时SDA准备下一个数据。

基于STM32的CAN与以太网的通信控制器设计

基于STM32的CAN与以太网的通信控制器设计

一一一一
订 一一一一
图2 C A N 总 线与 以太 网通信 的 网络模 型
豁 上似 机 监 上侮机
} I 心
三、实现方案
以 人 剐



通信控 制器
3 . 1 硬 件设计 。通 信控 制器 连接 了 毛丝检 测终 端C A N总
线 网络和数 据监 控 中心上位 机 的以太 网网络 ,实现 了终 端和
厂 — —— —— -— —— —— —— —— -— —— —— —— _— - I I — —— —— -— —— —— —— _— _ I

议[ 2 】 ,以 太 网采 用 T C P / I P 协议 ,而 通 信 控 制 器 则需 要 连 接 这 两种 结 构 和 协 议 完 全不 同 的 网络 。 因此 通 信 控 制 器 的核
图3通信控 制器 硬件 框 图
C AN/ 以 太 网协 议 转 换 的核 心 部 件 S T M3 2 微 控 制 器 采
太 网控 制 模 块 从T C P / I P  ̄ 文 中解 析 出数 据 放入 缓 存 区 中 , C A N控 制模 块 从 缓存 区 中读取 数 据并 封 装 成 C A N帧发 送 到
心 工作 就 是 对 C AN总 线数 据 帧 和 以太 网数 据 帧行 重 新 封装
让 } 』 奉潮I * …J 】 _ ' J 】 l S T M 3 2

l l I I
以使 它 们能 被 以太 网或 C A N总线 所读 取 。 网络模 型 如 冈2 所
示 。通 信 控 制 器 的CA N控 制模 块 从 C AN总线 发 送 来 的数 据
可靠双向通信 ,解决 了工业尼龙丝原丝检测 系统的检测终端和远程监控 中心的通信问题 。

STM32的CAN总线+J1939数据格式说明

STM32的CAN总线+J1939数据格式说明

在STM32中都是有标准的数据结构和函数供大家使用,那么对于具体的每一部分对应那些数据、每一位代表什么意思都没有具体说明。

特别在使用某些协议,需要辨别该部分的具体信息时,就必须对数据结构中的每位的意义清楚才能提取出具体的含义。

先来看一下下面的东西吧。

CAN帧结构。

这个就不具体介绍了,不过先提一点疑问:在STM32中直接给结构体中各成员直接赋值或读取,那么其实际的发送或接收的最底层的结构又是怎么样的呢?typedef struct{uint32_t StdId;uint32_t ExtId;uint8_t IDE;uint8_t RTR;uint8_t DLC;uint8_t Data[8];uint8_t FMI;} CanRxMsg; 接受结构体和发送结构体一样,就只是结构体名不一样而已(CanTxMsg)。

对于上面的问题,在一些协议中进行解析时,如何将这些标识符与协议的具体项对应呢?由于在做J1939协议的编程,所以就以这个为例说明一下。

如上所示,在J1939中CAN帧结构为32位,包含优先级、PDU格式(PF)、PS、SA。

而在STM32的结构体中却是32位的ID,8位的IDE、RTR、DLC。

如果要单独提取标识符中的某一个有如何提取呢?这就涉及到STM32的收发邮箱的寄存器存储结构了。

来看一下其标识符寄存器结构吧(接收和发送寄存器结构除0位外都一样)对于J1939协议来说,必须对帧数据和优先级、PF、PS、SA进行双向解析。

所以我们在发送数据或收到数据时必须做一定的处理。

在STM32的固件库函数中该寄存器中的各个部分的值提取出来赋给其结构体中个部分的值。

发送数据时:u32 Id_Ext = 0x00000000;Id_Ext = Id_Ext|Priority<<26;Id_Ext = ((Id_Ext>>16)|Pdu_PF)<<16;Id_Ext = ((Id_Ext>>8)|Pdu_Ps)<<8;Id_Ext = Id_Ext|Pdu_Sa;接收数据时:PDU_PF = (RxMessage.ExtId&0x00ff0000)>>16;PDU_PS = (RxMessage.ExtId&0x0000ff00)>>8;PDU_SA = RxMessage.ExtId&0x000000FF;注意:在帧结构图中我们看到PF被分成了两部分,而在上面的处理中PF却是连在一起的8位。

基于STM32的CAN总线接口设计与实现

基于STM32的CAN总线接口设计与实现

图1 系统总体框图是一款带隔离的高速CAN收发器芯片,该芯片内部集成了所有必需的CAN隔离及CAN收发器件。

芯片的主要功能是将CAN控制器的逻辑电平转换为CAN总线的差分电平,并且具有DC 2500V的隔离功能及ESD保护作用,其是CAN收发器的理想选择[2]。

2 CAN总线收发模块的硬件设计CAN总线收发模块的硬件结构如图2所示。

CAN总线(1978-),男,江西宜春人,研究生,工程师。

研究方向:汽车电子项目管理。

公飞(1989-),男,山东临沂人,本科,助理工程师。

研究方向:汽车电子硬件设计。

收发模块的主要功能是控制开关和与RS232进行数据通信,开关可以用来控制现场设备的运行,后者可以方便与外界进行通信,提供通讯接口。

其硬件结构节点可以划分为最小系统模块、功能模块。

电源STM32的工作电压(VDD)为2.0~3.6V[3]。

通过内置的电压调节器提供所需的1.8V电源。

当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源。

使用电池或其他电源连接到VBAT脚上,当VDD断电时,可以保存备份寄存器的内容和维持RTC的功能。

VBAT脚也图3 设置时钟流程图2.2 开关和RS232功能模块该节点具有两个功能,控制开关状态和与RS232通讯,开关选用八个TX2-5V继电器,两片MC1413作为驱动芯片,MC1413可以实现单片机端口电压到12V电平的转换。

与RS232通讯部分选用MAX232做为电平转换芯片。

2.3 CAN收发模块CAN收发模块主要是CAN收发器,CAN收发器的常用型号有CTM1050,CTM1050是一款带隔离的高速CAN收发器芯片,该芯片内部集成了所有必需的CAN隔离及CAN发器件。

芯片的主要功能是将CAN控制器的逻辑电平转换为CAN总线的差分电平,并且具有DC 2500V的隔离功能及ESD保护作用。

该芯片符合ISO 11898标准,因此,它可以和图2 节点硬件结构图图4 CAN初始化流程图选用的测试模式是环回模式,该模式下数据是自发自收的,即在发送成功的同时就接收到数据了。

基于STM32的CAN总线上下位机通信实验设计

基于STM32的CAN总线上下位机通信实验设计

基于STM32的CAN总线上下位机通信实验设计作者:刘泰廷李新建来源:《电脑知识与技术》2017年第05期摘要:随着技术的成熟和设备的完善,CAN总线在数据的实时传输和自动控制中展现出良好的灵活性与可靠性。

笔者以STM32为主控芯片搭建硬件电路,利用软件对其进行初始化设置,上位机与电路的连接使用USB—CAN转换器,并采用Visual C++的MFC编写的CAN 调试界面实现数据的实时收发,使上下位机完成通信。

本实验对于CAN总线的使用有一定的指导作用。

关键词:STM32;CAN总线;MFC;通信中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2017)05-0199-02CAN简称为控制器局域网络(Controller Area Network),它是由研发和生产汽车电子产品著称的德国BOSCH公司开发的,是国际上应用最广泛的现场总线之一,并最终成为国际标准(ISO11519)。

近年来,由于它的高可靠性和良好的错误检测能力受到人们的关注,CAN 总线协议逐渐成为汽车计算机控制系统和嵌入式工业控制局域网的标准总线,被广泛应用于汽车控制系统和环境温度恶劣、电磁辐射强的工业环境。

1 实验系统结构组成利用CAN总线可以将传统分布式控制系统的功能分散到不同的现场节点中,本实验只选用一个节点作为下位机的收发模块。

实验的系统框图如图1所示,系统主要分为三个部分:上位机(PC机)、CAN转换器、下位机(CAN收发模块电路)。

一般调试员的PC机(多为笔记本电脑)接入CAN总线往往没有串行接口,为此我们采用USB—CAN协议的转换器接入CAN总线,实现数据之间的转发。

下位机是以STM32F103RCT6单片机作为主控芯片的CAN 收发电路,主要完成数据采集和处理的任务,并实现与CAN总线的数据互传。

上位机利用MFC编写的控制界面,对CAN总线上收到的数据进行显示,同时也可以完成向CAN总线发送数据的指令。

can总线-stm32

can总线-stm32

can总线-stm32⼀、什么是can总线?can总线因为使⽤电压差表⽰逻辑1和0,所以抗⼲扰性强,传播距离远(500kbps 时130M),⽐特率越⼩越远1.can有⼏根线? 2根,can_H,can_L2.can怎么表⽰1,0? can_H - can_L > 0.9V ,为逻辑 0,也称为显性电平。

can_H - can_L < 0.5v ,为逻辑1,也称为隐性电平。

⼀般can_H为3.5V , 2.5V⼀般can_L为2.5V ,1.5V⼆、stm32 怎么使⽤can总线1.can接⼝在哪? stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯⽚: 这个芯⽚的主要作⽤是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。

2.can概念⼊门⽐较好的⽂档这个⽂档⽐较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。

下⾯的例程是数据帧。

3.can例程。

1 #ifndef CAN_H_2#define CAN_H_3 #include "stm32f10x.h"4#define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA5#define CAN_RXD GPIO_Pin_116#define CAN_TXD GPIO_Pin_127#define CAN_IO GPIOA89enum canrate_e10 {11 CANRATE125K=125,12 CANRATE250K=250,13 CANRATE500K=500,14 CANNOTLINK,15 };1617enum canStdExt_e18 {19 CANSTD=0,20 CANEXT=1,21 };22struct canrxtx_s23 {24 CanRxMsg rxMessage[3];25 u8 rx_newflag;26 uint32_t f;27 CanTxMsg txMessage;2829 };3031/*std ID*/32#define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional3334#define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical35#define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical36#define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter3738/*extend ID*/39#define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional40#define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA41#endif1 #include "can.h"2 #include <string.h>3 u8 std_or_ext;4struct canrxtx_s canrxtx;5void CAN1_init(enum canrate_e canrate)6 {78 GPIO_InitTypeDef GPIO_InitStructure;9 CAN_InitTypeDef CAN_InitStructure;1011 RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);12 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);13 GPIO_InitStructure.GPIO_Pin = CAN_RXD;14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;15 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;16 GPIO_Init(CAN_IO, &GPIO_InitStructure);1718 GPIO_InitStructure.GPIO_Pin = CAN_TXD;19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;20 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;21 GPIO_Init(CAN_IO, &GPIO_InitStructure);2223 CAN_DeInit(CAN1);24 CAN_StructInit(&CAN_InitStructure);2526 CAN_InitStructure.CAN_TTCM = DISABLE;27 CAN_InitStructure.CAN_ABOM = DISABLE;28 CAN_InitStructure.CAN_AWUM = DISABLE;29 CAN_InitStructure.CAN_NART = DISABLE;30 CAN_InitStructure.CAN_RFLM = DISABLE;31 CAN_InitStructure.CAN_TXFP = DISABLE;32 CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;33 CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;34 CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;35 CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;36//CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler37if(canrate==CANRATE125K) /* 125KBps */38 CAN_InitStructure.CAN_Prescaler =96;39else if(canrate==CANRATE250K) /* 250KBps */40 CAN_InitStructure.CAN_Prescaler =48;41else/* 500KBps */42 CAN_InitStructure.CAN_Prescaler = 24;4344 CAN_Init(CAN1, &CAN_InitStructure);45 }4647void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)48 {49 CAN_FilterInitTypeDef CAN_FilterInitStructure;50 NVIC_InitTypeDef NVIC_InitStructure;5152 CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~1353 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;54if(std_or_ext == CANSTD)55 {56 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;57 CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;58 CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;59 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;60 CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;6162 }63else64 {65 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;66 CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13);67 CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);68 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);69 CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);7071 }7273 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;74 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;75 CAN_FilterInit(&CAN_FilterInitStructure);7677 NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;7879 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;80 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;81 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;82 NVIC_Init(&NVIC_InitStructure);8384 CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);85 }86/************************init******************************/87void init_demo()88 {89 std_or_ext = CANEXT;90 CAN1_init(CANRATE500K);91 CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID92 }93/************************tx******************************/94/*datalen<=8*/95int CAN1_TransASerialData(u8* pdata,u8 datalen)96 {97 u8 i=0;9899 Delay_ms(20);100101if(std_or_ext == CANEXT)102 {103 canrxtx.txMessage.StdId=0x00;104 canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian105 canrxtx.txMessage.RTR=CAN_RTR_DATA;106 canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits107108 }109if(std_or_ext== CANSTD)110 {111 canrxtx.txMessage.StdId=CAN1_TX_STD_ID;112 canrxtx.txMessage.ExtId=0x00;113 canrxtx.txMessage.RTR=CAN_RTR_DATA;114 canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits115 }116117 canrxtx.txMessage.DLC=0x08;118 canrxtx.txMessage.Data[0]=datalen;119 memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);120121122while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))123124if(i>=3) //timeout125 {126return (-1);127 }128129 canrxtx.rx_newflag=0;130return (0);131132 }133/************************rx******************************/134void CAN1_RX1_IRQHandler(void)135 {136 memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));137if(CAN_MessagePending(CAN1,CAN_FIFO0))138 {139 CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);140 }141 canrxtx.rx_newflag=1;142 }三、标识符过滤器的解释过滤器只是⽤于接收,判断某个报⽂是否能通过过滤器,过滤器初始化如下:53 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;56 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;57 CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;58 CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;59 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;60 CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下⾯两个结构体成员的值可以有四种组合:CAN_FilterMode和CAN_FilterScale四、关于邮箱如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件⾃动管理的,软件不⽤管,只要判断发送成不成功,中断接收哪个FIFO就⾏了(要接收过滤器初始化时绑定的那个FIFO)。

STM32上的CAN通讯是什么CAN模式功能的详细分析

STM32上的CAN通讯是什么CAN模式功能的详细分析

STM32上的CAN通讯是什么CAN模式功能的详细分析CAN通信是控制器局域网(Controller Area Network)的缩写,它是一种广泛应用于工业领域的一种网络通信协议。

CAN通信协议最初是由德国BOSCH公司于1986年研发,主要用于汽车电子系统。

后来,CAN逐渐成为一种通用的通信协议,并且在其他领域,如工业自动化、航空航天等也得到了广泛应用。

CAN通信协议具有高可靠性、高实时性和高带宽的特点。

在STM32上,我们可以通过硬件支持的CAN接口实现CAN通信。

CAN通信协议可以分为两种模式,分别是CAN2.0A和CAN2.0B。

这两种模式的主要区别在于帧标志和数据帧的识别方式。

下面对CAN2.0A和CAN2.0B的主要特点进行详细分析。

一、CAN2.0A模式:在CAN2.0A模式下,帧标志位由11位组成,其中前6位是ID标识符,后5位是RTR(远程传输请求)和IDE(扩展标示符位)。

1.ID标识符:用于表示消息的优先级和类型。

CAN2.0A模式下,ID标识符可以是11位长,可以表示2^11=2048个不同的消息标识符。

2.RTR位:用于区分数据帧和远程帧。

当RTR=0时,表示是数据帧;当RTR=1时,表示是远程帧。

3.IDE位:用于区分标准帧和扩展帧。

当IDE=0时,表示是标准帧;当IDE=1时,表示是扩展帧。

二、CAN2.0B模式:在CAN2.0B模式下,帧标志位由29位组成,其中前11位是ID标识符,后18位是RTR(远程传输请求)和IDE(扩展标示符位)。

1.ID标识符:用于表示消息的优先级和类型。

CAN2.0B模式下,ID标识符可以是29位长,可以表示2^29=536,870,912个不同的消息标识符。

2.RTR位:用于区分数据帧和远程帧。

当RTR=0时,表示是数据帧;当RTR=1时,表示是远程帧。

3.IDE位:用于区分标准帧和扩展帧。

当IDE=0时,表示是标准帧;当IDE=1时,表示是扩展帧。

STM32的CAN现场总线应用总结

STM32的CAN现场总线应用总结

STM32的CAN现场总线应用总结CAN现场总线的应用最重要的就是其接口端口映射、初始化及数据的发送、接收。

STM32中的CAN物理引脚可以设置成三种:默认模式、重定义地址1模式、重定义地址2模式。

CAN信号可以被映射到端口A、端口B或端口D上,如下表所示,对于端口D,在36、48和64脚的封装上没有重映射功能。

重映射不适用于36脚的封装当PD0和PD1没有被重映射到OSC_IN和OSC_OUT时,重映射功能只适用于100脚和144脚的封装上---------------------------------------------------------------------------------------------------------------------- 默认模式/* Configure CAN pin: RX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);/* Configure CAN pin: TX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);---------------------------------------------------------------------------------------------------------------------- 重定义地址1模式/* Configure CAN pin: RX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);/* Configure CAN pin: TX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);/*Configure CAN Remap 重映射*/GPIO_PinRemapConfig(GPIO_Remap1_CAN,ENABLE);---------------------------------------------------------------------------------------------------------------------- /* Configure CAN pin: RX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);/* Configure CAN pin: TX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);/*Configure CAN Remap 重映射 */GPIO_PinRemapConfig(GPIO_Remap2_CAN,ENABLE);---------------------------------------------------------------------------------------------------------------------- 设置完CAN 的引脚之后还需要打开CAN 的时钟: /* CAN Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN,ENABLE); 2. 初始化2.1.1 CAN 单元初始化CAN 单元初始化最重要的就是波特率的设置,原理如下:t波特率=1/位时间位时间 = (1 + t BS1 + t BS2)× t q t q = t PCLKt PCLK = APB1例如现有一STM32系统时钟为72MHz ,关于CAN 波特率有以下设置: CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位 CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq; //时间段1为8个时间单位 CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq; //时间段2为7个时间单位 CAN_InitStructure.CAN_Prescaler = 45; //设定了一个时间单位的长度为45则其CAN 的波特率为1÷[(1+8+7)×456CAN 以外还包括以下设置:CAN_InitTypeDef CAN_InitStructure; //定义一个CAN 单元CAN_InitStructure.CAN_TTCM = DISABLE; //设置时间触发通信模式(失能) CAN_InitStructure.CAN_ABOM = DISABLE;// 使/失能自动离线管理(失能) CAN_InitStructure.CAN_AWUM = DISABLE;// 使/失能自动唤醒模式(失能) CAN_InitStructure.CAN_NART = DISABLE; //使/失能非自动重传输模式(失能) CAN_InitStructure.CAN_RFLM = DISABLE;// 使/失能接收FIFO 锁定模式(失能) CAN_InitStructure.CAN_TXFP = DISABLE; //使/失能发送FIFO 优先级(失能)CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;//设置CAN 工作模式(正常模式) 2.1.2 CAN 报文过滤器初始化STM32共有14组过滤器,每组过滤器包括了2个可配置的32位寄存器:CAN_FxR0和CAN_FxR1。

基于STM32的CAN通讯,已在实际项目中应用

基于STM32的CAN通讯,已在实际项目中应用

与本程序代码相关部分的原理图及PCB,基于STM32F103VET6,已在项目中应用。

开头篇:STM32的CAN波特率计算STM32里的CAN 支持2.0A,2.0B, 带有FIFO,中断等, 这里主要提一下内部的时钟应用。

bxCAN挂接在APB1总线上,采用总线时钟,所以我们需要知道APB1的总线时钟是多少。

我们先看看下图,看看APB1总线时钟:APB1时钟取自AHB的分频, 而AHB又取自系统时钟的分频, 系统时钟可选HSI,HSE, PLLCLK, 这个在例程的RC设置里都有的,然后再看看有了APB1的时钟后,如何算CAN的总线速率, 先看下图:有了上边的这个图,基本就清楚了:总线时钟MHz (3+TS1+TS2)*(BRP+1)======================================================================下面是我的计算:CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;注意//#define CAN_BS1_3tq ((uint8_t)0x02) /*!< 3 time quantum */ CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;CAN_InitStructure.CAN_Prescaler = 4;//2nominal bit time(3+5+1)tq=9tq关于分频系数,查看 system_stm32f10x.c下面的static void SetSysClockTo72(void) 函数:/* HCLK = SYSCLK *//* PCLK2 = HCLK *//* PCLK1 = HCLK/2 */所以can时钟 72MHZ/2/4=9 Mhz,tq=1/36Mhz波特率为 1/nominal bit time= 9/9=1MHZ=====================================================================void CAN_Configuration(void){CAN_InitTypeDef CAN_InitStructure;CAN_FilterInitTypeDef CAN_FilterInitStructure;/* CAN register init */CAN_DeInit();CAN_StructInit(&CAN_InitStructure);/* CAN cell init */CAN_InitStructure.CAN_TTCM=DISABLE;CAN_InitStructure.CAN_ABOM=DISABLE;CAN_InitStructure.CAN_AWUM=DISABLE;CAN_InitStructure.CAN_NART=DISABLE;CAN_InitStructure.CAN_RFLM=DISABLE;CAN_InitStructure.CAN_TXFP=DISABLE;CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;CAN_InitStructure.CAN_BS2=CAN_BS2_8tq;CAN_InitStructure.CAN_Prescaler=200;CAN_Init(&CAN_InitStructure);/* CAN filter init */CAN_FilterInitStructure.CAN_FilterNumber=0;CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;CAN_FilterInit(&CAN_FilterInitStructure);}注意//#define CAN_BS1_3tq ((uint8_t)0x02) /*!< 3 time quantum */波特率10K,公式:72MHZ/2/200/(1+9+8)=0.01,即10Kbps正文篇:程序代码/* Includes ---------------------------------- --------------------------------*/#include "stm32f10x.h"#include "platform_config.h"#include "stm32f10x_rcc.h"#include "stm32f10x_flash.h"#include "stm32f10x_usart.h"#include "stm32f10x_gpio.h"#include "stm32f10x_tim.h"#include "stdio.h"ErrorStatus HSEStartUpStatus;void Uart1_PutChar(u8 ch);unsigned int j; //j=2-8/* Private typedef -----------------------------------------------------------*/ typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus; //状态量__IO uint32_t ret = 0; //用于中断返回的传递变量volatile TestStatus TestRx;CanTxMsg TxMessage;CanRxMsg RxMessage;unsigned char read_temp;unsigned char open_temp,stop_temp,top_temp;uint16_t CCR1_Val=0 ;#define start 50#define accelerate 10#define Period 999#define Prescaler 9//double percent=0.9;vu32 counter=0;vu32 compare ;uint16_t High_fre=900;unsigned int Tulun_i=0; //500次作为一个脉冲GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;//Private functions 函数---------------------------------------------------------*/void UART_Init(void);ErrorStatus HSEStartUpStatus;void RCC_Configuration(void); //申明时钟初始化函数void GPIO_Configuration(void); //申明IO初始化函数void NVIC_Configuration(void); //申明中断管理器初始化函数void CAN_Configuration(void); //申明CAN初始化函数void CAN_TX(unsigned char add,unsigned char data1,unsigned char data2);//申明CAN发送函数TestStatus CAN_RX(void); //申明带返回参数的CAN接收函数void LED_RESET(void);void PWM_startN(void);void PWM_start(void);/****** Main program ***********/int main(void){u32 n;/* 系统时钟初始化 */RCC_Configuration();/* 中断管理器初始化 */NVIC_Configuration();/* IO初始化*/GPIO_Configuration();UART_Init(); //初始化串口函数/* CAN初始化*/CAN_Configuration();TIM_TimeBaseStructure.TIM_Period = Period;TIM_TimeBaseStructure.TIM_Prescaler = Prescaler;TIM_TimeBaseStructure.TIM_ClockDivision = 0;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);GPIO_ResetBits(GPIOA, GPIO_Pin_4);while (1){CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //开接收中断for(n=0;n<10000;n++); //延时if(ret == 1){for(j=0;j<8;j++) //发送8组数据到串口 {Uart1_PutChar(RxMessage.Data[j]);}open_temp=RxMessage.Data[0];top_temp=RxMessage.Data[1];stop_temp= RxMessage.Data[2];switch(open_temp){case 01:PWM_start(); break;case 02:PWM_startN();break;default: GPIO_ResetBits(GPIOA, GPIO_Pin_2);GPIO_ResetBits(GPIOA, GPIO_Pin_1); break;}ret = 0;}}}/* 开始输出PWM */void PWM_start(void){TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 1000-CCR1_Val;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable; TIM_OCInitStructure.TIM_Pulse = 1000-CCR1_Val;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);/* PWM1 Mode configuration: Channel2 */GPIO_ResetBits(GPIOA, GPIO_Pin_1);TIM_ARRPreloadConfig(TIM2, ENABLE);switch(top_temp){case 01: High_fre=100; break;case 02:High_fre=500 ;break;case 03:High_fre=900 ;break;default:break;}switch(stop_temp){case 01:compare=100000; break;case 02:compare=200000 ;break;case 03:compare=50000 ;break;default:break;}TIM_Cmd(TIM2, ENABLE);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/* TIM2 enable counter */}/* 停止输出PWM */void PWM_startN(void){TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 1000-CCR1_Val;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);/* PWM1 Mode configuration: Channel2 */GPIO_ResetBits(GPIOA, GPIO_Pin_2);TIM_ARRPreloadConfig(TIM2, ENABLE);switch(top_temp){case 01: High_fre=100; break;case 02:High_fre=500 ;break;case 03:High_fre=900 ;break;default:break;}switch(stop_temp){case 01:compare=100000; break;case 02:compare=200000 ;break;case 03:compare=50000 ;break;default:break;}TIM_Cmd(TIM2, ENABLE);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/* TIM2 enable counter */}void TIM2_IRQHandler(void){static unsigned int i=0;static unsigned int j=0;if (TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET){if(counter<compare){if(i<(High_fre-start)/accelerate){TIM2->CCR2=1000-(start+i*accelerate);TIM2->CCR3=1000-(start+i*accelerate);Tulun_i++;counter++;if( Tulun_i==500){i++;Tulun_i=0;}}else{TIM2->CCR2=1000-High_fre;TIM2->CCR3=1000-High_fre;counter++;}}if(counter==compare){TIM2->CCR2=1000-(start+i*accelerate-j*accelerate);TIM2->CCR3=1000-(start+i*accelerate-j*accelerate);Tulun_i++;if( Tulun_i==500){j++;Tulun_i=0;}if(j==i){TIM2->CCR2=1000;TIM2->CCR3=1000;if(Tulun_i==0){TIM_Cmd(TIM2, DISABLE);TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);i=0;j=0;counter=0;}}}TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}}/* 关LED */void LED_RESET(void){GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)0x00); //关LED GPIO_WriteBit(GPIOB, GPIO_Pin_1, (BitAction)0x00);}/*******************************************************************************Configures the different system clocks.*******************************************************************************/void RCC_Configuration(void){ErrorStatus HSEStartUpStatus;/* RCC system reset(for debug purpose) */RCC_DeInit(); //时钟控制寄存器全部恢复默认值/* Enable HSE */RCC_HSEConfig(RCC_HSE_ON); //外部高速时钟源开启(8M晶振)/* Wait till HSE is ready */HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部时钟就绪if(HSEStartUpStatus == SUCCESS) //如果时钟启动成功{/* HCLK = SYSCLK */RCC_HCLKConfig(RCC_SYSCLK_Div1); //定义AHB设备时钟为系统时钟1分频/* PCLK2 = HCLK */RCC_PCLK2Config(RCC_HCLK_Div1); //定义AHB2设备时钟为HCLK时钟1分频/* PCLK1 = HCLK/2 */RCC_PCLK1Config(RCC_HCLK_Div2); //定义AHB1设备时钟为HCLK时钟2分频/* Flash 2 wait state */FLASH_SetLatency(FLASH_Latency_2); //设定内部FLASH的的延时周期为2周期 /* Enable Prefetch Buffer */FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区/* PLLCLK = 8MHz * 9 = 72 MHz */RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //配置PLL时钟为外部高速时钟的9倍频/* Enable PLL */RCC_PLLCmd(ENABLE); //使能PLL时钟/* Wait till PLL is ready */while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟设置完成准备就绪 {}/* Select PLL as system clock source */RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //使用PLL时钟作为系统时钟源 /* Wait till PLL is used as system clock source *//* Wait till PLL is used as system clock source */while(RCC_GetSYSCLKSource() != 0x08) //返回系统所用时钟源确认为外部高速晶振,8M晶振。

STM32的CAN应用

STM32的CAN应用

最近向系统的学习一下CAN总线的应用,苦于找不到合适的板子来做实验。

刚好看到STM32单片机自带有CAN控制器,就想通过STM32作为载体来学习一下CAN总线。

CAN控制器之外加上CAN收发器就可以用于CAN通讯了,于是随便找了一个小板子,焊接上CAN收发器TJA1050,就可以用于CAN通讯了。

在这篇博文中,先把通常的思路给自己理清一下。

至于CAN协议的具体内容还是要参考CAN-BUS的规范了。

在这里就是讲使用STM32单片机的CAN的简单思路。

STM32 CAN总线初始化步骤:1、配置相关引脚的复用功能,使能CAN时钟。

使能CAN时钟,通过APB1ENR的第25位来设置。

其次要设置CAN的相关引脚为复用输出,设置为上拉输入(CAN_RX),设置为复用输出(CAN_TX),并使能PA口的时钟。

2、设置CAN工作模式及波特率等。

先设置CAN_MCR寄存器的INRQ位,让CAN进入初始化模式,然后设置CAN_MCR的其他相关控制位,再通过CAN_BTR设置波特率和工作模式(正常模式/环回模式)等信息。

最后设置INRQ为0,退出初始化模式。

3、设置滤波器。

设置CAN_FMR的FINIT位,让过滤器组工作在初始化模式下,然后设置滤波器组0的工作模式以及标识符ID和屏蔽为。

最后激活滤波器。

并退出滤波器初始化模式。

如果用到中断,还要配置中断模式。

配置系统时钟和引脚不用做过多的说明了,每一个例程基本上都有所包含。

重要的一点事如何设计CAN的工作模式和波特率。

当CAN进入初始化之后,先设置CAN_MCR的控制位。

见下面的图用来控制这些设置。

接下来是设置寄存器CAN_BTR,通过这个寄存器来设置CAN的工作模式和波特率。

寄存器描述程序代码mode用来设置模式,普通模式或者回环模式。

而下面的四个用来设置波特率,tsjw tbs2 tbs1 brp 这四个参数是怎么来决定CAN的波特率的呢?然后使CAN退出初始化模式然后再初始化过滤器然后就可以开始进行通讯了。

03--STM32之CAN---发送管理分析

03--STM32之CAN---发送管理分析

STM32之CAN---发送管理分析1 CAN发送邮箱STM32共有三个CAN发送邮箱,在检测到总线空闲时交发送,但需要注意的是,有可能会发送失败,有可能因为仲裁失败从而导致失败,也有可能是其它错误,原则上bxCAN将自动重发,但bxCAN也可以配置不自动重发。

正因为如此,发送邮箱中有可能同时存在多个需要发送的报文,一旦出现这种情况,那么发送邮箱中的多个报文又将是谁先发送谁后发送呢?有两种模式:ID模式和FIFO模式。

ID模式由报文的ID值决定,即ID值越小,优先级越高,另一种FIFO模式,顾名思义,即为消息队列方式,谁先到谁先发送,此种模式下三个邮箱与接收FIFO类似。

下图是发送邮箱的状态图:图1由上图可知,发送邮箱共有四种状态,空状态,挂号状态,预定发送状态(scheduled),发送状态。

发送报文的流程为:应用程序选择1个空发送邮箱;设置标识符,数据长度和待发送数据;然后对CAN_TIxR寄存器的TXRQ位置’1’,来请求发送。

TXRQ位置’1’后,邮箱就不再是空邮箱;而一旦邮箱不再为空,软件对邮箱寄存器就不再有写的权限。

TXRQ位置1后,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,参见发送优先级。

一旦邮箱成为最高优先级的邮箱,其状态就变为预定发送状态。

一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。

一旦邮箱中的报文被成功发送后,它马上变为空邮箱;硬件相应地对CAN_TSR寄存器的RQCP和TXOK位置1,来表明一次成功发送。

如果发送失败,由于仲裁引起的就对CAN_TSR寄存器的ALST位置’1’,由于发送错误引起的就对TERR位置’1’。

2 发送优先级如之前所述,如果三个邮箱中同时存在多个待发送的报文时,此时存在一个问题,即先送哪个邮箱中的报文好呢?此时,存在一个发送优先级的问题。

此时,非空发送邮箱进入发送仲裁,发送仲裁有两种策略:ID模式和FIFO模式。

基于STM32单片机CAN通信控制网络设计

基于STM32单片机CAN通信控制网络设计

基于STM32单片机CAN通信控制网络设计
柴文峰;丁学明
【期刊名称】《电子科技》
【年(卷),期】2017(030)003
【摘要】通过分析点对点通信方式控制网络的缺陷及总线的发展状况,利用CAN 总线的特点和优势,设计了基于广播方式通信控制网络.采用C#编写上位机界面做控制器,智能节点(下位机)作为执行器,根据CANKingdom应用层协议,制定节点间相互通信规则,将发送的控制命令以帧的形式进行打包,设计节点控制算法执行相应功能.文中设计的基于广播式CAN通信网络实现了对40个节点的数据通信和现场实时监控功能.
【总页数】4页(P142-145)
【作者】柴文峰;丁学明
【作者单位】上海理工大学光电信息与计算机工程学院,上海200093;上海理工大学光电信息与计算机工程学院,上海200093
【正文语种】中文
【中图分类】TN915.04;TP368.1
【相关文献】
1.基于CAN通信的变频电动机控制设计与实现 [J], 布朋生
2.基于CAN通信的掘进机自动控制系统设计 [J], 申洋
3.电动拖拉机CAN通信网络设计及硬件在环测试 [J], 徐海龙; 徐立友; 刘晓慧; 刘
孟楠; 王通
4.基于冗余CAN通信的智能集成供液控制系统 [J], 赵康康
5.重型拖拉机CAN通信网络设计 [J], 阚辉玉;李军伟;李德芳;高松
因版权原因,仅展示原文概要,查看原文内容请购买。

stm32 CAN总线例子

stm32 CAN总线例子

stm32 CAN总线例子利用stm32实现了1个简单的CAN功能,使用了队列缓存can.c 文件#include "includes.h"#define GPIO_CAN GPIOB#define RCC_APB2Periph_GPIO_CAN RCC_APB2Periph_GPIOB #define GPIO_Pin_RX GPIO_Pin_8#define GPIO_Pin_TX GPIO_Pin_9#define GPIO_Remap_CAN GPIO_Remap1_CAN1#define MAX_MAIL_NUM 3static u8 CAN_msg_num[MAX_MAIL_NUM]; // 发送邮箱标记///*** @brief Configures the CAN, transmit and receive by polling* @param None* @retval : PASSED if the reception is well done, FAILED in other case */void CAN_config_init(void){CAN_InitTypeDef CAN_InitStructure;CAN_FilterInitTypeDef CAN_FilterInitStructure;/* CAN register init */CAN_DeInit(CAN1);CAN_StructInit(&CAN_InitStructure);/* CAN cell init */ // 36M 250k速率CAN_InitStructure.CAN_TTCM=DISABLE;CAN_InitStructure.CAN_ABOM=DISABLE;CAN_InitStructure.CAN_AWUM=DISABLE;CAN_InitStructure.CAN_NART=DISABLE;CAN_InitStructure.CAN_RFLM=DISABLE;CAN_InitStructure.CAN_TXFP=DISABLE;CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;CAN_InitStructure.CAN_BS1=CAN_BS1_12tq;CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;CAN_InitStructure.CAN_Prescaler=9;CAN_Init(CAN1, &CAN_InitStructure);/* CAN filter init */CAN_FilterInitStructure.CAN_FilterNumber=0;CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;CAN_FilterInit(&CAN_FilterInitStructure);}void CAN_init(void){NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;// 首先打开电源及时钟/* GPIO for CAN and GPIO for LEDs clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIOI |RCC_APB2Periph_GPIO_CAN, ENABLE);/* CAN1 Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);/* Enable CAN1 RX0 interrupt IRQ channel */NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* Enable CAN1 TX0 interrupt IRQ channel */NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN1_TX_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 然后配置pin/* Configure CAN pin: RX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_RX;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIO_CAN, &GPIO_InitStructure);/* Configure CAN pin: TX */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_TX;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIO_CAN, &GPIO_InitStructure);// 映射下GPIO_PinRemapConfig(GPIO_Remap_CAN , ENABLE);// 波特率过滤器初始化CAN_config_init();CAN_ITConfig(CAN1, CAN_IT_FMP0 | CAN_IT_FF0 | CAN_IT_FOV0, ENABLE); // fifo0中断CAN_ITConfig(CAN1, CAN_IT_FMP1 | CAN_IT_FF1 | CAN_IT_FOV1, ENABLE); // fifo1中断CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE); // 发送中断CAN_ITConfig(CAN1, CAN_IT_EWG | CAN_IT_EPV | CAN_IT_BOF | CAN_IT_LEC | CAN_IT_ERR | CAN_IT_WKU | CAN_IT_SLK, ENABLE); // ERR中断// CAN缓存初始化memset(CAN_msg_num,0,MAX_MAIL_NUM);ClearCanQueue();}int CAN_tx_msg(CanTxMsg TxMessage){uint8_t TransmitMailbox = 0;OS_CPU_SR cpu_sr = 0;TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);if(CAN_NO_MB == TransmitMailbox){printf("tx can fail\r\n");return 0;}else{OS_ENTER_CRITICAL();CAN_msg_num[TransmitMailbox] = 1;OS_EXIT_CRITICAL();}CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);return 1;}int CAN_tx_data(void){CanTxMsg TxMessage;uint8_t TransmitMailbox = 0;OS_CPU_SR cpu_sr = 0;/* transmit */TxMessage.StdId=0x6f1;TxMessage.RTR=CAN_RTR_DATA;TxMessage.IDE=CAN_ID_STD;TxMessage.DLC=4;TxMessage.Data[0]=0x40;TxMessage.Data[1]=0x02;TxMessage.Data[2]=0x1a;TxMessage.Data[3]=0x80;TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);if(CAN_NO_MB == TransmitMailbox){printf("tx can fail\r\n");return 0;}else{OS_ENTER_CRITICAL();CAN_msg_num[TransmitMailbox] = 1;OS_EXIT_CRITICAL();}CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);return 1;}// 发送中断void USB_HP_CAN1_TX_IRQHandler(void){if(CAN_msg_num[0]){if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP0)){CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP0);CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);CAN_msg_num[0] = 0;}}if(CAN_msg_num[1]){if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP1)){CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP1);CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);CAN_msg_num[1] = 0;}}if(CAN_msg_num[2]){if(SET == CAN_GetITStatus(CAN1,CAN_IT_RQCP2)){CAN_ClearITPendingBit(CAN1,CAN_IT_RQCP2);CAN_ITConfig(CAN1, CAN_IT_TME, DISABLE);CAN_msg_num[2] = 0;}}}/*** @brief This function handles USB Low Priority or CAN RX0 interrupts* requests.* @param None* @retval : None*/void USB_LP_CAN1_RX0_IRQHandler(void){// u32 i;CanRxMsg RxMessage;if(SET == CAN_GetITStatus(CAN1,CAN_IT_FF0)){CAN_ClearITPendingBit(CAN1,CAN_IT_FF0);}else if(SET == CAN_GetITStatus(CAN1,CAN_IT_FOV0)){CAN_ClearITPendingBit(CAN1,CAN_IT_FOV0);}else{CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);InsertCanQueue(RxMessage);// printf("CAN_FIFO0 RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);// printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);// for(i = 0; i < RxMessage.DLC; i++)// {// printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);// }// printf("\r\n");}}void CAN1_RX1_IRQHandler(void){// u32 i;CanRxMsg RxMessage;if(SET == CAN_GetITStatus(CAN1,CAN_IT_FF1)){CAN_ClearITPendingBit(CAN1,CAN_IT_FF1);}else if(SET == CAN_GetITStatus(CAN1,CAN_IT_FOV1)){CAN_ClearITPendingBit(CAN1,CAN_IT_FOV1);}else{CAN_Receive(CAN1, CAN_FIFO1, &RxMessage);InsertCanQueue(RxMessage);// printf("CAN_FIFO1 RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);// printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);// for(i = 0; i < RxMessage.DLC; i++)// {// printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);// }// printf("\r\n");}}void CAN1_SCE_IRQHandler(void){}can.h文件#ifndef __CAN_H__#define __CAN_H__void CAN_init(void);int CAN_tx_data(void);int CAN_tx_msg(CanTxMsg TxMessage);#endifcan_queue.c文件#include "includes.h"struct _CANQueue CANQueue;/******************************************************************* 作者:版权:函数名称:函数功能: 清除通信队列入口参数: 无返回值: 无相关调用:备注:修改信息:********************************************************************/ void ClearCanQueue(void){int i;for(i = 0; i < MAX_CAN_SIZE; i++){memset(&CANQueue.Elem[i],0,sizeof(CanRxMsg));}CANQueue.front = 0;CANQueue.rear = 0;}/******************************************************************* 作者:版权:函数名称:函数功能: 判断串口队列是否为空入口参数:返回值: 1: 空; 0:非空相关调用:备注:修改信息:********************************************************************/ u8 IsEmptyCanQueue(void){if(CANQueue.front == CANQueue.rear){return 1;}else{return 0;}}/*******************************************************************作者:版权:函数名称:函数功能: 判队列是否满入口参数:返回值: 1: 满; 0:非满相关调用:备注:修改信息:********************************************************************/u8 IsFullCanQueue(void){if( CANQueue.front == (CANQueue.rear+1) % MAX_CAN_SIZE){return 1;}else{return 0;}}/*******************************************************************作者:版权:函数名称:函数功能: 将数据插入队列入口参数: element:被插元素返回值: 1: 成功; 0:失败相关调用:备注:修改信息:********************************************************************/u8 InsertCanQueue(CanRxMsg element){if(!IsFullCanQueue()) //是否为满{memcpy(&CANQueue.Elem[CANQueue.rear],&element,sizeof(CanRxMsg));CANQueue.rear = (CANQueue.rear + 1) % MAX_CAN_SIZE;return 1;}else //队列满{// printf("CAN queue is full\r\n");return 0;}}/******************************************************************* 作者:版权:函数名称:函数功能: 重新设置队列头指针入口参数: head: 新头返回值: 无相关调用:备注:修改信息:********************************************************************/ void SetHeadCanQueue(u16 head){if(CANQueue.front != CANQueue.rear){CANQueue.front = head;}}/******************************************************************* 作者:版权:函数名称:函数功能: 取对头入口参数: head:对头;*element;数据返回值: 1: 成功0: 失败相关调用:备注:修改信息:********************************************************************/ u8 GetCanQueue(u16 head,CanRxMsg *element){if(head != CANQueue.rear) //到队列尾{memcpy(element,&CANQueue.Elem[head],sizeof(CanRxMsg));//得到数据return 1;}else{return 0; //无指定对头数据}}/******************************************************************* 作者:版权:函数名称:函数功能: can数据处理入口参数:返回值:相关调用:备注:修改信息:********************************************************************/ void Can_data_process(void){u16 head;// u32 i;CanRxMsg RxMessage;CanTxMsg TxMessage;head = CANQueue.front;if(1 == GetCanQueue(head,&RxMessage)){head = (head + 1) % MAX_CAN_SIZE; //查询头前滚SetHeadCanQueue(head);// printf("RxMessage.StdId is 0x%x\r\n",RxMessage.StdId);// printf("RxMessage.DLC is 0x%x\r\n",RxMessage.DLC);// for(i = 0; i < RxMessage.DLC; i++)// {// printf("data[%d] is 0x%x\r\n",i,RxMessage.Data[i]);// }// printf("\r\n");// 把接收到的数据发回去/* transmit */// TxMessage.StdId=RxMessage.StdId;TxMessage.StdId=0x5f1;TxMessage.RTR=RxMessage.RTR;TxMessage.IDE=RxMessage.IDE;TxMessage.DLC=RxMessage.DLC;memcpy(TxMessage.Data,RxMessage.Data,TxMessage.DLC);CAN_tx_msg(TxMessage);}else{// printf("CAN queue is empty\r\n");}}can_queue.h文件#ifndef CAN_QUEUE_H_#define CAN_QUEUE_H_#define MAX_CAN_SIZE 50struct _CANQueue{CanRxMsg Elem[MAX_CAN_SIZE];u16 front;u16 rear;};void ClearCanQueue(void);u8 IsEmptyCanQueue(void);u8 IsFullCanQueue(void);u8 InsertCanQueue(CanRxMsg element);void SetHeadCanQueue(u16 head);u8 GetCanQueue(u16 head,CanRxMsg *element);void Can_data_process(void);#endif。

stm32之CAN发送、接收详解

stm32之CAN发送、接收详解

stm32之CAN发送、接收详解CAN接收报文并过滤之标识符过滤:(重点、难点) 在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。

因此,发送者以广播的形式把报文发送给所有的接收者。

节点在接收报文时-根据标识符的值-决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。

为满足这一需求,bxCAN为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),以便只接收那些软件需要的报文。

硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。

每个过滤器组x由2个32位寄存器,CAN_FxR0和CAN_FxR1组成。

这两个寄存器用途在下面有大用处;可变的位宽:  每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。

根据位宽的不同,每个过滤器组可提供: 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位===用于扩展ID(28位)和标准ID(11位) 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位====只用于标准ID 可参见图126 此外过滤器可配置为,屏蔽位模式和标识符列表模式。

屏蔽位模式 在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。

标识符列表模式 在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。

因此,不是采用1个标识符加1个屏蔽位的方式,而是使用2个标识符寄存器。

接收报文标识符的每一位都必须 跟过滤器标识符相同。

BxCAN过滤器的编号 在stm32中,过滤器编号用于加速CPU对收到报文的处理。

当受到一个有效报文时,BxCAN会将收到的报文以及它所通过的过滤器编号,一起存入邮箱中。

当CPU处理时,可以根据过滤器编号,快速地知道该报文的用途,从而做出处理。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

STM32 CAN总线通信CAN总线通信详细学习的话这里有个视频教程可以推荐看看,/programs/view/IIuJjM2RIxc做电子的一定要多练勤于动手,做多了就自然而然就手到擒来。

Can.h文件如下:#ifndef __CAN_H#define __CAN_H#include "sys.h"////////////////////////////////////////////////////////////////////////////////////CAN接收RX0中断使能#define CAN_RX0_INT_ENABLE 0 //0,不使能;1,使能.u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);//CAN初始化u8 Can_Send_Msg(u8* msg,u8 len); //发送数据u8 Can_Receive_Msg(u8 *buf); //接收数据#endifCan.c文件如下:#include "can.h"#include "led.h"#include "delay.h"#include "usart.h"//CAN初始化//tsjw:重新同步跳跃时间单元.范围:1~3; CAN_SJW_1tq CAN_SJW_2tqCAN_SJW_3tq CAN_SJW_4tq//tbs2:时间段2的时间单元.范围:1~8;//tbs1:时间段1的时间单元.范围:1~16; CAN_BS1_1tq ~CAN_BS1_16tq//brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1//注意以上参数任何一个都不能设为0,否则会乱.//波特率=Fpclk1/((tsjw+tbs1+tbs2)*brp);//mode:0,普通模式;1,回环模式;//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Normal_Init(1,8,7,5,1); //则波特率为:36M/((1+8+7)*5)=450Kbps//返回值:0,初始化OK;// 其他,初始化失败;u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode){GPIO_InitTypeDef GPIO_InitStructure;CAN_InitTypeDef CAN_InitStructure;CAN_FilterInitTypeDef CAN_FilterInitStructure;#if CAN_RX0_INT_ENABLENVIC_InitTypeDef NVIC_InitStructure;#endifRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA 时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IOGPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化IO//CAN单元设置CAN_InitStructure.CAN_TTCM=DISABLE;//非时间触发通信模式 //CAN_InitStructure.CAN_ABOM=DISABLE;//软件自动离线管理 //CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)//CAN_InitStructure.CAN_NART=ENABLE;//禁止报文自动传送 //CAN_InitStructure.CAN_RFLM=DISABLE;//报文不锁定,新的覆盖旧的 //CAN_InitStructure.CAN_TXFP=DISABLE;//优先级由报文标识符决定 //CAN_InitStructure.CAN_Mode= mode; //模式设置: mode:0,普通模式;1,回环模式; ////设置波特率CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tqCAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tqCAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tqCAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1 //CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;////32位IDCAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化#if CAN_RX0_INT_ENABLECAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);#endifreturn 0;}#if CAN_RX0_INT_ENABLE //使能RX0中断//中断服务函数void USB_LP_CAN1_RX0_IRQHandler(void){CanRxMsg RxMessage;int i=0;CAN_Receive(CAN1, 0, &RxMessage);for(i=0;i<8;i++)printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);}#endif//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)//len:数据长度(最大为8)//msg:数据指针,最大为8个字节.//返回值:0,成功;// 其他,失败;u8 Can_Send_Msg(u8* msg,u8 len){u8 mbox;u16 i=0;CanTxMsg TxMessage;TxMessage.StdId=0x12; // 标准标识符为0 TxMessage.ExtId=0x12; // 设置扩展标示符(29位)TxMessage.IDE=0; // 使用扩展标识符TxMessage.RTR=0; // 消息类型为数据帧,一帧8位TxMessage.DLC=len; // 发送两帧信息for(i=0;i<8;i++)TxMessage.Data[i]=msg[i]; // 第一帧信息mbox= CAN_Transmit(CAN1, &TxMessage);i=0;while((CAN_TransmitStatus(CAN1, mbox)!=CAN_TxStatus_Failed)&&(i<0XFFF))i++;//等待发送结束if(i>=0XFFF)return 1;return 0;}//can口接收数据查询//buf:数据缓存区;//返回值:0,无数据被收到;// 其他,接收的数据长度;u8 Can_Receive_Msg(u8 *buf){u32 i;CanRxMsg RxMessage;if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0; //没有接收到数据,直接退出CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据for(i=0;i<8;i++)buf[i]=RxMessage.Data[i];return RxMessage.DLC;}关于CAN总线的滤波等一系列设置可以参考:stm32的can总线的配置如下:????? CAN_InitStructure.CAN_TTCM=DISABLE;//禁止时间触发通信模式?????CAN_InitStructure.CAN_ABOM=DISABLE;?????CAN_InitStructure.CAN_AWUM=DISABLE;?????CAN_InitStructure.CAN_NART=DISABLE;//CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失)?????? CAN_InitStructure.CAN_RFLM=DISABLE;????? CAN_InitStructure.CAN_TXFP=DISABLE;?????CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;????? //CAN_Mode_LoopBack????? //CAN_Mode_Normal????? CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;?????CAN_InitStructure.CAN_BS1=CAN_BS1_5tq;//1--16?????CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;//1--8?????CAN_InitStructure.CAN_Prescaler=2;????? CAN_Init(&CAN_InitStructure);?????? /* CAN filter init */????? CAN_FilterInitStructure.CAN_FilterNumber=0;//选择过滤器0????? CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器被设置为标识符屏蔽模式?????CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//给出过滤器位宽为32位?下面根据设置的参数不同来决定can总线can总线的配置情况:1、对扩展数据帧进行过滤:(只接收扩展数据帧)?????CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<3)&0xFFFF0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFF;(注:标准帧数据帧、标准远程帧和扩展远程帧均被过滤)2、对扩展远程帧过滤:(只接收扩展远程帧)?????CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<3)&0xFFFF0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFF;3、对标准远程帧过滤:(只接收标准远程帧)?????CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<21)&0xffff0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFF;4、对标准数据帧过滤:(只接收标准数据帧)????? CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<21)&0xffff0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFF;5、对扩展帧进行过滤:(扩展帧不会被过滤掉)?????CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<3)&0xFFFF0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFC;6、对标准帧进行过滤:(标准帧不会被过滤掉)????? CAN_FilterInitStructure.CAN_FilterIdHigh?? =(((u32)slave_id<<21)&0xffff0000)>>16;?????CAN_FilterInitStructure.CAN_FilterIdLow?? =(((u32)slave_id<<21)|CAN_ID_STD)&0xffff;?????CAN_FilterInitStructure.CAN_FilterMaskIdHigh? = 0xFFFF;?????CAN_FilterInitStructure.CAN_FilterMaskIdLow?? = 0xFFFC;注:slave_id为要过滤的id 号。

相关文档
最新文档