你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32的CAN总线的基本原理及实现过程

[复制链接]
STMCU小助手 发布时间:2022-5-16 11:26
1、什么是CAN
        CAN是Controller Area Network 的缩写(简称称CAN),是ISO国际标准化的串行通信协议。由德国电气商博世公司在1986 年率先提出。此后,CAN 通过ISO11898 及ISO11519 进行了标准化。现在在欧洲已是汽车网络的标准协议。ISO11898是针对通信速率为125Kbps~1Mbps的高速通信标准,而ISO11519-2是针对通信速率为125Kbps以下的低速通信标准。现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的计算机局域网。

        CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。具有很高的可靠性,广泛应用于:汽车电子、工业自动化、船舶、医疗设备、工业设备等方面。

M)R$@(AS~3Y~ABOSVG`XZ(5.png

2、CAN协议的特点
        ①多主控制。

        ②系统柔软性。

        ③ 速度快,距离远。

        ④ 具有错误检测、错误通知和错误恢复功能。

        ⑤ 故障封闭功能。

        ⑥连接节点多。

3、ISO11898标准下的物理层特征
        CAN 控制器根据CAN_L和CAN_H上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。

        显性电平对应逻辑:0,CAN_H和CAN_L之差为2.5V左右。

        隐性电平对应逻辑:1,CAN_H和CAN_L之差为0V。

        显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。另外,在CAN总线的起止端都有一个120Ω的终端电阻,来做阻抗匹配,以减少回波反射。

GW6`_}C9PQX~H3{YFHADI0V.png

4、CAN 协议的5 种类型帧

@AJ$PZ5IE%3}AX2UMBV0}CO.png

其中,数据帧和遥控帧有标准格式和扩展格式两种格式。

       标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID 。

       其中,最常用,也是最复杂的是数据帧,接着就看看数据帧:

数据帧一般由 7 个段构成

(1) 帧起始。表示数据帧开始的段。
(2) 仲裁段。表示该帧优先级的段。
(3) 控制段。表示数据的字节数及保留位的段。
(4) 数据段。数据的内容,一帧可发送 0~8 个字节的数据。
(5) CRC 段。检查帧的传输错误的段。
(6) ACK 段。表示确认正常接收的段。
(7) 帧结束。表示数据帧结束的段。

~A5_U[81UV8]~5SJIFJF9TG.png

4.1、总线仲裁介绍
同时多个单元发送数据时,总线仲裁过程:

IJ)IDI{7Z@DSA615FA8)E.png

        上图中,单元 1 和单元 2 同时开始向总线发送数据,开始部分他们的数据格式是一样的,故无法区分优先级,直到 T 时刻,单元 1 输出隐性电平,而单元 2 输出显性电平,此时单元 1仲裁失利,立刻转入接收状态工作,不再与单元 2 竞争,而单元 2 则顺利获得总线使用权,继续发送自己的数据。这就实现了仲裁,让连续发送显性电平多的单元获得总线使用权.

        规律:

              1,总线空闲时,最先发送的单元获得发送优先权,一但发送,其他单元无法抢占。

              2,如果有多个单元同时发送,则连续输出显性电平多的单元,具有较高优先级。

4.2、位时序
       位速率:由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位一般可以分为如下四段:

            同步段(SS)
            传播时间段(PTS)
            相位缓冲段 1(PBS1)
            相位缓冲段 2(PBS2)

      这些段又由可称为 Time Quantum(以下称为 Tq)的最小时间单位构成,1 位分为 4 个段,每个段又由若干个 Tq 构成,这称为位时序。

       位时间=1/波特率,因此,知道位时间,我们就可以知道波特率1 位由多少个 Tq 构成、每个段又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。各段的作用和 Tq 数如表所示:

5N6DW5AM{KLFG360_S{4.png

1 个位的构成如图所示:

%QR7Z1KPF)9]}7_HZ)]IH78.png

上图的采样点,是指读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。根据这个位时序,我们就可以计算 CAN 通信的波特率了。图中采样时间加大或减少量的最大值就是SJW。

