IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Stm32之CAN通信(2021-08-13) -> 正文阅读

[嵌入式]Stm32之CAN通信(2021-08-13)

Stm32之CAN通信

1.CAN*(Controller Area Network)*协议简介

1)协议种类及特点:

  • 高速协议:ISO11898(125k~1Mbps);低速协议:ISO11519-2(125Kbps以下)。
  • 特点:
    • 多主控制(每个单元都可发送消息, 每个单元发送消息时,都会发送一个ID(不是地址,而是作为接收时的优先级顺序,0多且0比较靠高位的,优先级高)优先级高的继续,优先级的将被打断,等待高优先级发送完再发送 每个单元在接收时,可以通过对ID进行识别,判断自己是否要接收)
    • 系统柔软性:每个设备没有绑定的地址,所以可以随时添加设备单元;
    • 速度快,距离远:1Mbps(<40m),10km(<5Kbps)
    • 错误检测/通知/恢复功能;
    • 故障单元自动隔离功能;
    • 可连接的节点多;

2)物理层特征:

3)协议层简介:(均为MSB)

  • 5种帧类型:
  • 每个数据帧都由7个段组成:帧起始,仲裁段(包含ID 优先级 ),控制段,数据段,CRC段,ACK段,帧结束。

    • 帧起始: (SOF) 以一个位的显性电平‘0’开始。

    • 仲裁段:(标准格式和扩展格式有所不同)

      • 标准格式:由11位的ID和RTR (Remote Transmission Request) 位构成:0数据帧,1遥控帧;
      • 扩展格式:由1?? 11位标准ID,和 2?? SRR (Substitute Remote Request) 位:用来代替标准格式种RTR位,进行占位,和3?? IDE (Identifier Extension) :用于区分是否为扩展帧;标准格式(中IDE位在控制段)为显性‘0’,扩展格式为隐性‘1’,和4?? 18位的扩展ID,和5?? RTR位(0数据,1遥控)共五部分组成;
      • 对于ID先后的仲裁,从ID的高为一直往下比,0具有比1高的优先级,但CAN规定标准的ID中禁止高7位均为隐性,即不允许存在0x1111 111X XXX的ID .
    • 控制段:(标准格式和扩展格式有所不同)

      • 标准格式:1?? IDE位为显性‘0’ , 和2?? r0保留位(默认显性),和3?? DLC (Data Length Contorller ) 4位,用于表示接下来的报文数据有含有多少字节(0-8),三部分组成;

      • 扩展格式: 由两位保留位r1,r0(默认显性),和DLC(0-8)表示接下来的字节长度组成;

    • 数据段:0到8个字节的数据;MSB先行;

    • CRC段:15位的校验码,和1位的CRC界定符(隐性1),CRC计算范围包括:帧起始和仲裁段和控制段和数据段;发送与接收的计算的CRC不同时会报错;

    • ACK段:

    • 帧结束:由发送端发送7个位的隐性位表示帧结束;

      数据帧的构成如下图:

  • 位时序:

    对于没有时钟线的can协议,其采用的是与uart相同的通信的双方事先约定好波特率的形式。

    但can对应每一位的时间有较严格的要求,所以有位时序(即每一个位0/1中分出不同的时间段)的构成:(最小时间单位为1tq)(通常一个完整的位长8-25个tq)

    • SS (SYNC SEG) 段:同步段,要求总线的跳变沿发生在此段内,则表明该节点已与总线同步,大小为1tq;

    • PTS (PROP SEG) 段:传播时间段,用于补偿网络的物理延时,大小为1-8tq;

    • PBS1 (PHASE SEG1) 段:相位缓冲段1,通过在重新同步时加长该段时间,用来补偿边沿阶段的误差,大小为1-8tq;

    • PBS2 (PHASE SEG2) 段:相位缓冲段2,通过在重新同步时缩短该段时间,用来补偿边沿阶段的误差,大小为2-8tq;

    • SJW (reSynchornization Jump Width) : 再同步补偿宽度,用于重新同步时加长PSBS1和缩短PBS2所允许的限定宽度。不属于一个位的时段 ,一个位仅包含上面的四段。

    • 实际通讯时,

      • 硬同步:通过帧起始的跳变沿是否落在SS段内判断是否同步,以此调整节点与总线的同步;
      • 软同步:通过加长PBS1或者缩短PBS2,来使位的跳变沿落在SS段内,以此同步。

    在使用stm32的库函数时,会通过定义PBS1和PBS2段的长度及时钟预分频系数的大小来确定通讯的波特率。

