2. 无线按键状态传输

任务说明

本案例实现一个无线按键状态传输系统:发送端读取按键状态(按下/释放),通过无线模块发送;接收端收到数据后,根据按键状态控制LED的亮灭。系统需完成远程按键检测与LED联动控制。

硬件连接

发送端 MCU (ATmega328P) PB0 → 按键输入 PD2 → TX(发送) 按键S1 GND 内部上拉 NRF24L01+ 发送端模块 CE, CSN, SCK, MOSI, MISO, IRQ SPI 2.4GHz 无线传输 NRF24L01+ 接收端模块 CE, CSN, SCK, MOSI, MISO, IRQ 接收端 MCU (ATmega328P) PD2 → RX(接收) PB0 → LED控制 SPI LED GND 330Ω 按键状态 LED控制 无线数据包格式 0xAA 0x01 状态 0x55 帧头 类型 数据 帧尾

通信协议

无线数据包固定为4字节:0xAA(帧头)、0x01(按键状态类型)、状态字节(0x01表示按下,0x00表示释放)、0x55(帧尾)。接收端校验帧头帧尾后,提取状态字节控制LED。

发送端代码(sender.ino)


#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define KEY_PIN 3        // PB0 对应 Arduino 数字引脚 3(ATmega328P 的 PB0 为 D8,此处用 D3 示例)
#define CE_PIN  9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);
const byte pipe[6] = "2Node";

// 数据包结构
struct Packet {
  uint8_t header;
  uint8_t type;
  uint8_t state;
  uint8_t tail;
};

void setup() {
  pinMode(KEY_PIN, INPUT_PULLUP);  // 内部上拉,按下为 LOW
  radio.begin();
  radio.setChannel(100);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(pipe);
  radio.stopListening();
}

void loop() {
  Packet pkt;
  pkt.header = 0xAA;
  pkt.type   = 0x01;
  pkt.state  = (digitalRead(KEY_PIN) == LOW) ? 0x01 : 0x00;  // 按下=1
  pkt.tail   = 0x55;

  radio.write(&pkt, sizeof(pkt));
  delay(50);  // 20Hz 发送频率
}

接收端代码(receiver.ino)


#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define LED_PIN 5        // PB0 对应 Arduino 数字引脚 5(示例)
#define CE_PIN  9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);
const byte pipe[6] = "2Node";

struct Packet {
  uint8_t header;
  uint8_t type;
  uint8_t state;
  uint8_t tail;
};

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  Serial.begin(9600);

  radio.begin();
  radio.setChannel(100);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.openReadingPipe(1, pipe);
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    Packet pkt;
    radio.read(&pkt, sizeof(pkt));

    // 校验帧头帧尾
    if (pkt.header == 0xAA && pkt.tail == 0x55 && pkt.type == 0x01) {
      if (pkt.state == 0x01) {
        digitalWrite(LED_PIN, HIGH);   // 按键按下 → LED 亮
      } else {
        digitalWrite(LED_PIN, LOW);    // 按键释放 → LED 灭
      }
    }
  }
}

接线说明

发送端连接接收端连接
按键一端→ GNDLED 阳极→ 330Ω → PB0
按键另一端→ PB0 (D8)LED 阴极→ GND
NRF24L01 CE→ D9NRF24L01 CE→ D9
NRF24L01 CSN→ D10NRF24L01 CSN→ D10
NRF24L01 SCK/MOSI/MISO→ D13/D11/D12NRF24L01 SCK/MOSI/MISO→ D13/D11/D12
NRF24L01 VCC/GND→ 3.3V/GNDNRF24L01 VCC/GND→ 3.3V/GND

验证方法

  1. 分别将发送端和接收端代码烧录到两块 Arduino 板,按上述表格接线。
  2. 打开接收端串口监视器(波特率9600),观察是否有数据输出(可添加调试打印)。
  3. 按下发送端按键,观察接收端 LED 是否点亮;释放按键,LED 熄灭。
  4. 判定标准:按键按下时 LED 在 100ms 内点亮,释放后 100ms 内熄灭,且无错误触发,即验证通过。

关键说明

  • 发送端每 50ms 发送一次当前按键状态,即使状态未变化也持续发送,保证接收端能及时同步。
  • 接收端仅在有数据到达时更新 LED 状态,无数据时保持当前状态不变。
  • 两端必须设置相同的无线频道(channel=100)、数据速率和发送管道地址,否则无法通信。
  • NRF24L01 模块必须使用 3.3V 供电,不可直接接 5V。