STM32 can通信部分函数注释

news2025/1/19 2:23:51
-----CAN1_Mode_Init

CAN模式初始化函数:u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)

//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);
//则波特率为:42M/((6+7+1)*6)=500Kbps
//返回值:0,初始化OK;
//    其他,初始化失败; 


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;
#if CAN1_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif
    //使能相关时钟
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟	/AHB1ENR位 0 GPIOAEN:IO 端口 A 时钟使能                    											 

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	/APB1ENR位 25 CAN1EN:CAN 1 时钟使能
	
    //初始化GPIO
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
    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(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
	
	  //引脚复用映射配置
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为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位MASK
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
   	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
  	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
  	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
		
#if CAN1_RX0_INT_ENABLE
	
	  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);
#endif
	return 0;
}   
-----uint8_t CAN_Init  /
配置CAN接收滤波器:void CAN_FilterInit /
中断初始化函数:void NVIC_Init 

can初始化(寄存器操作):uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)

uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)
{
  uint8_t InitStatus = CAN_InitStatus_Failed;
  uint32_t wait_ack = 0x00000000;
  /* Check the parameters */
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TTCM));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_ABOM));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_AWUM));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_NART));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_RFLM));
  assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TXFP));
  assert_param(IS_CAN_MODE(CAN_InitStruct->CAN_Mode));
  assert_param(IS_CAN_SJW(CAN_InitStruct->CAN_SJW));
  assert_param(IS_CAN_BS1(CAN_InitStruct->CAN_BS1));
  assert_param(IS_CAN_BS2(CAN_InitStruct->CAN_BS2));
  assert_param(IS_CAN_PRESCALER(CAN_InitStruct->CAN_Prescaler));

  /* Exit from sleep mode */
  CANx->MCR &= (~(uint32_t)CAN_MCR_SLEEP);//2取反再与,CAN_MCR位1清0,此位由软件清零时,将退出睡眠模式

  /* Request initialisation */
  CANx->MCR |= CAN_MCR_INRQ ;//CAN_MCR位0置1软件通过将此位置 1 来请求 CAN 硬件进入初始化模式

  /* Wait the acknowledge *///退出初始化模式等待确认
  while (((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
  {//MSR位0  CAN 硬件退出初始化模式(以在 CAN 总线上进行同步)时,此位由硬件清零。(非初始化模式为0)
    wait_ack++;    //加到0x0000FFFF退出循环
  }
//程序在这里由上面的程序到下面,1-未进入初始化模式超时,2-上面的while不成立,已经进入初始化模式
  /* Check acknowledge */
  if ((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK)//已经退出初始化模式
  {
    InitStatus = CAN_InitStatus_Failed;
  }
  else 
  {
    /* Set the time triggered communication mode */
    if (CAN_InitStruct->CAN_TTCM == ENABLE)
    {
      CANx->MCR |= CAN_MCR_TTCM;//MCR位 7 TTCM:时间触发通信模式
    }
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_TTCM;
    }

    /* Set the automatic bus-off management */
    if (CAN_InitStruct->CAN_ABOM == ENABLE)
    {
      CANx->MCR |= CAN_MCR_ABOM;//MCR位 6 ABOM:自动的总线关闭管理
    }
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_ABOM;
    }

    /* Set the automatic wake-up mode */
    if (CAN_InitStruct->CAN_AWUM == ENABLE)
    {
      CANx->MCR |= CAN_MCR_AWUM;//位 5 AWUM:自动唤醒模式 
    }
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_AWUM;
    }

    /* Set the no automatic retransmission */
    if (CAN_InitStruct->CAN_NART == ENABLE)
    {
      CANx->MCR |= CAN_MCR_NART; //位 4 NART:禁止自动重发送
    }
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_NART;
    }

    /* Set the receive FIFO locked mode */
    if (CAN_InitStruct->CAN_RFLM == ENABLE)
    {
      CANx->MCR |= CAN_MCR_RFLM;//位 3 RFLM:接收 FIFO 锁定模式
    }                          //1:接收 FIFO 上溢后锁定。接收 FIFO 装满后,下一条传入消息将被丢弃。
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_RFLM;
    }

    /* Set the transmit FIFO priority */
    if (CAN_InitStruct->CAN_TXFP == ENABLE)
    {
      CANx->MCR |= CAN_MCR_TXFP;//位 2 TXFP:发送 FIFO 优先级;0:优先级由消息标识符确定 1:优先级由请求顺序(时间顺序)确定

    }
    else
    {
      CANx->MCR &= ~(uint32_t)CAN_MCR_TXFP;
    }

    /* Set the bit timing register *///CAN 位时序寄存器 CAN_BTR,/位 30 LBKM:环回模式(调试)/位 25:24 SJW:再同步跳转宽度
   // 位 19:16 TS1:时间段 1/位 22:20 TS2:时间段 2/位 9:0 BRP:波特率预分频器,tq = (BRP[9:0]+1) x tPCLK(APB的时钟周期)

    CANx->BTR = (uint32_t)((uint32_t)CAN_InitStruct->CAN_Mode << 30) | \
                ((uint32_t)CAN_InitStruct->CAN_SJW << 24) | \
                ((uint32_t)CAN_InitStruct->CAN_BS1 << 16) | \
                ((uint32_t)CAN_InitStruct->CAN_BS2 << 20) | \
               ((uint32_t)CAN_InitStruct->CAN_Prescaler - 1);

    /* Request leave initialisation */
    CANx->MCR &= ~(uint32_t)CAN_MCR_INRQ;//位 0 INRQ:软件通过将此位清零,来将硬件--切换到正常模式--
                                         
   /* Wait the acknowledge */
   wait_ack = 0;
