STC15W4K32S4系列单片机驱动nRF24L01 2.4G无线接收方案

一、硬件连接方案

1.1 nRF24L01模块引脚定义

复制代码
nRF24L01引脚 → STC15W4K32S4引脚
1 (GND)    → GND
2 (VCC)    → 3.3V(必须使用3.3V供电)
3 (CE)     → P2.5(可自定义)
4 (CSN)    → P2.4(可自定义)
5 (SCK)    → P1.5(SPI时钟)
6 (MOSI)   → P1.3(主机输出从机输入)
7 (MISO)   → P1.4(主机输入从机输出)
8 (IRQ)    → P3.2(外部中断0,可选)

1.2 电源注意事项

  • 必须使用3.3V供电:nRF24L01工作电压为1.9-3.6V,推荐3.3V
  • 电源滤波:VCC引脚需并联10μF和0.1μF电容
  • 天线匹配:确保天线阻抗匹配为50Ω

二、STC15W4K32S4 SPI配置

2.1 硬件SPI配置(推荐)

STC15W4K32S4内置硬件SPI模块,支持主从模式,最高时钟频率为Fosc/4。

c 复制代码
#include "stc15w4k32s4.h"
#include <intrins.h>

// SPI引脚定义(第二组SPI)
sbit CE  = P2^5;    // 芯片使能
sbit CSN = P2^4;    // 片选
sbit IRQ = P3^2;    // 中断引脚(可选)

// SPI初始化函数
void SPI_Init(void) {
    // 重要:STC15W4K32S4上电后PWM相关IO口为高阻态
    // 需设置为准双向口或强推挽模式
    P0M1 = 0; P0M0 = 0;  // 设置P0.0~P0.7为准双向口
    P2M1 = 0; P2M0 = 0;  // 设置P2.0~P2.7为准双向口
    P3M1 = 0; P3M0 = 0;  // 设置P3.0~P3.7为准双向口
    P4M1 = 0; P4M0 = 0;  // 设置P4.0~P4.7为准双向口
    P5M1 = 0; P5M0 = 0;  // 设置P5.0~P5.7为准双向口
    
    // 配置SPI为第二组引脚(P1.5/SCLK, P1.3/MOSI, P1.4/MISO)
    P_SW1 &= 0x3F;        // 清除SPI切换位
    P_SW1 |= 0x40;        // SPI切换到第二组(SPI_S1=1, SPI_S0=0)
    
    // SPI控制寄存器配置
    SPSTAT = 0xC0;        // 清除SPIF和WCOL标志位
    SPCTL = 0xD0;         // 使能SPI,主机模式,时钟最快
    // SSIG=1(忽略SS引脚),SPEN=1(使能SPI)
    // DORD=0(MSB先发送),MSTR=1(主机模式)
    // CPOL=0(时钟空闲低电平),CPHA=0(数据在第一个时钟沿采样)
    
    // 初始化nRF24L01控制引脚
    CE = 0;               // 芯片使能低
    CSN = 1;              // 片选高(不选中)
    
    // 如果使用中断
    // IT0 = 1;           // 设置INT0为下降沿触发
    // EX0 = 1;           // 使能INT0中断
    // EA = 1;            // 开启总中断
}

// SPI数据交换函数
unsigned char SPI_SwapByte(unsigned char dat) {
    SPDAT = dat;                    // 写入数据,启动传输
    while (!(SPSTAT & 0x80));      // 等待传输完成(SPIF=1)
    SPSTAT = 0xC0;                 // 清除SPIF和WCOL标志
    return SPDAT;                  // 返回接收到的数据
}

2.2 软件模拟SPI(备用方案)

如果硬件SPI被占用,可使用GPIO模拟SPI时序:

c 复制代码
// 软件SPI引脚定义
sbit CE   = P2^5;
sbit CSN  = P2^4;
sbit SCK  = P1^5;
sbit MOSI = P1^3;
sbit MISO = P1^4;
sbit IRQ  = P3^2;

// 软件SPI字节读写
unsigned char SPI_RW(unsigned char byte) {
    unsigned char i;
    for(i = 0; i < 8; i++) {
        MOSI = (byte & 0x80);      // 输出最高位
        byte <<= 1;                // 左移一位
        SCK = 1;                   // 时钟上升沿
        byte |= MISO;              // 读取MISO数据
        SCK = 0;                   // 时钟下降沿
    }
    return byte;
}

