CAN总线笔记

一、简介

​ 它是一种串行异步半双工的通信方式,无主从机之分,采用差分信号传输具有较好的抗干扰能力以及纠错能力,常被用在各种环境恶劣,干扰强的各种工业现场。

二、物理层

1.差分信号

Can总线总共有两条线,分别为can_high以及can_low,采用差分信号的方式传输数据。

在这里插入图片描述

显性电平:逻辑0

隐性电平:逻辑1

2.CAN的通讯节点

在这里插入图片描述

(1)单片的CAN外设并引出了两个引脚:CAN_TX、CAN_RX。和485串口一样,单片机的CAN外设并不能直接CAN网络所需要的差分信号,而是通过外接的CAN收发器,将CAN_TX的TTL信号转换为差分信号;将CAN网络的差分信号转换成TTL信号给CAN_RX

(2)CAN网络上的节点没有主从机之说原始的CAN节点之间是不做区分的,只有报文之间才做区分,节点之间没有地址或者片选线来寻址,CAN只负责向网络上发送消息,需要的节点自然会从网络上接收需要的消息;同理CAN网络上发送完消息后,需要的CAN节点自然会去接收对应的消息;

3.CAN的总线类型

根Can的物理形式主要分为开环总线和闭环总线两种。

(1)闭环总线

在这里插入图片描述

闭环总线适用于短距高速(相对与开环总线而言而言)的传输场合,其最大传输距离为40m最大传输速率为1Mbps。总线两端要求有两个120欧的终端电阻。

在这里插入图片描述

开环总线适用于长距低速场合,最大传输速率为125Kbps,最大传输距离为1km。每根总线上要求串联一个2.2k欧的电阻

三、协议层

1.同步

Can属于异步通讯方式,在通讯之前节点之间要约定好波特率,且CAN还会使用“位同步”的方式来对抗干扰、吸收误差

(1) 硬同步

在总线刚刚从空闲状态中走出来的时候,在帧头的位置都会进行一次同步。此时所有的节点位时间重新开始计算,就像所有的运动员都再一次回到了起跑线上。这种同步方式被称作硬同步。

(2) 再同步(位同步)

在这里插入图片描述

CAN的每个位都被分为SS段、PTS段、PSB1段、PBS2段。最小时间单位是Tq,一个完整的位由8~25Tq组成。

SS段: 同步段,长度固定为1Tq,当跳变沿落在ss段时认为总线时序是同步的。

PTS段: 传播时间段,用来弥补信号的物理延迟。

PBS1段:相位缓冲段,用来补偿边沿误差,在再同步的时候可以加长

PBS2段:相位缓冲段,用来补偿边沿误差,在再同步的时候可以缩短

采样点位置在PBS1和PSB2交界的地方。

2.波特率

波特率:总tq数分之一。

3.报文格式

(1) 报文类型

在这里插入图片描述

上述报文中数据帧最常用需要着重记忆

(2) 报文格式
1.数据帧

在这里插入图片描述

  • SOF:帧起始信号
  • RTR:远程帧标志 0 表示数据帧
  • IDE:扩展帧标志位 0 表示标准帧
  • DLC:数据段长度
  • DATA:数据段
(1)关于canid
  • CAN-ID不用来标识某个节点,而是用来标识某种类型的报文
  • 标准帧有CAN-ID11位扩展帧CAN-ID29位
2.其他帧

在这里插入图片描述

四、STM32中的CAN总线

1.功能框图

(1)stm32can总线外设简介(STM32F103)
  • Stm32can总线外设最高通信速率为1Mbps;

  • can外设可以自动收发can报文,且支持标准ID和扩展ID;

  • can外设有个发送邮箱,可以软件控制发送优先级,还可以记录发送时间;

  • can有两个深度为3的FIFO,同时有报文过滤功能;

  • 可以配置自动重发;

  • 不支持DMA接收数据;

(2)功能框图重要部分介绍

在这里插入图片描述