//MSR位0由硬件置 1,用于向软件指示 CAN 硬件此时处于初始化模式。
   while (((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
   {
     wait_ack++;
   }
   //程序到这里:1-处于初始化模式超时,2-上面的while不成立,已经进入正常模式
    /* ...and check acknowledged */
    if ((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)//CAN 硬件此时处于初始化模式
    {
      InitStatus = CAN_InitStatus_Failed;
    }
    else
    {
      InitStatus = CAN_InitStatus_Success ;
    }
  }

  /* At this step, return the status of initialization */
  return InitStatus;
}

配置CAN接收滤波器:void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)

void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
  uint32_t filter_number_bit_pos = 0;//下面的x位,代表0..27筛选器的哪一个
  /* Check the parameters */
  assert_param(IS_CAN_FILTER_NUMBER(CAN_FilterInitStruct->CAN_FilterNumber));
  assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode));
  assert_param(IS_CAN_FILTER_SCALE(CAN_FilterInitStruct->CAN_FilterScale));
  assert_param(IS_CAN_FILTER_FIFO(CAN_FilterInitStruct->CAN_FilterFIFOAssignment));
  assert_param(IS_FUNCTIONAL_STATE(CAN_FilterInitStruct->CAN_FilterActivation));

  filter_number_bit_pos = ((uint32_t)1) << CAN_FilterInitStruct->CAN_FilterNumber;

  /* Initialisation mode for the filter */
  CAN1->FMR |= FMR_FINIT;//位 0 FINIT置1:筛选器进入初始化模式

  /* Filter Deactivation */
  CAN1->FA1R &= ~(uint32_t)filter_number_bit_pos;//软件将x位置 1 可激活筛选器 x,取反是不激活

  /* Filter Scale */
  if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_16bit)
  {
    /* 16-bit scale for the filter */
    CAN1->FS1R &= ~(uint32_t)filter_number_bit_pos;0:双 16 位尺度配置

    /* First 16-bit identifier and First 16-bit mask *///FxR1--标识符和掩码(第1组)或者(列表模式)两个(1和2)标识符
    /* Or First 16-bit identifier and Second 16-bit identifier */
    CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 = 
       ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) |
        (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);

    /* Second 16-bit identifier and Second 16-bit mask *///FxR2--标识符和掩码(第2组)或者(列表模式)两个(3和4)标识符
    /* Or Third 16-bit identifier and Fourth 16-bit identifier */
    CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = 
       ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
        (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh);
  }

  if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_32bit)
  {
    /* 32-bit scale for the filter *///筛选器尺度寄存器 CAN_FS1R位 27:0 FSCx:这些位定义了筛选器13-0的尺度配置。
    CAN1->FS1R |= filter_number_bit_pos; //0:双 16 位尺度配置 1:单 32 位尺度配置
     /* 32-bit identifier or First 32-bit identifier *///32位标识符(对应FxR2的32掩码)或第一个32位标识符(列表模式)。--FxR1(手册FiRx)
    CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 = 
       ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh) << 16) |
        (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);
    /* 32-bit mask or Second 32-bit identifier *///设置32位掩码或第二个32位标识符(列表模式)--FxR2
    CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = 
       ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
        (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow);
  }

  /* Filter Mode */
  if (CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdMask)//掩码模式
  {
    /*Id/Mask mode for the filter*/
    CAN1->FM1R &= ~(uint32_t)filter_number_bit_pos;//标识符屏蔽模式
  }
  else /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdList *///列表模式
  {
    /*Identifier list mode for the filter*/
    CAN1->FM1R |= (uint32_t)filter_number_bit_pos;//寄存器第几位(哪个筛选器组0...27)标识符列表模式
  }

  /* Filter FIFO assignment *///过滤器FIFO(先进先出)分配的设置
  if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO0)//FIFO0
  {
    /* FIFO 0 assignation for the filter */
    CAN1->FFA1R &= ~(uint32_t)filter_number_bit_pos;//CAN筛选器FIFO分配寄存器(CAN_FFA1R)0:筛选器分配到FIFO0/1:筛选器分配到 FIFO1

  }

  if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO1)//FIFO1
  {
    /* FIFO 1 assignation for the filter */
    CAN1->FFA1R |= (uint32_t)filter_number_bit_pos;
  }
  
  /* Filter activation *///过滤器激活的设置
  if (CAN_FilterInitStruct->CAN_FilterActivation == ENABLE)
  {
    CAN1->FA1R |= filter_number_bit_pos;//筛选器 x 激活
  }

  /* Leave the initialisation mode for the filter */
  CAN1->FMR &= ~FMR_FINIT;//位 0 FINIT:筛选器初始化模式,取反就是工作模式
}

 中断初始化函数:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) 

