简介

CAN通信帧共分为数据帧、远程帧、错误帧、过载帧和帧间隔,本文这里以数据帧为例。

注:显性电平对应逻辑0,CAN_H和CAN_L之差为2.5V左右。而隐性电平对应逻辑1,CAN_H和CAN_L之差为0V, 数据帧有标准帧和扩张帧两种格式,一个11位,一个29位

标准帧和扩张帧两种格式区别:

  • 扩展帧的仲裁域有29位,可以出现2^29中报文,且在数据链路上是有间隙的(对操作者透明),帧ID的范围是0000 0000-1FFF FFFF。(PS:目的就是构造29位的CAN ID,可以实现更加庞大的ID群)
  • 标准帧的仲裁域是连续的11位,可以出现2^11种报文,也就是帧ID的范围是000-7FF;
  • 标准帧和扩张帧的控制帧中的DLC(数据长度)完全相同,但保留位不同,标准帧为IDE、R0,扩展帧为R1、R0,必须以显性电平发送(由数据链路层操作)

注意:这里的帧ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级(帧ID值越小,优先级越高,最小是0x00000000)

CAN协议特点:

1、多主控制。
2、系统柔软性。
3、通讯速度快,通讯距离远。
4、具有错误检测、错误通知、错误恢复功能。
5、故障封闭功能。
6、连接节点多。

CAN总线具有自动仲裁功能,这样就提高了总线的利用率。

CAN总线没有被发送出去的隐性信号,会由CAN控制器后续发送出去。这里牵涉到CAN总线优先级的问题,后续进一步讲述。
当然,CAN相比485具有明显优势,主要原因还是在于CAN控制器。

CAN直接通过TX连接对方的RX引脚,单向传输可以,双向传输就不行,因为CAN控制器会实时监测发送出去的信号是否正确。也就是说TX要与RX信号一致才行,否则CAN控制器认为你发送失败。

CAN总线收发,中断方式接收配置

平台:STM32F103RB
STM32CUBEMX V5.3


配置CAN

CAN的波特率最大为1Mbps。

波特率计算方法:时钟主频 / 分频 / (tq1 + tq2 + swj)

以500K的波特率配置为例
stm32f103的CAN的时钟主频是36M,分9频就是4M,在除以(5 + 2 + 1)得到500K的波特率。
注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。


CAN之数据帧格式

代码部分

CAN初始化

CAN_HandleTypeDef hcan1;
CAN_FilterTypeDef sFilterConfig;//CAN初始化:/* CAN init function */
void MX_CAN_Init(void)
{hcan1.Instance = CAN1;hcan1.Init.Prescaler = 9;hcan1.Init.Mode = CAN_MODE_LOOPBACK;                 // 回环模式,测试用。hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;hcan1.Init.TimeTriggeredMode = DISABLE;                   // 时间触发通信模式禁能hcan1.Init.AutoBusOff = DISABLE;                      // 软件自动离线管理禁能hcan1.Init.AutoWakeUp = DISABLE;                      // 睡眠模式自动唤醒禁能hcan1.Init.AutoRetransmission = DISABLE;              // 报文自动重传禁能hcan1.Init.ReceiveFifoLocked = DISABLE;                 // 报文锁定禁能,新报文覆盖旧报文hcan1.Init.TransmitFifoPriority = ENABLE;             // 使能优先级由报文标识符决定if (HAL_CAN_Init(&hcan1) != HAL_OK){Error_Handler();}sFilterConfig.FilterBank = 0;                                    // 使用过滤器0sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;             // 屏蔽位模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;             // 32位宽sFilterConfig.FilterIdHigh = 0x0000;                            // ID高十六位sFilterConfig.FilterIdLow = 0x0000;                               // ID低十六位sFilterConfig.FilterMaskIdHigh = 0x0000;                      // ID掩码高十六位sFilterConfig.FilterMaskIdLow = 0x0000;                         // ID掩码低十六位sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;              // 过滤器0关联到FIFO0sFilterConfig.FilterActivation = ENABLE;                        // 激活过滤器0sFilterConfig.SlaveStartFilterBank = 14;if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){Error_Handler();}if (HAL_CAN_Start(&hcan1) != HAL_OK){Error_Handler();}if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)        // 使能FIFO0数据中断接收{Error_Handler();}
}

覆写接收中断回调函数

(注意:上面的配置我们使用的式FIFO0,所以要覆写FIFO0的中断回调函数):