三、nRF24L01驱动代码

3.1 nRF24L01寄存器定义

c 复制代码
// nRF24L01寄存器地址
#define CONFIG      0x00    // 配置寄存器
#define EN_AA       0x01    // 自动应答使能
#define EN_RXADDR   0x02    // 接收地址使能
#define SETUP_AW    0x03    // 地址宽度设置
#define SETUP_RETR  0x04    // 自动重发设置
#define RF_CH       0x05    // RF频道设置
#define RF_SETUP    0x06    // RF设置寄存器
#define STATUS      0x07    // 状态寄存器
#define OBSERVE_TX  0x08    // 发送观察寄存器
#define CD          0x09    // 载波检测
#define RX_ADDR_P0  0x0A    // 接收地址通道0
#define RX_ADDR_P1  0x0B    // 接收地址通道1
#define RX_ADDR_P2  0x0C    // 接收地址通道2
#define RX_ADDR_P3  0x0D    // 接收地址通道3
#define RX_ADDR_P4  0x0E    // 接收地址通道4
#define RX_ADDR_P5  0x0F    // 接收地址通道5
#define TX_ADDR     0x10    // 发送地址
#define RX_PW_P0    0x11    // 接收数据宽度通道0
#define RX_PW_P1    0x12    // 接收数据宽度通道1
#define RX_PW_P2    0x13    // 接收数据宽度通道2
#define RX_PW_P3    0x14    // 接收数据宽度通道3
#define RX_PW_P4    0x15    // 接收数据宽度通道4
#define RX_PW_P5    0x16    // 接收数据宽度通道5
#define FIFO_STATUS 0x17    // FIFO状态寄存器
#define DYNPD       0x1C    // 动态载荷长度
#define FEATURE     0x1D    // 特性寄存器

// SPI命令
#define READ_REG    0x00    // 读寄存器
#define WRITE_REG   0x20    // 写寄存器
#define RD_RX_PLOAD 0x61    // 读RX有效数据
#define WR_TX_PLOAD 0xA0    // 写TX有效数据
#define FLUSH_TX    0xE1    // 清空TX FIFO
#define FLUSH_RX    0xE2    // 清空RX FIFO
#define REUSE_TX_PL 0xE3    // 重用TX有效数据
#define NOP         0xFF    // 空操作

// 状态寄存器位定义
#define RX_DR       6       // 数据就绪接收中断
#define TX_DS       5       // 数据发送完成中断
#define MAX_RT      4       // 达到最大重发次数中断

3.2 nRF24L01基本操作函数

c 复制代码
// 写寄存器
unsigned char NRF24L01_Write_Reg(unsigned char reg, unsigned char value) {
    unsigned char status;
    
    CSN = 0;                           // 使能SPI传输
    status = SPI_SwapByte(WRITE_REG | reg);  // 发送寄存器地址
    SPI_SwapByte(value);               // 写入值
    CSN = 1;                           // 禁止SPI传输
    
    return status;                     // 返回状态寄存器值
}

// 读寄存器
unsigned char NRF24L01_Read_Reg(unsigned char reg) {
    unsigned char value;
    
    CSN = 0;
    SPI_SwapByte(READ_REG | reg);      // 发送读命令
    value = SPI_SwapByte(NOP);         // 读取寄存器值
    CSN = 1;
    
    return value;
}

// 读多个字节
void NRF24L01_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char len) {
    unsigned char i;
    
    CSN = 0;
    SPI_SwapByte(READ_REG | reg);      // 发送读命令
    
    for(i = 0; i < len; i++) {
        pBuf[i] = SPI_SwapByte(NOP);   // 连续读取
    }
    
    CSN = 1;
}

// 写多个字节
void NRF24L01_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char len) {
    unsigned char i;
    
    CSN = 0;
    SPI_SwapByte(WRITE_REG | reg);     // 发送写命令
    
    for(i = 0; i < len; i++) {
        SPI_SwapByte(pBuf[i]);         // 连续写入
    }
    
    CSN = 1;
}

