【青风带你学stm32f051系列教程】第18课 无线RF24L01的读写

作者: 青风
上传时间为: 2013-04-02 10:23 PM
2013-04-02
阅读:

原理分析:

Nrf24L01是具有2.4GHZ的单片高速2Mbps无线收发芯片,是在无线领域使用比较广泛的无线设计方案。因此,我们在青风stm32f0开发板上加入了无线传输模块接口,用于大家做无线实验。

NRF24L01是采用spi接口进行数据传输,使用起来也是比较简单的。无线鼠标或者无线键盘都可以采用这个芯片,一共具有23个寄存器。因此设计方法和之前讲的spi通信相类似。 

硬件准备:

首先来看看:

// * 硬件连接 ----------------------------

// * | PA8-CE :24L01-CE |

// * | PC9-IRQ : 24L01-IRQ |

// * | PC8-CS : 24L01-CS |

// * | PB13-SPI2-SCK : 24L01-CLK |

// * | PB14-SPI2-MISO : 24L01-DO |

// * | PB15-SPI2-MOSI : 24L01-DIO |

// * ----------------------------

硬件电路图设计如下:

软件设计

首先我们需要对RF24L01所使用到的SPI端口进行初始化,这是设计接口操作的第一步:包含:配置IO端口和配置SPI参数。

配置IO端口可以按下面方式配置:

[c] GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_AHBPeriphClockCmd(FLASH_CS_PIN_SCK|FLASH_SCK_PIN_SCK|FLASH_MISO_PIN_SCK | FLASH_MOSI_PIN_SCK, ENABLE);//设置时钟 RCC_APB1PeriphClockCmd(RF_SPI2, ENABLE);

/*!< 配置 RF_SPI pins: SCK */ GPIO_InitStruct.GPIO_Pin = RF_SCK_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_2; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(RF_SCK_PORT, &GPIO_InitStruct); /*!< 配置 RF_SPI pins: MISO */ GPIO_InitStruct.GPIO_Pin = RF_MISO_PIN; GPIO_Init(RF_MISO_PORT, &GPIO_InitStruct); /*! GPIO_InitStruct.GPIO_Pin =RF_MOSI_PIN; GPIO_Init(RF_MOSI_PORT, &GPIO_InitStruct);

/* 设置SPI复用*/ GPIO_PinAFConfig(RF_SCK_PORT, RF_SCK_SOURCE, RF_SCK_AF); GPIO_PinAFConfig(RF_MISO_PORT, RF_MISO_SOURCE, RF_MISO_AF); GPIO_PinAFConfig(RF_MOSI_PORT, RF_MOSI_SOURCE, RF_MOSI_AF);

/*!< 配置RF 的CS pin */ GPIO_InitStruct.GPIO_Pin =RF_CS_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_2; GPIO_Init(RF_CS_PORT, &GPIO_InitStruct);<span style="text-indent: 2em;">GPIO_InitStruct.GPIO_Pin =RF_CE_PIN;</span>

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_2; GPIO_Init(RF_CE_PORT, &GPIO_InitStruct); SPI_RF_CS_HIGH() ; GPIO_InitStruct.GPIO_Pin =RF_IQR_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_2; GPIO_Init(RF_IQR_PORT , &GPIO_InitStruct); SPI_RF_CE_LOW(); [/c]

配置SPI的参数所有的库函数在前面使用SPI的时候已经详细讲解过,这里主要就是要注意设置SPI_CPOL 为低电平有效和SPI_CPHA为第一边缘触发。

[c]

/*!< SD_SPI Config */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; //时钟极性,空闲时为低 SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStruct.SPI_CRCPolynomial = 7; SPI_Init(SPI2, &SPI_InitStruct); SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF); SPI_Cmd(SPI2, ENABLE); /*!< SD_SPI enable */

[/c]

那么spi给出几个寄存器命令:

/********** NRF24L01寄存器操作命令 ***********/

#define READ_REG 0x00 //读配置寄存器,低5位为寄存器地址

#define 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 //空操作,可以用来读状态寄存器

首先写一个寄存器:

[c]