这张框图你只需要了解以下四点

  • CAN有三个发送邮箱
  • 有两个深度为3的接收FIFO
  • 有28个筛选器,0~13是给CAN1使用的, 14~27是给CAN2使用的
  • 每个筛选器都可以连接到对应的配置给某个FIFO,一个FIFO可以配置多个筛选器
(3)工作模式

在这里插入图片描述

CAN总共有四种工作模式:

  • 普通模式:可以接收,也可以发送。

  • 静默模式:可以接收,只能往总线上发送1(隐性位),发送的数据也会被自己接收。

  • 回环模式:不能接收总线上的数据,发送的数据会被自己接收,总线上的数据也可以被检测到。

  • 静默回环模式:不能接收总线上的数据,只能往总线上发送1 发送的数据会被自己接收。

(4)过滤器
1. 过滤器工作模式

stm32f103有28组过滤器,每组过滤器有2个32位的寄存器。在不同的工作模式下这两个寄存器有不同的作用,过滤器有两种工作模式:

  • 列表工作模式:

    列表模式类似于白名单,两个寄存器全部用来设置canid,只有和设置的canid完全匹配才能通过过滤器。STM32的CAN有两个FIFO。

  • 掩码工作模式:

    对于掩码工作模式,过滤器的一个寄存器用来设置掩码,另一个用来设置canid。掩码和设置的canid是与的关系,只有对应位和设置的canid的未屏蔽位匹配的CAN报文才能通过过滤器。

2.过滤器大小

过滤器有16位和32位两种大小,具体如下:
在这里插入图片描述

(5)重要中断介绍

bxCAN占用4个专用的中断向量。通过设置CAN中断允许寄存器(CAN_IER),每个中断源都可以

单独允许和禁用。

  • 发送中断可由下列事件产生:

    • 发送邮箱0变为空,CAN_TSR寄存器的RQCP0位被置’1’。
    • 发送邮箱1变为空,CAN_TSR寄存器的RQCP1位被置’1’。
    • 发送邮箱2变为空,CAN_TSR寄存器的RQCP2位被置’1’。
  • FIFO0中断可由下列事件产生:

    • FIFO0接收到一个新报文,CAN_RF0R寄存器的FMP0位不再是’00’。
    • FIFO0变为满的情况,CAN_RF0R寄存器的FULL0位被置’1’。
    • FIFO0发生溢出的情况,CAN_RF0R寄存器的FOVR0位被置’1’。
  • FIFO1中断可由下列事件产生:

    • FIFO1接收到一个新报文,CAN_RF1R寄存器的FMP1位不再是’00’。
    • FIFO1变为满的情况,CAN_RF1R寄存器的FULL1位被置’1’。
    • FIFO1发生溢出的情况,CAN_RF1R寄存器的FOVR1位被置’1’。
  • 错误和状态变化中断可由下列事件产生:

    • 出错情况,关于出错情况的详细信息请参考CAN错误状态寄存器(CAN_ESR)。

    • 唤醒情况,在CAN接收引脚上监视到帧起始位(SOF)。

    • CAN进入睡眠模式。

    上述中断对应的中断服务函数名称分别为:

    void CAN1_RX1_IRQHandler (void);
    void USB_HP_CAN1_TX_IRQHandler (void);
    void USB_LP_CAN1_RX0_IRQHandler (void);
    void CAN1_SCE_IRQHandler (void);
    

2.CAN配置和使用