/**
  * @brief  Initializes the NVIC peripheral according to the specified
  *         parameters in the NVIC_InitStruct.
  * @note   To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
  *         function should be called before. 
  * @param  NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
  *         the configuration information for the specified NVIC peripheral.
  * @retval None
  */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
  uint8_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
  
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));//中断使能参数检查
  assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));//抢占优先级  
  assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));//相应优先级
    
  if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)//如中断使能
  {
    /* Compute the Corresponding IRQ Priority -------*/ //寄存器AIRCR(内核指南手册)位10:8,优先级分组   
    tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;//7减AIRCR[10:8]得中断组号
    tmppre = (0x4 - tmppriority);//4减中断组号得响应优先级所占的位数(总位数为4,IP[7:4])
    tmpsub = tmpsub >> tmppriority;//0x0F左移中断组号得响应优先级最大值

    tmppriority = NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;//抢占优先级左移响应优先级位数(相对响应优先级的位置)
    tmppriority |=  (uint8_t)(NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub);//响应优先级和抢占优先级的4位组合
  //假设为分组2(对应寄存器位101,AIRCR寄存器值设0x0F5A0500),抢占1--0100,组合响应3---0111
  //AIRCR[31:16]任何对该寄存器的写操作,都必须同时把 0x05FA 写入此段
  
    tmppriority = tmppriority << 0x04;//把优先级值写入NVIC_IP寄存器[7:4]
  //NVIC_IRQChannel中断源对应中断向量表,例如can1中断,CAN1_RX0_IRQn= 20  , NVIC->IP[20]=0111
    NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
                   
    /* Enable the Selected IRQ Channels --------------------------------------*/
    NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =  //中断源使能,ISERx是按32位偏移所以左移5,代表是第几个寄存器
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);//与0x1F相当于除以32取余,代表在第几位
  }   //假设中断向量是20,NVIC->ISER[0]=0x01<<0x14//假设中断向量是(USART1_IRQn )37,NVIC->ISER[1]=0x01<<0x05
  else//假设中断向量是(I2C1_ER_IRQn)32,NVIC->ISER[1]=0x01<<0x0
  {
    /* Disable the Selected IRQ Channels -------------------------------------*/
    NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =//中断源失能
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
}
  -----can发送底层函数:uint8_t CAN_Transmit
