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

【经验分享】can总线-stm32

[复制链接]
STMCU小助手 发布时间:2022-1-17 20:39
一、什么是can总线?
can总线因为使用电压差表示逻辑1和0,所以抗干扰性强,传播距离远(500kbps 时130M),比特率越小越远
1.can有几根线?
  2根,can_H ,can_L
2.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接口在哪?
  

1247024-20190905145414413-588054644.png

  stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器
  但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片:
  这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。


1247024-20190904142132013-1652807192.png

2.can概念入门比较好的文档
https://wenku.baidu.com/view/7701528a6529647d2728520f.html
这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。
3.can例程。

  1. #ifndef CAN_H_
  2. #define CAN_H_
  3. #include "stm32f10x.h"
  4. #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA
  5. #define CAN_RXD GPIO_Pin_11
  6. #define CAN_TXD GPIO_Pin_12
  7. #define CAN_IO  GPIOA

  8. enum canrate_e
  9. {
  10.     CANRATE125K=125,
  11.     CANRATE250K=250,
  12.     CANRATE500K=500,
  13.     CANNOTLINK,
  14. };

  15. enum canStdExt_e
  16. {
  17.     CANSTD=0,
  18.     CANEXT=1,
  19. };
  20. struct canrxtx_s
  21. {
  22.     CanRxMsg rxMessage[3];
  23.     u8 rx_newflag;
  24.     uint32_t f;
  25.     CanTxMsg txMessage;

  26. };

  27. /*std ID*/
  28. #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional

  29. #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits  ECM ID,physical
  30. #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits  ECM ID,physical
  31. #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter

  32. /*extend ID*/
  33. #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits  ID,Functional
  34. #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits  ID,Functional   HONDA
  35. #endif
复制代码
  1. #include "can.h"
  2. #include <string.h>
  3. u8 std_or_ext;
  4. struct canrxtx_s canrxtx;
  5. void CAN1_init(enum canrate_e canrate)
  6. {

  7.     GPIO_InitTypeDef GPIO_InitStructure;
  8.     CAN_InitTypeDef  CAN_InitStructure;

  9.     RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
  10.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
  11.     GPIO_InitStructure.GPIO_Pin = CAN_RXD;
  12.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  13.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14.     GPIO_Init(CAN_IO, &GPIO_InitStructure);

  15.     GPIO_InitStructure.GPIO_Pin = CAN_TXD;
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.     GPIO_Init(CAN_IO, &GPIO_InitStructure);

  19.     CAN_DeInit(CAN1);
  20.     CAN_StructInit(&CAN_InitStructure);

  21.     CAN_InitStructure.CAN_TTCM = DISABLE;
  22.     CAN_InitStructure.CAN_ABOM = DISABLE;
  23.     CAN_InitStructure.CAN_AWUM = DISABLE;
  24.     CAN_InitStructure.CAN_NART = DISABLE;
  25.     CAN_InitStructure.CAN_RFLM = DISABLE;
  26.     CAN_InitStructure.CAN_TXFP = DISABLE;
  27.     CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
  28.     CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
  29.     CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
  30.     CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
  31.      //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler
  32.      if(canrate==CANRATE125K) /* 125KBps */
  33.          CAN_InitStructure.CAN_Prescaler =96;
  34.      else if(canrate==CANRATE250K) /* 250KBps */
  35.          CAN_InitStructure.CAN_Prescaler =48;
  36.      else  /* 500KBps */
  37.          CAN_InitStructure.CAN_Prescaler = 24;

  38.     CAN_Init(CAN1, &CAN_InitStructure);
  39. }

  40. void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)
  41. {
  42.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  43.     NVIC_InitTypeDef  NVIC_InitStructure;

  44.     CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~13
  45.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  46.     if(std_or_ext == CANSTD)
  47.     {
  48.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
  49.         CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
  50.         CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
  51.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;
  52.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;

  53.     }
  54.     else
  55.     {
  56.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
  57.         CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13);
  58.         CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);
  59.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);
  60.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);

  61.     }

  62.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
  63.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  64.     CAN_FilterInit(&CAN_FilterInitStructure);

  65.     NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;

  66.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  67.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  68.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  69.     NVIC_Init(&NVIC_InitStructure);

  70.     CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
  71. }
  72. /************************init******************************/
  73. void init_demo()
  74. {
  75.     std_or_ext = CANEXT;
  76.     CAN1_init(CANRATE500K);
  77.     CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID
  78. }
  79. /************************tx******************************/
  80. /*datalen<=8*/
  81. int CAN1_TransASerialData(u8* pdata,u8 datalen)
  82. {
  83.     u8 i=0;

  84.     Delay_ms(20);

  85.     if(std_or_ext == CANEXT)
  86.     {
  87.         canrxtx.txMessage.StdId=0x00;
  88.         canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian
  89.         canrxtx.txMessage.RTR=CAN_RTR_DATA;
  90.         canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits

  91.     }
  92.     if(std_or_ext== CANSTD)
  93.     {
  94.         canrxtx.txMessage.StdId=CAN1_TX_STD_ID;
  95.         canrxtx.txMessage.ExtId=0x00;
  96.         canrxtx.txMessage.RTR=CAN_RTR_DATA;
  97.         canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits
  98.     }

  99.     canrxtx.txMessage.DLC=0x08;
  100.     canrxtx.txMessage.Data[0]=datalen;
  101.     memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);


  102.     while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))

  103.     if(i>=3)    //timeout
  104.     {
  105.         return (-1);
  106.     }

  107.     canrxtx.rx_newflag=0;
  108.     return (0);

  109. }
  110. /************************rx******************************/
  111. void CAN1_RX1_IRQHandler(void)
  112. {
  113.     memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));
  114.     if(CAN_MessagePending(CAN1,CAN_FIFO0))
  115.         {
  116.             CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);
  117.         }
  118.     canrxtx.rx_newflag=1;
  119. }