// 读取接收数据
void NRF24L01_Read_RX_Buf(unsigned char *pBuf, unsigned char len) {
    CSN = 0;
    SPI_SwapByte(RD_RX_PLOAD);         // 发送读数据命令
    
    for(unsigned char i = 0; i < len; i++) {
        pBuf[i] = SPI_SwapByte(NOP);   // 读取数据
    }
    
    CSN = 1;
    
    // 清除RX_DR中断标志
    NRF24L01_Write_Reg(STATUS, 0x40);
}

// 清空RX FIFO
void NRF24L01_Flush_RX(void) {
    CSN = 0;
    SPI_SwapByte(FLUSH_RX);
    CSN = 1;
}

// 清空TX FIFO
void NRF24L01_Flush_TX(void) {
    CSN = 0;
    SPI_SwapByte(FLUSH_TX);
    CSN = 1;
}

四、nRF24L01接收端配置

4.1 初始化函数

c 复制代码
// 接收地址(5字节)
unsigned char RX_ADDRESS[5] = {0x34, 0x43, 0x10, 0x10, 0x01};

// nRF24L01初始化
void NRF24L01_Init(void) {
    CE = 0;      // 芯片使能低
    CSN = 1;     // 片选高
    
    // 延时等待模块稳定
    Delay_ms(5);
    
    // 配置为接收模式
    Set_RxMode();
    
    // 检查模块是否正常
    if(NRF24L01_Check()) {
        // 初始化成功
        printf("nRF24L01 Init OK!\r\n");
    } else {
        // 初始化失败
        printf("nRF24L01 Init Failed!\r\n");
    }
}

// 设置接收模式
void Set_RxMode(void) {
    CE = 0;  // 先拉低CE
    
    // 写入接收地址(通道0)
    NRF24L01_Write_Buf(RX_ADDR_P0, RX_ADDRESS, 5);
    
    // 设置接收数据宽度(32字节)
    NRF24L01_Write_Reg(RX_PW_P0, 32);
    
    // 使能通道0自动应答
    NRF24L01_Write_Reg(EN_AA, 0x01);
    
    // 使能通道0接收地址
    NRF24L01_Write_Reg(EN_RXADDR, 0x01);
    
    // 设置地址宽度为5字节
    NRF24L01_Write_Reg(SETUP_AW, 0x03);
    
    // 设置RF频道(2.4GHz + RF_CH值)
    NRF24L01_Write_Reg(RF_CH, 40);  // 2.440GHz
    
    // 设置RF参数:2Mbps速率,0dBm发射功率
    NRF24L01_Write_Reg(RF_SETUP, 0x0F);
    
    // 配置基本工作模式:PWR_UP, EN_CRC, 16BIT_CRC, PRIM_RX接收模式
    NRF24L01_Write_Reg(CONFIG, 0x0F);
    
    // 清空RX FIFO
    NRF24L01_Flush_RX();
    
    // 清空状态寄存器
    NRF24L01_Write_Reg(STATUS, 0x70);
    
    CE = 1;  // 使能接收模式
    Delay_us(130);  // 等待稳定
}

// 检查nRF24L01是否正常
unsigned char NRF24L01_Check(void) {
    unsigned char buf[5] = {0};
    unsigned char i;
    
    // 写入测试地址
    unsigned char test_addr[5] = {0x11, 0x22, 0x33, 0x44, 0x55};
    NRF24L01_Write_Buf(TX_ADDR, test_addr, 5);
    
    // 读取地址进行比较
    NRF24L01_Read_Buf(TX_ADDR, buf, 5);
    
    // 比较地址
    for(i = 0; i < 5; i++) {
        if(buf[i] != test_addr[i]) {
            return 0;  // 检查失败
        }
    }
    
    return 1;  // 检查成功
}

4.2 数据接收处理

c 复制代码
// 接收缓冲区
unsigned char RX_Buffer[32];
unsigned char RX_Flag = 0;

// 检查接收状态
unsigned char NRF24L01_RxPacket(void) {
    unsigned char status;
    
    status = NRF24L01_Read_Reg(STATUS);  // 读取状态寄存器
    
    if(status & 0x40) {  // 检查RX_DR位
        // 读取接收数据
        NRF24L01_Read_RX_Buf(RX_Buffer, 32);
        
        // 清除中断标志
        NRF24L01_Write_Reg(STATUS, 0x40);
        
        return 1;  // 接收成功
    }
    
    return 0;  // 没有数据
}

