nRF24L01 使用心得

为了方便大家测试程序,先将程序开发环境说明一下,程序是在 STC15W4K56S4 上开发的,开发板,nRF24L01 无线模块都是某宝淘来的.

nRF24L01 使用心得_第1张图片
nRF24L01 使用心得_第2张图片

原理图 PDF: https://download.csdn.net/download/longzhishen/10407195

  • 硬件准备就绪后,开始写程序
    打开 这里写图片描述
    新建一个项目
    nRF24L01 使用心得_第3张图片
    nRF24L01 使用心得_第4张图片
    nRF24L01 使用心得_第5张图片
    nRF24L01 使用心得_第6张图片
    nRF24L01 使用心得_第7张图片

好,项目新建好了,现在开始添加文件
分别添加新建以下几个文件
1.main.c // 主文件
2.nRF24L01.h/nRF24L01.c // nRF24L01 驱动
3.Sys.h/Sys.c // 包含单片机内部资源的一些文件(定时器/UART/SPI…等驱动)
4.Constant.h/Variable.c // 常量和变量

首先是 main.c

#include "Constant.h"
#include "nRF24L01.h"
#include "sys.h"

char str[16]="Hello World 0\r\n";

void nRF24L01_Process()
{
    #if(NRF24L01_RF_MODE == NRF24L01_TX_MODE)
        unsigned char n;

        if(Sys_Flag_A.nRF24L01_Send_Data_Flag)              // 这是一个标志, 放在 UpdateClock() 中, 每 1 秒会更新一次
        {
            Sys_Flag_A.nRF24L01_Send_Data_Flag = 0;

            SendString_1("RF24L01 Send Data \r\n");
            n = nRF24L01_Tx_Packet(str, 16);
            if(n == TX_OK)                                  // 发射是否成功
                SendString_1("RF24L01 Send OK \r\n");       // 成功
            else if(n == MAX_TX)
                SendString_1("RF24L01 Send MAX_TX \r\n");   // 超时
            else
                SendString_1("RF24L01 Send Fail \r\n");     // 发射失败


            str[12]++;
            if(str[12] > '9')
                str[12] = '0';
            RED_LED = 1;
        }
    #else
        RED_LED = ~RED_LED;
        nRF24L01_Buf_Size = nRF24L01_Rx_Packet(RxPayload);

        // 是否接收到数据
        if(nRF24L01_Buf_Size)
        {
            Send_Data_Buf_1(RxPayload, nRF24L01_Buf_Size);              // 发送接收到的数据到 串口 1
            nRF24L01_Buf_Size = 0;
        }
    #endif
}

void Sys_Init(void)
{
    /* 
       P0M1     P0M0
        0 ------ 0    准双向口
        0 ------ 1    推挽输出(强上拉输出,可达 20mA,要加限流电阻)
        1 ------ 0    高阻输入(电流既不能流入,也不能流出)
        1 ------ 1    开漏,内部上拉电阻断开,开漏模式即可读外部状态,也可对外输出(高电平、低电平),需外部加上拉电阻
    */
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;

    CLK_DIV &= 0xF8;      // 主时钟频率/1 不分频
    _nop_();
    _nop_();
    /*
        0x00    主时钟频率/1 不分频
        0x01    主时钟频率/2
        0x02    主时钟频率/4
        0x03    主时钟频率/8
        0x04    主时钟频率/16
        0x05    主时钟频率/32
        0x06    主时钟频率/64
        0x07    主时钟频率/128

        如果改变 系统时钟 则串口波特率会变
    */
    CLK_DIV |= 0x00;      // 主时钟频率/1

    _nop_();
    _nop_();
    _nop_();
    _nop_();

    Clock_Init();
    SPI_Init();
    Uart_1_Init();
    nRF24L01_Init();
    Time0_Init();
}


void main()
{
    Sys_Init();

    while(1)
    {
        UpdateClock();              // 时钟更新
        nRF24L01_Process();         // nRF24L01 数据收发处理
    }
}

nRF24L01.h 文件

#ifndef _NRF24L01_H_
#define _NRF24L01_H_

#include "Constant.h"
#include "sys.h"

// nRF24L01 工作模式, 发射模式/接收模式
#define NRF24L01_TX_MODE            (0)                     // 接收模式/主机
#define NRF24L01_RX_MODE            (1)                     // 接收模式/从机
#define NRF24L01_RF_MODE            NRF24L01_TX_MODE


/** 从机通道设置 */
#define RX_CHANGE_0         (0x01)
#define RX_CHANGE_1         (0x02)
#define RX_CHANGE_2         (0x04)
#define RX_CHANGE_3         (0x08)
#define RX_CHANGE_4         (0x10)
#define RX_CHANGE_5         (0x20)
#define RF_RX_CHANGE        (RX_CHANGE_2)                   // 从机通道选择


#define DYNAMIC_PACKET      1                               // 1:动态包, 0: 固定
#define FIXED_PACKET_LEN    32                              // 包长度
#define REPEAT_CNT          15                              // 重复次数

#if(NRF24L01_RF_MODE == NRF24L01_TX_MODE)
    #define RF_TX_CHANGE            (0x3F)                  // 发射模式要打通所以 接收通道
    #define RF_CHANGE               (RF_TX_CHANGE)
#else
    #define RF_CHANGE               (RX_CHANGE_0)           // 接收模式通道
#endif



/** RF24L01 硬件接口定义 */

#define NRF24L01_CE             SPI_CE
#define NRF24L01_IRQ            SPI_IRQ
#define NRF24L01_CS             SPI_NSS


/** I/O 口操作函数 */
#define NRF24L01_SET_CE_HIGH()          NRF24L01_CE = 1
#define NRF24L01_SET_CE_LOW()           NRF24L01_CE = 0

#define NRF24L01_SET_CS_HIGH()          SPI_SET_NSS_HIGH()
#define NRF24L01_SET_CS_LOW()           SPI_SET_NSS_LOW()

#define RF24L01_GET_IRQ_STATUS()        (( 1 != NRF24L01_IRQ ) ? 0 : 1 )

typedef enum ModeType
{
    MODE_TX = 0,
    MODE_RX
}nRf24l01ModeType;

typedef enum SpeedType
{
    SPEED_250K = 0,
    SPEED_1M,
    SPEED_2M
}nRf24l01SpeedType;

typedef enum PowerType
{
    POWER_F18DBM = 0,
    POWER_F12DBM,
    POWER_F6DBM,
    POWER_0DBM
}nRf24l01PowerType;

