本文的can是在stm32f105rc这种互联型的产品上做的实验,其它型号如果有出入,希望能发邮件(ranwei693532@163.com)不吝赐教。

STM32F105RC平台CAN简介

该平台CAN特性如下:

  • 支持CAN2.0A和CAN2.0B协议
  • 速率高达1 Mbit/s
  • 支持定时触发的通讯功能

发送:

  • 3个发送邮箱
  • 可配置的发送优先级
  • SOF发送模式中加时间戳

接收:

  • 两个接收FIFO
  • 可配置的过滤块
  • CAN1和CAN2共享28个过滤块
  • ID列表模式
  • 可配置FIFO溢出
  • SOF接收模式中加时间戳

定时触发通讯功能:

  • 自动重发模式
  • 16位定时器
  • 时间戳在数据最后两个字节

两路CAN:

  • CAN1:主CAN,用来管理从CAN和512字节的SRAM之间的通讯
  • CAN2:从CAN,不能直接访问SRAM。
  • 两个CAN单元恭喜512字节的SRAM。

CAN初始化

CAN1初始化

先看代码,然后从代码开始逐步拉开CAN的面纱

GPIO_InitTypeDef        GPIO_InitStructure;
    CAN_FilterInitTypeDef   CAN_FilterInitStructure;
    CAN_InitTypeDef         CAN_InitStructure;
    NVIC_InitTypeDef        NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    
	/* CAN1 RX pin init  */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	/* CAN1 TX pin init  */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* remap CAN1 pin, RX->PB8 TX->PB9. 
       如果使用CAN1 RX PA11 ,CAN1 TX PA12这对脚,就不需要使用下面的remap函数了 */
    GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);

    /* nvic setting  */
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_IRQn ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIO_PREEMP_CAN1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = NVIC_PRIO_SUB_CAN1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn ;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn ;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_SCE_IRQn ;
    NVIC_Init(&NVIC_InitStructure);

    /* CAN register init */
    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);

    /* CAN1 cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE; // 定时发送功能.
    CAN_InitStructure.CAN_ABOM = ENABLE;  // automatic bus-off management.
    CAN_InitStructure.CAN_AWUM = DISABLE; // 自动唤醒模式. 
    CAN_InitStructure.CAN_NART = ENABLE;  // 非自动重传模式
    CAN_InitStructure.CAN_RFLM = ENABLE;  // 接收FIFO锁定模式.
    CAN_InitStructure.CAN_TXFP = ENABLE;  // 传输FIFO优先级.
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    /* BaudRate:
                36M                  1               
        --------------------- * ----------- =  baudrate
        (SJW+(BS1)+(BS2))         (Prescaler)         
    */
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
    CAN_InitStructure.CAN_Prescaler = 2000000 / baud;
    CAN_Init(CAN1, &CAN_InitStructure);

	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode   = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale  = CAN_FilterScale_32bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh         = 0;
	CAN_FilterInitStructure.CAN_FilterIdLow          = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh     = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow      = 0;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation     = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
    
    CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_FMP1, ENABLE);

    /* IT Configuration for CAN1 */
    // arg CAN_IT_TME: Transmit mailbox empty Interrupt 
    // arg CAN_IT_FMP0: FIFO 0 message pending Interrupt 
    // arg CAN_IT_FF0: FIFO 0 full Interrupt
    // arg CAN_IT_FOV0: FIFO 0 overrun Interrupt
    // arg CAN_IT_FMP1: FIFO 1 message pending Interrupt 
    // arg CAN_IT_FF1: FIFO 1 full Interrupt
    // arg CAN_IT_FOV1: FIFO 1 overrun Interrupt
    // arg CAN_IT_WKU: Wake-up Interrupt
    // arg CAN_IT_SLK: Sleep acknowledge Interrupt  
    // arg CAN_IT_EWG: Error warning Interrupt
    // arg CAN_IT_EPV: Error passive Interrupt
    // arg CAN_IT_BOF: Bus-off Interrupt  
    // arg CAN_IT_LEC: Last error code Interrupt
    // arg CAN_IT_ERR: Error Interrupt
    CAN_ITConfig(CAN1, CAN_IT_EPV, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_EWG, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_BOF, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_LEC, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_ERR, ENABLE);

    while(CAN_ModeStatus_Failed == CAN_OperatingModeRequest(CAN1, CAN_OperatingMode_Normal));

