基于NRF24L01的CAN数据透传

2023-05-16

    闲谈:

    闲来无聊,恰好公司又经常用CAN数据的传输,自己觉得要是用无线传送多好,然后,就是一个奇想,就想做一个无线数据的透传,恰好身边又有NRF24L01,那就行动吧!

下面是NRF24L01 SPI1 的初始化程序:

void NRF24L01_Init(void)
{ 	
	GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA, ENABLE);	 //使能PB,G端口时钟
    	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 //PB12上拉 防止W25X的干扰
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOC, &GPIO_InitStructure);	//初始化指定IO

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	//PG8 7 推挽 	  
 	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化指定IO
  
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;   
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PG6 输入  
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_ResetBits(GPIOA,GPIO_Pin_4);//PA4上拉					 
	GPIO_ResetBits(GPIOC,GPIO_Pin_4|GPIO_Pin_5);//PC4,5上拉		 
  SPI1_Init();    		//初始化SPI	 
 
	SPI_Cmd(SPI1, DISABLE); // SPI外设不使能

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//SPI主机
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		//时钟悬空低
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;	//数据捕获于第1个时钟沿
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由软件控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;		//定义波特率预分频的值:波特率预分频值为16
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI1, ENABLE); //使能SPI外设
			 
	NRF24L01_CE=0; 			//使能24L01
	NRF24L01_CSN=1;			//SPI片选取消  
	 		 	 
}

这里是NRF24L01数据读取
 

