单片机,32无线通信代码,详细注释【NRF24L01传感器】【原创】

代码目录

  • nrf24l01传感器引脚
  • main.c
  • nrf24l01.c
  • nrf24l01.h
  • nrf24l01_demo.c
  • nrf24l01_demo.h


nrf24l01传感器引脚

单片机,32无线通信代码,详细注释【NRF24L01传感器】【原创】_第1张图片

单片机,32无线通信代码,详细注释【NRF24L01传感器】【原创】_第2张图片

//spi与iic都是串行
//stm32内部集成spi,需要模拟iic

//spi四线(三线根通讯,一根线片选)
//mosi主发,miso从发,sck,mss片选
//miso该引脚在从模式下发送,主模式下接收
//mosi相反,即主模式下输出发送

//主机从机mosi,miso管脚相连
//nss片选,一头接在单片机端口,另一头接从机,控制从机,也就是一个端口csn=cs=nss哈哈哈哈
//nss可以输入(从给主)也可以输出(主给从),通过寄存器设置
//触摸屏,检测是spi通讯(显示不是spi,好像是iic)(spi2)
//24L01也是spi通讯(spi2)
//以太网也是spi(spi_1)
//mp3也是spi2
//spi_1与spi_2不共用时钟线,相互不影响
//spi_2挂在SPB2时钟线上,可双击检查时钟线

//SPI是全双工通信
//CSN,SPI片选
//SCK,SPI时钟线
//MOSI,SPI数据线(主发从读)
//MISO,SPI数据线(从发主读)

//CE,模式控制线,在CSN为低时,CE协同CONFIG寄存器共同决定NRF24L01的状态
//IRQ,中断信号线,中断时变为低电平,三种情况会拉低,这里略
//点对点模式或一对多模式(1收6发就是1个接收6个发送)
//单字节传输高位在前,多字节传输低位在前

//大黄蜂上csn就是cs,就是24L01片选,上电默认高电平,高电平就是24L01未被选中
//当cs拉低时就是选中它,这个端口配置推挽输出
//spi中nss片选就是片选,也是spi片选,irq是上拉输入
//spi片选与24L01片选是连在一起,刚刚打电话给刘洋也确认了

//总结一下,csn=nss=cs

main.c

#include "pbdata.h"

//spi与iic都是串行
//stm32内部集成spi,需要模拟iic
//spi四线(三线根通讯,一根线片选)
//mosi主发,miso从发,sck,mss片选
//miso该引脚在从模式下发送,主模式下接收
//mosi相反,即主模式下输出发送
//主机从机mosi,miso管脚相连
//nss片选,一头接在单片机端口,另一头接从机,控制从机,也就是一个端口csn==cs==nss哈哈哈哈
//nss可以输入(从给主)也可以输出(主给从),通过寄存器设置
//触摸屏,检测是spi通讯(显示不是spi,好像是iic)(spi2)
//24L01也是spi通讯(spi2)
//以太网也是spi(spi_1)
//mp3也是spi2
//spi_1与spi_2不共用时钟线,相互不影响
//spi_2挂在SPB2时钟线上,可双击检查时钟线

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART_Configuration(void);

//SPI是全双工通信
//CSN,SPI片选
//SCK,SPI时钟线
//MOSI,SPI数据线(主发从读)
//MISO,SPI数据线(从发主读)

//CE,模式控制线,在CSN为低时,CE协同CONFIG寄存器共同决定NRF24L01的状态
//IRQ,中断信号线,中断时变为低电平,三种情况会拉低,这里略
//点对点模式或一对多模式(1收6发就是1个接收6个发送)
//单字节传输高位在前,多字节传输低位在前

//大黄蜂上csn就是cs,就是24L01片选,上电默认高电平,高电平就是24L01未被选中
//当cs拉低时就是选中它,这个端口配置推挽输出
//spi中nss片选就是片选,也是spi片选,irq是上拉输入
//spi片选与24L01片选是连在一起,刚刚打电话给刘洋也确认了

//总结一下,csn==nss==cs

int fputc(int ch,FILE *f)
{
		USART_SendData(USART1,(u8)ch);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
		return ch;
}