void can_msg_info(CAN_RxHeaderTypeDef* hdr, const void* data)
{printf("IDE     : %s\r\n",hdr->IDE == CAN_ID_STD ? "CAN_ID_STD" : "CAN_ID_EXT");printf("RTR     : %s\r\n",hdr->RTR == CAN_RTR_DATA ? "CAN_RTR_DATA" : "CAN_RTR_REMOTE");printf("DLC     : %ld\r\n", hdr->DLC);printf("StdId   : 0x%X\r\n", hdr->StdId);printf("ExtId   : 0x%X\r\n", hdr->ExtId);printf("Data    : %s\r\n", (char *) data);
}void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{if (hcan->Instance == hcan1.Instance){uint8_t buf[8];CAN_RxHeaderTypeDef CAN_RX_HDR;if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, buf)            // 获得接收到的数据头和数据== HAL_OK){can_msg_info(&CAN_RX_HDR, buf);HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // 再次使能FIFO0接收中断}}
}

CA发送函数:

uint8_t CAN_Transmit(const void* buf, uint32_t len)
{uint32_t txmailbox = 0;uint32_t offset = 0;CAN_TxHeaderTypeDef hdr;hdr.IDE = CAN_ID_STD;                // 帧ID:标准帧hdr.RTR = CAN_RTR_DATA;               // 帧类型:数据帧hdr.StdId = 0x12;                 // 标准帧ID,最大11位,也就是0x7FFhdr.ExtId = 0x12;                    // 扩展帧ID,最大29位,也就是0x1FFFhdr.TransmitGlobalTime = DISABLE;while(len != 0){hdr.DLC = len > 8 ? 8 : len;      // 数据长度if(HAL_CAN_AddTxMessage(&hcan1, &hdr, ((uint8_t *)buf) + offset, &txmailbox) != HAL_OK)return 1;offset += hdr.DLC;len -= hdr.DLC;}return 0;
}

附注:stm32cubemx can配置参数详解:

配置参数

参数 意思
Prescaler 预分频,即位时序提到的APB1 peripheral clocks继续分一次频
Time Quantum 最小时间单位Tq,自动计算出来的,不需要填写
Time Quanta in Bit Segment 1 PBS1段长度
Time Quanta in Bit Segment 2 PBS2段长度
ReSynchronization Jump Width 重同步跳跃宽度,即位时序提到的SJW
Time Triggered Communication Mode 是否使能时间触发
Automatic Bus-Off Management 是否使能自动离线管理
Automatic Wake-Up Modet 是否使能自动唤醒
Qutomatic Retransmission 是否使能自动重传
Receive Fifo Locked Mode 是否使能锁定FIFO
Transmit Fifo Priority 配置报文优先级的判断方法
Oprating Mode 操作模式
  1. 这些参数也可以在can.c中自行修改
  2. 中断(NVIC)设置,根据需要设置,一般勾上CAN1 RX0 Interrupt

8.1.2 协议层

位时序

意义:为了实现正确的总线电平采样,确保通讯正常。最小单位是Tq(Time Quantum),一个完整位由8~25个Tq组成
组成:SS段、PTS 段、PBS1段、PBS2段

段名 意义 作用
SS(1Tq) 同步段 补偿物理延时,是传播时间、收发器延时之和的两倍
PTS(1~8Tq) 传播时间段 补偿变压阶段误差
PBS1(1~8Tq) 相位缓冲段1 使总线各节点同步
PBS2(2~8Tq) 相位缓冲段2 补偿边沿阶段误差
SJW(1~4Tq) 再同步补偿宽度 补偿时钟频率偏差、传输延迟等

例如

通讯波特率的计算:CAN使用的时钟线是APB1 peripheral clocks(假设是APC),即一般是SYSCLK的四分频。而CAN通讯还要对此进行预分频(假设是Prescaler),则一个Tq为 Prescaler / APC(单位s)。而一个数据位占(SS+PTS+PBS1+PBS2+SJW)个Tq。则一秒可以传输的位数就是1 T q ∗ 一 个 位 得 T q 数 \frac{1}{Tq一个位得Tq数}Tq∗一个位得Tq数1
例如:在时钟树查得APB1 peripheral clocks是45MHz,预分频为5,则一个Tq为 4 45 M H z = 111.1111 … ( n s ) \frac{4}{45MHz}=111.1111\dots(ns)45MHz4=111.1111…(ns) ,上图中有19个Tq,则此时波特率为1 19 ∗ 111.11 ∗ 1 0 − 9 ≈ 473689 ( b p s ) \frac{1}{19
111.11*10^{-9}}\approx473689(bps)19∗111.11∗10−91≈473689(bps)