/检测24L01是否存在
//返回值:0,成功;1,失败	
u8 NRF24L01_Check(void)
{
	u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
	u8 i;
	SPI1_SetSpeed(SPI_BaudRatePrescaler_4); //spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   	 
	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.	
	NRF24L01_Read_Buf(TX_ADDR,buf,5); //读出写入的地址  
	for(i=0;i<5;i++)if(buf[i]!=0XA5)break;	 							   
	if(i!=5)return 1;//检测24L01错误	
	return 0;		 //检测到24L01
}	 	 
//SPI写寄存器
//reg:指定寄存器地址
//value:写入的值
u8 NRF24L01_Write_Reg(u8 reg,u8 value)
{
	u8 status;	
   	NRF24L01_CSN=0;                 //使能SPI传输
  	status =SPI1_ReadWriteByte(reg);//发送寄存器号 
  	SPI1_ReadWriteByte(value);      //写入寄存器的值
  	NRF24L01_CSN=1;                 //禁止SPI传输	   
  	return(status);       			//返回状态值
}
//读取SPI寄存器值
//reg:要读的寄存器
u8 NRF24L01_Read_Reg(u8 reg)
{
	u8 reg_val;	    
 	NRF24L01_CSN = 0;          //使能SPI传输		
  	SPI1_ReadWriteByte(reg);   //发送寄存器号
  	reg_val=SPI1_ReadWriteByte(0XFF);//读取寄存器内容
  	NRF24L01_CSN = 1;          //禁止SPI传输		    
  	return(reg_val);           //返回状态值
}	
//在指定位置读出指定长度的数据
//reg:寄存器(位置)
//*pBuf:数据指针
//len:数据长度
//返回值,此次读到的状态寄存器值 
u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len)
{
	u8 status,u8_ctr;	       
  	NRF24L01_CSN = 0;           //使能SPI传输
  	status=SPI1_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值   	   
 	for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=SPI1_ReadWriteByte(0XFF);//读出数据
  	NRF24L01_CSN=1;       //关闭SPI传输
  	return status;        //返回读到的状态值
}
//在指定位置写指定长度的数据
//reg:寄存器(位置)
//*pBuf:数据指针
//len:数据长度
//返回值,此次读到的状态寄存器值
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
	u8 status,u8_ctr;	    
    NRF24L01_CSN = 0;          //使能SPI传输
  	status = SPI1_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值
  	for(u8_ctr=0; u8_ctr<len; u8_ctr++)SPI1_ReadWriteByte(*pBuf++); //写入数据	 
  	NRF24L01_CSN = 1;       //关闭SPI传输
  	return status;          //返回读到的状态值
}				   
//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:发送完成状况
u8 NRF24L01_TxPacket(u8 *txbuf)
{
	u8 sta;
 	SPI1_SetSpeed(SPI_BaudRatePrescaler_8);//spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   
	NRF24L01_CE=0;
  NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 	NRF24L01_CE=1;//启动发送	   
	while(NRF24L01_IRQ!=0);//等待发送完成
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}
//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:0,接收完成;其他,错误代码
u8 NRF24L01_RxPacket(u8 *rxbuf)
{
	u8 sta;		    							   
	SPI1_SetSpeed(SPI_BaudRatePrescaler_8); //spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}					    
//该函数初始化NRF24L01到RX模式
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了		   
void NRF24L01_RX_Mode(void)
{
	  NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    //使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	     //设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}						 
//该函数初始化NRF24L01到TX模式
//设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,选择RF频道,波特率和LNA HCURR
//PWR_UP,CRC使能
//当CE变高后,即进入RX模式,并可以接收数据了		   
//CE为高大于10us,则启动发送.	 
void NRF24L01_TX_Mode(void)
{														 
	  NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,

这里是关于stm32can程序:

/******************** 鑫盛电子工作室 ********************
 * 文件名  :can.c
 * 描述    :CAN测试应用函数库。         
 * 实验平台:MINI STM32开发板 基于STM32F103C8T6
 * 硬件连接:-----------------
 *          | 						  |
            |  PB8-CAN-RX     |
 *          |  PB9-CAN-TX     |
 *          |                 |
 *           -----------------
 * 库版本  :ST3.0.0  																										  
 * 淘宝店:http://shop66177872.taobao.com
*********************************************************/
#include "can.h"
//#include "led.h"
#include "stdio.h"
#include "sys.h"
#include "stm32f10x_can.h"
#include "24l01.h"
//#include "os.h"
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;

/* 在中断处理函数中返回 */
__IO uint32_t ret = 0;

uint8_t CAN_RX_BUFF[17];
volatile TestStatus TestRx;	


static void CAN1_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 使能接收的中断和中断优先级 */
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);   //FIFO0消息挂号中断允许.	
}

/****************************************************************************
* Function Name  : CAN1_Config
* Description    : 初始化CAN,波特率设置为450K
* Input          : mode:用来选择要使用的工作模式:主要有四种工作模式:1、正常
*                * 模式:CAN_Mode_Normal;2、CAN_Mode_Silent :静默模式;3、环
*                * 回模式:CAN_Mode_LoopBack;4、静默环回模式:CAN_Mode_Silent
*                * _LoopBack。
* Output         : None
* Return         : None
****************************************************************************/

void CAN1_Config(uint8_t mode)
{

	GPIO_InitTypeDef GPIO_InitStructure;
	CAN_InitTypeDef CAN_InitStructure;

	/* 初始化IO口 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;        //PA12
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;        //PA11

	GPIO_Init(GPIOA, &GPIO_InitStructure);

/***************************************************************************/
/********************* CAN设置和初始化 *************************************/
/***************************************************************************/

	/* 打开时钟使能 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    /* 初始化CAN的参数 */

	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);

	/* CAN 参数初始化 */
	CAN_InitStructure.CAN_TTCM = DISABLE;    //失能时间触发模式
	CAN_InitStructure.CAN_ABOM = ENABLE;    //自动离线管理
	CAN_InitStructure.CAN_AWUM = DISABLE;    //失能睡眠模式通过软件唤醒
	CAN_InitStructure.CAN_NART = DISABLE;    //失能非自动重传输模式(也就是会自动重传输)
	CAN_InitStructure.CAN_RFLM = DISABLE;    //失能接收FIFO锁定模式,新数据会覆盖旧数据
	CAN_InitStructure.CAN_TXFP = DISABLE;    //优先级由报文标识符决定 
	CAN_InitStructure.CAN_Mode = mode;       //有普通模式和拓展模式
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃宽度 1 个时间单位

    /* 波特率设置, 当APB1的时钟频率是36MHZ的时候。 波特率的公式为: */
    /* 波特率(Kpbs) = 36M / ((CAN_BS1 + CAN_BS2 + 1) *  CAN_Prescaler) */
	CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq; //时间段 1 为8 个时间单位 
	CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq; //时间段 2 为7 个时间单位
	CAN_InitStructure.CAN_Prescaler = 4;//5;	 波特率改为了100K   20=100k   5=400k

	CAN_Init(CAN1, &CAN_InitStructure);
	

#ifdef CAN_RX0_INT_ENABLE
	CAN1_NVIC_Config();
#endif    

}
/****************************************************************************
* Function Name  : CAN1_SendMesg
* Description    : 发送一个报文
* Input          : id:发送的ID。
*                * len:发送的数据长度(注意发送数据长度不能超过8个字节)
*                * dat:存放数据的指针
* Output         : None
* Return         : None
****************************************************************************/