int main(void)
{
	 RCC_Configuration();	//系统时钟初始化
	 GPIO_Configuration();//端口初始化
	 USART_Configuration();
	 NVIC_Configuration();
	 NRF24L01_Init();
	 SPI_Configation();

	 while(1)
	 {
		NRF24L01_Demo2();   
	 }	
}

void RCC_Configuration(void)
{
		SystemInit();//72m
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 ,ENABLE);
}

void GPIO_Configuration(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;	

		GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
		GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
		GPIO_Init(GPIOA,&GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
		GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void NVIC_Configuration(void)
{
		NVIC_InitTypeDef NVIC_InitStructure; 

		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 

		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
		NVIC_Init(&NVIC_InitStructure);
}

void USART_Configuration(void)
{
		USART_InitTypeDef  USART_InitStructure;

		USART_InitStructure.USART_BaudRate=115200;
		USART_InitStructure.USART_WordLength=USART_WordLength_8b;
		USART_InitStructure.USART_StopBits=USART_StopBits_1;
		USART_InitStructure.USART_Parity=USART_Parity_No;
		USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
		USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

		USART_Init(USART1,&USART_InitStructure);
		USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
		USART_Cmd(USART1,ENABLE);
		USART_ClearFlag(USART1,USART_FLAG_TC);
}

nrf24l01.c

#include  "pbdata.h"

//以下为24L01底层硬件驱动代码文件

//很重要,必须两个地址相同
//这两个地址发送与接收40位地址(p0通道可更改 点对点),都是我们自己定义(也可以其它数值),是为了两个24L01之间通信
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; //接收地址

///根据不同的单片机更改以下3个函数//
void SPI_Configation(void)//对应改为stm32大黄蜂管脚     32自带内部SPI底层配置
{
  SPI_InitTypeDef  SPI_InitStructure;

  /* SPI2 配置 */ 
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;   //全双工  
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;						   //主模式
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;					   //8位
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;						   //时钟极性 空闲状态时,SCK保持低电平
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;						   //时钟相位 数据采样从第一个时钟边沿开始
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;							   //软件产生NSS
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;  //波特率控制 SYSCLK/16
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;				   //数据高位在前
  SPI_InitStructure.SPI_CRCPolynomial = 7;							   //CRC多项式寄存器初始值为7 
  SPI_Init(SPI2, &SPI_InitStructure);

  /* 使能SPI2  */
  SPI_Cmd(SPI2, ENABLE);   
}

u8 SPI_SendByte(u8 byte)//对应改为stm32,如果想用spi1则直接改名字就可以了
{
	/* 循环检测发送缓冲区是否是空 */
	while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
	/* 通过SPI2外设发出数据 */
	SPI_I2S_SendData(SPI2, byte);
	/* 等待接收数据,循环检查接收数据缓冲区 */
	while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
	/* 返回读出的数据 */
	return SPI_I2S_ReceiveData(SPI2);
}

void NRF24L01_Init(void)//初始化24L01,ce推挽输出,cs也是推挽输出(上电默认为高,高电平意思是模块不工作),irq上拉输入
{   
  GPIO_InitTypeDef GPIO_InitStructure;	   
 
  /* 配置 SPI2 引脚: SCK, MISO and MOSI(PB13, PB14, PB15) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//这三个是spi三个端口不包括片选,因为连在了一起,很重要
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;          //复用功能(推挽)输出  SPI2
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* 配置PB0为VS1003B的片选  */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);   

	//这一步禁止是因为大黄蜂开发板上mp3与其共用spi2,所以要禁止它
  GPIO_SetBits(GPIOB, GPIO_Pin_0);	   //禁止MP3片选

  /* 配置SPI2 NRF24L01+片选 */
  GPIO_InitStructure.GPIO_Pin = NRF_PIN_CS;			  					 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		   //输出模式最大速度50MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		   //通用推挽输出模式
  GPIO_Init(NRF_PORT_CS, &GPIO_InitStructure);

  /* 配置NRF24L01+ 模式选择 */
  GPIO_InitStructure.GPIO_Pin = NRF_PIN_CE;                //NRF24L01  MODE-CE
  GPIO_Init(NRF_PORT_CE, &GPIO_InitStructure);
  
  /* 配置NRF24L01+ 中断信号产生连接到 */
  GPIO_InitStructure.GPIO_Pin = NRF_PIN_IRQ;		 		  //NRF24L01 IRQ 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			  //上拉输入模式
  GPIO_Init(NRF_PORT_IRQ, &GPIO_InitStructure);
  
  SPI_RF_CS_H;
}

//

/*********************************************/
/* 函数功能:给24L01的寄存器写值(一个字节) */
/* 入口参数:reg   要写的寄存器地址          */
/*           value 给寄存器写的值            */
/* 出口参数:status 状态值                   */
/*********************************************/
u8 NRF24L01_Write_Reg(u8 reg,u8 value)//写时序通讯
{
    u8 status;
    
    SPI_RF_CS_L;//片选  
    status = SPI_SendByte(reg);//发送寄存器地址,并读取状态值,发送寄存器地址就是发送控制命令
                               //然后status是读取返回的状态值
	  SPI_SendByte(value);//这是要发送的命令或者数据
    SPI_RF_CS_H;
    return status;
}

/*************************************************/
/* 函数功能:读24L01的寄存器值 (一个字节)      */
/* 入口参数:reg  要读的寄存器地址               */
/* 出口参数:value 读出寄存器的值                */
/*************************************************/
u8 NRF24L01_Read_Reg(u8 reg)//读时序通讯
{
    u8 value;
    
    SPI_RF_CS_L;  
    SPI_SendByte(reg);//发送寄存器值(位置),并读取状态值
	                    //应该就是寄存器位置,锁定这个寄存器
    value = SPI_SendByte(NOP);//nop是空操作,就是读取值
    SPI_RF_CS_H;
    return value;
}

/*********************************************/
/* 函数功能:读24L01的寄存器值(多个字节)   */
/* 入口参数:reg   寄存器地址                */
/*           *pBuf 读出寄存器值的存放数组    */
/*           len   数组字节长度              */
/* 出口参数:status 状态值                   */
/*********************************************/
u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len)//len是长度,几就是几个字节
{
    u8 status,i;
    
    SPI_RF_CS_L;    
    status=SPI_SendByte(reg);//发送寄存器地址,并读取状态值   	   
    for(i=0;i<len;i++)
        pBuf[i]=SPI_SendByte(0XFF);//读出数据,0xff==nop,就是空操作
    SPI_RF_CS_H;
    return status;        //返回读到的状态值
}
/**********************************************/
/* 函数功能:给24L01的寄存器写值(多个字节)  */
/* 入口参数:reg  要写的寄存器地址            */
/*           *pBuf 值的存放数组               */
/*           len   数组字节长度               */
/**********************************************/
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
    u8 status,i;
    
    SPI_RF_CS_L;
    status = SPI_SendByte(reg);//发送寄存器值(位置),并读取状态值
    for(i=0; i<len; i++)
        SPI_SendByte(*pBuf++); //写入数据
    SPI_RF_CS_H;
    return status;          //返回读到的状态值
}

