完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本文只要是以软件模拟SPI总线,对NRF24L01进行读写操作!***代码,经过测试是没有问题的!
点C源文件如下: /************************************************** 1、地址的设置说明: 发射模式:通道0被用于接收应答信号,所以通道0地址需与发射节点的地址一致 接收模式:0通道地址任意设置,1~5通道地址高4个字节需一致。 当某通道地址与某发射节点地址一致时,便接收来自此节点的数据。 2、CE引脚的操作: 发射模式:NRF_CE=1 大于10us开始启动发射 接收模式:NRF_CE=1,130us后开始等待数据包 ***************************************************/ #include "DX_nrf24L01.h" DX_Nrf24L01::DX_Nrf24L01() { initGpio(); initArray(); } void DX_Nrf24L01::initArray() { unsigned char TX_ADDRESS[TX_ADDR_WIDTH] = {0xA0,0xA0,0xA0,0xA0,0xA0}; unsigned char RX_ADDRESS_P0[RX_ADDR_WIDTH] = {0xA0,0xA0,0xA0,0xA0,0xA0}; for(char i=0;i<5;i++) { this->TX_ADDRESS = TX_ADDRESS; this->RX_ADDRESS_P0 = RX_ADDRESS_P0; } } /************************************************** * 初始化IO **************************************************/ void DX_Nrf24L01::initGpio(void) { PC_DDR |= 0x68; PC_CR1 |= 0x68; //SPI_MOSI and SPI_SCK and NRF_CSN PP_OUT PG_DDR |= 0x01; PG_CR1 |= 0x01; //NRF_CE PP_OUT PC_DDR &= 0x7F; PC_CR1 &= 0x7F; //SPI_MISO FLOAT_IN PC_DDR &= ~0x10; PC_CR1 |= 0x10; //NRF_IRQ UP_IN NRF_CSN = 1; } /************************************************** * 根据SPI协议,写一字节数据到NRF24L01, * 同时从NRF24L01读出一字节 **************************************************/ unsigned char DX_Nrf24L01::readOrWrite(unsigned char byte) { unsigned char i; for(i=0; i<8; i++) // 循环8次 { if(byte&0x80) // byte最高位输出到SPI_MOSI SPI_MOSI = 1; else SPI_MOSI = 0; byte <<= 1; // 低一位移位到最高位 SPI_SCK = 1; // 拉高SCK,NRF24L01从SPI_MOSI读入1位数据,同时从SPI_MISO输出1位数据 byte |= SPI_MISO; // 读SPI_MISO到byte最低位 SPI_SCK = 0; // SCK置低 } return byte; // 返回读出的一字节 } /************************************************** * 写一字节数据到寄存器reg **************************************************/ unsigned char DX_Nrf24L01::writeReg (unsigned char reg, unsigned char byte) { unsigned char status; NRF_CSN = 0; // CSN置低,使能数据传输 NRF_CE = 0; //待机模式,才能对寄存器写操作 status = readOrWrite(reg); // 选择寄存器,同时返回状态字 readOrWrite(byte); // 然后写数据到该寄存器 NRF_CSN = 1; // CSN拉高,结束数据传输 return status; // 返回状态寄存器 } /************************************************** * 从寄存器reg读出一字节数据 **************************************************/ unsigned char DX_Nrf24L01::readReg (unsigned char reg) { unsigned char reg_value; NRF_CSN = 0; // CSN置低,使能数据传输 NRF_CE = 0; //待机模式,才能对寄存器写操作 readOrWrite(reg); // 选择寄存器 reg_value = readOrWrite(NOP); // 然后从该寄存器读数据 NRF_CSN = 1; // CSN拉高,结束数据传输 return reg_value; // 返回寄存器数据 } /************************************************** * 把pBuf缓存中的数据写入到NRF24L01, * 通常用来写入地址和通道数据 **************************************************/ unsigned char DX_Nrf24L01::writeBuf(unsigned char reg, unsigned char *pBuf, unsigned char bytes) { unsigned char status, i; NRF_CSN = 0; // CSN置低,使能数据传输 NRF_CE = 0; //待机模式,才能对寄存器写操作 status = readOrWrite(reg); // 选择寄存器,同时返回状态字 for(i=0; i readOrWrite(*(pBuf+i)); // 逐个字节写入NRF24L01 } NRF_CSN = 1; // CSN拉高,结束数据传输 return status; // 返回状态寄存器 } /************************************************** * 从寄存器reg读出bytes个字节数据, * 通常用来读取地址和通道数据。 **************************************************/ unsigned char DX_Nrf24L01::readBuf(unsigned char reg, unsigned char *pBuf, unsigned char bytes) { unsigned char status, i; NRF_CSN = 0; // CSN置低,使能数据传输 NRF_CE = 0; //待机模式,才能对寄存器写操作 status = readOrWrite(reg); // 选择寄存器,同时返回状态字 for(i=0; i *(pBuf+i) = readOrWrite(NOP);// 逐个字节从NRF24L01读出 } NRF_CSN = 1; // CSN拉高,结束数据传输 return status; // 返回状态寄存器 } /************************************************** * 将NRF24L01设置为发射模式 **************************************************/ void DX_Nrf24L01::TX_Mode(void) { /*拉低CE,进入低功耗模式才能操作寄存器*/ NRF_CE = 0; /*设置所有通道的地址宽度,默认为5字节*/ writeReg(WRITE_REG + SETUP_AW, 0x02); /*写入发送节点地址*/ writeBuf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADDR_WIDTH); /*接收通道地址设置,发送模式下应向通道0写入与发送节点一致的地址,用于接收应答信号*/ /*通道1~5的地址设置需遵循一定的规则,请查阅手册*/ writeBuf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADDR_WIDTH); /*接收通道地址使能设置,使能通道0的地址*/ writeReg(WRITE_REG + EN_RXADDR, 0x01); /*接收通道0有效数据宽度设置*/ writeReg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); /*接收通道自动应答设置,使能通道0自动应答*/ writeReg(WRITE_REG + EN_AA, 0x01); /*自动重发设置*/ writeReg(WRITE_REG + SETUP_RETR, 0x0D); //重发等待500+86us,自动重发5次 /*设置通信频率*/ /*计算公式:F=2400+RF_CH(MHz),从2.4G到2.525G,共125个频点可用*/ writeReg(WRITE_REG + RF_CH, 50); /*设置发射参数:传输速率,发射功率等*/ writeReg(WRITE_REG + RF_SETUP, 0x07); //速率1Mbps,功率最大0dBm,低噪声放大器增益 /*配置基本参数*/ /*开启IRQ引脚的三种中断,16位CRC校验,上电,发射模式*/ writeReg(WRITE_REG + CONFIG, 0x0E); } /************************************************** * 将NRF24L01设置为接收模式 **************************************************/ void DX_Nrf24L01::RX_Mode(void) { /*拉低CE,进入低功耗模式才能操作寄存器*/ NRF_CE = 0; /*设置所有通道的地址宽度,默认为5字节*/ writeReg(WRITE_REG + SETUP_AW, 0x02); /*设置接收通道0地址,通道1~5的地址设置需遵循一定的规则,请查阅手册*/ writeBuf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS_P0, RX_ADDR_WIDTH); /*接收通道地址使能设置,使能通道0的地址*/ writeReg(WRITE_REG + EN_RXADDR, 0x01); /*接收通道0有效数据宽度设置*/ writeReg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); /*接收通道自动应答设置,使能通道0自动应答*/ writeReg(WRITE_REG + EN_AA, 0x01); /*设置通信频率*/ /*计算公式:F=2400+RF_CH(MHz),从2.4G到2.525G,共125个频点可用*/ writeReg(WRITE_REG + RF_CH, 50); /*设置发射参数:传输速率,发射功率等*/ writeReg(WRITE_REG + RF_SETUP, 0x07); //速率1Mbps,功率最大0dBm,低噪声放大器增益 /*配置基本参数*/ /*开启IRQ引脚的三种中断,16位CRC校验,上电,接收模式*/ writeReg(WRITE_REG + CONFIG, 0x0F); /*CE拉高,130us后开始等待数据包*/ NRF_CE = 1; } /************************************************** * 参数: *txbuf -> 要发送的数据包 * 返回值:发送成功与否的状态 **************************************************/ unsigned char DX_Nrf24L01::sendData(unsigned char *txbuf) { unsigned char status; /*CE置低,进入待机模式*/ NRF_CE = 0; /*写数据包到TX FIFO,最大32个字节*/ writeBuf(WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH); /*CE置高,10us后发送数据包 */ NRF_CE = 1; /*等待发送完成,IRQ中断引脚会被拉低 */ while(NRF_IRQ !=0); /*读取状态寄存器STATUS的值 */ status = readReg(STATUS); /*向STATUS的相应位写'1',清除相应的中断标志*/ writeReg(WRITE_REG + STATUS, status); writeReg(WRITE_REG + STATUS, NOP); /*清除FIFO状态寄存器*/ writeReg(FIFO_STATUS, NOP); /*判断中断类型*/ if(status & TX_DS) //1、发送完成 return TX_DS; else if(status & MAX_RT) //2、达到最大重发次数 return MAX_RT; else return ERROR; //3、其它不明原因导致的发送失败 } /************************************************** * 参数: *rxbuf -> 接收的数据包的存放位置 * 返回值:接收成功与否的状态 **************************************************/ unsigned char DX_Nrf24L01::receiveData(unsigned char *rxbuf) { unsigned char status; /*CE置高,130us后开始接收数据包 */ NRF_CE = 1; /*等待接收完成,IRQ中断引脚会被拉低 */ while(NRF_IRQ !=0); /*CE置低,进入待机模式*/ NRF_CE = 0; /*读取状态寄存器STATUS的值 */ status = readReg(STATUS); /*向STATUS的相应位写'1',清除相应的中断标志*/ writeReg(WRITE_REG + STATUS, status); writeReg(WRITE_REG + STATUS, NOP); /*清除FIFO状态寄存器*/ writeReg(FIFO_STATUS, NOP); /*判断中断类型*/ if(status & RX_DR) //1、接收完成 { /*从RX FIFO读出数据包*/ readBuf(RD_RX_PLOAD, rxbuf, RX_PLOAD_WIDTH); return RX_DR; } else return ERROR; //2、其它不明原因导致的接收失败 } /************************************************** * 检查MCU与NRF24L01连接是否正常 **************************************************/ unsigned char DX_Nrf24L01::checkConnect(void) { unsigned char wbuf[5]={0xC2,0xC2,0xC2,0xC2,0xC2}; unsigned char rbuf[5]; unsigned char i=0; NRF_CSN = 0; // CSN置低,使能数据传输 NRF_CE = 0; //待机模式,才能对寄存器写操作 /*尝试向TX_ADDR写入5个字节*/ writeBuf(WRITE_REG + TX_ADDR, wbuf, 5); /*再从TX_ADDR读出刚写入的5个字节*/ readBuf(TX_ADDR, rbuf, 5); /*比较,完全匹配则说明连接正常*/ for(i=0; i<5; i++) { if(rbuf!=0xC2) break; } if(i==5) return SUCCESS; //MCU与NRF连接成功 else return ERROR; //MCU与NRF连接失败 } |
|
|
|
点H头文件如下,主要是类的封装。
#ifndef __DX_NRF24L01_H__ #define __DX_NRF24L01_H__ #include "iostm8s105c6.h" #define SUCCESS 0 #define ERROR !SUCCESS /*地址宽度定义*/ #define TX_ADDR_WIDTH 5 //发射节点的地址宽度 #define RX_ADDR_WIDTH 5 //接收节点的地址宽度 /*数据宽度定义*/ #define TX_PLOAD_WIDTH 13 //发送数据的有效宽度,即一包数据包含的字节数 #define RX_PLOAD_WIDTH 13 //接收数据的有效宽度,即一包数据包含的字节数 /*标志位定义*/ #define RX_DR 0x40 //接收完成标志,状态寄存器的第6位 #define TX_DS 0x20 //发送完成标志,状态寄存器的第5位 #define MAX_RT 0x10 //重发最大次数标志,状态寄存器的第4位 /*一共8条指令码定义*/ #define READ_REG 0x00 // Define read command to register #define WRITE_REG 0x20 // Define write command to register #define RD_RX_PLOAD 0x61 // Define RX payload register address #define WR_TX_PLOAD 0xA0 // Define TX payload register address #define FLUSH_TX 0xE1 // Define flush TX register command #define FLUSH_RX 0xE2 // Define flush RX register command #define REUSE_TX_PL 0xE3 // Define reuse TX payload register command #define NOP 0xFF // Define No Operation, might be used to read status /*NRF寄存器地址定义*/ #define CONFIG 0x00 // 'Config' register address #define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address #define EN_RXADDR 0x02 // 'Enabled RX addresses' register address #define SETUP_AW 0x03 // 'Setup address width' register address #define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address #define RF_CH 0x05 // 'RF channel' register address #define RF_SETUP 0x06 // 'RF setup' register address #define STATUS 0x07 // 'Status' register address #define OBSERVE_TX 0x08 // 'Observe TX' register address #define CD 0x09 // 'Carrier Detect' register address #define RX_ADDR_P0 0x0A // 'RX address pipe0' register address #define RX_ADDR_P1 0x0B // 'RX address pipe1' register address #define RX_ADDR_P2 0x0C // 'RX address pipe2' register address #define RX_ADDR_P3 0x0D // 'RX address pipe3' register address #define RX_ADDR_P4 0x0E // 'RX address pipe4' register address #define RX_ADDR_P5 0x0F // 'RX address pipe5' register address #define TX_ADDR 0x10 // 'TX address' register address #define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address #define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address #define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address #define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address #define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address #define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address #define FIFO_STATUS 0x17 // 'FIFO Status Register' register address /**************引脚定义**************************/ #define SPI_MOSI PC_ODR_ODR6 #define SPI_MISO PC_IDR_IDR7 #define SPI_SCK PC_ODR_ODR5 #define NRF_CE PG_ODR_ODR0 #define NRF_CSN PC_ODR_ODR3 #define NRF_IRQ PC_IDR_IDR4 class DX_Nrf24L01 { private: /*节点地址定义*/ unsigned char TX_ADDRESS[TX_ADDR_WIDTH]; unsigned char RX_ADDRESS_P0[RX_ADDR_WIDTH]; /*封闭函数声明*/ void initGpio(void); void initArray(void); unsigned char readOrWrite(unsigned char byte); unsigned char readReg (unsigned char reg); unsigned char readBuf(unsigned char reg, unsigned char * pBuf, unsigned char bytes); unsigned char writeReg (unsigned char reg, unsigned char value); unsigned char writeBuf(unsigned char reg, unsigned char * pBuf, unsigned char bytes); public: void TX_Mode(void); void RX_Mode(void); unsigned char sendData(unsigned char *txbuf); unsigned char receiveData(unsigned char *rxbuf); unsigned char checkConnect(void); DX_Nrf24L01(); }; #endif main文件应用如下:主要是实现收发数据的测试以及硬件连接的检测。 #include "DX_nrf24L01.h" #include "DX_uart2.h" #include "DX_delay.h" //实例化设备对象 DX_Nrf24L01 NRF24L01; DX_Delay Delay; extern DX_Uart2 Uart2; unsigned char TX_Buf[TX_PLOAD_WIDTH]= "GDUTELC-2015"; //要发送的数据可以是单个字节数据,也可以是字符串 unsigned char RX_Buf[RX_PLOAD_WIDTH]; unsigned char Status=0; int main(void) { while(1) { Status = NRF24L01.checkConnect(); if(Status==SUCCESS) Uart2.sendStr((unsigned char*)"MCU与NRF24L01连接成功! rn"); else Uart2.sendStr((unsigned char*)"MCU与NRF24L01连接失败! rn"); NRF24L01.RX_Mode(); //发送成功后马上转为接收模式, //等待从机将接收到的数据原封不动地发回来 Uart2.sendStr((unsigned char*)"当前设置为:接收模式!rn"); Status = NRF24L01.receiveData(RX_Buf); //接收从机发回的数据,同时返回接收状态 if(Status==RX_DR) { Uart2.sendStr((unsigned char*)"数据接收成功!rn"); Uart2.sendStr((unsigned char*)"已接收数据:"); Uart2.sendStr(RX_Buf); Uart2.sendStr((unsigned char*)"rnrn"); } else Uart2.sendStr((unsigned char*)"数据接收失败rnrn"); NRF24L01.TX_Mode(); Uart2.sendStr((unsigned char*)"当前设置为:发射模式!rn"); Status = NRF24L01.sendData(TX_Buf); //发送数据,同时返回发送状态 if(Status==TX_DS) { Uart2.sendStr((unsigned char*)"数据发送成功!rn"); Uart2.sendStr((unsigned char*)"已发送数据:"); Uart2.sendStr(TX_Buf); Uart2.sendStr((unsigned char*)"rnrn"); } else if(Status==MAX_RT) Uart2.sendStr((unsigned char*)"达到最大重发次数!rnrn"); else Uart2.sendStr((unsigned char*)"数据发送失败rnrn"); Delay.delayS(4); } return 0; } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1632 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1559 浏览 1 评论
985 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1605 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
653浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
523浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 14:15 , Processed in 1.003144 second(s), Total 81, Slave 64 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号