STM32F103C8T6 + nRF24L01 无线中继方案

STM32F103C8T6 + nRF24L01 无线中继方案

STM32F103C8T6与nRF24L01无线中继系统,支持多跳中继、自动路由和信号放大功能。

一、硬件连接方案

1. 硬件清单

组件 型号 数量 说明
MCU STM32F103C8T6 1 主控芯片
无线模块 nRF24L01+ 2 无线收发模块
天线 2.4GHz PCB天线 2 无线信号
电源 3.3V稳压 1 电源管理
指示灯 LED 2 状态指示

2. 引脚连接

STM32F103C8T6  <->  nRF24L01#1 (接收)  <->  nRF24L01#2 (发送)
---------------------------------------------------------
PA4 (SPI1_NSS)  <->  CSN1               <->  CSN2
PA5 (SPI1_SCK)  <->  SCK                <->  SCK
PA6 (SPI1_MISO) <->  MISO               <->  MISO
PA7 (SPI1_MOSI) <->  MOSI               <->  MOSI
PB0             <->  CE1                <->  CE2
PB1             <->  IRQ1               <->  IRQ2
3.3V            <->  VCC                <->  VCC
GND             <->  GND                <->  GND

二、代码实现

1. 头文件 nrf24l01_relay.h

#ifndef __NRF24L01_RELAY_H
#define __NRF24L01_RELAY_H

#include "stm32f10x.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// nRF24L01寄存器定义
#define NRF24L01_CONFIG      0x00
#define NRF24L01_EN_AA       0x01
#define NRF24L01_EN_RXADDR   0x02
#define NRF24L01_SETUP_AW    0x03
#define NRF24L01_SETUP_RETR  0x04
#define NRF24L01_RF_CH       0x05
#define NRF24L01_RF_SETUP    0x06
#define NRF24L01_STATUS      0x07
#define NRF24L01_OBSERVE_TX  0x08
#define NRF24L01_CD          0x09
#define NRF24L01_RX_ADDR_P0  0x0A
#define NRF24L01_RX_ADDR_P1  0x0B
#define NRF24L01_TX_ADDR     0x10
#define NRF24L01_RX_PW_P0    0x11
#define NRF24L01_FIFO_STATUS 0x17
#define NRF24L01_DYNPD       0x1C
#define NRF24L01_FEATURE     0x1D

// 命令定义
#define NRF24L01_CMD_R_REGISTER    0x00
#define NRF24L01_CMD_W_REGISTER    0x20
#define NRF24L01_CMD_R_RX_PAYLOAD  0x61
#define NRF24L01_CMD_W_TX_PAYLOAD  0xA0
#define NRF24L01_CMD_FLUSH_TX      0xE1
#define NRF24L01_CMD_FLUSH_RX      0xE2
#define NRF24L01_CMD_REUSE_TX_PL   0xE3
#define NRF24L01_CMD_ACTIVATE      0x50
#define NRF24L01_CMD_R_RX_PL_WID   0x60
#define NRF24L01_CMD_W_ACK_PAYLOAD 0xA8
#define NRF24L01_CMD_W_TX_PAYLOAD_NOACK 0xB0
#define NRF24L01_CMD_NOP           0xFF

// 中继配置
#define RELAY_MAX_NODES        10
#define RELAY_MAX_HOPS         5
#define RELAY_PACKET_SIZE      32
#define RELAY_CHANNEL          76  // 2.476GHz
#define RELAY_DATA_RATE        RF_SETUP_2Mbps
#define RELAY_POWER            RF_SETUP_PWR_0dBm
#define RELAY_RETRY_DELAY      0x0F  // 4000us
#define RELAY_RETRY_COUNT      15

// 数据包类型
typedef enum {
    PKT_TYPE_DATA = 0x01,
    PKT_TYPE_ACK = 0x02,
    PKT_TYPE_ROUTE_REQUEST = 0x03,
    PKT_TYPE_ROUTE_REPLY = 0x04,
    PKT_TYPE_HEARTBEAT = 0x05
} PacketType;