复制代码

三、标识符过滤器的解释
过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下:   
  1. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;      
复制代码
  1. <font face="Tahoma" color="#000000">CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;          </font><div><font face="Tahoma" color="#000000">CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;                                                                        CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;                                                                            CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;                                                                  CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;  </font></div>
复制代码

stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale
1247024-20190905141229352-7031333.png

四、关于邮箱
如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。
每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。

1247024-20190905145743356-1283941053.png

五、can中容易理解错的概念
1.CAN总线中是没有地址这个概念的,每个报文都是群发。
所有节点都可以发送和接收,先发送的有优先权,此时其它节点处于监听模式,看是否有能通过自己过滤器的报文。
当同时有多个节点需要同时发送时,can总线将实行仲裁,标识符小的优先发送,被仲裁下去想要发送的节点立即转入监听状态,等待下次机会。
标识符是报文的一部分,如下图所示:
2.不管是标准帧或者扩展帧,最多只能携带8字节数据,用户可以根据这8个字节私立协议。
SOF:帧起始信号,显性电平,即can_H和can_L相差很小,小于0.5V,库函数做了赋值,不管。
标识符:11bit或者29bits,代表着本条报文的优先级
RTR:帧类型,是远程帧还是数据帧
IDE:标准帧还是扩展帧
R0:保留位,库函数做了,不管
DLC:数据域长度
数据域:具体携带的数据,最长8字节
CRC:对CRC前所有字节进行校验,得到的结果,库函数进行了这一步,不需要我们自己计算,不管。
CRC分隔符:1个隐性电平,库函数做了,不管
ACK Field:库函数做了,
EOF:帧结束标志,至少连续7位的隐性电平。不管。

1247024-20190905145048384-430469517.png

3.位填充的概念
在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。
我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。


收藏 评论0 发布时间:2022-1-17 20:39

举报

0个回答

所属标签

相似分享

官网相关资源

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