nRF24L01 使用心得

爲了方便大家測試程序,先將程序開發環境說明一下,程序是在 STC15W4K56S4 上開發的,開發板,nRF24L01 無線模塊都是某寶淘來的.

開發板圖片
開發板原理圖

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

  • 硬件準備就緒後,開始寫程序
    打開 這裏寫圖片描述
    新建一個項目
    這裏寫圖片描述
    這裏寫圖片描述
    這裏寫圖片描述
    這裏寫圖片描述
    這裏寫圖片描述

好,項目新建好了,現在開始添加文件
分別添加新建以下幾個文件
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<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT) )

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; i<len; i++)
    {
        pBuf[i] = SPI_Read_Write_Byte(0xFF);        // 讀數據
    }

    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<len; i++)
    {
        SPI_Read_Write_Byte(*pBuf++);
    }
    NRF24L01_SET_CS_HIGH();
}


/**
  * @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; i<Width; i++ )
    {
        pRxBuf[i] = SPI_Read_Write_Byte( 0xFF );                    // 讀數據
    }
    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<length; btmp++ )
    {
        SPI_Read_Write_Byte( *pTxBuf++ );               // 發送數據
    }

    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<<MASK_RX_DR ) |*/             // 接收中斷
                                        ( 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; i<nLen; i++)
    {
        ddh = 48 + 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<len; i++)
    {
        SendData_1(*dat++);
    }
}


// 定時器 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 <STC/STC15.H>
#include <INTRINS.H>
#include <STRING.H>

#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;

項目截圖
這裏寫圖片描述

項目配置
這裏寫圖片描述

STC15-ISP 配置
這裏寫圖片描述

編譯結果
這裏寫圖片描述

有很大警告,這些警告是因爲有些函數聲明,定義了,但是沒有調用造成的,總體來說不影響使用.
這裏寫圖片描述
這裏寫圖片描述
測試,數據發送接收正常.

總結一下:
使用 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 接收)
因爲 發射模塊 所以接收通道都打開,所以不管從機使用哪個通道發送,都能接收到數據.
這裏寫圖片描述
而從機的接收,只需打開 0 通道就可以了.
這裏寫圖片描述

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章