// 中继数据包结构
#pragma pack(push, 1)
typedef struct {
    uint8_t packet_type;      // 包类型
    uint8_t source_id;        // 源节点ID
    uint8_t dest_id;          // 目标节点ID
    uint8_t relay_id;         // 中继节点ID
    uint8_t hop_count;        // 跳数
    uint8_t ttl;              // 生存时间
    uint32_t sequence;        // 序列号
    uint32_t timestamp;       // 时间戳
    uint8_t payload[16];      // 载荷数据
    uint8_t checksum;         // 校验和
} RelayPacket;
#pragma pack(pop)

// 路由表项
typedef struct {
    uint8_t node_id;          // 节点ID
    uint8_t next_hop;         // 下一跳节点
    uint8_t hop_count;        // 跳数
    uint8_t quality;          // 链路质量
    uint32_t last_update;     // 最后更新时间
    bool active;              // 是否活跃
} RouteEntry;

// 中继节点状态
typedef enum {
    RELAY_STATE_IDLE = 0,
    RELAY_STATE_RECEIVING,
    RELAY_STATE_FORWARDING,
    RELAY_STATE_WAIT_ACK,
    RELAY_STATE_ERROR
} RelayState;

// 中继统计
typedef struct {
    uint32_t packets_received;
    uint32_t packets_forwarded;
    uint32_t packets_dropped;
    uint32_t route_requests;
    uint32_t route_replies;
    uint32_t ack_received;
    uint32_t ack_timeout;
    uint8_t rssi;
    uint8_t lqi;
} RelayStats;

// 函数声明
void NRF24L01_Init(void);
void NRF24L01_SetChannel(uint8_t channel);
void NRF24L01_SetPower(uint8_t power);
void NRF24L01_SetDataRate(uint8_t rate);
void NRF24L01_SetAutoAck(bool enable);
void NRF24L01_SetRetries(uint8_t delay, uint8_t count);
void NRF24L01_SetRXAddress(uint8_t pipe, uint8_t *address);
void NRF24L01_SetTXAddress(uint8_t *address);
void NRF24L01_StartListening(void);
void NRF24L01_StopListening(void);
bool NRF24L01_SendPacket(RelayPacket *packet);
bool NRF24L01_ReceivePacket(RelayPacket *packet);
bool NRF24L01_IsDataAvailable(void);
void NRF24L01_FlushTX(void);
void NRF24L01_FlushRX(void);
uint8_t NRF24L01_GetStatus(void);
uint8_t NRF24L01_GetRetransmissions(void);
void NRF24L01_ClearInterrupts(void);

// 中继功能
void Relay_Init(uint8_t node_id);
void Relay_Process(void);
void Relay_SendData(uint8_t dest_id, uint8_t *data, uint8_t len);
void Relay_ForwardPacket(RelayPacket *packet);
void Relay_RequestRoute(uint8_t dest_id);
void Relay_UpdateRouteTable(uint8_t node_id, uint8_t next_hop, uint8_t hop_count);
RouteEntry* Relay_FindRoute(uint8_t dest_id);
void Relay_SendHeartbeat(void);
void Relay_PrintStats(void);

// 中断处理
void NRF24L01_IRQHandler(void);

#endif /* __NRF24L01_RELAY_H */

2. SPI驱动 spi.c

#include "spi.h"
#include "stm32f10x.h"

// SPI初始化
void SPI1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // 配置SPI引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置CSN引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置CE引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置IRQ引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置SPI参数
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 9MHz
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    
    // 使能SPI
    SPI_Cmd(SPI1, ENABLE);
    
    // 默认拉高CSN
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

// SPI发送接收字节
uint8_t SPI1_Transfer(uint8_t data)
{
    // 等待发送缓冲区空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送数据
    SPI_I2S_SendData(SPI1, data);
    
    // 等待接收完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 返回接收的数据
    return SPI_I2S_ReceiveData(SPI1);
}

// 写寄存器
void NRF24L01_WriteReg(uint8_t reg, uint8_t value)
{
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);  // CSN拉低
    SPI1_Transfer(NRF24L01_CMD_W_REGISTER | reg);
    SPI1_Transfer(value);
    GPIO_SetBits(GPIOA, GPIO_Pin_4);    // CSN拉高
}

// 读寄存器
uint8_t NRF24L01_ReadReg(uint8_t reg)
{
    uint8_t value;
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_R_REGISTER | reg);
    value = SPI1_Transfer(NRF24L01_CMD_NOP);
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
    return value;
}