//NRF24L01 寄存器操作命令
#define NRF_READ_REG        0x00    // 读配置寄存器, 低 5 位为寄存器地址
#define NRF_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 R_RX_PL_WID         0x60
#define NOP                 0xFF    // 空操作, 可以用来读取状态寄存器
#define W_ACK_PLOAD         0xA8
#define WR_TX_PLOAD_NACK    0xB0
// SPI ( nRF24L01 ) 寄存器地址
/*
配置寄存器地址,    Bit0:   1       接收模式
                            0       发射模式
                    Bit1:           电选择
                    Bit2:           CRC 模式
                    Bit3:           CRC 使能
                    Bit4:           中断 MAX_RT (达到最大重发次数中断) 使能
                    Bit5:           中断 TX_DS 使能
                    Bit6:           中断 RX_DR 使能
*/
#define CONFIG          0x00
#define EN_AA           0x01    // 使能自动应答功能 Bit0 - 5, 对应通道 0 - 5
#define EN_RXADDR       0x02    // 接收地址允许, Bit0 - 5, 对应通道 0 - 5
#define SETUP_AW        0x03    // 设置地址宽度 ( 所有数据通道 ) : Bit0-1: 00 3字节   01 4字节  10 5字节
#define SETUP_RETR      0x04    // 建立自动重发, Bit0-3: 自动重发计数, Bit4-7: 自动重发延时 250 * x + 86us
#define RF_CH           0x05    // RF 通道, Bit0-6: 工作通道频率
#define RF_SETUP        0x06    // RF 寄存器, Bit3: 传输速度 (0: 1 Mbps, 1: 2 Mbps), Bit1-2: 发射功率, Bit0: 低噪声发大器增益
#define STATUS          0x07    // 状态寄存器, Bit0: RX FIFO 满标志, Bit1-3: 接收数据通道号 (最大: 6 ), Bit4: 达到最多次重发, Bit5: 数据发送完成中断, Bit6: 接收数据中断
#define MAX_TX          0x10    // 达到最大发送次数中断
#define TX_OK           0x20    // TX 发送完成中断
#define RX_OK           0x40    // 接收到数据中断

#define OBSERVE_TX      0x08    // 发送检测寄存器, Bit4-7: 数据包丢失计数器, Bit0-3: 重发计数器
#define CD              0x09    // 载波检测寄存器, Bit0: 载波检测
#define RX_ADDR_P0      0x0A    // 数据通道 0 接收地址, 最大长度 5 个字节, 低字节在前
#define RX_ADDR_P1      0x0B    // 数据通道 1 接收地址, 最大长度 5 个字节, 低字节在前
#define RX_ADDR_P2      0x0C    // 数据通道 2 接收地址, 最低字节可设置, 高字节必须同 RX_ADDR_P1[39:8]相等
#define RX_ADDR_P3      0x0D    // 数据通道 3 接收地址, 最低字节可设置, 高字节必须同 RX_ADDR_P1[39:8]相等
#define RX_ADDR_P4      0x0E    // 数据通道 4 接收地址, 最低字节可设置, 高字节必须同 RX_ADDR_P1[39:8]相等
#define RX_ADDR_P5      0x0F    // 数据通道 5 接收地址, 最低字节可设置, 高字节必须同 RX_ADDR_P1[39:8]相等
#define TX_ADDR         0x10    // 发送地址 (低字节在前), ShockBurstTM 模式下, RX_ADDR_P0 与地址相等
#define RX_PW_P0        0x11    // 接收数据通道 0 有效数据宽度 (1-32字节), 设置为 0 则非法
#define RX_PW_P1        0x12    // 接收数据通道 1 有效数据宽度 (1-32字节), 设置为 0 则非法
#define RX_PW_P2        0x13    // 接收数据通道 2 有效数据宽度 (1-32字节), 设置为 0 则非法
#define RX_PW_P3        0x14    // 接收数据通道 3 有效数据宽度 (1-32字节), 设置为 0 则非法
#define RX_PW_P4        0x15    // 接收数据通道 4 有效数据宽度 (1-32字节), 设置为 0 则非法
#define RX_PW_P5        0x16    // 接收数据通道 5 有效数据宽度 (1-32字节), 设置为 0 则非法
#define FIFO_STATUS     0x17    // FIFO 状态寄存器, Bit0: RX FIFO 寄存器空标志, Bit1 RX FIFO 满标志, Bit2-3 保留
                                // Bit4 TX FIFO 空标志, Bit5 TX FIFO 满标志, Bit6 1 循环发送上一次数据包, 0 不循环
#define DYNPD           0x1C    // 启用动态数据长度, Bit6-7: NULL, Bit5: 启用动态数据长度管道 5
#define FEATRUE         0x1D    // 功能寄存器, Bit3-7: 无用,总是为 0, Bit2: 启用动态数据长度, Bit1: 启用 ACK, Bit0: 启用 W_TX_PAYLOAD_NOACK 命令

//???
#define MASK_RX_DR      6 
#define MASK_TX_DS      5 
#define MASK_MAX_RT     4 
#define EN_CRC          3 
#define CRCO            2 
#define PWR_UP          1 
#define PRIM_RX         0 

#define ENAA_P5         5 
#define ENAA_P4         4 
#define ENAA_P3         3 
#define ENAA_P2         2 
#define ENAA_P1         1 
#define ENAA_P0         0 

#define ERX_P5          5 
#define ERX_P4          4 
#define ERX_P3          3 
#define ERX_P2          2 
#define ERX_P1          1 
#define ERX_P0          0 

#define AW_RERSERVED    0x0 
#define AW_3BYTES       0x1
#define AW_4BYTES       0x2
#define AW_5BYTES       0x3

#define ARD_250US       (0x00<<4)
#define ARD_500US       (0x01<<4)
#define ARD_750US       (0x02<<4)
#define ARD_1000US      (0x03<<4)
#define ARD_2000US      (0x07<<4)
#define ARD_4000US      (0x0F<<4)
#define ARC_DISABLE     0x00
#define ARC_15          0x0F

#define CONT_WAVE       7 
#define RF_DR_LOW       5 
#define PLL_LOCK        4 
#define RF_DR_HIGH      3 
//bit2-bit1:
#define PWR_18DB        (0x00<<1)
#define PWR_12DB        (0x01<<1)
#define PWR_6DB         (0x02<<1)
#define PWR_0DB         (0x03<<1)

#define RX_DR           6 
#define TX_DS           5 
#define MAX_RT          4 
//for bit3-bit1, 
#define TX_FULL_0       0 

#define RPD             0 

#define TX_REUSE        6 
#define TX_FULL_1       5 
#define TX_EMPTY        4 
//bit3-bit2, reserved, only '00'
#define RX_FULL         1 
#define RX_EMPTY        0 

#define DPL_P5          5 
#define DPL_P4          4 
#define DPL_P3          3 
#define DPL_P2          2 
#define DPL_P1          1 
#define DPL_P0          0 

#define EN_DPL          2 
#define EN_ACK_PAY      1 
#define EN_DYN_ACK      0 
#define IRQ_ALL  ( (1<

extern unsigned char nRF24L01_Buf_Size;
extern xdata unsigned char TxPayload[32];
extern xdata unsigned char RxPayload[32];