(1)标准库
1.重要结构体
初始化结构体
typedef struct
{
  uint16_t CAN_Prescaler;   //can外设时钟预分频器
  uint8_t CAN_Mode;         //CAN的操作模式:初始化模式、普通模式(工作时使用这个模式)、睡眠模式
  uint8_t CAN_SJW;          //再同步时,相位缓冲段调整的长度
  uint8_t CAN_BS1;          //相位缓冲段1
  uint8_t CAN_BS2;          //相位缓冲段2
  FunctionalState CAN_TTCM; //时间除服模式,bool值
  FunctionalState CAN_ABOM; //自动离线模式,bool值
  FunctionalState CAN_AWUM;  //自动唤醒模式,bool值
  FunctionalState CAN_NART;  //是否关闭自动重传
  FunctionalState CAN_RFLM;  //接收FIFO锁定模式,FIFO满时锁定
  FunctionalState CAN_TXFP;  //发送邮箱是否按优先级顺序发送报文
} CAN_InitTypeDef;
过滤器结构体
typedef struct
{
  uint16_t CAN_FilterIdHigh;            //过滤器高16位
  uint16_t CAN_FilterIdLow;             //过滤器低16位
  uint16_t CAN_FilterMaskIdHigh;        //过滤器掩码高16位
  uint16_t CAN_FilterMaskIdLow;         //过滤器掩码低16位
  uint16_t CAN_FilterFIFOAssignment;    //FIFO号
  uint8_t CAN_FilterNumber;             //过滤器号
  uint8_t CAN_FilterMode;               //过滤器工作模式:列表模式、掩码模式
  uint8_t CAN_FilterScale;              //过滤器宽度:16位或32位
  FunctionalState CAN_FilterActivation; //是否激活这个过滤器
} CAN_FilterInitTypeDef;
消息头结构体
typedef struct
{
  uint32_t StdId;  //标准CANID
  uint32_t ExtId;  //扩展CANID
  uint8_t IDE;     //是否使用扩展帧
  uint8_t RTR;     //是否是远程帧
  uint8_t DLC;     //数据段长度
  uint8_t Data[8]; //数据段数据
} CanTxMsg;
2.初始化代码
static void Can_Init(void)
{
  CAN_InitTypeDef CAN_InitStruct;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);

  CAN_InitStruct.CAN_ABOM = ENABLE;
  CAN_InitStruct.CAN_AWUM = ENABLE;
  CAN_InitStruct.CAN_NART = DISABLE;
  CAN_InitStruct.CAN_RFLM = DISABLE;
  CAN_InitStruct.CAN_TXFP = DISABLE;

  CAN_InitStruct.CAN_TTCM = DISABLE;
  CAN_InitStruct.CAN_Mode = CAN_Mode_Normal;
  
  /* 波特率:36MHz/9/(2+1+1)=1mbps */
  CAN_InitStruct.CAN_Prescaler = 9;
  CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;
  CAN_InitStruct.CAN_BS1 = CAN_BS1_2tq;
  CAN_InitStruct.CAN_BS2 = CAN_BS2_1tq;
  
  CAN_Init(Canfestival_Canx,&CAN_InitStruct);
  
  /*开启FIFO0有数据中断*/
  CAN_ITConfig(Canfestival_Canx,CAN_IT_FMP0,ENABLE);

}
3.常用的API
初始化
/**********************************************************************************
  * @brief  初始化CAN外设
  * @param  CANx: CAN外设
  * @param  CAN_InitStruct:  初始化结构体
  * @retval  CAN_InitStatus_Failed 或者 CAN_InitStatus_Success.
  ********************************************************************************/
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)
开中断
/*****************************************************************************************
  * @brief  配置CAN中断
  * @param  can外设
  * @param  CAN_IT: 中断类型 
  *                 - CAN_IT_TME,    //发送邮箱空
  *                 - CAN_IT_FMP0,   //FIFO0中有数据
  *                 - CAN_IT_FF0,    //FIFO0满
  *                 - CAN_IT_FOV0,   //FIFO0溢出
  *                 - CAN_IT_FMP1,   //FIFO1中有数据
  *                 - CAN_IT_FF1,    //FIFO1满
  *                 - CAN_IT_FOV1,   //FIFO1溢出
  *                 - CAN_IT_EWG, 
  *                 - CAN_IT_EPV,
  *                 - CAN_IT_LEC, 
  *                 - CAN_IT_ERR,   //错误
  *                 - CAN_IT_WKU or //唤醒
  *                 - CAN_IT_SLK.   //睡眠确认
  * @param  NewState: new state of the CAN interrupts.
  *                   This parameter can be: ENABLE or DISABLE.
  * @retval None.
  *************************************************************************************/