// 写多个字节
void NRF24L01_WriteBuf(uint8_t reg, uint8_t *buf, uint8_t len)
{
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_W_REGISTER | reg);
    for (uint8_t i = 0; i < len; i++) {
        SPI1_Transfer(buf[i]);
    }
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

// 读多个字节
void NRF24L01_ReadBuf(uint8_t reg, uint8_t *buf, uint8_t len)
{
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_R_REGISTER | reg);
    for (uint8_t i = 0; i < len; i++) {
        buf[i] = SPI1_Transfer(NRF24L01_CMD_NOP);
    }
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

3. nRF24L01驱动 nrf24l01.c

#include "nrf24l01_relay.h"
#include "spi.h"
#include <stdlib.h>

// 静态变量
static uint8_t rx_address[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
static uint8_t tx_address[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
static RelayPacket rx_packet;
static RelayPacket tx_packet;
static volatile bool data_ready = false;

// 初始化nRF24L01
void NRF24L01_Init(void)
{
    // 初始化SPI
    SPI1_Init();
    
    // 配置CE引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置IRQ引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 复位nRF24L01
    GPIO_ResetBits(GPIOB, GPIO_Pin_0);  // CE拉低
    Delay_ms(100);
    
    // 配置寄存器
    NRF24L01_WriteReg(NRF24L01_CONFIG, 0x0C);  // 禁止中断,CRC 2字节,上电
    NRF24L01_WriteReg(NRF24L01_EN_AA, 0x01);   // 使能管道0自动应答
    NRF24L01_WriteReg(NRF24L01_EN_RXADDR, 0x01); // 使能管道0
    NRF24L01_WriteReg(NRF24L01_SETUP_AW, 0x03); // 地址宽度5字节
    NRF24L01_WriteReg(NRF24L01_SETUP_RETR, 0x1F); // 自动重传延迟500us,最多15次
    NRF24L01_WriteReg(NRF24L01_RF_CH, RELAY_CHANNEL); // 设置频道
    NRF24L01_WriteReg(NRF24L01_RF_SETUP, 0x0F); // 2Mbps, 0dBm, LNA开启
    NRF24L01_WriteReg(NRF24L01_RX_PW_P0, RELAY_PACKET_SIZE); // 接收管道0有效数据宽度
    
    // 设置地址
    NRF24L01_WriteBuf(NRF24L01_RX_ADDR_P0, rx_address, 5);
    NRF24L01_WriteBuf(NRF24L01_TX_ADDR, tx_address, 5);
    
    // 清除中断标志
    NRF24L01_WriteReg(NRF24L01_STATUS, 0x70);
    
    // 清空FIFO
    NRF24L01_FlushTX();
    NRF24L01_FlushRX();
    
    // 配置中断
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    
    // 上电
    NRF24L01_WriteReg(NRF24L01_CONFIG, 0x0E);  // 上电,PRX模式
    GPIO_SetBits(GPIOB, GPIO_Pin_0);  // CE拉高
    Delay_us(130);  // 等待稳定
}

// 设置频道
void NRF24L01_SetChannel(uint8_t channel)
{
    if (channel > 125) channel = 125;
    NRF24L01_WriteReg(NRF24L01_RF_CH, channel);
}

// 设置功率
void NRF24L01_SetPower(uint8_t power)
{
    uint8_t rf_setup = NRF24L01_ReadReg(NRF24L01_RF_SETUP);
    rf_setup &= ~0x06;  // 清除功率位
    rf_setup |= (power & 0x03) << 1;
    NRF24L01_WriteReg(NRF24L01_RF_SETUP, rf_setup);
}

// 设置数据速率
void NRF24L01_SetDataRate(uint8_t rate)
{
    uint8_t rf_setup = NRF24L01_ReadReg(NRF24L01_RF_SETUP);
    rf_setup &= ~0x28;  // 清除速率位
    rf_setup |= rate;
    NRF24L01_WriteReg(NRF24L01_RF_SETUP, rf_setup);
}

// 设置自动应答
void NRF24L01_SetAutoAck(bool enable)
{
    if (enable) {
        NRF24L01_WriteReg(NRF24L01_EN_AA, 0x01);
    } else {
        NRF24L01_WriteReg(NRF24L01_EN_AA, 0x00);
    }
}

// 设置重传参数
void NRF24L01_SetRetries(uint8_t delay, uint8_t count)
{
    NRF24L01_WriteReg(NRF24L01_SETUP_RETR, (delay << 4) | (count & 0x0F));
}

// 设置接收地址
void NRF24L01_SetRXAddress(uint8_t pipe, uint8_t *address)
{
    uint8_t reg = NRF24L01_RX_ADDR_P0 + pipe;
    NRF24L01_WriteBuf(reg, address, 5);
}

// 设置发送地址
void NRF24L01_SetTXAddress(uint8_t *address)
{
    NRF24L01_WriteBuf(NRF24L01_TX_ADDR, address, 5);
}

// 开始监听
void NRF24L01_StartListening(void)
{
    uint8_t config = NRF24L01_ReadReg(NRF24L01_CONFIG);
    config |= 0x01;  // PRIM_RX = 1
    NRF24L01_WriteReg(NRF24L01_CONFIG, config);
    GPIO_SetBits(GPIOB, GPIO_Pin_0);  // CE拉高
    Delay_us(130);
}

// 停止监听
void NRF24L01_StopListening(void)
{
    GPIO_ResetBits(GPIOB, GPIO_Pin_0);  // CE拉低
    Delay_us(10);
    uint8_t config = NRF24L01_ReadReg(NRF24L01_CONFIG);
    config &= ~0x01;  // PRIM_RX = 0
    NRF24L01_WriteReg(NRF24L01_CONFIG, config);
}

// 发送数据包
bool NRF24L01_SendPacket(RelayPacket *packet)
{
    // 停止接收
    NRF24L01_StopListening();
    
    // 清空TX FIFO
    NRF24L01_FlushTX();
    
    // 写入发送数据
    NRF24L01_WriteBuf(NRF24L01_CMD_W_TX_PAYLOAD, (uint8_t *)packet, sizeof(RelayPacket));
    
    // 启动发送
    GPIO_SetBits(GPIOB, GPIO_Pin_0);  // CE拉高
    Delay_us(10);  // 至少10us
    GPIO_ResetBits(GPIOB, GPIO_Pin_0);  // CE拉低
    
    // 等待发送完成或超时
    uint32_t timeout = HAL_GetTick() + 100;  // 100ms超时
    while (!(NRF24L01_GetStatus() & 0x20)) {  // 检查TX_DS位
        if (HAL_GetTick() > timeout) {
            return false;  // 发送超时
        }
    }
    
    // 清除中断标志
    NRF24L01_WriteReg(NRF24L01_STATUS, 0x20);
    
    return true;
}

// 接收数据包
bool NRF24L01_ReceivePacket(RelayPacket *packet)
{
    if (!NRF24L01_IsDataAvailable()) {
        return false;
    }
    
    // 读取数据
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_R_RX_PAYLOAD);
    for (uint8_t i = 0; i < sizeof(RelayPacket); i++) {
        ((uint8_t *)packet)[i] = SPI1_Transfer(NRF24L01_CMD_NOP);
    }
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
    
    // 清除中断标志
    NRF24L01_WriteReg(NRF24L01_STATUS, 0x40);
    
    return true;
}

// 检查是否有数据
bool NRF24L01_IsDataAvailable(void)
{
    uint8_t status = NRF24L01_GetStatus();
    return (status & 0x40) ? true : false;  // RX_DR位
}

// 清空TX FIFO
void NRF24L01_FlushTX(void)
{
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_FLUSH_TX);
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

// 清空RX FIFO
void NRF24L01_FlushRX(void)
{
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    SPI1_Transfer(NRF24L01_CMD_FLUSH_RX);
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

// 获取状态寄存器
uint8_t NRF24L01_GetStatus(void)
{
    return NRF24L01_ReadReg(NRF24L01_STATUS);
}

// 获取重传次数
uint8_t NRF24L01_GetRetransmissions(void)
{
    uint8_t observe_tx = NRF24L01_ReadReg(NRF24L01_OBSERVE_TX);
    return (observe_tx >> 4) & 0x0F;  // ARC_CNT
}

// 清除中断
void NRF24L01_ClearInterrupts(void)
{
    NRF24L01_WriteReg(NRF24L01_STATUS, 0x70);
}

// 中断处理函数
void NRF24L01_IRQHandler(void)
{
    uint8_t status = NRF24L01_GetStatus();
    
    if (status & 0x40) {  // RX_DR中断
        data_ready = true;
        NRF24L01_ClearInterrupts();
    }
    
    if (status & 0x20) {  // TX_DS中断
        NRF24L01_ClearInterrupts();
    }
    
    if (status & 0x10) {  // MAX_RT中断
        NRF24L01_FlushTX();
        NRF24L01_ClearInterrupts();
    }
}

// EXTI中断处理
void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) != RESET) {
        NRF24L01_IRQHandler();
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

4. 中继功能实现 relay.c

#include "nrf24l01_relay.h"
#include <stdlib.h>

// 静态变量
static uint8_t my_node_id = 0;
static RelayState current_state = RELAY_STATE_IDLE;
static RouteEntry route_table[RELAY_MAX_NODES];
static RelayStats stats = {0};
static uint32_t sequence_counter = 0;
static uint32_t last_heartbeat = 0;

// 初始化中继
void Relay_Init(uint8_t node_id)
{
    my_node_id = node_id;
    
    // 初始化路由表
    memset(route_table, 0, sizeof(route_table));
    
    // 初始化nRF24L01
    NRF24L01_Init();
    NRF24L01_SetChannel(RELAY_CHANNEL);
    NRF24L01_SetDataRate(RELAY_DATA_RATE);
    NRF24L01_SetPower(RELAY_POWER);
    NRF24L01_SetRetries(RELAY_RETRY_DELAY, RELAY_RETRY_COUNT);
    
    // 设置地址
    uint8_t addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, node_id};
    NRF24L01_SetRXAddress(0, addr);
    NRF24L01_SetTXAddress(addr);
    
    // 开始监听
    NRF24L01_StartListening();
    
    // 添加自己到路由表
    route_table[0].node_id = my_node_id;
    route_table[0].next_hop = my_node_id;
    route_table[0].hop_count = 0;
    route_table[0].quality = 255;
    route_table[0].active = true;
    route_table[0].last_update = HAL_GetTick();
    
    current_state = RELAY_STATE_IDLE;
    
    printf("Relay Node %d initialized\n", my_node_id);
}