/*********************************************/
/* 函数功能:24L01接收数据                   */
/* 入口参数:rxbuf 接收数据数组              */
/* 返回值: 0   成功收到数据                 */
/*          1   没有收到数据                 */
/*********************************************/
u8 NRF24L01_RxPacket(u8 *rxbuf)//注意接收数据   不等于  读取寄存器值
{
    u8 state;
    
    state=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
    NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
    if(state&RX_OK)//接收到数据
    {
        NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据,注意参数是指针类型
        NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
        return 0; 
    }
    return 1;//没收到任何数据
}
/**********************************************/
/* 函数功能:设置24L01为发送模式              */
/* 入口参数:txbuf  发送数据数组              */
/* 返回值; 0x10    达到最大重发次数,发送失败*/
/*          0x20    成功发送完成              */
/*          0xff    发送失败                  */
/**********************************************/
u8 NRF24L01_TxPacket(u8 *txbuf)
{
    u8 state;
    
    SPI_RF_CE_L;//CE拉低,使能24L01配置
    NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
    SPI_RF_CE_H;//CE置高,使能发送
    while (SPI_RF_IRQ!=0);//等待发送完成 
    state=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
    NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
    NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
    if(state&MAX_TX)//达到最大重发次数
    {
        NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
        return MAX_TX; 
    }
    if(state&TX_OK)//发送完成
    {
        return TX_OK;
    }
    return 0xff;//发送失败
}