波特率的计算公式为:
stm32cubeMX自动添加回调函数_优先级
CAN2的初始化

GPIO_InitTypeDef        GPIO_InitStructure;
    CAN_FilterInitTypeDef   CAN_FilterInitStructure;
    CAN_InitTypeDef         CAN_InitStructure;
    NVIC_InitTypeDef        NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    
	/* CAN1 RX pin init  */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	/* CAN1 TX pin init  */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* nvic setting  */
    NVIC_InitStructure.NVIC_IRQChannel = CAN2_TX_IRQn ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIO_PREEMP_CAN2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = NVIC_PRIO_SUB_CAN2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn ;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX1_IRQn ;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = CAN2_SCE_IRQn ;
    NVIC_Init(&NVIC_InitStructure);

    /* CAN register init */
    CAN_DeInit(CAN2);
    CAN_StructInit(&CAN_InitStructure);

    /* CAN1 cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE; // 定时发送功能.
    CAN_InitStructure.CAN_ABOM = ENABLE;  // automatic bus-off management.
    CAN_InitStructure.CAN_AWUM = DISABLE; // 自动唤醒模式. 
    CAN_InitStructure.CAN_NART = ENABLE;  // 非自动重传模式
    CAN_InitStructure.CAN_RFLM = ENABLE;  // 接收FIFO锁定模式.
    CAN_InitStructure.CAN_TXFP = ENABLE;  // 传输FIFO优先级.
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    /* BaudRate:
                36M                  1               
        --------------------- * ----------- =  baudrate
        (SJW+(BS1)+(BS2))         (Prescaler)         
    */
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
    CAN_InitStructure.CAN_Prescaler = 2000000 / baud;
    CAN_Init(CAN2, &CAN_InitStructure);
    CAN_SlaveStartBank(14);

	CAN_FilterInitStructure.CAN_FilterNumber = 14;
	CAN_FilterInitStructure.CAN_FilterMode   = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale  = CAN_FilterScale_32bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh         = 0;
	CAN_FilterInitStructure.CAN_FilterIdLow          = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh     = 0;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow      = 0;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation     = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
    
    CAN_ITConfig(CAN2, CAN_IT_TME, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_FMP0, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_FMP1, ENABLE);

    /* IT Configuration for CAN1 */
    // arg CAN_IT_TME: Transmit mailbox empty Interrupt 
    // arg CAN_IT_FMP0: FIFO 0 message pending Interrupt 
    // arg CAN_IT_FF0: FIFO 0 full Interrupt
    // arg CAN_IT_FOV0: FIFO 0 overrun Interrupt
    // arg CAN_IT_FMP1: FIFO 1 message pending Interrupt 
    // arg CAN_IT_FF1: FIFO 1 full Interrupt
    // arg CAN_IT_FOV1: FIFO 1 overrun Interrupt
    // arg CAN_IT_WKU: Wake-up Interrupt
    // arg CAN_IT_SLK: Sleep acknowledge Interrupt  
    // arg CAN_IT_EWG: Error warning Interrupt
    // arg CAN_IT_EPV: Error passive Interrupt
    // arg CAN_IT_BOF: Bus-off Interrupt  
    // arg CAN_IT_LEC: Last error code Interrupt
    // arg CAN_IT_ERR: Error Interrupt
    CAN_ITConfig(CAN2, CAN_IT_EPV, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_EWG, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_BOF, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_LEC, ENABLE);
    CAN_ITConfig(CAN2, CAN_IT_ERR, ENABLE);

    while(CAN_ModeStatus_Failed == CAN_OperatingModeRequest(CAN2, CAN_OperatingMode_Normal));

CAN过滤器

现在来介绍最重要的CAN过滤器。CAN过滤器有两种工作模式:MASK模式和ID列表模式。

MASK模式的工作原理:先将ID和MASK寄存器中的值做与运算,然后再和ID寄存器中的值比较,相等的才允许接收。

ID列表模式的工作原理是:和MASK寄存器和ID寄存器中存储的ID作为一个列表,允许在列表中的ID通过,不在列表中的ID就无法接收。

因为所有的包都要过过滤器,所以初始化的时候一定要配置CAN过滤器,不然会出现无法到任何包的情况。

另外,由于CAN1是主can,管理所有的资源,函数CAN_DeInit(CAN1)会将CAN1和CAN2的过滤器都恢复到初始化状态。