// 中断方式接收(使用IRQ引脚)
void INT0_ISR(void) interrupt 0 {
    unsigned char status;
    
    status = NRF24L01_Read_Reg(STATUS);
    
    if(status & 0x40) {  // RX_DR中断
        // 读取数据
        NRF24L01_Read_RX_Buf(RX_Buffer, 32);
        RX_Flag = 1;  // 设置接收标志
        
        // 清除中断标志
        NRF24L01_Write_Reg(STATUS, 0x40);
    }
    
    if(status & 0x20) {  // TX_DS中断
        // 发送完成(如果也用于发送)
        NRF24L01_Write_Reg(STATUS, 0x20);
    }
    
    if(status & 0x10) {  // MAX_RT中断
        // 达到最大重发次数
        NRF24L01_Flush_TX();  // 清空TX FIFO
        NRF24L01_Write_Reg(STATUS, 0x10);
    }
}

五、主程序示例

5.1 轮询方式接收

c 复制代码
#include "stc15w4k32s4.h"
#include "nrf24l01.h"
#include <stdio.h>

void main(void) {
    unsigned char i;
    
    // 系统初始化
    System_Init();      // 系统时钟初始化
    UART1_Init();       // 串口初始化,用于调试
    SPI_Init();         // SPI初始化
    NRF24L01_Init();    // nRF24L01初始化
    
    printf("STC15W4K32S4 nRF24L01 Receiver Started!\r\n");
    
    while(1) {
        // 检查是否有数据
        if(NRF24L01_RxPacket()) {
            printf("Received Data: ");
            
            // 打印接收到的数据
            for(i = 0; i < 32; i++) {
                if(RX_Buffer[i] != 0) {
                    printf("%02X ", RX_Buffer[i]);
                }
            }
            printf("\r\n");
            
            // 处理数据
            Process_Data(RX_Buffer);
        }
        
        // 其他任务
        Delay_ms(10);
    }
}

// 系统初始化
void System_Init(void) {
    // 设置系统时钟(内部22.1184MHz)
    CLK_DIV = 0x00;
    
    // IO口模式设置
    P0M1 = 0; P0M0 = 0;
    P1M1 = 0; P1M0 = 0;
    P2M1 = 0; P2M0 = 0;
    P3M1 = 0; P3M0 = 0;
    P4M1 = 0; P4M0 = 0;
    P5M1 = 0; P5M0 = 0;
}

// 串口1初始化(用于调试)
void UART1_Init(void) {
    SCON = 0x50;        // 8位数据,可变波特率
    AUXR |= 0x40;       // 定时器1时钟为Fosc
    AUXR &= 0xFE;       // 定时器1为12T模式
    TMOD &= 0x0F;       // 清除定时器1模式位
    TMOD |= 0x20;       // 定时器1为8位自动重装
    TH1 = 0xFA;         // 波特率9600@22.1184MHz
    TL1 = 0xFA;
    TR1 = 1;            // 启动定时器1
    ES = 1;             // 使能串口中断(可选)
    EA = 1;             // 开启总中断
}

5.2 中断方式接收

c 复制代码
// 中断方式主程序
void main(void) {
    // 系统初始化
    System_Init();
    UART1_Init();
    SPI_Init();
    NRF24L01_Init();
    
    // 配置外部中断0(IRQ引脚)
    IT0 = 1;            // 下降沿触发
    EX0 = 1;            // 使能INT0中断
    EA = 1;             // 开启总中断
    
    printf("nRF24L01 Receiver with Interrupt Mode\r\n");
    
    while(1) {
        // 主循环处理其他任务
        if(RX_Flag) {
            RX_Flag = 0;  // 清除标志
            
            printf("Interrupt Received: ");
            for(unsigned char i = 0; i < 32; i++) {
                if(RX_Buffer[i] != 0) {
                    printf("%c", RX_Buffer[i]);
                }
            }
            printf("\r\n");
        }
        
        // 低功耗模式或延时
        Delay_ms(100);
    }
}

参考代码 STC15W4K32S4系列单片机2.4G无线接收nRF24L01 www.youwenfan.com/contentcsv/71229.html

六、调试与故障排除

6.1 常见问题及解决方案