// 中继主处理
void Relay_Process(void)
{
    // 检查是否有数据
    if (NRF24L01_IsDataAvailable()) {
        RelayPacket packet;
        
        if (NRF24L01_ReceivePacket(&packet)) {
            stats.packets_received++;
            
            // 验证校验和
            uint8_t checksum = 0;
            uint8_t *p = (uint8_t *)&packet;
            for (uint8_t i = 0; i < sizeof(RelayPacket) - 1; i++) {
                checksum ^= p[i];
            }
            
            if (checksum == packet.checksum) {
                // 处理数据包
                switch (packet.packet_type) {
                    case PKT_TYPE_DATA:
                        Relay_HandleDataPacket(&packet);
                        break;
                        
                    case PKT_TYPE_ACK:
                        Relay_HandleAckPacket(&packet);
                        break;
                        
                    case PKT_TYPE_ROUTE_REQUEST:
                        Relay_HandleRouteRequest(&packet);
                        break;
                        
                    case PKT_TYPE_ROUTE_REPLY:
                        Relay_HandleRouteReply(&packet);
                        break;
                        
                    case PKT_TYPE_HEARTBEAT:
                        Relay_HandleHeartbeat(&packet);
                        break;
                }
            } else {
                stats.packets_dropped++;
            }
        }
    }
    
    // 发送心跳包
    if (HAL_GetTick() - last_heartbeat > 10000) {  // 每10秒
        Relay_SendHeartbeat();
        last_heartbeat = HAL_GetTick();
    }
    
    // 清理过期路由表项
    static uint32_t last_cleanup = 0;
    if (HAL_GetTick() - last_cleanup > 60000) {  // 每分钟
        for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
            if (route_table[i].active && 
                (HAL_GetTick() - route_table[i].last_update > 300000)) {  // 5分钟过期
                route_table[i].active = false;
            }
        }
        last_cleanup = HAL_GetTick();
    }
}