void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState);
过滤器
/*********************************************************************************
  * @brief  初始化过滤器
  * @param  配置结构体
  * @retval None.
*********************************************************************************/
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
接收数据
/******************************************************************************
  * @brief  Receives a message.
  * @param  CANx:       where x can be 1 or 2 to to select the CAN peripheral.
  * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
  * @param  RxMessage:  pointer to a structure receive message which contains 
  *                     CAN Id, CAN DLC, CAN datas and FMI number.
  * @retval None.
******************************************************************************/
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
发送数据
/*********************************************************************************
  * @brief  Initiates the transmission of a message.
  * @param  CANx:      where x can be 1 or 2 to to select the CAN peripheral.
  * @param  TxMessage: pointer to a structure which contains CAN Id, CAN
  *                    DLC and CAN data.
  * @retval The number of the mailbox that is used for transmission
  *                    or CAN_TxStatus_NoMailBox if there is no empty mailbox.
**********************************************************************************/
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
4.中断服务函数
void CAN1_RX1_IRQHandler (void);
void USB_HP_CAN1_TX_IRQHandler (void);
void USB_LP_CAN1_RX0_IRQHandler (void);
void CAN1_SCE_IRQHandler (void);
(2)hal库
1. cubmax配置
参数配置

在这里插入图片描述

  • Prescaler (for Time Quantum) : 分频系数,决定了Tq的大小
  • Time Quanta in Bit Segment 1 :相位缓冲段1 同步时加长
  • Time Quanta in Bit Segment 2 :相位缓冲段2 同步时缩短
  • ReSynchronization Jump Width: 再同步时相位缓冲段增加和减少的长度单位是Tq
  • Time Triggered Communication Mode :时间触发模式
  • Automatic Bus-Off Management: 自动下线功能,当检测128次11位连续的隐性位下线
  • Automatic Wake-Up Mode: 自动唤醒功能,通过检测CAN报文 由硬件唤醒CAN
  • Automatic Retransmission:自动重发功能,会一直重传到发送成功
  • Receive FIfo Locked Mode:当接收FIFO满时,FIFO被锁定,新来的报文被丢弃;否则会覆盖原有的报文
  • Transmit Fifo Priority: 使能时CAN报文发送的顺序由发送的顺序决定;不使能时,由报文优先级决定。
2. 重要结构体
CAN对象
typedef struct
{
  CAN_TypeDef                 *Instance;                 /*寄存器接口 */
  CAN_InitTypeDef                  Init;                 /*初始化参数 */
  ...                                                    /*其他成员不常用,暂时不列出*/
} CAN_HandleTypeDef;
初始化结构体
//和上述CubMax配置相同,不过多介绍
typedef struct
{
  uint32_t                   Prescaler;                 
  uint32_t                        Mode;                      
  uint32_t               SyncJumpWidth;              
  uint32_t                    TimeSeg1;                   
  uint32_t                    TimeSeg2;                   
  FunctionalState    TimeTriggeredMode;  
  FunctionalState           AutoBusOff;          
  FunctionalState           AutoWakeUp;          
  FunctionalState   AutoRetransmission; 
  FunctionalState    ReceiveFifoLocked;  
  FunctionalState TransmitFifoPriority;
} CAN_InitTypeDef;
过滤器结构体
typedef struct
{
  uint32_t                FilterIdHigh;    //过滤器高位     
  uint32_t                 FilterIdLow;    //过滤器低位        
  uint32_t            FilterMaskIdHigh;    //过滤器掩码高位    
  uint32_t             FilterMaskIdLow;    //过滤器掩码低位   
  uint32_t        FilterFIFOAssignment;    //FIFO号
  uint32_t                  FilterBank;    //过滤器号    
  uint32_t                  FilterMode;    //过滤器模式:掩码模式、列表模式       
  uint32_t                 FilterScale;    //过滤器大小        
  uint32_t            FilterActivation;    //是否使能该过滤器  
  uint32_t        SlaveStartFilterBank;    
} CAN_FilterTypeDef;
消息结构体
typedef struct
{
  uint32_t                     StdId;  
  uint32_t                     ExtId;    
  uint32_t                       IDE;     
  uint32_t                       RTR;     
  uint32_t                       DLC;     
  FunctionalState TransmitGlobalTime; 
} CAN_TxHeaderTypeDef;
3.cubmax生成的初始化代码以及分析
4. 常用的API
/**************************************************************************************************
* @brief 发送CAN_Message
* @param [in] hcan can对象/句柄
* @param [in] pHeader 报文头
* @param [in] aData   数据
* @param [out] pTxMailbox该消息通过哪个邮箱发送这个消息
* @retval  HAL_OK       成功
           HAL_ERROR    错误
***************************************************************************************************/
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, const CAN_TxHeaderTypeDef *pHeader,
                                       const uint8_t aData[], uint32_t *pTxMailbox);