can接收底层函数:void CAN_Receive

can发送函数:u8 CAN1_Send_Msg(u8* msg,u8 len)和接收函数:u8 CAN1_Receive_Msg(u8 *buf)

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//		 其他,失败;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x12;	 // 标准标识符为0
  TxMessage.ExtId=0x12;	 // 设置扩展标示符(29位)
  TxMessage.IDE=0;		  // 使用扩展标识符,/为0是标准帧,4(二进制100,这样就无需再移位直接对应了寄存器的位)扩展帧
  TxMessage.RTR=0;		  // 消息类型为数据帧,/标准数据帧通常包含8个数据位,0数据帧,2(10)遥控帧
  TxMessage.DLC=len;							 // 数据字段有多少个字节
  for(i=0;i<len;i++)                //这个循环用于复制数据到TxMessage的数据字段
  TxMessage.Data[i]=msg[i];				           
  mbox= CAN_Transmit(CAN1, &TxMessage);   // 通过CAN1接口发送TxMessage,返回值是三个邮箱0或1或2
  i=0;
  while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//邮箱的发送消息状态失败等待超时
  if(i>=0XFFF)return 1;
  return 0;	//返回0代表发送成功	

}
//can口接收数据查询
//buf:数据缓存区;	 
//返回值:0,无数据被收到;
//		 其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{		   		   
 	u32 i;
	CanRxMsg RxMessage;
    if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;	//CAN_FIFO0挂起的消息数量为0,没有待处理的消息,函数立即返回0,忽略后面的代码
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//能执行到这里,就代表有消息,则从FIFO0中接收该消息	
    for(i=0;i<RxMessage.DLC;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	//最后返回接收的数据长度(其数值是通过CAN_Receive函数的调用被填充到RxMessage结构体中的)
}

 

 can发送底层函数:uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)

uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
{ 
  uint8_t transmit_mailbox = 0;
  /* Check the parameters */
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
  assert_param(IS_CAN_RTR(TxMessage->RTR));
  assert_param(IS_CAN_DLC(TxMessage->DLC));

  /* Select one empty transmit mailbox *///选择一个空邮箱
  if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)//TSR位 26,当邮箱 0 没有挂起的发送请求时,此位由硬件置 1。
  {
    transmit_mailbox = 0;
  }
  else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)//TSR位 27,邮箱 1
  {
    transmit_mailbox = 1;
  }
  else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)//TSR位 28,邮箱 2
  {
    transmit_mailbox = 2;
  }
  else
  {
    transmit_mailbox = CAN_TxStatus_NoMailBox;//4
  }

  if (transmit_mailbox != CAN_TxStatus_NoMailBox)//有邮箱被选中
  {
    /* Set up the Id */
    CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ;//位 0 TXRQ:发送邮箱请求/寄存器保留位0,忽略其他位
    if (TxMessage->IDE == CAN_Id_Standard)
    {
      assert_param(IS_CAN_STDID(TxMessage->StdId));  //位 31:21 STID[10:0]/EXID[28:18]:标准标识符或扩展标识符 
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \
                                                  TxMessage->RTR);
    }
    else
    {
      assert_param(IS_CAN_EXTID(TxMessage->ExtId));
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
                                                  TxMessage->IDE | \
                                                  TxMessage->RTR);
    }
    
    /* Set up the DLC */
    TxMessage->DLC &= (uint8_t)0x0000000F;
    CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;//低4位清0,其他位不变
    CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;

    /* Set up the data field *///最多8个(字节)数据占64个位,两个寄存器
    CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) | 
                                             ((uint32_t)TxMessage->Data[2] << 16) |
                                             ((uint32_t)TxMessage->Data[1] << 8) | 
                                             ((uint32_t)TxMessage->Data[0]));
    CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) | 
                                             ((uint32_t)TxMessage->Data[6] << 16) |
                                             ((uint32_t)TxMessage->Data[5] << 8) |
                                             ((uint32_t)TxMessage->Data[4]));
    /* Request transmission */
    CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;//TIxR寄存器位0置1,用于请求发送相应邮箱的内容
  }
  return transmit_mailbox;
}

 can接收底层函数:void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage) 

