您的位置:首页 > 编程语言 > C语言/C++

C++在STM8单片机上封装NRF24L01模块

2016-06-13 19:34 387 查看
本文只要是以软件模拟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[i] = TX_ADDRESS[i];

this->RX_ADDRESS_P0[i] = RX_ADDRESS_P0[i];

}

}

/**************************************************

* 初始化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<bytes; 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<bytes; 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[i]!=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连接成功! \r\n");

else

Uart2.sendStr((unsigned char*)"MCU与NRF24L01连接失败! \r\n");

NRF24L01.RX_Mode(); //发送成功后马上转为接收模式,

//等待从机将接收到的数据原封不动地发回来

Uart2.sendStr((unsigned char*)"当前设置为:接收模式!\r\n");

Status = NRF24L01.receiveData(RX_Buf);
//接收从机发回的数据,同时返回接收状态

if(Status==RX_DR)

{

Uart2.sendStr((unsigned char*)"数据接收成功!\r\n");

Uart2.sendStr((unsigned char*)"已接收数据:");

Uart2.sendStr(RX_Buf);

Uart2.sendStr((unsigned char*)"\r\n\r\n");

}

else

Uart2.sendStr((unsigned char*)"数据接收失败\r\n\r\n");

NRF24L01.TX_Mode();

Uart2.sendStr((unsigned char*)"当前设置为:发射模式!\r\n");

Status = NRF24L01.sendData(TX_Buf);
//发送数据,同时返回发送状态

if(Status==TX_DS)

{

Uart2.sendStr((unsigned char*)"数据发送成功!\r\n");

Uart2.sendStr((unsigned char*)"已发送数据:");

Uart2.sendStr(TX_Buf);

Uart2.sendStr((unsigned char*)"\r\n\r\n");

}

else if(Status==MAX_RT)

Uart2.sendStr((unsigned char*)"达到最大重发次数!\r\n\r\n");

else

Uart2.sendStr((unsigned char*)"数据发送失败\r\n\r\n");

Delay.delayS(4);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: