查看: 53|回复: 0

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

[复制链接]

主题

好友

1114

积分

版主

该用户从未签到

发表于 2013-4-2 22:23:44 |显示全部楼层
原理分析:
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]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /4 下一条

手机版|电路城

GMT+8, 2019-7-20 01:36 , Processed in 0.116673 second(s), 14 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz!

返回顶部