2.Stm32的bxCAN (Basic eXtend CAN)

1)bxCAN简介:

  • 普通stm32f103系列具有一个CAN(14个过滤器),互联型和f407有2个CAN(28个过滤器);(介绍普通型为主)

  • 拥有3个发送报文邮箱,两个拥有三级邮箱的FIFO (First Input First Output) 用于接收报文;(邮箱:存放要发送和收到的内容)

  • 14组位宽可变,可配置标识符的接受过滤器 (Acceptance Filters) 用于对传输来的ID 优先级 进行识别,判断是否要接收该 ID 优先级 的报文。

2)过滤器位宽及模式

  • 位宽:32位时用于过滤带扩展的ID(如上图中的映象一栏);16位时用于过滤标准ID;

  • 过滤器模式:一个过滤器是由两个32位的寄存器组成:(1个标识符寄存器+1个屏蔽寄存器)

    • 设置为标识符列表模式时,屏蔽寄存器也被作为标识符寄存器使用,过滤器会检查收到的ID是否与所设置的ID(标识符寄存器中的ID)一模一样,只有一样,才会接收其报文,将其存入FIFO0/1的邮箱中;

    • 设置为标识符屏蔽位时,只有屏蔽寄存器(掩码)中为1的位 ,过滤器才会检查收到的ID与 所设置的ID(标识符寄存器中的ID)再该位与是否一致,屏蔽寄存器中为0的位则不与理会,是0是1均可,这样符合情况的(一组)ID所发送的报文才会接收,将其存入FIFO0/1的邮箱中;

3)bxCAN模式简介:

  • 三种模式:
  • 三种工作模式的转换:

  • 三种测试模式的区别:

    • 静默模式:对总线一直保持1隐性电平,接收数据帧正常;

    • 环回模式:自发自收,将自己发送出去的报文自己接收,可以用于自测试,而忽略接收数据帧;

    • 环回静默模式:对总线一直保持1隐性电平,且忽略接收的数据帧,完全与总线断开的自发自收;

4)邮箱发送过程:

红色表示一次发送成功的过程:

  • 当有超过1个发送邮箱在挂号时,发送顺序由邮箱中报文的标识符决定。 根据CAN协议,标识符 数值最低的报文具有最高的优先级。如果标识符的值相等,那么邮箱号小的报文先被发送

5)邮箱接收过程:

3.bxCAN寄存器介绍:

寄存器的数量较多分为三组:(较多,每个位没有全部列出,详情看手册)

1)CAN控制和状态寄存器

  • CAN_MCR (Main Controller) :主控制寄存器,[5]AWUM 自动唤醒模式选择位(0软件,1硬件);[1]SLEEP 睡眠请求位(1进入睡眠模式,0退出睡眠模式) [0] INRQ 初始化请求位(0 由初始化进入正常模式,1 由正常模式进入初始化模式 (退出CAN时)

  • CAN_MSR :主状态寄存器,[1]SLAK 睡眠模式确认位,表明正处于睡眠模式;[0]INAK 表明正处于初始化状态;

  • CAN_TSR:发送邮箱1/2/3的各种状态位;

  • CAN_RF0R :FIFO0的对应状态及控制寄存器,[5]RFOM0 释放FIFO0 的输出邮箱,释放后,该位由软件清零;

  • CAN_RF1R:与CAN_RF0R的各位功能相同,控制及状态是FIFO1.

  • CAN_IER:CAN各中断的使能位。

  • CAN_ESR:CAN错误状态寄存器。

  • CAN_BTR:CAN位时序寄存器,

    • [25:24]SJWT 这两位定义了重新同步时可延长或缩短的时间单位上限,(JwT+1)个tq.

    • [22:20]TS2 这两位定义了时间段2占几(TS2+1个)个时间单元tq.

    • [19:16]TS1 这两位定义了时间段1占几(TS1+1个)个tq.

    • [9:0]BRP ((Baud rate prescaler)): 波特率分频器,该位域定义了时间单元(tq)的时间长度.
      f B a u d = 1 正 常 位 时 间 = 1 ( t q + t B S 1 + t B S 2 ) = 1 t q [ ( T S 1 + 1 ) + ( T S 2 + 1 ) + 1 ] = 1 1 f P L C k B R P + 1 [ ( T S 1 + 1 ) + ( T S 2 + 1 ) + 1 ] = f P L C K ( B R P + 1 ) ( T S 1 + 1 + T S 2 + 1 + 1 ) f_{Baud}=\frac{1}{正常位时间}=\cfrac{1}{(t_q+t_{BS1}+t_{BS2})}=\cfrac{1}{t_q[(TS1+1)+(TS2+1)+1]}\\= \cfrac{1}{\cfrac{1}{\cfrac{f_{PLCk}}{BRP+1}}[(TS1+1)+(TS2+1)+1]}=\frac{f_{PLCK}}{(BRP+1)(TS1+1+TS2+1+1)} fBaud?=1?=(tq?+tBS1?+tBS2?)1?=tq?[(TS1+1)+(TS2+1)+1]1?=BRP+1fPLCk??1?[(TS1+1)+(TS2+1)+1]1?=(BRP+1)(TS1+1+TS2+1+1)fPLCK??

2)CAN邮箱寄存器

  • 如上图,邮箱的寄存器按功能可以分成4种:(x表示0/1 (FIFO0/1) 每个FIFO虽然有3极深度,但读取时只能从寄存器中读出最先收到的报文,y表示1/2/3,发送缓存的三个邮箱)

    • CAN_RIxP/TIyR :(Identify Register)邮箱标识符寄存器 ,32位,前31位用于存放要发送或者接收到的ID,TIyR[0]为TXRQ 发送请求位,1是请求邮箱发送数据,发送完成邮箱空时,硬件清零;接收邮箱该位保留;

    • CAN_RDTxR/TDTyR: (Data length message Time):邮箱数据长度和时间戳寄存器,

      • [31:16]TIME为发送报文的时间记录(16位定时器的值,时间戳);

      • [15:8]FMI,对应接收邮箱(FIFO)匹配的过滤器的序号(0-13),

        发送邮箱[15:9]保留,中只有[8]TGT为发送时间戳使能位,使能该位时,CAN必须处于发送模式,且发送字节长度必为8,时间戳作为发送数据的第7,8字节被发送;

      • [3:0]DLC:决定了接收/要发送的数据长度(字节数,取值0-8);

    • CAN_RDLXR/TDLyR: 储存接收到/要发送的报文的第1到第4个字节数据;

    • CAN_RDHXR/TDHyR: 储存接收到/要发送的报文的第5到第8个字节数据。