void CAN1_SendMesg(uint32_t id, uint8_t len, uint8_t *dat)
{
	uint16_t i = 0;
	CanTxMsg TxMessage;

    /* 一次发送只能发送8个字节 */
    if(len > 8)
    {
        return ;
    }
	/* 配置邮箱:设置标识符,数据长度和待发送数据 */
	TxMessage.StdId = (id & 0x7FF); //标准帧ID11位
	TxMessage.ExtId = (id );   //设置扩展标示符(拓展标示符有29位1本来是TxMessage.ExtId = (id >> 11);
	TxMessage.RTR = CAN_RTR_DATA;   //设置为数据帧(或远程帧为CAN_RTR_Remote)
    if((id & 0x7FF) == 0x7FF)       //检测是标准帧还是拓展帧(拓展帧大于11位)
    {
    	TxMessage.IDE = CAN_ID_STD;	//拓展ID   
    }
    else
    {
    	TxMessage.IDE = CAN_ID_EXT;	//标准ID
    }
	TxMessage.DLC = len;	        //发送的数据长度

	/* 将数据放入到邮箱中 */
	for(i=0; i<len; i++)	         
	{
		TxMessage.Data[i] = *dat;
		dat++;	
	}
    
    /* 开始传送数据 */
	CAN_Transmit(CAN1, &TxMessage); 
}

/****************************************************************************
* Function Name  : CAN1_Config16BitFilter
* Description    : 设置CAN接收16两个标准ID(设置ID位数全部相同才能够通过)
* Input          : id1:要接收的一个ID
*                * id2:要接收的一个ID
* Output         : None
* Return         : None
****************************************************************************/

void CAN1_Config16BitFilter(uint16_t id1, uint16_t id2)
{
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    uint16_t mask = 0xFFFF;

	/* CAN filter init 屏蔽寄存器初始化 */
	CAN_FilterInitStructure.CAN_FilterNumber = 1;	               //过滤器1
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;//ID模式

	/* 寄存器组设置为16位 */
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh = (id1 << 5);    //要接收的ID标示符1		
    CAN_FilterInitStructure.CAN_FilterIdLow =  (id2 << 5);	  //要接收的ID标示符2

	/* 设置为所有ID位都要相同才接收 */	
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (mask << 5); //MASK
	CAN_FilterInitStructure.CAN_FilterMaskIdLow  = (mask << 5);
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器1

	CAN_FilterInit(&CAN_FilterInitStructure);
}

/****************************************************************************
* Function Name  : CAN1_Config32BitFilter
* Description    : 设置一个拓展ID的接收
* Input          : id:要接收的ID
* Output         : None
* Return         : None
****************************************************************************/

void CAN1_Config32BitFilter(uint32_t id)
{
//    uint32_t mask = 0x000006D1;//0xFFFFFFFF;   //发送0x00000601    接收0x000006D1
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;

	/* CAN filter init 屏蔽寄存器初始化 */
	CAN_FilterInitStructure.CAN_FilterNumber = 1;	               //过滤器1
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;//ID模式

	/* 寄存器组设置为32位 */
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh =0x0000;// (id >> 13);    //要接收的ID标示符1		
    CAN_FilterInitStructure.CAN_FilterIdLow  =0x0000;//  (id << 3 ) | 4;//要接收的ID标示符2

	/* 设置为所有ID位都要相同才接收 */	
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh =0x0000;// mask >> 13;     //MASK
	CAN_FilterInitStructure.CAN_FilterMaskIdLow  =0x0000;// (mask << 3) | 4;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器1

	CAN_FilterInit(&CAN_FilterInitStructure);
}

/****************************************************************************
* Function Name  : CAN1_ReceiveMesg
* Description    : 接收一个报文
* Input          : receiveBuff:接收数据的数组指针
* Output         : None
* Return         : None
****************************************************************************/

void CAN1_ReceiveMesg(uint8_t *receiveBuff)
{
	uint8_t i = 0;

	CanRxMsg RxMessage;	//设置接收邮箱

	if((CAN_MessagePending(CAN1, CAN_FIFO0) != 0)) //检查FIFO0里面是否有数据
	{
    	CAN_Receive(CAN1,CAN_FIFO0,&RxMessage); //读取FIFO0里面的数据
    	for(i=0; i<RxMessage.DLC; i++)          //将读取到的数据位赋给CAN_RXSBUF
    	{
    		*receiveBuff = RxMessage.Data[i];
    		receiveBuff++;
    	}
    }			
}