// 处理数据包
void Relay_HandleDataPacket(RelayPacket *packet)
{
    // 如果是发给自己的包
    if (packet->dest_id == my_node_id) {
        printf("Received data from node %d: %s\n", 
               packet->source_id, packet->payload);
        
        // 发送ACK
        RelayPacket ack;
        memset(&ack, 0, sizeof(ack));
        ack.packet_type = PKT_TYPE_ACK;
        ack.source_id = my_node_id;
        ack.dest_id = packet->source_id;
        ack.sequence = packet->sequence;
        ack.timestamp = HAL_GetTick();
        ack.checksum = 0;
        uint8_t *p = (uint8_t *)&ack;
        for (uint8_t i = 0; i < sizeof(ack) - 1; i++) {
            ack.checksum ^= p[i];
        }
        
        NRF24L01_StopListening();
        NRF24L01_SendPacket(&ack);
        NRF24L01_StartListening();
        
        stats.packets_forwarded++;
    }
    // 需要转发
    else if (packet->hop_count < RELAY_MAX_HOPS) {
        RouteEntry *route = Relay_FindRoute(packet->dest_id);
        
        if (route && route->active) {
            packet->relay_id = my_node_id;
            packet->hop_count++;
            packet->ttl--;
            
            // 更新校验和
            packet->checksum = 0;
            uint8_t *p = (uint8_t *)packet;
            for (uint8_t i = 0; i < sizeof(RelayPacket) - 1; i++) {
                packet->checksum ^= p[i];
            }
            
            // 转发到下一跳
            uint8_t addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, route->next_hop};
            NRF24L01_SetTXAddress(addr);
            
            NRF24L01_StopListening();
            if (NRF24L01_SendPacket(packet)) {
                stats.packets_forwarded++;
            } else {
                stats.packets_dropped++;
            }
            NRF24L01_StartListening();
            
            // 恢复地址
            uint8_t my_addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, my_node_id};
            NRF24L01_SetTXAddress(my_addr);
        } else {
            // 没有路由,请求路由
            Relay_RequestRoute(packet->dest_id);
            stats.packets_dropped++;
        }
    } else {
        stats.packets_dropped++;
    }
}