void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)//
{
  /* Check the parameters */
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_CAN_FIFO(FIFONumber));
  /* Get the Id */
  RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;//形参RxMessage赋值,如果是0,ID标准帧
  if (RxMessage->IDE == CAN_Id_Standard)
  {
    RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
  }                                  //标准帧寄存器值右移21,与7FF是因为标准帧数据只有11位
  else
  {
    RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);//扩展帧右移3
  }
  
  RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;//接收的是数据帧还是遥控帧
  /* Get the DLC */
  RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;//接收的数据帧长度
  /* Get the FMI *///获取筛选器编号/邮箱中存储的消息需要经过该筛选器
    RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);
  /* Get the data field */
  RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;
  RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);
  RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);
  RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);
  RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;
  RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);
  RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);
  RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);
  /* Release the FIFO */
  /* Release FIFO0 *///释放该邮箱
  if (FIFONumber == CAN_FIFO0)
  {
    CANx->RF0R |= CAN_RF0R_RFOM0;//位 5 RFOM0:释放 FIFO 0 输出邮箱,释放后,此位由硬件清零。
  }
  /* Release FIFO1 */
  else /* FIFONumber == CAN_FIFO1 */
  {
    CANx->RF1R |= CAN_RF1R_RFOM1;
  }
}
-----中断向量关联图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1568963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day63 单调栈part02

503. 下一个更大元素 II 中等 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更…

vue快速入门(六)v-else和v-else-if

注释很详细&#xff0c;直接上代码 上一篇 新增内容 v-else-if用法v-else用法 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-s…

docker部署nacos,单例模式(standalone),使用内置的derby数据库,简易安装

文章目录 前言安装创建文件夹docker指令安装docker指令安装-瘦身版 制作docker-compose.yaml文件查看页面 前言 nacos作为主流的服务发现中心和配置中心&#xff0c;广泛应用于springcloud框架中&#xff0c;现在就让我们一起简易的部署一个单例模式的nacos&#xff0c;版本可…

算法学习系列(四十六):迭代加深、双向DFS

目录 引言概念一、加成序列二、送礼物 引言 本文主要讲了&#xff0c; D F S DFS DFS 的另外两种优化&#xff0c;分别是迭代加深和双向 D F S DFS DFS &#xff0c;思路还是非常清晰明了的&#xff0c;只要会写 D F S DFS DFS 那么这些剪枝和优化其实还是非常的容易的&…

Vue监听器watch的基本用法

文章目录 1. 作用2. 格式3. 示例3.1 value 值为字符串3.2 value 值为函数3.3 value 值为对象 4. 与计算属性对比 1. 作用 监视数据变化&#xff0c;执行一些业务逻辑或异步操作。 2. 格式 监听器 watch 内部以 key &#xff1a;value 的形式定义&#xff0c;key 是 data 中的…

用html写一个爱心

<!DOCTYPE html> <html lang"zh-CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><title>爱您</title><style>* {padding: 0;margin: 0;}body {background-color: pin…

C语言笔试题之求解X的平方根

求解X的平方根 一、实例要求 1、给定一个非负整数 x &#xff0c;计算并返回 x 的算术平方根 &#xff1b;2、由于返回类型是整数&#xff0c;结果只保留整数部分 &#xff0c;小数部分将被舍去&#xff1b;3、不允许使用任何内置指数函数、运算符&#xff1b; 二、实例分析…

图DP

目录 有向无环图DP 力扣 329. 矩阵中的最长递增路径 力扣 2192. 有向无环图中一个节点的所有祖先 有向有环图DP 力扣 1306. 跳跃游戏 III 有向无环图DP 力扣 329. 矩阵中的最长递增路径 给定一个 m x n 整数矩阵 matrix &#xff0c;找出其中 最长递增路径 的长度。 对…

C语言:文件操作(二)

目录 前言 4、文件的顺序读写 4.1fputc 4.2 fgetc 4.3 fputs 4.4 fgets 4.5 fprintf 4.6 fscanf 4.7 fread和fwrite 结&#xff08;二&#xff09; 前言 接者“C语言&#xff1a;文件操作&#xff08;一&#xff09;”往下讲。 本篇文章将介绍C语言的文件操作&#xf…

