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

本文只要是以软件模拟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;
}



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本遥控小车是使用STM8S105K4T6为主控芯片设计的一款遥控接收玩具小车,采用nrf24l01模块作为发射及接收,OLED 屏幕可以实时关注系统电量以及系统状态,是一个完完整整的从底层硬件撸到demo和3D结构的完整项目,遥控板和接收板都是自行设计,接口丰富,二次开发省时省力。为了方便二次开发,写了一个使用手册文档和录制了两个视频教程,一个是代码整体架构简介(16分钟),另一个是如何编译并下载程序到遥控板及接收板(5分钟),视频讲的很一般,但看明白应该问题不大。小车支持控制两路电机的前进后退左转右转加减速(使用TB6612作为驱动ic);支持四路舵机控制(小车目前只使用两路舵机);支持三路开关通断控制,在小车上则其中一路作为激光,一路作为水弹枪开关,预留一路(使用mos管作为开关管);支持超声波距离检测;电量显示(遥控板有OLED 屏幕)等。每个功能遥控板都有对应的按键或电位器控制,接收板有对应的接口。同时也可以根据自己的意愿在原代码基础上开发出自己想要的特殊功能的遥控车,这可以减少大家的宝贵时间。接出了串口2接口可方便开发。虽然小车的默认功能是水弹枪遥控小车,而且只使用了两路的舵机接口,但可以轻松实现为4通道械臂小车,遥控消防小车,遥控船等其他不同功能的遥控作品。 注:小车遥控板采用1个18650电池供电,使用LDO降压供电方式,非常省电,同时,电路板上有tp4056电池充电电路,没电时直接用USB线插入板上充电口,连接手机充电器即可实现充电,充满电板上的LED由红变绿。 接收板没有设计充电电路,小车的供电为两个18650串联组成8.4V电池组。但为了方便,特别设计了一个双路充电板,分别支持单节锂电4.2V充电和双节锂电8.4V充电。其中单节锂电充电电路采用tp4056充电ic,和遥控板上的一样,而5V转8.4V充电电路则采用专门的5V转8.4V充电ic,可以将手机充电器的5V输出转化为8.4V给两串的电池组充电,充电电流为1A,该电路板支持安卓口,USB2.0和USB typeC三种接口,基本上用我们手机的充电线和手机充电器就可以给小车充电,非常方便。使用方法也很简单,将电池插头和接收板拔开,再将电池插头和这个充电器预留的8.4V插头接好,再用手机充电器给这个充电板供电即可,充满电充电板上的LED会自动熄灭。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值