STM32 can通信部分函数注释

-----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 时钟使能//初始化GPIOGPIO_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;//100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12//引脚复用映射配置GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1GPIO_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_4tqCAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tqCAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tqCAN_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=0x0000;32位IDCAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化#if CAN1_RX0_INT_ENABLECAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
#endifreturn 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位标识符(列表模式)--FxR2CAN1->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]=0111NVIC->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<<0x05else//假设中断向量是(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;	 // 标准标识符为0TxMessage.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或2i=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.mzph.cn/news/792314.shtml

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

相关文章

Codeforces Round 931 (Div. 2) ---- E. Weird LCM Operations ---- 题解

E. Weird LCM Operations&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 这是一道构造题&#xff0c;那么观察这个构造有啥性质&#xff0c;观察到最多操作次数为 n/6 5&#xff0c;然后每次操作需要选择三个数&#xff0c;如果每次操作的三个数都不和之前的重复的…

3月造车新势力销量出炉:问界继续领跑,哪吒下滑,岚图抢眼

进入4月份&#xff0c;各大造车新势力们纷纷公布了3月份最新销量成绩&#xff0c;根据相关数据显示&#xff0c;问界再度超越理想&#xff0c;夺得造车新势力头名的位置。而零跑、蔚来、小鹏的销量也实现不错的增长&#xff0c;岚图汽车的表现同样十分亮眼。不过日前遭到周鸿祎…

Shell与Bash与POSIX与Linux间的关系

shell是什么&#xff1f; Shell的英语翻译是“壳”&#xff0c;其作用也跟名字差不多&#xff0c;为操作系统套个壳&#xff0c;人与操作系统的壳交互。与壳相对应的则是操作系统内核&#xff0c;一个“壳”一个“核”。核从1970年代开始就基本定型了&#xff0c;没什么大的改…

Windows 11安装kb5035853补丁时,提示错误0x800f0922,并且弹出“某些操作未按计划进行,不必担心,正在撤消更改。请不要关机”

Windows 11安装kb5035853补丁时&#xff0c;提示错误0x800f0922&#xff0c;并且还在重启后弹出“某些操作未按计划进行&#xff0c;不必担心&#xff0c;正在撤消更改。请不要关机”&#xff0c;按微软官方的作法是&#xff1a;https://learn.microsoft.com/zh-cn/windows/rel…

精准扶贫管理系统|基于Springboot的精准扶贫管理系统设计与实现(源码+数据库+文档)

精准扶贫管理系统目录 目录 基于Springboot的精准扶贫管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 &#xff08;1&#xff09;用户信息管理 &#xff08;2&#xff09;贫困户信息管理 &#xff08;3&#xff09;新闻类型管理 &a…

YooAssets 使用相关

## 使用 YooAssets 动态加载原生文件时候 > 原生文件&#xff1a;txt&#xff1b;json&#xff1b;等需要直接保存文件内string字符的文件 需要将打包方式设置成为&#xff0c;PackRawFile 并且加载时候使用 API &#xff1a; YooAssets.LoadRawFileSync()YooAssets.LoadRa…

腾讯云轻量4核8G12M应用服务器性能测评和优惠价格表

腾讯云4核8G服务器价格&#xff1a;轻量4核8G12M优惠价格646元15个月、CVM S5服务器4核8G配置1437元买1年送3个月。腾讯云4核8G服务器支持多少人同时在线&#xff1f;支持30个并发数&#xff0c;可容纳日均1万IP人数访问。腾讯云百科txybk.com整理4核8G服务器支持多少人同时在线…

16.springboot项目下使用事务(springboot-016-transaction)

事务是一个完整的功能&#xff0c;也叫作是一个完整的业务 事务只跟什么SQL语句有关&#xff1f;事务只跟DML语句有关系&#xff1a;增删改 DML,DQL,DDL,TCL,DCL 首先添加两个依赖以及MyBatis代码自动生成插件 <!--MySql驱动--><dependency><groupId>mysql…

腾讯云4核8g服务器承载量?4C8G能支持多少人?

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

Python快速入门系列-10(Python进阶与扩展)

第十章:Python进阶与扩展 10.1 Python与其他语言的整合10.1.1 使用Python的C API示例:使用C API创建一个简单的Python扩展10.1.2 使用Cython加速Python代码示例:使用Cython编写一个快速的矩阵乘法函数10.1.3 使用SWIG创建接口示例:使用SWIG为C++类生成Python接口10.2 Pytho…

Prisma ORM 5.12 发布,支持 Cloudflare D1 数据库

昨晚&#xff0c;Prisma ORM 发布了 5.12.0 稳定版本&#xff0c;在此版本中 Prisma ORM 新增了对 Cloudflare D1 的预览支持&#xff0c;现在我们可以选择将本地的 SQLite 数据库逐步迁移到 Cloudflare 上面&#xff0c;从而实现无需额外成本即可构建处理大量用户的应用程序。…

OpenKylin安装MySQL

在麒麟操作系统上安装MySQL&#xff0c;可以通过以下步骤进行&#xff1a; 1、更新系统包列表&#xff1a; sudo apt-get update2、安装MySQL服务 sudo apt-get install mysql-server3、进行安全设置&#xff0c;设置root密码和是否允许匿名登陆之类 sudo mysql_secure_ins…

Redis数据库②高可用+持久化+性能管理

目录 一.高可用 二.持久化 1.Redis 提供两种方式进行持久化 2.RDB 持久化 &#xff08;1&#xff09;手动触发 &#xff08;2&#xff09;自动触发 &#xff08;3&#xff09;执行流程 &#xff08;4&#xff09;启动时加载 3.AOF持久化 &#xff08;1&#xff09;开…

SpringBoot整合Flowable/Activiti

SpringBoot版本: 2.0.1.RELEASE Flowable版本: 6.3.1 Activiti版本: 6.0.0 一.添加pom依赖 因为之前我整合的时候有报错关于sqlsession的错误,后面查询文章才发现flowable要排除掉mybatis,又没说具体排除哪一个,所以我这干脆全部排除了 <!-- Flowable dependencies -->…

【Java SE】继承

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 继承1.1 继承是什么1.2 继承的意义1.3 继承的语法1.4 继承的方式1.5 子类中访问父类成员1.5.1 子类中访问…

js类型转换

类型转换只有这四种&#xff0c;例如如果要对象转数字&#xff0c;那么就需要先把对象转成原始类型&#xff0c;再从原始类型转到数字。 空数组转原始类型是一个空字符串。空对象转原始类型是[object Object]。 let a {} console.log(a);// NaN //等价于 a->原始 然后原始…

北京大学创新推出ManipLLM黑科技 | 大幅提升机器人操作的鲁棒性与智能性

机器人操作依赖于准确预测接触点和执行器方向以确保成功操作。然而&#xff0c;基于学习的机器人操作&#xff0c;在模拟器中仅针对有限类别进行训练&#xff0c;往往难以实现泛化&#xff0c;特别是在面临大量类别时。 因此&#xff0c;作者提出了一种创新的方法&#xff0c;…

网络安全基础之网络协议与安全威胁

OSI(OpenSystem Interconnect)&#xff0c;即开放式系统互联。 一般都叫OSI参考模型&#xff0c;是ISO(国际标准化组织)组织在1985年研究的网络互联模型。 网络协议的简介&#xff1a; 定义&#xff1a;协议是网络中计算机或设备之间进行通信的一系列规则集合。 什么是规则?…

Android操作sqlite数据库

Sqlite数一种轻量级的关系型数据库&#xff0c;android里面可以用来持久化存储一些用户数据。 一、SQLiteOpenHelper方式 SQLiteOpenHelper是原生的数据库帮助类&#xff0c;继承这个类&#xff0c;用来创建&#xff0c;更新数据库的操作 public class MySqliteOpenHelper e…

算法整理:链表

链表定义 struct ListNode { int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {} }; 链表的遍历&#xff1a;ListNode phead; while(p!null) pp.next; 找到链表的尾结点&#xff1a;phead; while(p.next!null)pp.next; 链表节点的个数&#xff1a; phead…