问题现象 可能原因 解决方案
无法通信 电源电压不正确 确保使用3.3V供电,检查电源滤波电容
通信距离短 天线匹配问题 检查天线阻抗是否为50Ω,确保天线完好
数据错误 SPI时序问题 降低SPI时钟频率,检查接线是否可靠
无法进入接收模式 寄存器配置错误 检查CONFIG寄存器PRIM_RX位是否设置为1
频繁丢包 RF频道干扰 更换RF_CH值,避开WiFi频道(1,6,11)

6.2 调试建议

  1. 使用逻辑分析仪:检查SPI时序是否正确
  2. 串口调试:通过串口打印状态寄存器值
  3. 电源监测:使用示波器检查3.3V电源是否稳定
  4. 信号测试:使用频谱分析仪检查2.4GHz信号质量

七、性能优化建议

7.1 提高通信可靠性

c 复制代码
// 启用自动重发
void Enable_Auto_Retransmit(void) {
    // 设置自动重发延迟250us,重发15次
    NRF24L01_Write_Reg(SETUP_RETR, 0x5F);
}

// 启用动态载荷长度
void Enable_Dynamic_Payload(void) {
    NRF24L01_Write_Reg(FEATURE, 0x06);   // 使能动态载荷和ACK载荷
    NRF24L01_Write_Reg(DYNPD, 0x01);     // 通道0启用动态载荷
}

// 设置发射功率和速率
void Set_RF_Power_Rate(unsigned char power, unsigned char rate) {
    unsigned char rf_setup = NRF24L01_Read_Reg(RF_SETUP);
    
    // 清除功率和速率位
    rf_setup &= 0xF0;
    
    // 设置功率(00:-18dBm, 01:-12dBm, 10:-6dBm, 11:0dBm)
    rf_setup |= (power << 1);
    
    // 设置速率(0:1Mbps, 1:2Mbps)
    if(rate == 1) {
        rf_setup |= 0x08;  // 2Mbps
    }
    
    NRF24L01_Write_Reg(RF_SETUP, rf_setup);
}

7.2 低功耗优化

c 复制代码
// 进入低功耗模式
void Enter_Power_Down_Mode(void) {
    unsigned char config = NRF24L01_Read_Reg(CONFIG);
    config &= ~0x02;  // 清除PWR_UP位
    NRF24L01_Write_Reg(CONFIG, config);
    CE = 0;           // 确保CE为低
}

// 唤醒从低功耗模式
void Wake_Up_From_Power_Down(void) {
    unsigned char config = NRF24L01_Read_Reg(CONFIG);
    config |= 0x02;   // 设置PWR_UP位
    NRF24L01_Write_Reg(CONFIG, config);
    Delay_ms(5);      // 等待稳定
}

八、完整工程文件结构

复制代码
nRF24L01_Receiver/
├── main.c              # 主程序
├── nrf24l01.c          # nRF24L01驱动
├── nrf24l01.h          # nRF24L01头文件
├── spi.c               # SPI驱动
├── spi.h               # SPI头文件
├── uart.c              # 串口驱动
├── uart.h              # 串口头文件
├── delay.c             # 延时函数
├── delay.h             # 延时头文件
└── STC15W4K32S4.H      # 单片机寄存器定义
相关推荐
淘晶驰AK11 小时前
农业物联网 / 温室:组态屏监控系统搭建教程
嵌入式硬件
崇山峻岭之间11 小时前
单片机蜂鸣器实验
单片机·嵌入式硬件
西城微科方案开发11 小时前
厨房电子秤MCU芯片解决方案
单片机·嵌入式硬件
深圳市晨芯阳科技有限公司11 小时前
HC7253晨芯阳高端电流检测降压LED恒流驱动器
stm32·单片机·嵌入式硬件·驱动ic·深圳市晨芯阳科技有限公司
隔窗听雨眠12 小时前
STM32/ESP32实战驱动的达林顿阵列高效复用指南
stm32·单片机·嵌入式硬件
XiYang-DING12 小时前
【Java EE】TCP(Transmission Control Protocol)
单片机·tcp/ip·java-ee
bubiyoushang88812 小时前
STM32L051 的 串口升级
stm32·单片机·嵌入式硬件
210Brian12 小时前
蓝桥杯单片机学习笔记(十二):V2026 大模板构建(上)
单片机·学习·蓝桥杯
潜创微科技13 小时前
潜创微科技|沁恒微电子 (WCH) 官方授权代理商&方案商 一站式国产接口芯片解决方案
科技·嵌入式硬件