STM32_CAN接收

实验平台:STM32F407ZGT6

bxCAN简介

基本扩展CAN外设又称bxCAN,可与CAN网络进行交互。
STM32F4中CAN的框图如下图所示:
STM32_CAN接收_第1张图片

  • 发送
    图中红框所示,bxCAN提供了三个发送邮箱,可配置发送优先级。
  • 接收
    图中蓝框所示,bxCAN提供了两个具有三级深度的接收FIFO,可调整筛选器组。
  • 筛选器
    图中橙框所示,bxCAN提供了28个可调整/可配置的标识符筛选器组,由CAN1和CAN2共享,用于选择软件所需传入的消息并丢弃其余消息。

筛选器

筛选器组的配置如下图所示:
STM32_CAN接收_第2张图片

  • 寄存器
    图中红框所示,每个筛选器组x均包含两个32位寄存器,CAN_FxR1和CAN_FxR2。
    根据尺度不同,每个筛选器组可以提供一个32位筛选器或两个16位筛选器,相应标识符等的映射如图所示。
  • 掩码模式
    图中蓝框所示。
    掩码模式下,标识符寄存器与掩码寄存器关联,用以指示标识符的哪些位“必须匹配”,哪些位“无需理会”。若掩码某一位为1,则该位标识符必须匹配,若为0,则无需理会。
    掩码模式主要用于筛选一组标识符。
  • 列表模式
    图中橙框所示。
    列表模式下,指定两个标识符寄存器,标识符的所有位都必须匹配。
    列表模式主要用于筛选单个标识符

接收状态

接收FIFO的状态如下图所示:
STM32_CAN接收_第3张图片

  • FMP[1:0]位——接收到
    当FIFO为空状态时,CAN_RFR寄存器的FMP[1:0]位为0x00;当接收到第一条有效消息后,硬件将FMP[1:0]位置为0x01;如果未释放邮箱,当接收到第二条有效消息后,置为0x10;当接收到第三条有效消息后,置为0x11;此时若不释放邮箱,下一次接收到有效消息时将导致上溢。
  • RFOM位
    软件读取邮箱内容,并通过将CAN_RFR寄存器的RFOM位置为1来释放邮箱,此时FMP[1:0]位减1。
  • FULL位——接收满
    当FIFO存储了第三条消息后,CAN_RFR寄存器的FULL位置为1。
  • FOVR位——上溢
    当FIFO存储满三条消息后且未及时释放,下一次接收到有效消息时将导致上溢,硬件将CAN_RFR寄存器的FOVR位置为1指示上溢状况。

中断

bxCAN共有四个专用的中断向量,如下图所示:
STM32_CAN接收_第4张图片
图中红框为接收相关的中断,对应接收到、接收满、上溢三种接收状态,以FIFO0中断为例:

  • 接收到,CAN_RF0R寄存器的FMP0[1:0]位不是0x00
  • 接收满,CAN_RF0R寄存器的FULL0位置为1
  • 上溢,CAN_RF0R寄存器的FOVR0位置为1

中断接收程序

本程序采用STM32F407ZGT6的CAN1接口,采用筛选器0,并关联到FIFO1,采用FMP0位产生中断,采集四路电机的转子角度、转速、电流和温度。

h文件

#include "sys.h"
#include "stm32f4xx_can.h"

//电机ID
typedef enum
{
	CAN_Motor1_RX_ID = 0x201,
	CAN_Motor2_RX_ID = 0x202,
	CAN_Motor3_RX_ID = 0x203,
	CAN_Motor4_RX_ID = 0x204,
}CAN_Message_ID;

//电机测量值
typedef struct
{
	uint16_t 	real_angle;			//转子机械角度[0,8191]对应[0,360°]
	int16_t	 	real_rpm;			//转子转速
	int16_t  	real_current;		//实际转矩电流
	int8_t		real_temp;			//电机温度
}Motor_Measure_t;

extern Motor_Measure_t  Motor_Chassis[];

u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);
void get_motor_measure(Motor_Measure_t *ptr, CanRxMsg* RxMessage);

c文件

#include "can.h"

Motor_Measure_t  Motor_Chassis[4] = {0};

u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
	GPIO_InitTypeDef 		GPIO_InitStructure; 
	CAN_InitTypeDef			CAN_InitStructure;
	CAN_FilterInitTypeDef  	CAN_FilterInitStructure;
	NVIC_InitTypeDef  		NVIC_InitStructure;
	
	//使能相关时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);	                   											 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	
    //初始化GPIO
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//引脚复用映射配置
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_CAN1);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_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;	  					//筛选器0
  	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;	//掩码模式 
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;	//一个32位筛选器 
  	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;				//32位ID
  	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;			//32位掩码,不对任何位进行匹配,将接收任意ID的消息
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
   	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;	//筛选器0关联到FIFO0
  	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; 				//激活筛选器
  	CAN_FilterInit(&CAN_FilterInitStructure);							//初始化筛选器
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    
  
  	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
  	
	return 0;
}

//中断服务函数			    
void CAN1_RX0_IRQHandler(void)
{
	CanRxMsg RxMessage;
	u8 i = 0;
	if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)			//中断发生,接收到消息
	{
		CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);			//清除中断标志
		CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);			//读取消息数据
		i = RxMessage.StdId - CAN_Motor1_RX_ID;				//得到电机编号:0、1、2、3
		get_motor_measure(&Motor_Chassis[i], &RxMessage);	//将4个电机的测量值存入结构体数组中
	}		
}

//电机测量值处理函数
void get_motor_measure(Motor_Measure_t *ptr, CanRxMsg* RxMessage)
{
	ptr->real_angle = (uint16_t)(RxMessage->Data[0]<<8 | RxMessage->Data[1]);
	ptr->real_rpm = (uint16_t)(RxMessage->Data[2]<<8 | RxMessage->Data[3]);
	ptr->real_current = (int16_t)(RxMessage->Data[4]<<8 | RxMessage->Data[5]);
	ptr->real_temp = RxMessage->Data[6];
}

你可能感兴趣的:(STM32学习笔记,stm32,can)