【数字图像处理matlab系列】空间域处理之亮度变换(imadjust函数使用)

【数字图像处理matlab系列】空间域处理之亮度变换(imadjust函数使用) 在空间域中&#xff0c;图像处理就是直接对图像的像素进行操作 imadjust 是 MATLAB 中用于调整图像强度值或颜色图的函数。它可以改变图像的对比度&#xff0c;使得图像更清晰或更易于分析。以下是 imadju…

【MATLAB源码-第178期】基于matlab的8PSK调制解调系统频偏估计及补偿算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在通信系统中&#xff0c;频率偏移是一种常见的问题&#xff0c;它会导致接收到的信号频率与发送信号的频率不完全匹配&#xff0c;进而影响通信质量。在调制技术中&#xff0c;QPSK&#xff08;Quadrature Phase Shift Keyi…

4.2总结

了解了部分Api的使用并学习了接口的API API API包含了较多种类&#xff08;System,Runtime等&#xff09; System其实就是一个工具类&#xff0c;提供了一些与系统相关的方法 下面有一些常间的System方法 方法名说明public static void exit (int status)终止当前运行的ja…

Android JNI 调用第三方SO

最近一个项目使用了Go 编译了一个so库&#xff0c;但是这个so里面还需要使用第三方so库pdfium, 首先在Android工程把2个so库都放好 在jni中只能使用dlopen方式&#xff0c;其他的使用函数指针的方式来调用&#xff0c;和windows dll类似&#xff0c;不然虽然编译过了但是会崩溃…

picGo图床搭建gitee和smms(建议使用)

picGoGitee 这个需要下载gitee插件, 因为官方频繁的检索文件类型, 有时候也会失效 如果没有特殊要求平时存个学习的要看图中文字的重要的图片建议就是smms, 免费也够用! 图片存本地不方便, 各种APP中来回传还会失帧损失画质, 所以你值得往下看 picGosmms 建议使用这个, sm…

为移动云数据实现基于可撤销属性组的加密:多代理辅助方法

参考文献为2023年发表的Achieving Revocable Attribute Group-Based Encryption for Mobile Cloud Data: A Multi-Proxy Assisted Approach 动机 对于目前的代理辅助的可撤销基于属性加密来说&#xff0c;外包解密存一些缺点。当多个具有相同属性的用户请求外包转换时&#x…

非写代码无以致远

标题党一下&#xff0c;本篇文章主要汇总了一些代码题&#xff0c;让大家写一些代码练习一下吧&#xff01; 变种水仙花_牛客题霸_牛客网 (nowcoder.com) #include<stdio.h> int main() {for (int i 10000; i < 99999; i) {int sum 0;for (int j 10; j < 1000…

业务网关的设计与实践

在过去的两年里&#xff0c;主要在做业务网关的开发。今年春节后选择转岗去做更偏近业务的开发。公司的业务是金融相关&#xff0c;一直觉得金融相关的业务是有一定门槛并且是对职业生涯有帮助的&#xff0c;所以趁这个机会来深入了解这块业务。 仔细回想&#xff0c;在做业务…

数据结构和算法:十大排序

排序算法 排序算法用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 排序算法中的数据类型可以是整数、浮点数、字符或字符串等。排序的判断规则可根据需求设定&#xff0c;如数字大小、字符 ASCII…

【算法】单单单单单调栈,接接接接接雨水

【算法】单单单单单调栈&#xff0c;接接接接接雨水 今天没有小故事。 参考以及题单来源&#xff1a; 代码随想录 (programmercarl.com) Part 1 啥是单调栈&#xff1f; 1.啥啥啥是单调栈&#xff1f; 栈的特性想必各位再熟悉不过了&#xff1a;先进后出。栈仅仅有一个出口&a…

递归算法讲解2

前情提要 上一篇递归算法讲解在这里 递归算法讲解&#xff08;结合内存图&#xff09; 没看过的小伙伴可以进去瞅一眼&#xff0c;谢谢&#xff01; 递归算法的重要性 递归算法是非常重要的&#xff0c;如果想要进大厂&#xff0c;以递归算法为基础的动态规划是必考的&…