The HC-12 sends serial text over 433 MHz for hundreds of metres. Paired with a NodeMCU it makes a good receiver and Wi-Fi gateway for a gate sensor, a pump-house alarm or a field node that Wi-Fi can’t reach.
The radio uses SoftwareSerial on D5 (RX) and D6 (TX) with SET on D7, all pins with no boot role. At start-up the sketch reads the module’s settings, then listens for numbered UNO <n> packets from a second HC-12 and reports how many arrived and how many were lost — a simple range tester.
Wiring
| NodeMCU ESP8266 | HC-12 433 MHz wireless serial module | Wire | Notes |
|---|---|---|---|
| VIN | VCC | red | 5 V from USB, so the ~100 mA transmit peaks don’t load the NodeMCU’s 3.3 V regulator. 100–470 µF across VCC/GND at the module. |
| GND | GND | black | |
| D5 | TXD | green | GPIO14, SoftwareSerial RX. HC-12 TXD is a 3.3 V output. |
| D6 | RXD | yellow | GPIO12, SoftwareSerial TX. |
| D7 | SET | orange | GPIO13. LOW = AT mode, HIGH = radio mode. |
3.2–5.5 V (100 mA peaks at full power) part, 3.3 V board. TXD is a 3.3 V output, which every board reads as HIGH. RXD is designed to accept 3.3 V or 5 V UART levels, so ESP32, Pico and Uno connect directly. Power it from 3.3 V or 5 V.
Board quirks
- The ESP8266’s only full UART is wired to USB, so the radio uses SoftwareSerial on D5/D6. At the HC-12’s default 9600 baud that is reliable even with Wi-Fi on.
- Keep the radio off D3, D4 and D8. They decide the boot mode, and the HC-12’s pulled-up SET or a TXD idling HIGH on D8 can stop the NodeMCU starting. D1/D2 stay free for an I2C display.
- Both sides use 3.3 V logic, so the NodeMCU drives SET HIGH and LOW directly — no “only pull it low” trick needed.
- The sketch expects lines like
UNO 17. A gap in the numbers is a lost packet, so carrying the sender around the building or along a farm boundary shows where the link breaks. Anything else received is printed with a timestamp. - India’s 433 MHz licence-free band is narrow and meant for low power: stay on channels 001–004 and a low power setting (for example
AT+P4) unless you have checked the current rules. Both radios must match on channel, baud and FU mode. - A NodeMCU receiver is a natural gateway: radio from the field, Wi-Fi to your phone or an MQTT broker.
Code
// HC-12 433 MHz serial radio on a NodeMCU (ESP8266) — range-test receiver that counts lost packets.
// HC-12 TXD → D5 (GPIO14, soft RX), RXD ← D6 (GPIO12, soft TX), SET ← D7 (GPIO13),
// VCC → VIN (5 V) with a 100–470 µF capacitor at the module, GND → GND.
// Pairs with a sender that transmits "UNO <n>" lines (see the Uno HC-12 guide): gaps in n = lost packets.
#include <SoftwareSerial.h>
SoftwareSerial hc12(D5, D6); // RX, TX
constexpr uint8_t SET_PIN = D7;
String line;
long lastSeq = -1;
uint32_t got = 0, lost = 0;
void setup() {
Serial.begin(115200);
Serial.println();
hc12.begin(9600); // HC-12 default: 9600 baud, FU3
pinMode(SET_PIN, OUTPUT);
digitalWrite(SET_PIN, LOW); // AT mode for a moment
delay(60);
hc12.println("AT+RX");
delay(250);
while (hc12.available()) Serial.write(hc12.read());
digitalWrite(SET_PIN, HIGH); // radio mode (3.3 V HIGH is fine for the HC-12)
delay(100);
Serial.println("Listening for UNO <n> packets");
}
void loop() {
while (hc12.available()) {
char c = hc12.read();
if (c == '\r') continue;
if (c != '\n') {
if (line.length() < 60) line += c;
continue;
}
if (line.startsWith("UNO ")) {
long seq = line.substring(4).toInt();
if (lastSeq >= 0 && seq > lastSeq + 1) lost += seq - lastSeq - 1;
lastSeq = seq;
got++;
Serial.printf("%lu s #%ld received %lu lost %lu (%.0f%% ok)\n", millis() / 1000, seq, (unsigned long)got,
(unsigned long)lost, 100.0 * got / (got + lost));
} else if (line.length()) {
Serial.printf("%lu s %s\n", millis() / 1000, line.c_str());
}
line = "";
}
while (Serial.available()) hc12.write(Serial.read());
}// HC-12 433 MHz serial radio on a NodeMCU (ESP8266) — range-test receiver that counts lost packets.
// HC-12 TXD → D5 (GPIO14, soft RX), RXD ← D6 (GPIO12, soft TX), SET ← D7 (GPIO13),
// VCC → VIN (5 V) with a 100–470 µF capacitor at the module, GND → GND.
// Pairs with a sender that transmits "UNO <n>" lines (see the Uno HC-12 guide): gaps in n = lost packets.
#include <SoftwareSerial.h>
SoftwareSerial hc12(D5, D6); // RX, TX
constexpr uint8_t SET_PIN = D7;
String line;
long lastSeq = -1;
uint32_t got = 0, lost = 0;
void setup() {
Serial.begin(115200);
Serial.println();
hc12.begin(9600); // HC-12 default: 9600 baud, FU3
pinMode(SET_PIN, OUTPUT);
digitalWrite(SET_PIN, LOW); // AT mode for a moment
delay(60);
hc12.println("AT+RX");
delay(250);
while (hc12.available()) Serial.write(hc12.read());
digitalWrite(SET_PIN, HIGH); // radio mode (3.3 V HIGH is fine for the HC-12)
delay(100);
Serial.println("Listening for UNO <n> packets");
}
void loop() {
while (hc12.available()) {
char c = hc12.read();
if (c == '\r') continue;
if (c != '\n') {
if (line.length() < 60) line += c;
continue;
}
if (line.startsWith("UNO ")) {
long seq = line.substring(4).toInt();
if (lastSeq >= 0 && seq > lastSeq + 1) lost += seq - lastSeq - 1;
lastSeq = seq;
got++;
Serial.printf("%lu s #%ld received %lu lost %lu (%.0f%% ok)\n", millis() / 1000, seq, (unsigned long)got,
(unsigned long)lost, 100.0 * got / (got + lost));
} else if (line.length()) {
Serial.printf("%lu s %s\n", millis() / 1000, line.c_str());
}
line = "";
}
while (Serial.available()) hc12.write(Serial.read());
}Expected serial output
OK+B9600
OK+RC001
OK+RP:+20dBm
OK+FU3
Listening for UNO <n> packets
42 s #8 received 1 lost 0 (100% ok)
47 s #9 received 2 lost 0 (100% ok)
57 s #11 received 3 lost 1 (75% ok)OK+B9600 OK+RC001 OK+RP:+20dBm OK+FU3 Listening for UNO <n> packets 42 s #8 received 1 lost 0 (100% ok) 47 s #9 received 2 lost 0 (100% ok) 57 s #11 received 3 lost 1 (75% ok)
Common errors
Nothing printed after “Listening”
TXD/RXD swapped (HC-12 TXD goes to D5), the sender on another channel or baud, or no common GND. Run AT+RX on both modules.
NodeMCU doesn’t boot with the HC-12 connected
A wire is on D3, D4 or D8. Use D5, D6 and D7 as shown.
Many lost packets even close by
Missing capacitor, antennas touching other wires, or two transmitters on the same channel. Add the capacitor and straighten the spring antennas.