STM32 CAN通讯配置相关推荐

  1. stm32串口通讯问题

    stm32串口通讯问题 在串口试验中,串口通讯不正常,则可能会出现以下问题: 1. 配置完成后,串口没有任何消息打印. 原因:1,端口配置有问题,需要重新检查I/O口的配置 2,接线有问题,检查接线是 ...

  2. STM32 GPIO的配置寄存器(CRL、CRH)输入输出模式配置

    STM32 GPIO的配置寄存器(CRL.CRH)输入输出模式配置 1.学会使用寄存器设定所需IO的方向,学会配置CRL.CRH 2.理解如下代码的含义 //IO方向设置 #define DS18B2 ...

  3. STM32 GPIO的配置寄存器(CRL、CRH)快速学习

    1.问题 在使用STM32的时候配置GPIO是最常见的操作,可以使用比较简单明白的库函数配置,但很繁杂.使用寄存器的方式可以快速配置,对于同一个IO口的输入输出都需要使用到的时候,比如IIC通讯的SD ...

  4. K210学习笔记(五)——MAIX BIT(K210)与STM32串口通讯

    前言 uart 模块主要用于驱动开发板上的异步串口,可以自由对 uart 进行配置.k210 一共有3个 uart,每个 uart 可以进行自由的引脚映射. 一.MAIX BIT串口使用步骤 1.引脚 ...

  5. python与STM32串口通讯(踩坑记录)

    1.环境 python端需要安装pyserial包和serial包,安装命令为 pip install pyserial 和 pip install serial.如果安装速度很慢可考虑使用清华镜像源 ...

  6. 安卓设备通过USB串口与STM32单片机通讯之二

    安卓设备通过USB串口与STM32单片机通讯之二 本博文系JGB联合商务组的原创作品,引用请标明出处. 本博文接续上一篇的末尾章节. (二) APP的JAVA代码部分(使用Android Studio ...

  7. STM32 BOOT 引脚配置

    STM32 BOOT 引脚配置 在STM32F10xxx里,可以通过BOOT[1:0]引脚选择三种不同启动模式: BOOT1=x BOOT0=0 从用户闪存启动,芯片内置的Flash,这是正常的工作模 ...

  8. STM32 RCC时钟配置

    STM32 RCC时钟配置 时钟源 外部高速晶振HSE,通常是8MHz. 内部高速晶振HSI,8MHz. 外部低速晶振LSE,32.768KHz. 内部低速晶振LSI,40KHz. 时钟源选择 通常使 ...

  9. 研华webaccess与西门子PLC以太网通讯配置

    研华webaccess与西门子PLC以太网通讯配置 摘要 通过研华WebAccess软件实现以太网采集现场设备的实时生产数据和设备状态数据.现场控制器采用西门子S7200和S7300系列PLC,以太网 ...

最新文章

  1. 数据结构与算法(6-5)二叉树的应用--哈夫曼树与哈夫曼编码
  2. delphi 窗体透明详解TransparentColorValue,窗体透明控件不透明
  3. vue项目-封装API接口
  4. buuctf 基础破解
  5. 首次构建android studio gradle 下载缓慢的问题
  6. android 左滑按钮,android开发类似微信列表向左滑动按钮操作
  7. Java 算法 字串统计
  8. pytorch 一些关于模型参数冻结的问题
  9. 性能测试用例、策略和方法
  10. Oracle数据库间的数据复制 - SQLPlus中的COPY命令
  11. SQLServer 2000 126错误的解决方法
  12. 计算机配件模拟,模拟计算机是指什么
  13. 决策树算法小结(三) CART原理及代码实现
  14. 《物联网Android程序开发案例式教程》Demo1:线性布局
  15. .git文件过大,如何清理
  16. 算法工程师面试基础题目及答案
  17. [转] 制作PPT的全过程,存着有用
  18. scrapy多个url爬虫
  19. ABAP-SAP 账号批量创建分配权限程序
  20. java判断小数位数_java如何获取一个double的小数位数

热门文章

  1. HTML网站微信打开自动播放音乐JS
  2. C#GDI+简单绘图
  3. 马克飞象(Mark Dumbo)
  4. dlopen android 权限,Android7.0对dlopen的改变——读取私有.so结果变化
  5. 说话技巧:目标、逻辑、语速
  6. vue自适应单位换算
  7. c语言强制转换为结构体,C语言结构体的强制类型转换
  8. undefined reference to symbol 'GOMP_parallel@@GOMP_4.0'
  9. 火锅店点餐数据库设计_第一次实验报告
  10. 微信该服务器已饱满,微信官方:看看你们都许的什么愿望!把我服务器都干崩了...