STM32 CAN使用

来源:互联网 发布:网络歌手什么意思 编辑:程序博客网 时间:2024/06/07 00:56

CAN工作模式:

CAN_Mode_Silent:静默模式,简单理解收到数据不发送应答信号。

在静默模式下,总线必须要有2个或2个以上的节点,才能收到数据,个人理解有应答信号stm32can内核才认为只是一个完整的数据。

 

CAN波特率设置:

   CAN_InitStructure.CAN_BS1 = tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq

   CAN_InitStructure.CAN_BS2 = tbs2; //Tbs2范围CAN_BS2_1tq ~ CAN_BS2_8tq

   CAN_InitStructure.CAN_Prescaler = brp; //分频系数

BPS = AHB1_CLOCK / (tbs1 + tbs2 + brp + 1);


CAN滤波与FIFO,直接看代码如下:
u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode){int ext_id = 0x000000FF;//期望 想要看到的ID,例如 我先要ID 后2位时FF的数据,那么ext_id = 0x000000FF即可GPIO_InitTypeDef       GPIO_InitStructure; CAN_InitTypeDef        CAN_InitStructure;CAN_FilterInitTypeDef  CAN_FilterInitStructure;   NVIC_InitTypeDef  NVIC_InitStructure;    //使能相关时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//使能PORTD时钟                      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟    //初始化GPIOGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉    GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化PD0,PD1  //引脚复用映射配置GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1); //GPIOD0复用为CAN1GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1); //GPIOD1复用为CAN1    //CAN单元设置   CAN_InitStructure.CAN_TTCM = DISABLE;//非时间触发通信模式     CAN_InitStructure.CAN_ABOM = DISABLE;//软件自动离线管理    CAN_InitStructure.CAN_AWUM = DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)  CAN_InitStructure.CAN_NART = ENABLE;//禁止报文自动传送   CAN_InitStructure.CAN_RFLM = DISABLE;//报文不锁定,新的覆盖旧的    CAN_InitStructure.CAN_TXFP = DISABLE;//优先级由报文标识符决定   CAN_InitStructure.CAN_Mode = mode; //模式设置   CAN_InitStructure.CAN_SJW = tsjw;//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq  CAN_InitStructure.CAN_BS1 = tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq  CAN_InitStructure.CAN_BS2 = tbs2;//Tbs2范围CAN_BS2_1tq ~CAN_BS2_8tq  CAN_InitStructure.CAN_Prescaler = brp;  //分频系数(Fdiv)为brp+1  CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1     //配置过滤器CAN_FilterInitStructure.CAN_FilterNumber = 0;  //过滤器0CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //32位 //设置屏蔽寄存器,这里当标识符寄存器CAN_FilterInitStructure.CAN_FilterIdHigh = ((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterIdLow = ((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节//设置标识符寄存器CAN_FilterInitStructure.CAN_FilterMaskIdHigh = ((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterMaskIdLow = ((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节   CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;//过滤器0关联到FIFO0  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //激活过滤器0  CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);//配置过滤器2ext_id = 0x00000000;CAN_FilterInitStructure.CAN_FilterNumber = 1;  //过滤器1CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //32位 //设置屏蔽寄存器,这里当标识符寄存器CAN_FilterInitStructure.CAN_FilterIdHigh = ((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterIdLow = ((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节//设置标识符寄存器CAN_FilterInitStructure.CAN_FilterMaskIdHigh = ((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterMaskIdLow = ((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节   CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1;//过滤器0关联到FIFO1  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //激活过滤器0  CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化CAN_ITConfig(CAN1,CAN_IT_FMP1,ENABLE);//FIFO1消息挂号中断允许.    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;            // 次优先级为3  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);return 0;}   u8 CAN2_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode){int ext_id = 0x00000000;//期望 想要看到的ID,例如 我先要ID 后2位时FF的数据,那么ext_id = 0x000000FF即可  GPIO_InitTypeDef    GPIO_InitStructure; CAN_InitTypeDef        CAN_InitStructure;  CAN_FilterInitTypeDef  CAN_FilterInitStructure;   NVIC_InitTypeDef  NVIC_InitStructure;    //使能相关时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能PORTB时钟                      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);//使能CAN2时钟    //初始化GPIOGPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化PB12,PB13  //引脚复用映射配置GPIO_PinAFConfig(GPIOB,GPIO_PinSource12,GPIO_AF_CAN2); //GPIOB12复用为CAN2GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_CAN2); //GPIOB13复用为CAN2    //CAN单元设置   CAN_InitStructure.CAN_TTCM=DISABLE;//非时间触发通信模式     CAN_InitStructure.CAN_ABOM=DISABLE;//软件自动离线管理    CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)  CAN_InitStructure.CAN_NART=ENABLE;//禁止报文自动传送   CAN_InitStructure.CAN_RFLM=DISABLE;//报文不锁定,新的覆盖旧的    CAN_InitStructure.CAN_TXFP=DISABLE;//优先级由报文标识符决定   CAN_InitStructure.CAN_Mode= mode; //模式设置   CAN_InitStructure.CAN_SJW=tsjw;//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq  CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq  CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~CAN_BS2_8tq  CAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1  CAN_Init(CAN2, &CAN_InitStructure);   // 初始化CAN2    //配置过滤器 CAN_FilterInitStructure.CAN_FilterNumber=14;  //过滤器14  CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 //设置屏蔽寄存器,这里当标识符寄存器CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节//设置标识符寄存器CAN_FilterInitStructure.CAN_FilterMaskIdHigh = ((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节CAN_FilterInitStructure.CAN_FilterMaskIdLow = ((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节   CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器1关联到FIFO1  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0  CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化CAN_ITConfig(CAN2,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.        NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;            // 次优先级为1  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);return 0;}      void CAN1_RX0_IRQHandler(void){CAN_Receive(CAN1, CAN_Filter_FIFO0, &CAN1_RxMessage);CAN_Flag = 1;}void CAN1_RX1_IRQHandler(void){CAN_Receive(CAN1, CAN_Filter_FIFO1, &CAN1_RxMessage);CAN_FIFO1_Flag = 1;}    void CAN2_RX0_IRQHandler(void){    CAN_Receive(CAN2, CAN_Filter_FIFO0, &CAN2_RxMessage);CAN2_Flag = 1;}u8 CAN1_Send_Msg(int extid,u8* msg,u8 len){  u8 mbox;  u16 i = 0;  CanTxMsg TxMessage;  TxMessage.StdId = 0x12;       // 标准标识符(12位)  TxMessage.ExtId = extid;     // 设置扩展标示符(29位)  TxMessage.IDE = 4;         // 使用1为扩展标识符、0为标准标识符  TxMessage.RTR = 0;         // 消息类型为数据帧,0为数据帧、1为远程帧  TxMessage.DLC = len; // 发送帧字节数  for(i = 0;i < len;i++)    TxMessage.Data[i] = msg[i]; // 第一帧信息            mbox = CAN_Transmit(CAN1, &TxMessage);     i = 0;  while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))i++;//等待发送结束  if(i >= 0XFFF)return 1;  return 0;}u8 CAN2_Send_Msg(u8* msg,u8 len){  u8 mbox;  u16 i=0;  CanTxMsg TxMessage;  TxMessage.StdId=0x12;       // 标准标识符(12位)  TxMessage.ExtId=0x0005ffff; // 设置扩展标示符(29位)  TxMessage.IDE=4;         // 使用1为扩展标识符、0为标准标识符  TxMessage.RTR=0;         // 消息类型为数据帧,0为数据帧、1为远程帧  TxMessage.DLC=len; // 发送帧字节数  for(i=0;i=0XFFF)return 1;  return 0;}
该代码在main中调用
CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,12,CAN_Mode_Normal);//bsp = APB1_CLK / BRP / (1 + BS2 + BS1) 250kbps
进行初始化

直接看代码中配置滤波器段,首先选择滤波器编号(个人理解在32位标识符屏蔽位模式下CAN1对应滤波器组0 ~13 ,CAN2对应滤波器组14 ~ 27),选择好过滤器后,接着就是设置两个屏蔽寄存器,之后是关键,要把这个滤波器编号对应到FIFO上,只有这样对应FIFO中才能有数据。
代码中写了两个滤波器,分别对应FIFO0和FIFO1,STM32的can在进行筛选时根据滤波器编号从0到13,所以在设置两个滤波器的情况下,第二个要筛选的数对应位数要比第一个少。如,上述代码我要ID=00 00 00 FF的数据单独进入一个中断,那么我就必须使用编号低的滤波器组。

原创粉丝点击