// 发送数据
void Relay_SendData(uint8_t dest_id, uint8_t *data, uint8_t len)
{
    RelayPacket packet;
    memset(&packet, 0, sizeof(packet));
    
    packet.packet_type = PKT_TYPE_DATA;
    packet.source_id = my_node_id;
    packet.dest_id = dest_id;
    packet.relay_id = my_node_id;
    packet.hop_count = 0;
    packet.ttl = RELAY_MAX_HOPS;
    packet.sequence = ++sequence_counter;
    packet.timestamp = HAL_GetTick();
    
    // 复制数据
    if (len > sizeof(packet.payload)) len = sizeof(packet.payload);
    memcpy(packet.payload, data, len);
    
    // 计算校验和
    packet.checksum = 0;
    uint8_t *p = (uint8_t *)&packet;
    for (uint8_t i = 0; i < sizeof(packet) - 1; i++) {
        packet.checksum ^= p[i];
    }
    
    // 查找路由
    RouteEntry *route = Relay_FindRoute(dest_id);
    if (route && route->active) {
        uint8_t addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, route->next_hop};
        NRF24L01_SetTXAddress(addr);
    } else {
        // 广播到所有邻居
        uint8_t broadcast_addr[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        NRF24L01_SetTXAddress(broadcast_addr);
    }
    
    NRF24L01_StopListening();
    if (NRF24L01_SendPacket(&packet)) {
        stats.packets_forwarded++;
    } else {
        stats.packets_dropped++;
    }
    NRF24L01_StartListening();
    
    // 恢复地址
    uint8_t my_addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, my_node_id};
    NRF24L01_SetTXAddress(my_addr);
}

// 请求路由
void Relay_RequestRoute(uint8_t dest_id)
{
    RelayPacket packet;
    memset(&packet, 0, sizeof(packet));
    
    packet.packet_type = PKT_TYPE_ROUTE_REQUEST;
    packet.source_id = my_node_id;
    packet.dest_id = dest_id;
    packet.relay_id = my_node_id;
    packet.sequence = ++sequence_counter;
    packet.timestamp = HAL_GetTick();
    
    // 计算校验和
    packet.checksum = 0;
    uint8_t *p = (uint8_t *)&packet;
    for (uint8_t i = 0; i < sizeof(packet) - 1; i++) {
        packet.checksum ^= p[i];
    }
    
    // 广播请求
    uint8_t broadcast_addr[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    NRF24L01_SetTXAddress(broadcast_addr);
    
    NRF24L01_StopListening();
    NRF24L01_SendPacket(&packet);
    NRF24L01_StartListening();
    
    // 恢复地址
    uint8_t my_addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, my_node_id};
    NRF24L01_SetTXAddress(my_addr);
    
    stats.route_requests++;
}