unsigned char nRF24L01_Read_Reg( unsigned char RegAddr );                                                                           // 读取 nRF24L01 寄存器
unsigned char nRF24L01_Read_Buf(unsigned char Reg_Addr, unsigned char *pBuf, unsigned char len);                                    // 读取 nRF24L01 数据
void nRF24L01_Write_Reg(unsigned char Reg_Addr, unsigned char dat);                                                                 // 写 nRF24L01 寄存器
void nRF24L01_Write_Buf(unsigned char Reg_Addr, unsigned char *pBuf, unsigned char len);                                            // 写 nRF24L01 数据
void nRF24L01_Flush_Tx_Fifo ( void );                                                                                               // 清发送 FIFO 缓存
void nRF24L01_Flush_Rx_Fifo( void );                                                                                                // 清接收 FIFO 缓存
void nRF24L01_Reuse_Tx_Payload( void );
void nRF24L01_Nop( void );
unsigned char nRF24L01_Read_Status_Register( void );                                                                                // 读取状态寄存器
unsigned char nRF24L01_Clear_IRQ_Flag( unsigned char IRQ_Source );                                                                  // 清中断标志
unsigned char nRF24L01_Read_IRQ_Status( void );
unsigned char nRF24L01_Read_Top_Fifo_Width( void );
unsigned char nRF24L01_Read_Rx_Payload( unsigned char *pRxBuf );
void nRF24L01_Write_Tx_Payload_Ack( unsigned char *pTxBuf, unsigned char len );
void nRF24L01_Write_Tx_Payload_NoAck( unsigned char *pTxBuf, unsigned char len );
void nRF24L01_Write_Tx_Payload_InAck( unsigned char *pData, unsigned char len );
void nRF24L01_Set_TxAddr( unsigned char *pAddr, unsigned char len );
void nRF24L01_Set_RxAddr( unsigned char PipeNum, unsigned char *pAddr, unsigned char Len );
void nRF24L01_Set_Speed( nRf24l01SpeedType Speed );
void nRF24L01_Set_Power( nRf24l01PowerType Power );
void nRF24LL01_Write_Hopping_Point( unsigned char FreqPoint );
void nRF24L01_Set_Mode( nRf24l01ModeType Mode );                                                                                    // 设置 nRF24L01 工作模式,发射/接收(主机/从机)
unsigned char nRF24L01_Check( void );                                                                                               // 检测 nRF24L01 模块
unsigned char nRF24L01_Tx_Packet( unsigned char *txbuf, unsigned char Length );                                                     // 通过 nRF24L01 发送数据包
unsigned char nRF24L01_Rx_Packet( unsigned char *rxbuf );                                                                           // 从 nRF24L01 接收数据包
void nRF24L01_Init( void );                                                                                                         // 初始化 nRF24L01 模块


#endif

nRF24L01.c 文件

#include "nRF24L01.h"

unsigned char nRF24L01_Buf_Size;
xdata unsigned char TxPayload[32];
xdata unsigned char RxPayload[32];


unsigned char code INIT_ADDR0[5]={0x02,0x3A,0xB1,0xB1,0x01};
unsigned char code INIT_ADDR1[5]={0x02,0x3A,0x01,0x01,0x01};
unsigned char code INIT_ADDR2[5]={0x03,0x3A,0x01,0x01,0x01};
unsigned char code INIT_ADDR3[5]={0x04,0x3A,0x01,0x01,0x01};
unsigned char code INIT_ADDR4[5]={0x05,0x3A,0x01,0x01,0x01};
unsigned char code INIT_ADDR5[5]={0x06,0x3A,0x01,0x01,0x01};


/**
 * @brief :NRF24L01 读寄存器
 * @param :
          @Addr: 寄存器地址
 * @note  : 地址在设备中有效
 * @retval: 读数据
 */
unsigned char nRF24L01_Read_Reg(unsigned char Reg_Addr)
{
    unsigned reg_val;

    NRF24L01_SET_CS_LOW();                      // 片选

    SPI_Read_Write_Byte(Reg_Addr);              // 读命令地址
    reg_val = SPI_Read_Write_Byte(0xFF);        // 读数据

    NRF24L01_SET_CS_HIGH();

    return reg_val;
}

/**
  * @brief :NRF24L01 读指定长度数据
  * @param :
  *         @reg: 地址
  *         @pBuf: 数据存放地址
  *         @len: 数据长度
  * @note  : 数据长度不超过 255, 地址在设备中有效
  * @retval: 读取状态
  */
unsigned char nRF24L01_Read_Buf(unsigned char Reg_Addr, unsigned char *pBuf, unsigned char len)
{
    unsigned char status, i;

    NRF24L01_SET_CS_LOW();                          // 片选

    status = SPI_Read_Write_Byte(Reg_Addr);         // 读命令地址

    for(i=0; i0xFF);        // 读数据
    }

    NRF24L01_SET_CS_HIGH();

    return status;
}

/**
 * @brief :NRF24L01 写寄存器
 * @param :无
 * @note  :地址在设备中有效
 * @retval:读写状态
 */