/*********************************************/ /* 函数功能:给24L01的寄存器写值(一个字节) */ /* 入口参数:reg 要写的寄存器地址 */ /* value 给寄存器写的值 */ /* 出口参数:status 状态值 */ /*********************************************/ uint8_t NRF24L01_Write_Reg(uint8_t reg,uint8_t value) { uint8_t status;

SPI_RF_CS_LOW() ; //CSN=0; status = SPI_RF_SendByte(reg);//发送寄存器地址,并读取状态值 SPI_RF_SendByte(value); SPI_RF_CS_HIGH(); //CSN=1; return status; }

<span style="text-indent: 2em;"> [/c]

读一个寄存器:

[c]

/*************************************************/ /* 函数功能:读24L01的寄存器值 (一个字节) */ /* 入口参数:reg 要读的寄存器地址 */ /* 出口参数:value 读出寄存器的值 */ /*************************************************/ uint8_t NRF24L01_Read_Reg(uint8_t reg) { uint8_t value;

SPI_RF_CS_LOW() ; //CSN=0; SPI_RF_SendByte(reg);//发送寄存器值(位置),并读取状态值 value = SPI_RF_SendByte(NOP); SPI_RF_CS_HIGH(); //CSN=1; return value; }

<span style="text-indent: 2em;"> [/c]

读多个寄存器:

[c]

/*********************************************/ /* 函数功能:读24L01的寄存器值(多个字节) */ /* 入口参数:reg 寄存器地址 */ /* *pBuf 读出寄存器值的存放数组 */ /* len 数组字节长度 */ /* 出口参数:status 状态值 */ /*********************************************/ uint8_t NRF24L01_Read_Buf(uint8_t reg,uint8_t *pBuf,uint8_t len) { uint8_t status,u8_ctr; SPI_RF_CS_LOW() ;//CSN=0 status=SPI_RF_SendByte(reg);//发送寄存器地址,并读取状态值 for(u8_ctr=0;u8_ctr<len;u8_ctr++) pBuf[u8_ctr]=SPI_RF_SendByte(0XFF);//读出数据 SPI_RF_CS_HIGH(); //CSN=1 return status; //返回读到的状态值 }

[/c]

写多个寄存器:

[c]

/**********************************************/ /* 函数功能:给24L01的寄存器写值(多个字节) */ /* 入口参数:reg 要写的寄存器地址 */ /* *pBuf 值的存放数组 */ /* len 数组字节长度 */ /**********************************************/ uint8_t NRF24L01_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len) { uint8_t status,u8_ctr; SPI_RF_CS_LOW() ; status = SPI_RF_SendByte(reg);//发送寄存器值(位置),并读取状态值 for(u8_ctr=0; u8_ctr SPI_RF_SendByte(*pBuf++); //写入数据 SPI_RF_CS_HIGH(); return status; //返回读到的状态值 }

[/c]

设置24L01为接收模式:

[c]

/*********************************************/ /* 函数功能:设置24L01为接收模式 */ /*********************************************/ void NRF24L01_RX_Mode(void) {

SPI_RF_CE_LOW() ; //CE拉低,使能24L01配置

NRF24L01_Write_Buf(WRITE_REG+RX_ADDR_P0, (uint8_t*)RX_ADDRESS, RX_ADR_WIDTH);//写RX接收地址

NRF24L01_Write_Reg(WRITE_REG+EN_AA,0x01); //开启通道0自动应答 NRF24L01_Write_Reg(WRITE_REG+EN_RXADDR,0x01);//通道0接收允许 NRF24L01_Write_Reg(WRITE_REG+RF_CH,40); //设置RF工作通道频率 NRF24L01_Write_Reg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH); / /选择通道0的有效数据宽度 NRF24L01_Write_Reg(WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启 NRF24L01_Write_Reg(WRITE_REG+CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 SPI_RF_CE_HIGH(); //CE置高,使能接收 }

[/c]

设置24L01为接收模式:

[c]

/*********************************************/ /* 函数功能:24L01接收数据 */ /* 入口参数:rxbuf 接收数据数组 */ /* 返回值: 0 成功收到数据 */ /* 1 没有收到数据 */ /*********************************************/ uint8_t NRF24L01_RxPacket(uint8_t *rxbuf) { uint8_t state;

state=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值 NRF24L01_Write_Reg(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;//没收到任何数据 }

[/c]

24L01接收数据:

[c]

/*********************************************/ /* 函数功能:24L01接收数据 */ /* 入口参数:rxbuf 接收数据数组 */ /* 返回值: 0 成功收到数据 */ /* 1 没有收到数据 */ /*********************************************/ uint8_t NRF24L01_RxPacket(uint8_t *rxbuf) { uint8_t state; state=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值 NRF24L01_Write_Reg(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;//没收到任何数据 }

[/c]

设置24L01为发送模式:

[c]

/**********************************************/ /* 函数功能:设置24L01为发送模式 */ /* 入口参数:txbuf 发送数据数组 */ /* 返回值; 0x10 达到最大重发次数,发送失败*/ /* 0x20 成功发送完成 */ /* 0xff 发送失败 */ /**********************************************/ uint8_t NRF24L01_TxPacket(uint8_t *txbuf) { uint8_t state; SPI_RF_CE_LOW() ; //CE拉低,使能24L01配置 NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF 32个字节 SPI_RF_CE_HIGH(); //CE置高,使能发送 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送完成 state=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值 NRF24L01_Write_Reg(WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志 if(state&MAX_TX)//达到最大重发次数 { NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 return MAX_TX; } if(state&TX_OK)//发送完成 { return TX_OK; } return 0xff;//发送失败 }

[/c]

全部评论 ()
条评论
写评论

创建讨论帖子

登录 后参与评论
系统提示