本文的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));
波特率的计算公式为:
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的过滤器都恢复到初始化状态。