// 更新路由表
void Relay_UpdateRouteTable(uint8_t node_id, uint8_t next_hop, uint8_t hop_count)
{
    // 查找现有条目
    for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
        if (route_table[i].node_id == node_id && route_table[i].active) {
            // 更新更好的路由
            if (hop_count < route_table[i].hop_count) {
                route_table[i].next_hop = next_hop;
                route_table[i].hop_count = hop_count;
                route_table[i].last_update = HAL_GetTick();
            }
            return;
        }
    }
    
    // 查找空槽
    for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
        if (!route_table[i].active) {
            route_table[i].node_id = node_id;
            route_table[i].next_hop = next_hop;
            route_table[i].hop_count = hop_count;
            route_table[i].quality = 255;
            route_table[i].last_update = HAL_GetTick();
            route_table[i].active = true;
            return;
        }
    }
}

// 查找路由
RouteEntry* Relay_FindRoute(uint8_t dest_id)
{
    for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
        if (route_table[i].node_id == dest_id && route_table[i].active) {
            return &route_table[i];
        }
    }
    return NULL;
}

// 发送心跳包
void Relay_SendHeartbeat(void)
{
    RelayPacket packet;
    memset(&packet, 0, sizeof(packet));
    
    packet.packet_type = PKT_TYPE_HEARTBEAT;
    packet.source_id = my_node_id;
    packet.dest_id = 0xFF;  // 广播
    packet.relay_id = my_node_id;
    packet.sequence = ++sequence_counter;
    packet.timestamp = HAL_GetTick();
    
    // 包含路由表信息
    uint8_t route_count = 0;
    for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
        if (route_table[i].active) {
            packet.payload[route_count * 2] = route_table[i].node_id;
            packet.payload[route_count * 2 + 1] = route_table[i].hop_count;
            route_count++;
            if (route_count >= 8) break;  // 最多8个路由
        }
    }
    
    // 计算校验和
    packet.checksum = 0;
    uint8_t *p = (uint8_t *)&packet;
    for (uint8_t i = 0; i < sizeof(packet) - 1; i++) {
        packet.checksum ^= p[i];
    }
    
    // 广播心跳
    uint8_t broadcast_addr[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    NRF24L01_SetTXAddress(broadcast_addr);
    
    NRF24L01_StopListening();
    NRF24L01_SendPacket(&packet);
    NRF24L01_StartListening();
    
    // 恢复地址
    uint8_t my_addr[5] = {0xC2, 0xC2, 0xC2, 0xC2, my_node_id};
    NRF24L01_SetTXAddress(my_addr);
}

// 打印统计信息
void Relay_PrintStats(void)
{
    printf("\n=== Relay Node %d Statistics ===\n", my_node_id);
    printf("Packets Received: %lu\n", stats.packets_received);
    printf("Packets Forwarded: %lu\n", stats.packets_forwarded);
    printf("Packets Dropped: %lu\n", stats.packets_dropped);
    printf("Route Requests: %lu\n", stats.route_requests);
    printf("Route Replies: %lu\n", stats.route_replies);
    printf("ACK Received: %lu\n", stats.ack_received);
    printf("ACK Timeout: %lu\n", stats.ack_timeout);
    printf("\nRouting Table:\n");
    for (uint8_t i = 0; i < RELAY_MAX_NODES; i++) {
        if (route_table[i].active) {
            printf("  Node %d -> Next Hop %d (%d hops)\n",
                   route_table[i].node_id,
                   route_table[i].next_hop,
                   route_table[i].hop_count);
        }
    }
    printf("==============================\n");
}

5. 主程序 main.c

#include "stm32f10x.h"
#include "nrf24l01_relay.h"
#include "relay.h"
#include <stdio.h>