3)CAN过滤器寄存器

  • CAN_FMR:过滤器主控寄存器,非互联型stm32只有[0]FINT位有效,(1过滤器组初始化,0过滤器组工作在正常模式);

    以下寄存器在配置时,CAN的过滤器需处于初始化状态,即,FINT=1

    以下寄存器中,均是低28位有效,但非互联型产品则是低14位有效,

  • CAN_FS1R: (Filter scale) 用于设置过滤器的位宽,对应位为1,该过滤器为单个32位;为0,该过滤器为2个16位

  • CAN_FFA1R:(Filter FIFO assignment) 过滤器FIFO关联寄存器,对应位为0是,报文在该过滤器过滤后进入FIFO0;若为1,则进入FIFO1;

  • CAN_FA1R: ( Filter active) 过滤器激活寄存器,对应位置为1,则激活该过滤器;

  • CAN_FiRx (x=1/2,i=0 -13):过滤器组i的寄存器x;一组过滤器组寄存器两个32位,在不同模式(屏蔽位模式/标识符列表模式)时充当的角色不同,用于存放我们要求的ID号 优先级 ,或掩码。 [详情见](#### 2)过滤器位宽及模式)

4.库函数使用

1)流程:

  • 初始化流程:

初始化时,需填入两个结构体到两个初始化函数中:

CAN_Init(CAN1, &CAN_InitStructure);//CAN初始化函数,需要一个CAN_InitTypeDef类型结构体;该结构体成员如下:
typedef struct
{
//与波特率相关的成员
 uint16_t CAN_Prescaler;// Baud的预分频系数,1-1024
 uint8_t CAN_SJW; //定义好的宏:...1-4tq
 uint8_t CAN_BS1; //定义好的宏...1-16tq
 uint8_t CAN_BS2;//定义好的宏....2-8tq
//与模式相关的成员
 uint8_t CAN_Mode; //模式,定义好的宏:正常/静默/回环/静默回环
 //以下均是ENABLE/DISABLE
 FunctionalState CAN_TTCM;//是否使用时间触发通信,即使用CAN内部定时器生成时间戳 
 FunctionalState CAN_ABOM;//是否在发生错误时由硬件进入自动离线管理状态
 //硬件自动控制时:硬件检测到128次11位连续隐性电平后自动进入离线状态;软件控制时:软件对INRQ置1随后请0,再检测到128次11位连隐性才离线
 FunctionalState CAN_AWUM;// 是否由硬件自动唤醒,由软件唤醒时需清除CAN->MCR的SLEEP位
 FunctionalState CAN_NART;// 是否!禁止!在发送失败时自动重传;DISABLE即自动重传开启
 FunctionalState CAN_RFLM;//FIFO是否锁定,锁定时,FIFO溢出时会丢弃新报文,不锁定时,新报文会覆盖旧报文 
 FunctionalState CAN_TXFP;// 报文发送优先级判定方法,ENABLE时由报文请求顺序决定,DISABLE时,由报文标识符决定
} CAN_InitTypeDef;
 CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)//过滤器初始化函数;填入结构体成员如下:
 typedef struct
{
 uint8_t CAN_FilterNumber; //要选择的过滤器组0-13
 uint8_t CAN_FilterScale; //过滤器的过滤的位宽....16bit/....32bit
 uint8_t CAN_FilterMode; //过滤器模式...MASK/....LAST
 uint16_t CAN_FilterFIFOAssignment; //该过滤器与那个FIFO关联
 
 uint16_t CAN_FilterIdHigh; 
 uint16_t CAN_FilterIdLow; //过滤器的目标标识符ID高16位和低16位;
 uint16_t CAN_FilterMaskIdHigh; 
 uint16_t CAN_FilterMaskIdLow; //32位屏蔽位寄存器,1的位则要求与目标一致,0的位不关心
 FunctionalState CAN_FilterActivation; //是否激活该过滤器;
} CAN_FilterInitTypeDef
 

CAN与其他外设在库函数上最大的不同,可能是它发送及接收数据时得使用结构体将数据传入,因为CAN每次发送的数据帧较大 (f103中没有CAN1/2,CAN1就是CAN)

  • 发送数据:

    需要使用一个库函数定义好的结构体:CanTxMsg 类型

    mbox=CAN_Transmit(CAN1, &TxMessage)//发送函数;此函数的返回值为发送的邮箱号
    
    //所需结构体成员分析如下:
    typedef struct
    {
      uint32_t StdId;  /*要发送的自身的标准ID,取值 0 to 0x7FF. */
      uint32_t ExtId;  /*要发送的自身的扩展ID,取值 0 to 0x1FFFFFFF. */
      uint8_t IDE;     /*是否为扩展帧,可选为预先定义好的宏 ....Standard/....Extended*/
      uint8_t RTR;     /*是否为遥控帧,预定义好的宏,....Data/Remote */
      uint8_t DLC;     /*所要发送的数据长度(字节数),取值  0 to 8 */
      uint8_t Data[8]; /*所要发送的8个字节的数据的缓冲区数组,将要发送的数据对数组中成员一一赋值即可. */
    } CanTxMsg;
    

    注意,每次发送数据后,需检查对应的标志位,保证数据发送完成,才能退出

    可以像原子一样使用如下的检验函数(设置检查标志位的次数限制,防止卡在死循环中)

      u16 i=0;
      while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
    //CAN_TransmitStatus(CAN1, mbox)该函数查询对应的邮箱号(上面发送函数的返回值)是否发送结束
      if(i>=0XFFF)return 1;
      return 0;	
    
  • 接收数据:

    与发送完数据要检查数据是否发送完成一样,接收数据时先检查是否有对应的接收标志位被挂起

     if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;		//没有接收到数据,直接退出 
     //CAN_MessagePending(CAN1,CAN_FIFO0)检查输入的FIFO是否有挂起接收到报文的标志位
    

    读取数据时同样需要使用一个库函数定义好的结构体:CanRxMsg 类型

    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//接收报文函数,将定义的结构体指针传入,然后读取该结构体变量的成员即可;
    
    //结构体成员分析如下:
    typedef struct
    {
      uint32_t StdId;  /*所接收到报文的标准ID,读出的值在 0 to 0x7FF. */
      uint32_t ExtId;  /*!所接收到报文的扩展ID,读出的值在 0 to 0x1FFFFFFF. */
      uint8_t IDE;     /*!接收到是扩展帧还是标准帧,可与预定义好的宏比较 */
      uint8_t RTR;     /*!接收到是遥控帧还是数据帧,可与预定义好的宏比较 */
      uint8_t DLC;     /*!接收到的数据长度,读出的值在 0 to 8 */
      uint8_t Data[8]; /*!存放接收数据的字符数组缓冲区,可从其中取出得到的数据 */
      uint8_t FMI;     /*将该报文存入邮箱的 过滤器序号*/
    } CanRxMsg;
    
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-14 14:14:35  更:2021-08-14 14:17:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:27:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码