//以下三个函数需要重点理解

 
/********************************************/
/* 函数功能:检测24L01是否存在              */
/* 返回值;  0  存在                        */
/*           1  不存在                      */
/********************************************/	
u8 NRF24L01_Check(void)
{
    u8 check_in_buf[5]={0x11,0x22,0x33,0x44,0x55};
    u8 check_out_buf[5]={0x00};
		
    //tx_addr是发送地址,发送check_in_buf 数组数据到tx_addr寄存器地址里,NRF_WRITE_REG是写寄存器地址
    NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR, check_in_buf, 5); 
    NRF24L01_Read_Buf(NRF_READ_REG+TX_ADDR, check_out_buf, 5);//然后再读出此寄存器中数组数据
    
    if( (check_out_buf[0] == 0x11)&&\
        (check_out_buf[1] == 0x22)&&\
        (check_out_buf[2] == 0x33)&&\
        (check_out_buf[3] == 0x44)&&\
        (check_out_buf[4] == 0x55))return 0;//如果返回0说明24L01是正常的模块,实现检测功能
    else return 1;
}

/*********************************************/
/* 函数功能:设置24L01为接收模式             */
/*********************************************/
void NRF24L01_RX_Mode(void)
{
    SPI_RF_CE_L;//CE拉低,使能24L01配置
    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,0);	 //设置RF工作通道频率 ,2.4G不变		  
    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_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
    SPI_RF_CE_H;//CE置高,进入接收模式 
}

/*********************************************/
/* 函数功能:设置24L01为发送模式             */
/*********************************************/
void NRF24L01_TX_Mode(void)
{
    SPI_RF_CE_L;//CE拉低,使能24L01配置	    
    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,0);        //设置RF通道为0,也是2.4G
    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启  2Mbps 
    NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发送模式,开启所有中断
    SPI_RF_CE_H;//CE置高,10us后启动发送 
}

void NRF24L01_RT_Mode(void)
{	
    SPI_RF_CE_L;
    NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
    NRF24L01_Write_Reg(FLUSH_RX,0xff);			  //清除RX FIFO寄存器    
    
	  //下面的两个地址就是const u8 TX_ADDRESS[TX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; //发送地址
    //const u8 RX_ADDRESS[RX_ADR_WIDTH]={0xFF,0xFF,0xFF,0xFF,0xFF}; //接收地址
    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,0);        //设置RF通道为2.400GHz  频率=2.4+0GHz
    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,接收模式,开启所有中断
    SPI_RF_CE_H;   
}			    

nrf24l01.h

#ifndef _RF24L01_H
#define _RF24L01_H

///根据不同的单片机更改以下引脚定义//
#include "stm32f10x.h"

//修改以下24L01端口,也就是cs片选端口,ce模式选择端口,irq终端端口

#define NRF_PIN_CS        GPIO_Pin_12//这个片选端也就是spi片选端  默认上电拉高
#define NRF_PORT_CS       GPIOB

#define NRF_PIN_CE        GPIO_Pin_1
#define NRF_PORT_CE       GPIOB

#define NRF_PIN_IRQ       GPIO_Pin_0
#define NRF_PORT_IRQ      GPIOA

#define SPI_RF_CS_L      GPIO_ResetBits(NRF_PORT_CS, NRF_PIN_CS)
#define SPI_RF_CS_H      GPIO_SetBits(NRF_PORT_CS, NRF_PIN_CS)
#define SPI_RF_CE_L      GPIO_ResetBits(NRF_PORT_CE, NRF_PIN_CE)
#define SPI_RF_CE_H      GPIO_SetBits(NRF_PORT_CE, NRF_PIN_CE)
#define SPI_RF_IRQ       GPIO_ReadInputDataBit(NRF_PORT_IRQ, NRF_PIN_IRQ)

//

/**********  NRF24L01寄存器操作命令  ***********/
#define NRF_READ_REG        0x00  //读配置寄存器,低5位为寄存器地址
#define NRF_WRITE_REG       0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD     0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD     0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX        0xE1  //清除TX FIFO寄存器.发射模式下用
#define FLUSH_RX        0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL     0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP             0xFF  //空操作,可以用来读状态寄存器	 
/**********  NRF24L01寄存器地址   *************/
#define CONFIG          0x00  //配置寄存器地址                             
#define EN_AA           0x01  //使能自动应答功能 
#define EN_RXADDR       0x02  //接收地址允许
#define SETUP_AW        0x03  //设置地址宽度(所有数据通道)
#define SETUP_RETR      0x04  //建立自动重发
#define RF_CH           0x05  //RF通道
#define RF_SETUP        0x06  //RF寄存器
#define STATUS          0x07  //状态寄存器
#define OBSERVE_TX      0x08  // 发送检测寄存器
#define CD              0x09  // 载波检测寄存器
#define RX_ADDR_P0      0x0A  // 数据通道0接收地址
#define RX_ADDR_P1      0x0B  // 数据通道1接收地址
#define RX_ADDR_P2      0x0C  // 数据通道2接收地址
#define RX_ADDR_P3      0x0D  // 数据通道3接收地址
#define RX_ADDR_P4      0x0E  // 数据通道4接收地址
#define RX_ADDR_P5      0x0F  // 数据通道5接收地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收数据通道0有效数据宽度(1~32字节) 
#define RX_PW_P1        0x12  // 接收数据通道1有效数据宽度(1~32字节) 
#define RX_PW_P2        0x13  // 接收数据通道2有效数据宽度(1~32字节) 
#define RX_PW_P3        0x14  // 接收数据通道3有效数据宽度(1~32字节) 
#define RX_PW_P4        0x15  // 接收数据通道4有效数据宽度(1~32字节)
#define RX_PW_P5        0x16  // 接收数据通道5有效数据宽度(1~32字节)
#define FIFO_STATUS     0x17  // FIFO状态寄存器
/*————————————————————————————————————————————————————————————————————*/

/******   STATUS寄存器bit位定义      *******/
#define MAX_TX  	0x10  //达到最大发送次数中断
#define TX_OK   	0x20  //TX发送完成中断
#define RX_OK   	0x40  //接收到数据中断
/*——————————————————————————————————————————————————*/

/*********     24L01发送接收数据宽度定义	  ***********/
#define TX_ADR_WIDTH    5   //5字节地址宽度
#define RX_ADR_WIDTH    5   //5字节地址宽度
#define TX_PLOAD_WIDTH  32  //32字节有效数据宽度
#define RX_PLOAD_WIDTH  32  //32字节有效数据宽度
/*———————————————————————————————————————————————————————*/

extern void NRF24L01_Init(void);
extern u8 NRF24L01_Write_Reg(u8 reg,u8 value);
extern u8 NRF24L01_Read_Reg(u8 reg);
extern u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len);
extern u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len);
extern u8 NRF24L01_Check(void);
extern void NRF24L01_RX_Mode(void);
extern void NRF24L01_TX_Mode(void);
extern void NRF24L01_RT_Mode(void);
extern u8 NRF24L01_RxPacket(u8 *rxbuf);
extern u8 NRF24L01_TxPacket(u8 *txbuf);
extern void SPI_Configation(void);
extern u8 SPI_SendByte(u8 byte);

#endif

nrf24l01_demo.c

#include "pbdata.h"

//如果想实现两块单片机通信,最好,demo1,和demo2配合使用

#define uart_max 32
u8 rece_buf[uart_max];//定义数组///接收是接收数组中的数据,发送也是发送里面的数据
u8 uart_count=0;


//模块通过串口助手中的无线模块配置将无线模块配置好,然后通过波特率为115200发给模块数据
//usb转无线模块插上不用管,一个助手发送,一个助手接收