// 重定向printf到串口
int fputc(int ch, FILE *f)
{
    USART_SendData(USART1, (uint8_t)ch);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    return ch;
}

// 系统时钟配置
void SystemClock_Init(void)
{
    ErrorStatus HSEStartUpStatus;
    
    RCC_DeInit();
    RCC_HSEConfig(RCC_HSE_ON);
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
    if (HSEStartUpStatus == SUCCESS) {
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        RCC_PLLCmd(ENABLE);
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        while (RCC_GetSYSCLKSource() != 0x08);
    }
}

// 串口初始化
void USART1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);
}

// 延时函数
void Delay_ms(uint32_t ms)
{
    for (uint32_t i = 0; i < ms * 8000; i++);
}

int main(void)
{
    // 系统初始化
    SystemClock_Init();
    USART1_Init();
    
    printf("STM32F103C8T6 nRF24L01 Wireless Relay\n");
    printf("=====================================\n\n");
    
    // 初始化中继节点(节点ID=1)
    Relay_Init(1);
    
    // 发送测试数据
    uint8_t test_data[] = "Hello from Relay Node 1!";
    
    while (1) {
        // 处理中继逻辑
        Relay_Process();
        
        // 每5秒发送一次测试数据
        static uint32_t last_send = 0;
        if (HAL_GetTick() - last_send > 5000) {
            Relay_SendData(2, test_data, sizeof(test_data));  // 发送到节点2
            last_send = HAL_GetTick();
        }
        
        // 每30秒打印统计信息
        static uint32_t last_stats = 0;
        if (HAL_GetTick() - last_stats > 30000) {
            Relay_PrintStats();
            last_stats = HAL_GetTick();
        }
        
        Delay_ms(10);
    }
}

三、网络拓扑示例

节点1 (ID=1) <----> 中继节点 (ID=2) <----> 节点3 (ID=3)
     |                    |                    |
     |                    |                    |
  传感器              路由器/中继             执行器

参考代码 stm32F103c8t6关联nRF24L01无线射频模块进行无线中继 www.youwenfan.com/contentcsv/72016.html

四、配置与使用

1. 编译与烧录

# 使用Keil MDK或STM32CubeIDE
# 1. 创建工程,包含所有源文件
# 2. 配置编译器选项
# 3. 编译生成hex文件
# 4. 使用ST-Link烧录到STM32F103C8T6

2. 测试步骤

  1. 节点1:发送数据到节点3
  2. 中继节点2:接收并转发数据
  3. 节点3:接收数据并回复ACK
  4. 中继节点2:转发ACK回节点1

3. 预期输出

STM32F103C8T6 nRF24L01 Wireless Relay
=====================================

Relay Node 1 initialized
Sending data to node 2
Received data from node 3: Hello from Node 3!

=== Relay Node 1 Statistics ===
Packets Received: 15
Packets Forwarded: 12
Packets Dropped: 0
Route Requests: 2
Route Replies: 2
ACK Received: 10
ACK Timeout: 0

Routing Table:
  Node 2 -> Next Hop 2 (1 hops)
  Node 3 -> Next Hop 2 (2 hops)
==============================

五、优化建议

1. 功耗优化

// 进入低功耗模式
void EnterLowPowerMode(void)
{
    NRF24L01_StopListening();
    GPIO_ResetBits(GPIOB, GPIO_Pin_0);  // CE拉低
    __WFI();  // 等待中断
}

2. 信号质量监测

// 监测RSSI
uint8_t GetRSSI(void)
{
    uint8_t rpd = NRF24L01_ReadReg(NRF24L01_CD);
    return rpd ? 100 : 0;  // 简单RSSI指示
}

3. 多通道中继

// 支持多个信道
void SwitchChannel(uint8_t channel)
{
    NRF24L01_StopListening();
    NRF24L01_SetChannel(channel);
    NRF24L01_StartListening();
}

六、故障排除

问题 可能原因 解决方案
无法通信 地址不匹配 检查所有节点的地址设置
距离短 功率设置低 增加发射功率
丢包严重 干扰大 更换信道或降低数据速率
中继不工作 路由表为空 检查路由请求和回复

这个方案提供了一个完整的无线中继系统,支持多跳路由、自动发现和故障恢复。您可以根据实际需求调整参数和功能。

专注于matlab/simulink,电子电路,编程