void nRF24L01_Write_Reg(unsigned char Reg_Addr, unsigned char dat)
{   
    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte(NRF_WRITE_REG | Reg_Addr);
    SPI_Read_Write_Byte(dat);

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief :NRF24L01 写指定长度数据
  * @param :
  *         @reg: 地址
  *         @pBuf: 写入的数据地址
  *         @len: 数据长度
  * @note  : 数据长度不超过 255, 地址在设备中有效
  * @retval:
  */
void nRF24L01_Write_Buf(unsigned char Reg_Addr, unsigned char *pBuf, unsigned char len)
{
    unsigned char i;

    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte(NRF_WRITE_REG | Reg_Addr);

    for(i=0; i/**
  * @brief : 清空 TX 缓冲区
  * @param : 无
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Flush_Tx_Fifo ( void )
{
    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( FLUSH_TX );    // 清空 TX FIFO 命令

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief : 清空 RX 缓冲区
  * @param : 无
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Flush_Rx_Fifo( void )
{
    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( FLUSH_RX );    // 清 RX FIFO 命令

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief : 重新使用上一包数据
  * @param : 无
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Reuse_Tx_Payload( void )
{
    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( REUSE_TX_PL );     // 重新使用上一包命令

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief : NRF24L01 空操作
  * @param : 无
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Nop( void )
{
    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte(NOP);

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief :NRF24L01 读状态寄存器
  * @param :无
  * @note  :无
  * @retval:RF24L01 状态
  */
unsigned char nRF24L01_Read_Status_Register( void )
{
    unsigned char Status;

    NRF24L01_SET_CS_LOW();

    Status = SPI_Read_Write_Byte( NRF_READ_REG + STATUS );  // 读取状态寄存器

    NRF24L01_SET_CS_HIGH(); 

    return Status;
}


/**
 * @brief : NRF24L01 清中断
 * @param :
          @IRQ_Source: 中断源
 * @note  : 无
 * @retval: 清除后状态寄存器的值
 */
unsigned char nRF24L01_Clear_IRQ_Flag( unsigned char IRQ_Source )
{
    unsigned char btmp = 0;

    IRQ_Source &= ( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT );    // 中断标志处理
    btmp = nRF24L01_Read_Status_Register();                             // 读状态寄存器

    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( NRF_WRITE_REG + STATUS );                      // 写状态寄存器命令
    SPI_Read_Write_Byte( IRQ_Source | btmp );                           // 清相应中断标志

    NRF24L01_SET_CS_HIGH();

    return ( nRF24L01_Read_Status_Register( ));                         // 返回状态寄存器状态
}


/**
  * @brief : 读 RF24L01 中断状态
  * @param : 无
  * @note  : 无
  * @retval: 中断状态
  */
unsigned char nRF24L01_Read_IRQ_Status( void )
{
    return ( nRF24L01_Read_Status_Register( ) & (( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT )));   // 返回中断状态
}


/**
  * @brief : 读 FIFO 中数据宽度
  * @param : 无
  * @note  : 无
  * @retval: 数据宽度
  */
unsigned char nRF24L01_Read_Top_Fifo_Width( void )
{
    unsigned char btmp;

    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( R_RX_PL_WID );         // 读 FIFO 中数据宽度命令
    btmp = SPI_Read_Write_Byte( 0xFF );         // 读数据

    NRF24L01_SET_CS_HIGH();

    return btmp;
}


/**
  * @brief : 读接收到的数据
  * @param : 无
  * @note  : 无
  * @retval:
           @pRxBuf: 数据存放地址首地址
  */
unsigned char NRF24L01_Read_Rx_Payload( unsigned char *pRxBuf )
{
    unsigned char Width, i;

    i = ( nRF24L01_Read_Reg( STATUS ) >> 1 ) & 0x07;                // 读接收状态
    Width = nRF24L01_Read_Top_Fifo_Width( );                        // 读接收数据个数

    NRF24L01_SET_CS_LOW();
    SPI_Read_Write_Byte( RD_RX_PLOAD );                             // 读有效数据命令

    for( i=0; i0xFF );                    // 读数据
    }
    NRF24L01_SET_CS_HIGH();

    nRF24L01_Flush_Rx_Fifo();                                       // 情空 RX FIFO

    return Width;
}


/**
  * @brief : 发送数据 ( 带应答 )
  * @param :
  *         @pTxBuf: 发送数据地址
  *         @len: 长度
  * @note  : 一次不超过 32 个字节
  * @retval: 无
  */
void nRF24L01_Write_Tx_Payload_Ack( unsigned char *pTxBuf, unsigned char len )
{
    unsigned char btmp;
    unsigned char length = ( len > 32 ) ? 32 : len;     // 数据长度超过 32 则只发送 32 个

    nRF24L01_Flush_Tx_Fifo();                           // 清 TX FIFO

    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( WR_TX_PLOAD );                 // 发送命令

    for( btmp=0; btmp// 发送数据
    }

    NRF24L01_SET_CS_HIGH();
}


 /**
  * @brief : 发送数据 ( 不带应答 )
  * @param :
  *         @pTxBuf: 发送数据地址
  *         @len: 长度
  * @note  : 一次不超过 32 个字节
  * @retval: 无
  */
void NRF24L01_Write_Tx_Payload_NoAck( unsigned char *pTxBuf, unsigned char len )
{
    if( len > 32 || len == 0 )
    {
        return ;        // 数据长度大于 32 或者等于 0 则不执行
    }

    NRF24L01_SET_CS_LOW();
    SPI_Read_Write_Byte( WR_TX_PLOAD_NACK );    // 发送命令

    while( len-- )
    {
        SPI_Read_Write_Byte( *pTxBuf++ );           // 发送数据
    }

    NRF24L01_SET_CS_HIGH();
}


 /**
  * @brief : 在接收模式下向 TX FIFO 写数据 (带 ACK )
  * @param :
  *         @pData: 数据地址
  *         @len: 长度
  * @note  : 一次不超过 32 个字节
  * @retval: 无
  */
void NRF24L01_Write_Tx_Payload_InAck( unsigned char *pData, unsigned char len )
{
    unsigned char btmp;

    len = ( len > 32 ) ? 32 : len;                      // 数据长度大于 32 个则只写 32 个字节

    NRF24L01_SET_CS_LOW();

    SPI_Read_Write_Byte( W_ACK_PLOAD );                 // 命令
    for( btmp = 0; btmp < len; btmp ++ )
    {
        SPI_Read_Write_Byte( *pData++ );                // 写数据
    }

    NRF24L01_SET_CS_HIGH();
}


/**
  * @brief :设置发送地址
  * @param :
  *         @pAddr: 地址存放地址
  *         @len: 长度
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Set_TxAddr( unsigned char *pAddr, unsigned char len )
{
    len = ( len > 5 ) ? 5 : len;                    // 地址不能大于 5 个字节
    nRF24L01_Write_Buf( TX_ADDR, pAddr, len );      // 写地址
}


/**
  * @brief : 设置接收通道地址
  * @param :
  *         @PipeNum: 通道
  *         @pAddr: 地址存放的地址
  *         @Len: 长度
  * @note  : 通道不大于 5 地址长度不大于 5 个字节
  * @retval: 无
  */
void NRF24L01_Set_RxAddr( unsigned char PipeNum, unsigned char *pAddr, unsigned char Len )
{
    Len = ( Len > 5 ) ? 5 : Len;
    PipeNum = ( PipeNum > 5 ) ? 5 : PipeNum;                // 通道不大于 5 地址长度不大于 5 个字节

    nRF24L01_Write_Buf( RX_ADDR_P0 + PipeNum, pAddr, Len ); // 写入地址
}


/**
  * @brief : 设置通信速度
  * @param :
  *         @Speed: 速度
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Set_Speed( nRf24l01SpeedType Speed )
{
    unsigned char btmp = 0;

    btmp = nRF24L01_Read_Reg( RF_SETUP );
    btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );

    if( Speed == SPEED_250K )                   // 250K
    {
        btmp |= ( 1<<5 );
    }
    else if( Speed == SPEED_1M )                // 1M
    {
        btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );
    }
    else if( Speed == SPEED_2M )                // 2M
    {
        btmp |= ( 1<<3 );
    }

    nRF24L01_Write_Reg( RF_SETUP, btmp );
}

 /**
  * @brief : 设置功率
  * @param :
  *         @Power: 功率
  * @note  : 无
  * @retval: 无
  */
void NRF24L01_Set_Power( nRf24l01PowerType Power )
{
    unsigned char btmp;

    btmp = nRF24L01_Read_Reg( RF_SETUP ) & ~0x07;
    switch( Power )
    {
        case POWER_F18DBM:
            btmp |= PWR_18DB;
            break;
        case POWER_F12DBM:
            btmp |= PWR_12DB;
            break;
        case POWER_F6DBM:
            btmp |= PWR_6DB;
            break;
        case POWER_0DBM:
            btmp |= PWR_0DB;
            break;
        default:
            break;
    }
    nRF24L01_Write_Reg( RF_SETUP, btmp );
}

 /**
  * @brief : 设置频率
  * @param :
  *         @FreqPoint: 频率参数
  * @note  : 值不大于 127
  * @retval: 无
  */
void RF24LL01_Write_Hopping_Point( unsigned char FreqPoint )
{
    nRF24L01_Write_Reg(  RF_CH, FreqPoint & 0x7F );
}

/**
  * @brief : nRF24L01 检测
  * @param : 无
  * @note  : 无
  * @retval: 无
  */ 
unsigned char nRF24L01_Check( void )
{
    unsigned char i;
    unsigned char buf[5]={ 0XA5, 0XA5, 0XA5, 0XA5, 0XA5 };
    unsigned char read_buf[ 5 ] = { 0 };


    nRF24L01_Write_Buf( TX_ADDR, buf, 5 );          // 写入 5 个字节的地址
    nRF24L01_Read_Buf( TX_ADDR, read_buf,5 );       // 读出写入的地址

    for( i = 0; i < 5; i++ )
    {
        if( buf[i] != read_buf[i] )
            return false;                           // 读出的值和写入的值不同  
    }

    return true;
}

 /**
  * @brief : 设置模式
  * @param :
  *         @Mode: 发送模式/接收模式
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Set_Mode( nRf24l01ModeType Mode )
{
    unsigned char controlreg = 0;

    controlreg = nRF24L01_Read_Reg( CONFIG );

    if( Mode == MODE_TX )       
    {
        controlreg &= ~( 1<< PRIM_RX );
    }
    else 
    {
        if( Mode == MODE_RX )  
        { 
            controlreg |= ( 1<< PRIM_RX ); 
        }
    }

    nRF24L01_Write_Reg( CONFIG, controlreg );
}

/**
  * @brief : nRF24L01 发送一次数据
  * @param :
  *         @txbuf: 待发送数据的首地址
  *         @Length: 发送数据长度
  * @note  :
  * @retval:
  *         MAX_TX: 达到最大重发次数
  *         TX_OK: 发送完成
  *         0xFF: 其他原因
  */ 
unsigned char nRF24L01_Tx_Packet( unsigned char *txbuf, unsigned char Length )
{
    unsigned char l_Status = 0;
    unsigned int l_MsTimes = 0;

    NRF24L01_SET_CS_LOW();
    SPI_Read_Write_Byte( FLUSH_TX );
    NRF24L01_SET_CS_HIGH();

    NRF24L01_SET_CE_LOW();      
    nRF24L01_Write_Buf( W_ACK_PLOAD, txbuf, Length );   // 写数据到 TX BUF 32 字节  TX_PLOAD_WIDTH
    NRF24L01_SET_CE_HIGH();                             // 启动发送
    while( 0 != RF24L01_GET_IRQ_STATUS())
    {
        Delay1ms(1);
        if( 500 == l_MsTimes++ )                                // 500ms 还没有发送成功, 重新初始化设备
        {
            SendString_1("RF24L01 Reset \r\n");
            SPI_Init();
            nRF24L01_Init();
            nRF24L01_Set_Mode( MODE_TX );
            break;
        }
    }

    l_Status = nRF24L01_Read_Reg(STATUS);                       // 读状态寄存器
    nRF24L01_Write_Reg( STATUS, 0xFF );                     // 清除 TX_DS 或 MAX_RT 中断标志

    if( l_Status & MAX_TX )                                     // 达到最大重发次数
    {
        nRF24L01_Write_Reg( FLUSH_TX,0xFF );                    // 清除 TX FIFO 寄存器
        return MAX_TX; 
    }
    if( l_Status & TX_OK )                                      // 发送完成
    {
        return TX_OK;
    }

    return 0xFF;                                                // 其他原因发送失败
}

/**
  * @brief : nRF24L01 接收数据
  * @param :
  *         @rxbuf: 接收数据存放地址
  * @note  : 无
  * @retval:
  *         0: 接收完成
  *         1: 没有接收到数据
  */ 
unsigned char nRF24L01_Rx_Packet( unsigned char *rxbuf )
{
    unsigned char l_Status = 0, l_RxLength = 0, l_100MsTimes = 0;

    NRF24L01_SET_CS_LOW();
    SPI_Read_Write_Byte( FLUSH_RX );
    NRF24L01_SET_CS_HIGH();


    while( 0 != RF24L01_GET_IRQ_STATUS( ))
    {
        Delay1ms(1);

        if( 10 == l_100MsTimes++ )                          // 10 ms 没有接收到数据, 重新初始化模块
        {
            // 这个地方看实际情况调整
            // SPI_Init();
            // nRF24L01_Init();
            // nRF24L01_Set_Mode( MODE_RX );
            break;
        }
    }

    l_Status = nRF24L01_Read_Reg( STATUS );                 // 读状态寄存器
    nRF24L01_Write_Reg( STATUS,l_Status );                  // 清中断
    if( l_Status & RX_OK)                                   // 接收到数据
    {
        l_RxLength = nRF24L01_Read_Reg( R_RX_PL_WID );      // 读取接收到的数据个数
        nRF24L01_Read_Buf( RD_RX_PLOAD,rxbuf,l_RxLength );  // 接收到数据
        nRF24L01_Write_Reg( FLUSH_RX,0xFF );                // 清除 RX FIFO
        return l_RxLength; 
    }   

    return 0;                                               // 没有收到数据
}

 /**
  * @brief : nRF24L01 模块初始化
  * @param : 无
  * @note  : 无
  * @retval: 无
  */
void nRF24L01_Init( void )
{
    // 检查 nRF24L01 模块是否正常
    if(nRF24L01_Check())
    {
         NRF24L01_SET_CE_HIGH();
        nRF24L01_Clear_IRQ_Flag( IRQ_ALL );


        #if DYNAMIC_PACKET == 1                                         // 动态包

            nRF24L01_Write_Reg( DYNPD, RF_CHANGE );                     // 使能通道 1 动态数据长度
            nRF24L01_Write_Reg( FEATRUE, 0x07 );                        // 0000 01111

        #elif DYNAMIC_PACKET == 0                                       // 固定包长度

            L01_WriteSingleReg( L01REG_RX_PW_P0, FIXED_PACKET_LEN );    // 固定数据长度

        #endif

        nRF24L01_Write_Reg( CONFIG, /*( 1<             // 接收中断
                                        ( 1 << EN_CRC ) |               // 使能 CRC 1 个字节
                                        ( 1 << PWR_UP ) );              // 开启设备
        nRF24L01_Write_Reg( EN_AA, RF_CHANGE );                         // 通道 x 自动应答
        nRF24L01_Write_Reg( EN_RXADDR, RF_CHANGE );                     // 使能 通道 x 接收
        nRF24L01_Write_Reg( SETUP_AW, AW_5BYTES );                      // 地址宽度 5 个字节
        nRF24L01_Write_Reg( SETUP_RETR, ARD_4000US |
                            ( REPEAT_CNT & 0x0F ) );                    // 重复等待时间 4000 US
        nRF24L01_Write_Reg( RF_CH, 1 );                                 // 初始化频率,----------> 这里是可以修改,发射模块接收模块频率必须一样,不然就收不到数据
        nRF24L01_Write_Reg( RF_SETUP, 0x26 );                           // 0010 0110 1M kbps 0dBm
        /* 
            这是 接收 地址, 如果你需要 1 对 6 的话,则 6 个地址都需要设置,
            如果你是 1 对 1 的话, 只设置对应的一个地址就可以
        */
        #if(NRF24L01_RF_MODE == NRF24L01_TX_MODE)                       // 设置 接收 地址
            nRF24L01_Set_TxAddr(&INIT_ADDR0[0], 5 );                    // 使用通道 0 ,地址 0 发射

            nRF24L01_Set_RxAddr( 0, &INIT_ADDR0[0], 5 );                // 通道 0-1 地址都必须设置, 2-5 地址只能设定低 8 位,高 32 位与 1 地址相同
            nRF24L01_Set_RxAddr( 1, &INIT_ADDR1[0], 5 );
            nRF24L01_Set_RxAddr( 2, &INIT_ADDR2[0], 5 );
            nRF24L01_Set_RxAddr( 3, &INIT_ADDR3[0], 5 );
            nRF24L01_Set_RxAddr( 4, &INIT_ADDR4[0], 5 );
            nRF24L01_Set_RxAddr( 5, &INIT_ADDR5[0], 5 );
        #else
            // 如果 你是 1 对 6 的话, 那么这里分别就是 6 个从机的 接收地址, 请单独设置
            nRF24L01_Set_RxAddr( 0, &INIT_ADDR0[0], 5 );                    // 从机接收地址 0 地址

            #if (RF_RX_CHANGE == RX_CHANGE_0)
                nRF24L01_Set_TxAddr(&INIT_ADDR0[0], 5 );                    // 使用通道 0 ,地址 0 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_1)
                nRF24L01_Set_TxAddr(&INIT_ADDR1[0], 5 );                    // 使用通道 0 ,地址 1 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_2)
                nRF24L01_Set_TxAddr(&INIT_ADDR2[0], 5 );                    // 使用通道 0 ,地址 2 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_3)
                nRF24L01_Set_TxAddr(&INIT_ADDR3[0], 5 );                    // 使用通道 0 ,地址 3 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_4)
                nRF24L01_Set_TxAddr(&INIT_ADDR4[0], 5 );                    // 使用通道 0 ,地址 4 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_5)
                nRF24L01_Set_TxAddr(&INIT_ADDR5[0], 5 );                    // 使用通道 0 ,地址 5 发射
            #endif
        #endif


        #if(NRF24L01_RF_MODE == NRF24L01_TX_MODE)
            nRF24L01_Set_Mode( MODE_TX );       // 发送模式
        #else
            nRF24L01_Set_Mode( MODE_RX );       // 接收模式
        #endif

        #ifdef DEBUG_UART1_OUT
        SendString_1("RF24L01 Check OK \r\n");
        #endif
    }
    else
    {
        #ifdef DEBUG_UART1_OUT
        SendString_1("RF24L01 Check Fail \r\n");
        #endif
    }
}

Sys.h 文件

#ifndef _SYS_H_
#define _SYS_H_

#include "Constant.h"

// SPI 接口定义,参考原理图
sbit    SPI_IRQ = P3^3;     // 中断
sbit    SPI_CE  = P3^4;     // 使能
sbit    SPI_NSS = P1^2;     // 片选
sbit    SPI_MOSI = P1^3;    
sbit    SPI_MISO = P1^4;
sbit    SPI_SCK = P1^5;

#define SPI_SET_CLK_HIGH()          SPI_SCK = 1
#define SPI_SET_CLK_LOW()           SPI_SCK = 0

#define SPI_SET_MOSI_HIGH()         SPI_MOSI = 1
#define SPI_SET_MOSI_LOW()          SPI_MOSI = 0

#define SPI_GET_MISO()              (( 1 != SPI_MISO ) ? 0 : 1 )

#define SPI_SET_NSS_HIGH()          SPI_NSS = 1
#define SPI_SET_NSS_LOW()           SPI_NSS = 0


void SPI_Init(void);                                                                                                    // 初始化 SPI
unsigned char SPI_Read_Write_Byte(unsigned char TxByte);                                                                // SPI 读写一个字节
void SPI_Read_Write_String(unsigned char *ReadBuffer, unsigned char *WriteBuffer, unsigned int Length);                 // SPI 读写数据串


// 串口 1
#define FOSC    12000000L               // 时钟频率,我这里是使用单片机内部时钟 12MHz
#define BAUD    115200                  // 串口波特率
#define TM      (65536-(FOSC/4/BAUD))

void Uart_1_Init();                                                 // 串口 1 初始化
void SendData_1(unsigned char dat);                                 // 通过串口 1 发射 1 个字节
void SendString_1(unsigned char *s);                                // 通过串口 1 发射 1 个字符串 0x00 结尾
void Send_Data_Buf_1(unsigned char *dat, unsigned char len);        // 发射指定长度的数据,包括 0x00


// 定时器 1
struct _stClock
{
    struct{
        unsigned char t100msFlag            :1;                     // 100 ms 时间到
        unsigned char t500msFlag            :1;
        unsigned char t1secFlag             :1;
        unsigned char t1minFlag             :1;
        unsigned char t1HorFlag             :1;
        unsigned char t1WekFlag             :1;
        unsigned char t1DayFlag             :1;
        unsigned char t1MonFlag             :1;
        unsigned char t1YerFlag             :1;
    }Flag;
    unsigned char t1ms;
    unsigned char t100ms;
    unsigned char t500ms;
    unsigned char tSec;
    unsigned char tMin;
    unsigned char tHor;
    unsigned char tDay;
    unsigned char tMon;
    unsigned char tYer;
    unsigned char tWek;
};

extern struct _stClock stClock;

#define T1MS    (65536-FOSC/1000)       // 1T模式

void Time0_Init();
void Clock_Init();
void UpdateClock();
unsigned char ReturnWeekDay( unsigned int iYear, unsigned char iMonth, unsigned char iDay );
unsigned char GetMaxDay(unsigned char y, unsigned char m);
unsigned char IsLeapYear(unsigned char y);

// 延时 x 微秒
void Delay1us(unsigned char t_ns);
// 延时 x 毫秒
void Delay1ms(unsigned char t_ms);
// 十六进制转字符串
void HexToStr(char *pbDest, unsigned char *pbSrc, unsigned char nLen);

#endif

Sys.c 文件

#include "sys.h"

struct _stClock stClock;

void Delay1us(unsigned char t_ns)       //@12.000MHz
{
    while(t_ns--);
}

void Delay1ms(unsigned char t_ms)       //@12.000MHz
{
    unsigned char i;

    i = 169;
    while(t_ms--)
    {
        while(i--)
        {
            _nop_();
            _nop_();
        }
    };
}


void HexToStr(char *pbDest, unsigned char *pbSrc, unsigned char nLen)
{
    char ddl,ddh;
    int i;

    for (i=0; i48 + pbSrc[i] / 16;
        ddl = 48 + pbSrc[i] % 16;
        if (ddh > 57) ddh = ddh + 7;
        if (ddl > 57) ddl = ddl + 7;
        pbDest[i*2] = ddh;
        pbDest[i*2+1] = ddl;
    }
}

void SPI_Init(void)
{
    // 引脚配置 部分51单片机不需要
    // SCK MOSI NSS CE 配置为推挽输出
    // MISO IRQ 配置为输入
    P1M1 &= 0xD3;       // 1101 0011
    P1M1 |= 0x10;       // 0001 0000
    P1M0 |= 0x2C;       // 0010 1100

    P3M1 &= 0xEF;       // 1110 1111
    P3M1 |= 0x08;       // 0000 1000
    P1M0 |= 0x10;       // 0010 1100

    // 时钟置低
    SPI_SCK = 0;    
    // MOSI MISO NSS置高
    SPI_MOSI = 1;       
    SPI_NSS = 1;

    SPI_CE = 0;                 // 使能设备
    SPI_SET_NSS_HIGH();         // 取消 SPI 片选
}

/**
 * @brief : SPI收发一个字节
 * @param :
 *          @TxByte: 发送的数据字节
 * @note  : 非堵塞式,一旦等待超时,函数会自动退出
 * @retval: 接收到的字节
 */
unsigned char SPI_Read_Write_Byte(unsigned char TxByte)
{
    unsigned char i, Data;

    SPI_SET_CLK_LOW();

    for(i=0; i<8; i++)
    {
        /** 发送 */
        if(TxByte & 0x80)
            SPI_SET_MOSI_HIGH();            // 如果即将要发送的位为 1 则置高IO引脚
        else
            SPI_SET_MOSI_LOW();             // 如果即将要发送的位为 0 则置低IO引脚
        TxByte <<= 1;                           // 数据左移一位,先发送的是最高位

        SPI_SET_CLK_HIGH();
        _nop_();

        /* 接收 */
        Data <<= 1;                             // 接收数据左移一位,先接收到的是最高位
        if(SPI_GET_MISO())
            Data |= 0x01;                       // 如果接收时IO引脚为高则认为接收到 1

        SPI_SET_CLK_LOW();
        _nop_();
    }

    return Data;
}

/**
 * @brief :SPI收发字符串
 * @param :
 *          @ReadBuffer: 接收数据缓冲区地址
 *          @WriteBuffer:发送字节缓冲区地址
 *          @Length:字节长度
 * @note  :非堵塞式,一旦等待超时,函数会自动退出
 * @retval:无
 */
void SPI_Read_Write_String(unsigned char *ReadBuffer, unsigned char *WriteBuffer, unsigned int Length)
{
    SPI_SET_NSS_LOW();

    while(Length--)
    {
        *ReadBuffer = SPI_Read_Write_Byte(*WriteBuffer);
        ReadBuffer++;
        WriteBuffer++;
    }

    SPI_SET_NSS_HIGH();
}

// 串口 1
/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4 using 1
{
    if (RI)
    {
        RI = 0;                 //清除 RI 位
    }
}


void Uart_1_Init()
{
    SCON = 0x50;                        // 8位可变波特率
    T2L = TM;                           // 设置波特率重装值
    T2H = TM>>8;
    AUXR |= 0x15;                        // T2为1T模式, 并启动定时器2
    ES = 1;                             // 使能串口中断
    EA = 1;
}

void SendData_1(unsigned char dat)
{
    ES = 0;                             // 关闭串口中断
    SBUF = dat;                         // 写数据到UART数据寄存器
    while(!TI);
    TI = 0;
    ES = 1;                             // 使能串口中断
}

void SendString_1(unsigned char *s)
{
    while (*s)                  // 检测字符串结束标志
    {
        SendData_1(*s++);         // 发送当前字符
    }
}

void Send_Data_Buf_1(unsigned char *dat, unsigned char len)
{
    unsigned char i;

    for(i=0; i// 定时器 0
// Timer0 中断函数
void tm0_isr() interrupt 1 using 1
{
    stClock.t1ms++;
    if(stClock.t1ms >=100)
    {
        //BLE_LED =~BLE_LED;
        stClock.Flag.t100msFlag = true;
        stClock.t1ms = 0;
        stClock.t100ms++;
        if(stClock.t100ms >= 5)
        {
            stClock.Flag.t500msFlag = true;
            stClock.t100ms = 0;
            stClock.t500ms++;
            if(stClock.t500ms >= 2)
            {
                stClock.t500ms = 0;
                stClock.Flag.t1secFlag = true;
            }
            GRR_LED = !GRR_LED;                     // 将测试口取反
        }
    }

}


void Time0_Init()
{
    AUXR |= 0x80;                                   // 定时器0为1T模式
    TMOD = 0x00;                                    // 设置定时器为模式0(16位自动重装载)
    TL0 = T1MS;                                     // 初始化计时值
    TH0 = T1MS >> 8;
    TR0 = 1;                                        // 定时器0开始计时
    ET0 = 1;                                        // 使能定时器0中断
    EA = 1;
}


void Clock_Init()
{
    memset(&stClock, 0, sizeof(struct _stClock));

    stClock.tYer = 18;              // 2018 年
    stClock.tMon = 5;               // 5 月
    stClock.tDay = 11;              // 11 日
    stClock.tHor = 18;              // 18 点
    stClock.tMin = 19;              // 19 分
    stClock.tSec = 0;

    stClock.tWek = ReturnWeekDay(2000 + stClock.tYer, stClock.tMon, stClock.tDay);      // 计算星期
}

// 平年/闰年计算函数
unsigned char IsLeapYear(unsigned char y)
{
    unsigned int year;
    year = 2000 + y;

    if((year%4==0 && year%100!=0) || year%400==0)
        return true;
    else
        return false;
}

// 计算指定 年/月 判断这个月是多少天
unsigned char GetMaxDay(unsigned char y, unsigned char m)
{
    if(m == 2)
    {
        if(IsLeapYear(y))
            return 29;
        else
            return 28;
    }
    else if((m == 4)||(m == 6)||(m == 9)||(m == 11))
        return 30;
    else
        return 31;
}

unsigned char ReturnWeekDay( unsigned int iYear, unsigned char iMonth, unsigned char iDay )  
{  
    int iWeek = 0;  
    unsigned int y = 0, c = 0, m = 0, d = 0;  

    if ( iMonth == 1 || iMonth == 2 )  
    {  
        c = ( iYear - 1 ) / 100;  
        y = ( iYear - 1 ) % 100;  
        m = iMonth + 12;  
        d = iDay;  
    }  
    else  
    {  
        c = iYear / 100;  
        y = iYear % 100;  
        m = iMonth;  
        d = iDay;  
    }  

    iWeek = y + y / 4 + c / 4 - 2 * c + 26 * ( m + 1 ) / 10 + d - 1;    // 蔡勒公式  
    iWeek = iWeek >= 0 ? ( iWeek % 7 ) : ( iWeek % 7 + 7 );             // iWeek为负时取模  
    if ( iWeek == 0 )                                                   // 星期日不作为一周的第一天  
    {  
        iWeek = 7;  
    }  

    return iWeek;  
}


void UpdateClock()
{
    // 1 秒钟
    if(stClock.Flag.t1secFlag)
    {
        stClock.Flag.t1secFlag = false;
        Sys_Flag_A.nRF24L01_Send_Data_Flag = 1;
        stClock.tSec++;
    }

    // 1 分钟
    if(stClock.tSec >= 60)
    {
        stClock.tSec = 0;
        stClock.Flag.t1minFlag = true;
        stClock.tMin++;
    }

    // 1 小时
    if(stClock.tMin >= 60)
    {
        stClock.tMin = 0;
        stClock.Flag.t1HorFlag = true;
        stClock.tHor++;
    }

    // 1 天
    if(stClock.tHor >= 24)
    {
        stClock.tHor = 0;
        stClock.Flag.t1DayFlag = true;
        stClock.tDay++;
        // 计算当前星期几, 1 - 7
        stClock.tWek = ReturnWeekDay(2000 + stClock.tYer, stClock.tMon, stClock.tDay);
    }

    // 一月, GetMaxDay() 用于计算当月有多少天
    if(stClock.tDay > GetMaxDay(stClock.tYer, stClock.tMon))
    {
        stClock.tMon++;
        stClock.Flag.t1MonFlag = true;
    }

    // 1年
    if(stClock.tMon > 12)
    {
        stClock.tMon = 1;
        stClock.tYer++;
        stClock.Flag.t1YerFlag = true;
    }
}

Constant.h 文件

#ifndef _CONSTAN_H_
#define _CONSTAN_H_

#include 
#include 
#include 

#define TRUE                (1)
#define FALSE               (0)

#define true                (1)
#define false               (0)

sbit BLE_LED = P0^5;
sbit GRR_LED = P0^6;
sbit RED_LED = P0^7;

#define DEBUG_UART1_OUT     (0)


union _uInt
{
    struct
    {
        unsigned char Int8H;
        unsigned char Int8L;
    }bt;

    unsigned int Int16;
};

struct _Sys_Flag_A
{
    unsigned char nRF24L01_Send_Data_Flag           :1;
};

extern struct _Sys_Flag_A Sys_Flag_A;

#endif

Variable.c 文件

#include "Constant.h"

struct _Sys_Flag_A Sys_Flag_A;

项目截图
nRF24L01 使用心得_第8张图片

项目配置
nRF24L01 使用心得_第9张图片

STC15-ISP 配置
nRF24L01 使用心得_第10张图片

编译结果
nRF24L01 使用心得_第11张图片

有很大警告,这些警告是因为有些函数声明,定义了,但是没有调用造成的,总体来说不影响使用.
nRF24L01 使用心得_第12张图片
nRF24L01 使用心得_第13张图片
测试,数据发送接收正常.

总结一下:
使用 nRF24L01 遇到最大/最多的问题是,大家搞不清怎么使用 1 对 6 通信问题,其实搞明白了就很简单了.

1.主机发送地址始终必须是通道 0, 接收地址全部打开.

#if(NRF24L01_RF_MODE == NRF24L01_TX_MODE)                       // 设置 接收 地址
            nRF24L01_Set_TxAddr(&INIT_ADDR0[0], 5 );                    // 使用通道 0 ,地址 0 发射

            nRF24L01_Set_RxAddr( 0, &INIT_ADDR0[0], 5 );                // 通道 0-1 地址都必须设置, 2-5 地址只能设定低 8 位,高 32 位与 1 地址相同
            nRF24L01_Set_RxAddr( 1, &INIT_ADDR1[0], 5 );
            nRF24L01_Set_RxAddr( 2, &INIT_ADDR2[0], 5 );
            nRF24L01_Set_RxAddr( 3, &INIT_ADDR3[0], 5 );
            nRF24L01_Set_RxAddr( 4, &INIT_ADDR4[0], 5 );
            nRF24L01_Set_RxAddr( 5, &INIT_ADDR5[0], 5 );

2.从机发射地址为 0 通道 0-6 地址,接收地址必须使用通道 0 地址.

nRF24L01_Set_RxAddr( 0, &INIT_ADDR0[0], 5 );                    // 从机接收地址 0 地址

            #if (RF_RX_CHANGE == RX_CHANGE_0)
                nRF24L01_Set_TxAddr(&INIT_ADDR0[0], 5 );                    // 使用通道 0 ,地址 0 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_1)
                nRF24L01_Set_TxAddr(&INIT_ADDR1[0], 5 );                    // 使用通道 0 ,地址 1 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_2)
                nRF24L01_Set_TxAddr(&INIT_ADDR2[0], 5 );                    // 使用通道 0 ,地址 2 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_3)
                nRF24L01_Set_TxAddr(&INIT_ADDR3[0], 5 );                    // 使用通道 0 ,地址 3 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_4)
                nRF24L01_Set_TxAddr(&INIT_ADDR4[0], 5 );                    // 使用通道 0 ,地址 4 发射
            #elif (RF_RX_CHANGE == RX_CHANGE_5)
                nRF24L01_Set_TxAddr(&INIT_ADDR5[0], 5 );                    // 使用通道 0 ,地址 5 发射

流程图,不管主机/从机,发送只能使用通道 0, 地址 0-5 发送,接收可以使用 0-5通道 0-5 地址接收.
Tx(通道 0 ,地址 0 发送发送) –> Rx(通道 0 ,地址 0 接收)
Rx(通道 0 ,地址 0 发送) –> Tx(通道 0 接收)
Rx(通道 0 ,地址 1 发送) –> Tx(通道 1 ,地址 1 接收)
Rx(通道 0 ,地址 2 发送) –> Tx(通道 2 ,地址 2 接收)
Rx(通道 0 ,地址 3 发送) –> Tx(通道 3 ,地址 3 接收)
Rx(通道 0 ,地址 4 发送) –> Tx(通道 4 ,地址 4 接收)
Rx(通道 0 ,地址 5 发送) –> Tx(通道 5 ,地址 5 接收)
因为 发射模块 所以接收通道都打开,所以不管从机使用哪个通道发送,都能接收到数据.
nRF24L01 使用心得_第14张图片
而从机的接收,只需打开 0 通道就可以了.
nRF24L01 使用心得_第15张图片

好了,谢谢!
完整项目地址:https://download.csdn.net/download/longzhishen/10408454

你可能感兴趣的:(单片机开发)