射频通信¶
射频通信是指通过无线电波进行信息传输的技术。它广泛应用于无线电、电视、手机、卫星通信等领域。射频通信的基本原理是将信息调制到射频信号上,通过天线发射和接收。本项目使用nRF24L01无线模块进行射频通信。
以下是nRF24L01无线模块的相关代码实现:
rf.hpp
#pragma once
#include <Arduino.h>
#include <RF24.h>
#define RF_CHANNEL 108
#define RF_PIPE_BASE 0xF0F0F0F000LL
struct RFMessage
{
uint8_t from_id;
uint8_t to_id;
char payload[24];
uint64_t timestamp_ms;
};
bool rf_init();
bool rf_send(uint8_t to_id, const RFMessage &msg, bool require_ack = false);
bool rf_receive(RFMessage &msg, unsigned long timeout_ms);
bool rf_send_then_receive(const RFMessage &msg, uint8_t to_id, unsigned long timeout_ms, uint8_t retries);
void rf_stop_listening();
void rf_start_listening();
void rf_set_rx_address(uint8_t id);
String rf_format_address(uint16_t node_id);
rf.cpp
#include "rf.hpp"
#include "config.hpp"
#include <SPI.h>
RF24 radio(9, 8);
String rf_format_address(uint16_t node_id)
{
char buf[6];
snprintf(buf, sizeof(buf), "N%03d", node_id);
return String(buf);
}
void rf_set_rx_address(uint8_t id)
{
uint64_t address = RF_PIPE_BASE | id;
radio.openReadingPipe(1, address);
radio.setAutoAck(true);
}
bool rf_init()
{
if (!radio.begin())
{
Serial.println("[INIT] <RF> Initialization failed.");
return false;
}
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.setChannel(RF_CHANNEL);
radio.setRetries(5, 15);
radio.enableDynamicPayloads();
radio.setCRCLength(RF24_CRC_16);
rf_set_rx_address(NODE_ID);
radio.startListening();
Serial.print("[INIT] <RF> Initialized. Listening on ");
Serial.println(rf_format_address(NODE_ID));
return true;
}
void rf_stop_listening() { radio.stopListening(); }
void rf_start_listening() { radio.startListening(); }
bool rf_send(uint8_t to_id, const RFMessage &msg, bool require_ack)
{
uint64_t tx_address = RF_PIPE_BASE | to_id;
radio.openWritingPipe(tx_address);
return radio.write(&msg, sizeof(RFMessage), require_ack);
}
bool rf_receive(RFMessage &msg, unsigned long timeout_ms)
{
unsigned long start_time = millis();
while (millis() - start_time < timeout_ms)
{
if (radio.available())
{
radio.read(&msg, sizeof(RFMessage));
return true;
}
}
return false;
}
bool rf_send_then_receive(const RFMessage &msg, uint8_t to_id, unsigned long timeout_ms, uint8_t retries)
{
for (uint8_t attempt = 0; attempt < retries; ++attempt)
{
rf_stop_listening();
bool sent = rf_send(to_id, msg);
rf_start_listening();
if (!sent)
{
Serial.print("[RF] Send failed (attempt ");
Serial.print(attempt + 1);
Serial.println(")");
continue;
}
RFMessage response;
if (rf_receive(response, timeout_ms) && response.to_id == NODE_ID)
return true;
Serial.print("[RF] No response received (attempt ");
Serial.print(attempt + 1);
Serial.println(")");
}
return false;
}
关键函数¶
函数名 | 功能描述 |
---|---|
rf_init() | 初始化 nRF24L01 模块,设置频道、数据速率等参数,并开始监听。 |
rf_send(uint8_t to_id, const RFMessage &msg, bool require_ack = false) | 向指定节点 ID 发送 RFMessage 消息,可选择是否需要确认应答。 |
rf_receive(RFMessage &msg, unsigned long timeout_ms) | 在指定超时时间内接收 RFMessage 消息。 |
rf_send_then_receive(const RFMessage &msg, uint8_t to_id, unsigned long timeout_ms, uint8_t retries) | 发送消息后等待接收响应,支持设置重试次数。 |
rf_stop_listening() | 停止监听,切换到发送模式。 |
rf_start_listening() | 开始监听,切换到接收模式。 |
rf_set_rx_address(uint8_t id) | 设置接收地址,指定要监听的节点 ID。 |
rf_format_address(uint16_t node_id) | 将节点 ID 格式化为字符串形式,便于打印和调试。 |
RFMessage 结构体说明¶
RFMessage
结构体用于定义无线通信中传输的消息格式,包含以下字段:
from_id
:发送方节点 ID。to_id
:接收方节点 ID。payload
:消息的有效载荷,最大长度为 24 字节。timestamp_ms
:消息的发送时间戳,单位为毫秒。
rf_init() 函数说明¶
rf_init()
函数用于初始化 nRF24L01 模块。函数首先尝试启动模块,如果失败返回 false
。接着配置发射功率、数据速率、频道、重试机制,并启用动态有效载荷和 CRC 校验。随后调用 rf_set_rx_address(NODE_ID)
设置本节点接收地址,并进入监听模式。初始化成功后会打印当前节点地址并返回 true
。
rf_set_rx_address() 函数说明¶
rf_set_rx_address(uint8_t id)
函数用于设置 nRF24L01 模块的接收地址。它将节点 ID 与预设基地址 RF_PIPE_BASE
进行位或操作,生成完整地址,然后调用 radio.openReadingPipe(1, address)
打开接收管道,并启用自动应答功能。
rf_format_address() 函数说明¶
rf_format_address(uint16_t node_id)
函数将节点 ID 格式化为字符串,格式为 "Nxxx"(如 N001、N100),使用 snprintf
实现,方便打印与调试。
rf_send() 函数说明¶
rf_send(uint8_t to_id, const RFMessage &msg, bool require_ack)
函数用于发送 RFMessage 消息到指定接收节点。它先生成对应的写入地址并执行发送。如果 require_ack
为 true
,会等待接收方的确认应答。函数返回发送是否成功的布尔值。
rf_receive() 函数说明¶
rf_receive(RFMessage &msg, unsigned long timeout_ms)
函数用于在给定超时时间内尝试接收一条消息。如果成功接收到数据,则将其写入传入的 msg
对象,并返回 true
;否则在超时后返回 false
。
rf_send_then_receive() 函数说明¶
rf_send_then_receive(const RFMessage &msg, uint8_t to_id, unsigned long timeout_ms, uint8_t retries)
函数用于发送消息并等待回应。它会尝试最多 retries
次发送,每次发送后切换至监听模式等待响应。如果收到的响应中 to_id
与当前节点 ID 匹配,则返回 true
,否则继续重试。所有尝试失败时返回 false
。
rf_stop_listening() 和 rf_start_listening() 函数说明¶
rf_stop_listening()
用于停止监听模式,切换至发送模式,通过调用radio.stopListening()
实现。rf_start_listening()
用于启动监听模式,通过调用radio.startListening()
实现接收功能。