/**************************************************************************************************
* @brief 接收CAN_Message
* @param [in] hcan can对象/句柄
* @param [in] RxFifo FIFO号
* @param [out] pHeader 报文头
* @param [in] aData   数据
* @retval  HAL_OK       成功
           HAL_ERROR    错误
***************************************************************************************************/
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo,
                                       CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);

/**************************************************************************************************
* @brief 配置过滤器
* @param [in] hcan can对象/句柄
* @param [in] sFilterConfig 过滤器配置
* @retval  HAL_OK       成功
           HAL_ERROR    错误
***************************************************************************************************/
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, const CAN_FilterTypeDef *sFilterConfig);

/**************************************************************************************************
* @brief 激活中断
* @param [in] hcan can对象/句柄
* @param [in] ActiveITs 中断类型
* @retval  HAL_OK       成功
           HAL_ERROR    错误
***************************************************************************************************/
HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs);

/**************************************************************************************************
* @brief 失活中断
* @param [in] hcan can对象/句柄
* @param [in] ActiveITs 中断类型
* @retval  HAL_OK       成功
           HAL_ERROR    错误
***************************************************************************************************/
HAL_StatusTypeDef HAL_CAN_DeactivateNotification(CAN_HandleTypeDef *hcan, uint32_t InactiveITs);

/*************************************************************************************************
  * @brief  判断某个mailbox是否发送完成
  * @param  hcan CAN 句柄
  * @param  TxMailboxes mailbox号
  * @retval Status
  *          - 0 : No pending transmission request on any selected Tx Mailboxes.
  *          - 1 : Pending transmission request on at least one of the selected
  *                Tx Mailbox.
**************************************************************************************************/
uint32_t HAL_CAN_IsTxMessagePending(const CAN_HandleTypeDef *hcan, uint32_t TxMailboxes)

5. 中断回调函数
/*发送邮箱发送完成回调函数*/
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan);

/*fifo收到消息和fifo满回调函数*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan);
void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan);
/*睡眠回调函数*/
void HAL_CAN_SleepCallback(CAN_HandleTypeDef *hcan);
/*被唤醒回调函数*/
void HAL_CAN_WakeUpFromRxMsgCallback(CAN_HandleTypeDef *hcan);
/*错误回调函数*/
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan);

注意:上述回调函数被调用后,对应中断有可能会被关闭,需要在对应回调函数中调用HAL_CAN_ActivateNotification来重行激活

6.重要配置
滤波器配置代码
  1. 32位滤波器,掩码模式(29位CAN-ID)

    //敬请期待[坏笑]
    
  2. 32位滤波器,列表模式(29位CAN-ID)

    //敬请期待[坏笑]
    
  3. 16位滤波器,掩码模式(11位CAN-ID)

    //敬请期待[坏笑]
    
  4. 16位滤波器,列表模式(11位CAN-ID)

    //敬请期待[坏笑]
    
发送消息配置代码
//敬请期待[坏笑]
(3)LL库(CAN这种复杂外设,没有对应的LL库)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值