/* 发送两个字节的数据*/

																																																																												void can_tx(u8 Data1,u8 Data2,u8 Data3,u8 Data4,u8 Data5,u8 Data6,u8 Data7,u8 Data8)
{ 
  CanTxMsg TxMessage;  

  TxMessage.StdId=0x0023;	//标准标识符为0x00
  TxMessage.ExtId=0x001C; //扩展标识符0x0000
  TxMessage.IDE=CAN_ID_STD;//使用标准标识符
  TxMessage.RTR=CAN_RTR_DATA;//为数据帧
  TxMessage.DLC=8;	//	消息的数据长度为8个字节
  TxMessage.Data[0]=Data1; //第一个字节数据
  TxMessage.Data[1]=Data2; //第二个字节数据 
  TxMessage.Data[2]=Data3; //第三个字节数据
  TxMessage.Data[3]=Data4; //第一个字节数据
  TxMessage.Data[4]=Data5; //第二个字节数据 
  TxMessage.Data[5]=Data6; //第三个字节数据
  TxMessage.Data[6]=Data7; //第一个字节数据
  TxMessage.Data[7]=Data8; //第二个字节数据 
  CAN_Transmit(CAN1,&TxMessage); //发送数据

}
void can_tx1(u8 Data1,u8 Data2,u8 Data3,u8 Data4,u8 Data5,u8 Data6,u8 Data7,u8 Data8)
{ 
  CanTxMsg TxMessage;  

  TxMessage.StdId=0x22;	//标准标识符为0x00
  TxMessage.ExtId=0x18DADDF1; //扩展标识符0x0000
  TxMessage.IDE=CAN_ID_STD;//使用标准标识符
  TxMessage.RTR=CAN_RTR_DATA;//为数据帧
  TxMessage.DLC=8;	//	消息的数据长度为8个字节
  TxMessage.Data[0]=Data1; //第一个字节数据
  TxMessage.Data[1]=Data2; //第二个字节数据 
  TxMessage.Data[2]=Data3; //第三个字节数据
  TxMessage.Data[3]=Data4; //第一个字节数据
  TxMessage.Data[4]=Data5; //第二个字节数据 
  TxMessage.Data[5]=Data6; //第三个字节数据
  TxMessage.Data[6]=Data7; //第一个字节数据
  TxMessage.Data[7]=Data8; //第二个字节数据 
  CAN_Transmit(CAN1,&TxMessage); //发送数据

}

/* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  
  CanRxMsg RxMessage;
	
  RxMessage.StdId=0x00;
  RxMessage.ExtId=0x00;
  RxMessage.IDE=0;
  RxMessage.DLC=0;
  RxMessage.FMI=0;
  RxMessage.Data[0]=0x00;
  RxMessage.Data[1]=0x00;    

  CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  

	CAN_RX_BUFF[0]=((RxMessage.StdId)&0x0000ff00)>>8;
	CAN_RX_BUFF[1]=(RxMessage.StdId)&0x000000ff;  //标注0-7ff

	
  CAN_RX_BUFF[2]=((RxMessage.ExtId)&0xff000000)>>24;
  CAN_RX_BUFF[3]=((RxMessage.ExtId)&0x00ff0000)>>16;
	CAN_RX_BUFF[4]=((RxMessage.ExtId)&0x0000ff00)>>8;
	CAN_RX_BUFF[5]=((RxMessage.ExtId)&0x000000ff);
	
  CAN_RX_BUFF[6]=RxMessage.IDE;
  CAN_RX_BUFF[7]=RxMessage.DLC;
	CAN_RX_BUFF[8]=RxMessage.RTR;
	CAN_RX_BUFF[9]=RxMessage.Data[0];
	CAN_RX_BUFF[10]=RxMessage.Data[1];
	CAN_RX_BUFF[11]=RxMessage.Data[2];
	CAN_RX_BUFF[12]=RxMessage.Data[3];
	CAN_RX_BUFF[13]=RxMessage.Data[4];
	CAN_RX_BUFF[14]=RxMessage.Data[5];
	CAN_RX_BUFF[15]=RxMessage.Data[6];
	CAN_RX_BUFF[16]=RxMessage.Data[7];
	
  NRF24L01_TxPacket((u8*)(CAN_RX_BUFF));		
} 


最后得到的实验现象:

 

can数据的接收,出现大量数据接收时,数据发送方大概每0.005s一个数据发送,而接收数据未0.05s一个数据,但由于数据量比较大时,数据的丢包比较明显,所以该无线程序可以使用在数据量比较小时的数据透传;

程序百度云:链接:https://pan.baidu.com/s/1p3n7kVxUlBTIt9rWlx_Q8Q 
提取码:cyx1 
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于NRF24L01的CAN数据透传 的相关文章

  • CAN通讯的byte序和bit序

    听别人说起CAN通讯协议的时候总说到Intel格式和motorola格式的时候 Intel格式如何 xff0c Motorola格式又如何 xff1f 觉得很有必要搞懂这些知识 xff0c 也看了相关资料 xff0c 可直到今天还没明白 真
  • ubuntu 使用虚拟can 与 socketCAN使用

    原文链接 xff1a https blog csdn net xiandang8023 article details 127990159 创建虚拟CAN接口 在Linux上能使用虚拟CAN接口之前 xff0c 需要在终端执行以下三个步骤
  • CAN通信讲解——总目录

    本文注意参考了 CAN入门书 xff0c 源于此书图片不再特殊标注 总目录 CAN通信讲解 xff08 1 xff09 基本知识 CAN通信讲解 xff08 2 xff09 数据帧和遥控帧 CAN通信讲解 xff08 3 xff09 错误据
  • G2O库和Eigen库can not find 问题——FindG2O.cmake FindEigen3.cmake

    目录 CMakeLists设置FindG2O cmake文件内容FindEigen3 cmake 文件内容 CMakeLists设置 在CMakeLists里加入如下这句话 xff0c 并在项目文件夹中新建cmake文件夹 LIST APP
  • 【车载开发系列】CAN总线帧种类介绍篇

    车载开发系列 CAN总线帧种类介绍篇 CAN总线帧种类介绍篇 车载开发系列 CAN总线帧种类介绍篇一 CAN总线当中帧的种类二 五种类型帧用途说明三 数据帧的组成1 xff09 帧起始2 xff09 仲裁段3 xff09 控制段4 xff0
  • CAN总线电平(隐性与显性)

    nbsp nbsp nbsp nbsp CAN2 0B规范定义了两种互补的逻辑数值 显性和隐性 同时传送显性和隐性位时 总线呈现显性状态 同时传送显性状态位时 总线呈现显性状态 同时传送隐性状态位时 总线呈现隐性状态 显性数值表示逻辑0 隐
  • CAN总线多帧即连续帧数据发送 拆包与重装

    1939协议支持多帧数据发送即数据超过8个的帧发送 用户可以通过ID来识别当前帧是否为多帧发送 xff08 连续帧 xff09 xff0c 如果是多帧发送ID xff0c 举例 xff1a 1C EC F4 56 其中 F4和56为目标地址
  • CAN报文格式简析

    Date xff1a 2022 5 11 Author xff1a MJQ Meta xff1a CAN CAN基础篇 CAN报文格式简析 1 Motornala和Intel格式 建议直接看图 xff0c 小白也能秒懂 xff01 注 xf
  • CAN扩展帧过滤器设置

    纪要 CAN xff08 Controller Area Network xff09 总线是一种广泛应用于工业控制和汽车电子领域的串行通信协议 在CAN总线中 xff0c 节点间通过CAN总线发送和接收消息 每个CAN帧包含一个标准或扩展标
  • IMX6ULL与STM32F103的CAN通信实现

    IMX6ULL与STM32F103的CAN通信实现 硬件连接驱动层实现IMX6ULLSTM32F103ZET6 应用层实现IMX6ULLSTM32F103ZET6 结果 在上一篇博文中 xff0c 我们利用USBCAN设备及其上位机软件 x
  • CAN为什么会发送失败

    CAN总线调试过程中出现报文发送失败 xff0c 很多工程师都对此只知其一不知其二 xff0c 这里就CAN报文发送失败的问题我们来做一次探讨 在了解CAN报文为什么会发送失败之前我们先看看一条正确的CAN报文到底应该是怎么样的 xff0c
  • 使用STM32F103做CAN的收发通信

    下面也是搭建嵌入式系统所必须的一个部分 参考网站 xff1a https www cnblogs com craigtao p 3645148 html https blog csdn net qq 29413829 article det
  • STM32 CAN通信的学习笔记总结

    转载地址 xff1a STM32 CAN通信的学习笔记总结 xff08 从小白开始 xff09 目录 1 总体概述 1 1 基本概念1 2 通讯方式1 3 为什么使用CAN 1 4 CAN的协议及组成 2 上帝视角看CAN的通讯过程 2 1
  • STM32F042 CAN使用例子

    代码如下 include mycan h CAN初始化 tsjw 重新同步跳跃时间单元 范围 1 3 CAN SJW 1tq CAN SJW 2tq CAN SJW 3tq CAN SJW 4tq tbs2 时间段2的时间单元 范围 1 8
  • 一文读懂CAN总线及通信协议

    CAN总线的汽车 CAN概念 CAN是控制器域网 Controller Area Network CAN 的简称 是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的 并最终成为国际标准 ISO11898 是ISO国际标准化的串行通信
  • STM32的CAN总线的接收双FIFO使用方法

    通过下面的框图我们可以看到 STM32F013有两个接收FIFO 但是实际的使用中如何让着两个FIFO都被使用呢 解决办法就在这里 1 STM32F103有0 13共14个过滤器组 每个过滤器组都可以绑定指定的FIFO 2 特别需要注意的一
  • CAN 为什么需要收发器

    在RTL代码中集成了两个CAN node 打算直接连接将两个node的Rx和Tx对接 发现两个CAN Node无法通信 询问技术支持后才知道必须要收发器 那为什么一定需要收发器呢 除了转换单端的CAN信号用于不同的传输 收发器也会将CANT
  • CAN总线的报文分析(三)

    系列文章目录 文章目录 系列文章目录 前言 一 数据帧 最常用 1 帧起始 2 仲裁段 3 控制段 4 数据段 5 CRC段 6 ACK段 7 帧结束 二 远程帧 三 错误帧 四 过载帧 五 帧间隔 总结 前言 CAN总线上的节点发送数据都
  • Ubuntu 周立功CAN分析仪 USBCAN-II 驱动

    首先从官网https www zlg cn Index Search search key linux的下载资料界面下载 Linux驱动 USBCAN I I II II 2A I MINI安装驱动 USBCAN II新版驱动基于libus
  • CAN协议详解-01

    CAN 是控制器局域网络 Controller Area Network 的简称 它是由研发和生产汽车电子产品著称的德国 BOSCH 公司开发的 并最终成为国际标准 ISO11519以及ISO11898 是国际上应用最广泛的现场总线之一 差

随机推荐

  • Unity3D之物体跟随鼠标移动和旋转

    void FixedUpdate if Input GetMouseButton 0 Vector3 aimPos 61 Camera main ScreenToWorldPoint new Vector3 Input mousePosit
  • 【寒武纪】视觉算法MLU220硬件适配(1)

    1 xff0c 环境搭建 xff1a MLU220快速上手指南 寒武纪开发者社区 安装硬件驱动和软件工具链 xff0c 也可以直接使用寒武纪官方开发平台 xff1a 寒武纪开发平台 本地开发安装完工具需要进行一些配置 xff1a 安装后配置
  • 【自动驾驶】second模型训练

    1 xff0c 数据组织 xff1a 训练验证数据生成 xff1a python create data py nuscenes data prep data path 61 NUSCENES TRAINVAL DATASET ROOT v
  • OpenMP入门

    OpenMP 是 Open MultiProcessing 的缩写 可以在 Visual Studio 或者 gcc 中使用 Hello World 把下面的代码保存为 omp cc include lt iostream gt inclu
  • 【蒸馏】PointDistiller: Structured Knowledge DistillationTowards Efficient and Compact 3D Detection

    简述 方法的细节 fT和f S 教师检测器和学生检测器中的特征编码层 AT和AS 抽取的待蒸馏体素或重要性得分最高的点的特征 CT和CS 教师和学生检测特征的通道数 GT和GS 教师和学生检测器的图形特征 该方法基于预先定义的重要度评分 x
  • 【自动驾驶】多传感器感知技术解析

    1 传感器 自动驾驶中的传感器主要用到激光雷达 xff0c 毫米波雷达 xff0c 摄像头 xff0c 超声波 xff0c 优缺点如下 xff1a 1 xff09 激光雷达的测距精度 测距范围及对温度和光照的适应性很强 xff0c 缺点线束
  • 【自动驾驶】单目3D检测M3D-RPN解析与paddle复现

    1 简介 作者提出了一种单个的端到端区域建议网络用于多类别3D目标检测 2D和3D检测任务各自的目标是最终对一个对象的所有实例进行分类 xff0c 而它们在定位目标的维数上是不同的 直观地说 xff0c 我们期望能够利用2D检测的强大功能来
  • 【模型压缩】实例分析量化原理

    1 从定点模型训练来分析量化原理 xff1a 定点模型训练是一个迁移训练的过程 xff1a 在浮点网络的相应位置插入定点化处理节点 xff08 相 当于激活函数 xff09 xff0c 然后在这个经过定点化的计算图上重新训练神经网络 以全连
  • 【3D视觉】深度摄像头与3D重建

    1 xff0c Kinect 是微软在2010年6月14日对XBOX360体感周边外设正式发布的名字 大家在上图可以看到 xff0c Kinect两端有两个3D深度摄像头 xff0c 左边那个发射红外线 xff0c 右边那个是一个红外线感应
  • 【3D视觉】realsense D435三维重建

    1 xff0c 硬件 xff1a realsense D435 驱动及SDK开发包安装 GitHub IntelRealSense librealsense Intel RealSense SDK 下载最新驱动 安装后打开 Intel Re
  • ssh: connect to host 10.112.1.5 port 10083: Connection refused

    ssh connect to host 10 112 1 5 port 10083 Connection refused 1 查看已知端口占用情况 我们想知道10083端口的使用情况 xff0c 或者说被谁占用了 xff0c 命令如下 xf
  • Unity之将Texture保存成png

    using UnityEngine using System Collections using System IO public class SaveToPng MonoBehaviour public Shader outShader
  • 基于容器训练OpenPCdet

    基于容器训练OpenPCdet 1 先拉取一个运行的镜像 docker pull djiajun1206 pcdet pytorch1 6 2 基于镜像创建一个容器 nvidia docker run it name pcdet privi
  • 【CUDA入门笔记】概述

    1 xff0c CUDA架构 xff08 1 xff09 一个GPU包含多个多核处理器 xff1b xff08 2 xff09 一个多核处理器包含多个线程处理器 xff08 3 xff09 线程处理器是最基本的计算单元 xff0c 有自己的
  • 【CUDA入门笔记】CUDA内核与线程配置

    1 CUDA核函数 在GPU上调用的函数成为CUDA核函数 Kernel function xff0c 核函数会被GPU上的多个线程执行 每个线程都会执行核函数里的代码 xff0c 当然由于线程编号的不同 xff0c 执行的代码路径可能会有
  • 【CUDA入门笔记】GPU存储结构模型(1)

    GPU存储结构模型 1 CPU可以读写GPU设备中的Global Memory Constant Memory以及Texture Memory内存储的内容 xff1b 主机代码可以把数据传输到设备上 xff0c 也可以从设备中读取数据 xf
  • 【CUDA入门笔记】GPU存储结构模型(2)

    GPU存储结构模型 1 CPU可以读写GPU设备中的Global Memory Constant Memory以及Texture Memory内存储的内容 xff1b 主机代码可以把数据传输到设备上 xff0c 也可以从设备中读取数据 xf
  • 基于多二维码识别的无人机运动真值获取

    基于多二维码识别的三维运动真值获取 1 背景介绍2 原理2 1 二维码基础2 2图像预处理2 3 定位标轮廓提取2 4 多二维码鲁棒识别 3 运行结果3 1对单张图片进行多二维码识别3 2 获取一系列静止图片的轨迹3 3 相机做圆周运动的轨
  • c++实现简单http服务器

    http基于tcp协议的应用层协议 xff0c 说白了就是写死的自定义协议 xff0c 代码实现了简单的get请求 xff0c 打开服务后 xff0c 可以通过网站访问本地资源 xff0c 适合新手学习的简单代码 xff0c 有助于理解ge
  • 基于NRF24L01的CAN数据透传

    闲谈 xff1a 闲来无聊 xff0c 恰好公司又经常用CAN数据的传输 xff0c 自己觉得要是用无线传送多好 xff0c 然后 xff0c 就是一个奇想 xff0c 就想做一个无线数据的透传 xff0c 恰好身边又有NRF24L01 那