//这个函数是模块24L01,模块波特率不等于串口打印波特率,这个也就是模块接收数据,然后串口打印告诉电脑我已接收
//也许你会问,谁发送给模块信息呢?就是通过串口助手(usb转接口)发给模块(一个助手发送一个助手显示串口打印)
void NRF24L01_Demo1(void)//接收函数
{
   u8 i=0;
   NRF24L01_RX_Mode();//设置24L01为接收模式
    
    while(1)
    {
        if(SPI_RF_IRQ==0)//IRQ为0说明进入中断,这个irq是24L01内部寄存器,为0时说明接收数据了,还有两种main解释有
        {
					  //参数是指针,数组名刚好是指针,至于为啥这样就接收与寄存器内部,不深究
					  
					  //差不多明白了,下面一步过后就将接受的数据传到了rece_buf中,因为此函数形参是指针,正好recebuf就是数组名,就是指针
            if(NRF24L01_RxPacket(rece_buf)==0)//为0说明正常接收数据,这个是说明接收到数据,上面只是说明开始接受了,这个说明接收成功且完成
            {
                if(rece_buf[0]<uart_max)//首先判定小于32个字节(因为无线接收最大就32位字节)
                {
                    for(i=0;i<rece_buf[0];i++)//注意首先发送rece_buf[1]数据,这是自己定义的报文格式
                    {
												USART_SendData(USART1,rece_buf[i+1]);//发送数组中的数据,不是很理解,反正
												while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//这是串口打印显示在助手
                    }
                }
            }
        }
    }
}

//也就是将大黄蜂开发板上的24L01设置为发送模式,上面的是接收,usb转接口发,它接
//这是定义好的数据发给模块
void NRF24L01_Demo2(void)//发送函数
{
    u8 i=0;
   
    NRF24L01_TX_Mode();//设置24L01为发送模式
    
    while(1)
    {
        rece_buf[0]=0x04;//表示发送四个字节有效数据
        
        for(i=1;i<5;i++)//这里是事先存储数组为1234,rece_buf[0]=0x04
        {
            rece_buf[i]=i;
        }
        
        SPI_RF_CE_L;
        NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);//配置工作发送模式
        SPI_RF_CE_H;//CE拉高
				
				//下面形参也是指针,也就是说执行这一步,发送数组中的数据
        NRF24L01_TxPacket(rece_buf);//发送数据,rece_buf就是
        SPI_RF_CE_L;
        NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0f);//配置工作接收模式
        SPI_RF_CE_H;
        
        delay_ms(1000);
    }
}

//这个函数作用是,单片机通过串口接收数据时,再通过无线模块发送这个数据
void NRF24L01_Demo3(void)//发送及接收函数
{
    u8 i=0;
  
    NRF24L01_RT_Mode();//接收发射双模式

    while(1)
    {
        //串口接收 无线模块发送
        if(uart_count>0)
        {
            delay_ms(20);//串口接收数组也需要时间,所以要时间
            rece_buf[0]=uart_count;
            uart_count=0;
            
            SPI_RF_CE_L;
            NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
            SPI_RF_CE_H;
            NRF24L01_TxPacket(rece_buf);
            SPI_RF_CE_L;
            NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0f);
            SPI_RF_CE_H;          
        }
        //无线模块收到数据转发串口
        if(SPI_RF_IRQ==0)
        {
            if(NRF24L01_RxPacket(rece_buf)==0)
            {
                if(rece_buf[0]<uart_max)
                {
                    for(i=0;i<rece_buf[0];i++)
                    {
												 USART_SendData(USART1,rece_buf[i+1]);
												 while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
                    }
                }
            }
        }
    }
}

//作用是将串口接受的数据传到rece_buf数组里
void UART1_Recv_Byte(u8 byte)//这个函数,放在了串口中断里,就是下面注释的函数
{
    if(uart_count<uart_max)
    {
        rece_buf[++uart_count]=byte;
    }
    else
    {
        uart_count=0;
    }
}

//void USART1_IRQHandler(void)
//{
//   if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
//   {
//			//USART_SendData(USART1,USART_ReceiveData(USART1));
//			//while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
//			UART1_Recv_Byte(USART_ReceiveData(USART1));
//   } 

//   
//}

/************************ 论坛地址 www.zxkjmcu.com ******************************/

nrf24l01_demo.h

#ifndef _NRF24L01_DEMO_H  //宏定义,定义文件名称
#define _NRF24L01_DEMO_H

/*---------------------------头文件引用--------------------------------------*/
#include "stm32f10x.h"

void NRF24L01_Demo1(void);
void NRF24L01_Demo2(void);
void NRF24L01_Demo3(void);
void UART1_Recv_Byte(u8 byte);
#endif //定义文件名称结束


/************************ 论坛地址 www.zxkjmcu.com ******************************/

你可能感兴趣的:(学校-32单片机,stm32,经验分享,学习)