5、STM32 CAN控制器简介

       STM32F4 自带的是 bxCAN,即基本扩展 CAN。它支持 CAN 协议 2.0A 和 2.0B。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用, bxCAN 提供所有支持时间触发通信模式所需的硬件功能。
STM32F4 的 bxCAN 的主要特点有:
          ①支持 CAN 协议 2.0A 和 2.0B 主动模式
          ②波特率最高达 1Mbps
          ③支持时间触发通信
          ④具有 3 个发送邮箱
          ⑤具有 3 级深度的 2 个接收 FIFO
          ⑥可变的过滤器组(28 个, CAN1 和 CAN2 共享)

E)16~{@VDJYEVZN9IKG(T%H.png

5.1、标识符筛选器
CAN的标识符不表示目的地址而是表示发送优先级。接收节点根据标识符的值,来决定是否接收对应消息。
STM32 CAN控制器,提供了28个可配置的筛选器组(F1仅互联型才有28个,其他的只有14个),可降低CPU处理CAN通信的开销。
STM32 CAN控制器每个筛选器组由2个32位寄存器组成(CAN_FxR1和CAN_FxR2,x=0~27)。根据位宽不同,每个筛选器组可提供:
                 ● 1个32位筛选器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位

                 ● 2个16位筛选器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

     4.筛选器可配置为:屏蔽位模式和标识符列表模式。

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

在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟筛选器标识符相同。

[P7INPM[EOETS7MBWATI[UE.png

为了过滤出一组标识符,应该设置筛选器组工作在屏蔽位模式。
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。
应用程序不用的筛选器组,应该保持在禁用状态(通过CAN_FA1R设置)。
筛选器组中的每个筛选器,都被编号为(即:筛选器编号)从0开始,到某个最大数值-取决于筛选器组的模式和位宽的设置。
通过CAN_FFA1R的设置,可以将筛选器组关联到FIFO0/FIFO1
5.2、STM32 CAN模式
1)工作模式

       ①初始化模式(INRQ=1,SLEEP=0)

       ②正常模式(INRQ=0,SLEEP=0)

       ③睡眠模式(SLEEP=1)

2)测试模式

静默模式( LBKM=0,SILM=1 )

V[~PZ75X~{REEKT21P(PX0D.png

环回模式( LBKM=1,SILM=0 )

28PCEV8K9R~FJ4U3F9X6E@5.png

环回静默模式(LBKM=1,SILM=1)

N((0PJ%SJ_H[)WACIRR[N.png

3)调试模式

5.3、STM32 CAN发送流程
      CAN发送流程为:

        程序选择1个空置的邮箱(TME=1)--->设置标识符(ID),数据长度和发送数据--->设置CAN_TIxR的TXRQ位为1,请求发送--->邮箱挂号(等待成为最高优先级)--->预定发送(等待总线空闲)--->发送--->邮箱空置。

        还包含了很多其他处理,终止发送(ABRQ=1)和发送失败处理等

]H1Q8B)[T86KV_74XRMXFDP.png

5.4、STM32 CAN接收流程
CAN接收流程为:

        FIFO空--->收到有效报文--->挂号_1(存入FIFO的一个邮箱,这个由硬件控制,从而节省了 CPU 的处理负荷,简化了软件并保证了数据的一致性)---->收到有效报文---->挂号_2---->收到有效报文---->挂号_3---->收到有效报文à溢出。

        CAN收到的有效报文,存储在3级邮箱深度的FIFO中。FIFO接收到的报文数,我们可以通过查询CAN_RFxR的FMP寄存器来得到,只要FMP不为0,我们就可以从FIFO读出收到的报文。

         报文FIFO具有锁定功能(由CAN_MCR,RFLM位控制),锁定后,新数据将丢弃,不锁定则新数据将替代老数据

Z{NCPU77TQBGI%J$%]XO[XU.png

5.5、STM32 CAN位时序
      STM32F4 把传播时间段和相位缓冲段 1(STM32F4 称之为时间段1)合并了,所以 STM32F4 的 CAN 一个位只有 3 段:同步段(SYNC_SEG)、时间段 1(BS1)和时间段 2(BS2)。 STM32F4 的 BS1 段可以设置为 1~16 个时间单元,刚好等于CAN的传播时间段和相位缓冲段 1 之和。

DV)@KRRV56{DVXE1BBK895T.png

         图中还给出了 CAN 波特率的计算公式,我们只需要知道 BS1 和 BS2 的设置,以及 APB1的时钟频率(一般为 42Mhz),就可以方便的计算出波特率。

         比如:

                  STM32F103,设TS1=8、TS2=7、BRP=3,波特率=36000/[(9+8+1)*4]=500Kbps。

                  STM32F407,设TS1=6、TS2=5、BRP=5,波特率=42000/[(7+6+1)*6]=500Kbps。

6、参考代码
  1. #include "can.h"
  2. #include "delay.h"
  3. #include "usart.h"

  4. u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
  5. {
  6.           GPIO_InitTypeDef GPIO_InitStructure;
  7.         CAN_InitTypeDef        CAN_InitStructure;
  8.           CAN_FilterInitTypeDef  CAN_FilterInitStructure;

  9.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  10.           RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

  11.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
  12.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  13.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  14.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  15.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  16.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  17.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1);
  18.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1);
  19.          
  20.            CAN_InitStructure.CAN_TTCM=DISABLE;
  21.           CAN_InitStructure.CAN_ABOM=DISABLE;
  22.           CAN_InitStructure.CAN_AWUM=DISABLE;
  23.           CAN_InitStructure.CAN_NART=ENABLE;
  24.           CAN_InitStructure.CAN_RFLM=DISABLE;
  25.           CAN_InitStructure.CAN_TXFP=DISABLE;
  26.           CAN_InitStructure.CAN_Mode= mode;
  27.           CAN_InitStructure.CAN_SJW=tsjw;
  28.           CAN_InitStructure.CAN_BS1=tbs1;
  29.           CAN_InitStructure.CAN_BS2=tbs2;
  30.           CAN_InitStructure.CAN_Prescaler=brp;
  31.           CAN_Init(CAN1, &CAN_InitStructure);

  32.          CAN_FilterInitStructure.CAN_FilterNumber=0;
  33.           CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  34.           CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
  35.           CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
  36.           CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  37.           CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
  38.           CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  39.            CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;
  40.           CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  41.           CAN_FilterInit(&CAN_FilterInitStructure);
  42.                
  43.         CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);            

  44.           NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  45.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   
  46.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           
  47.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  48.           NVIC_Init(&NVIC_InitStructure);

  49.         return 0;
  50. }   

  51.                     
  52. void CAN1_RX0_IRQHandler(void)
  53. {
  54.           CanRxMsg RxMessage;
  55.         int i=0;
  56.     CAN_Receive(CAN1, 0, &RxMessage);
  57.         for(i=0;i<8;i++)
  58.         printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data<i>);
  59. }


  60. u8 CAN1_Send_Msg(u8* msg,u8 len)
  61. {        
  62.   u8 mbox;
  63.   u16 i=0;
  64.   CanTxMsg TxMessage;
  65.   TxMessage.StdId=0x12;        
  66.   TxMessage.ExtId=0x12;
  67.   TxMessage.IDE=0;               
  68.   TxMessage.RTR=0;        
  69.   TxMessage.DLC=len;                                                
  70.   for(i=0;i<len;i++)
  71.   TxMessage.Data<i>=msg<i>;                              
  72.   mbox= CAN_Transmit(CAN1, &TxMessage);   
  73.   i=0;
  74.   while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;
  75.   if(i>=0XFFF)return 1;
  76.   return 0;               

  77. }

  78. u8 CAN1_Receive_Msg(u8 *buf)
  79. {                                      
  80.          u32 i;
  81.         CanRxMsg RxMessage;
  82.     if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;               
  83.     CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
  84.     for(i=0;i<RxMessage.DLC;i++)
  85.     buf<i>=RxMessage.Data<i>;  
  86.         return RxMessage.DLC;        
  87. }
  88. </i></i></i></i></i>
复制代码


收藏 评论0 发布时间:2022-5-16 11:26

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版