Understanding and Implementing The HC

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 19

Understanding and Implementing the HC-

12 Wireless Transceiver Module


November 02, 2016 by Mark Hughes

https://www.allaboutcircuits.com/projects/understanding-and-implementing-the-hc-12-
wireless-transceiver-module/

Learn about the HC-12 transceiver module and how to use it to transmit and receive digital
data.

The HC-12 is a half-duplex wireless serial communication module with 100 channels in the
433.4-473.0 MHz range that is capable of transmitting up to 1 km. This project will begin by
using the HC-12 to create a wireless link between two computers and end with a second
article that creates a simple wireless GPS tracker.

Parts Required

Item Cost More Information


HC-12 transceiver (x2) $4 Datasheet
IPEX-to-SMA adapter (optional) $3 Specification
Arduino Uno R3 (or compatible) $10 Reference
GPS Receiver (x2) $16 Datasheet
or Adafruit GPS Logger Shield (x2) $45 Project Guide
433MHz antenna $2-$5 Datasheet Search

About the HC-12

The HC-12 is a half-duplex 20 dBm (100 mW) transmitter paired with a receiver that has -
117 dBm (2×10-15 W) sensitivity at 5000 bps.

Paired with an external antenna, these transceivers are capable of communicating up to and
possibly slightly beyond 1 km in the open and are more than adequate for providing coverage
throughout a typical house.

The HC-12 circuit board. Image courtesy of Seeed. This image has been digitally manipulated to enhance
chip markings.
The HC-12 circuit board is built around the STM8S003F3 microcontroller and the Si4463
transceiver.

The Si4463 Transceiver

The Si4463 provides the wireless communication in this circuit. It has a maximum transmit
power of 20 dBm (100 mW) and receive sensitivity of -129 dBm. Two 64-byte Rx and Tx
FIFO memories are built into the chip along with a great many advanced features that are not
implemented in the HC-12 design. See the datasheet for more information on multiband
operation, frequency hopping, etc.

The STM8S003FS Microcontroller

This is an 8-bit microcontroller with 8 kB of flash memory, 128 bytes of EEPROM, and a 10-
bit ADC. It supports UART, SPI, and I²C and has multiple I/O pins. It offers many of the
same capabilities as its ATMega and XMC counterparts. It is programmed to control the
Si4463 as well as handle the UART communication between the HC-12 and whatever it is
connected to on the other end.

The HC-12 Transceiver Module

Combined with other components, the Si4463 and STM8S003 create the HC-12 transceiver,
which provides a 4-pin TTL-level UART interface (Vcc, Gnd, Tx, Rx), with a 5th pin that is
used to enter "command" mode for changing the module's configuration. The HC-12 has 100
supported channels spaced 400 kHz apart, eight transmit levels, eight supported baud rates,
and three different working modes.

The 5th pin on the HC-12 is labeled "Set" and, when driven to logic low, allows various
settings to be selected on the HC-12 using AT commands sent to the "RXD" pin.

The default configuration of the HC-12 is FU3—on Channel 1, FU3 is a fully automatic and
transparent (to other devices) setting that adapts to the transmission rate of the connected
device (although 9600 baud is still required to program it in Command mode).

Note that as the transmission rate increases, the sensitivity of the receiver decreases. You can
return to the default state by sending AT+DEFAULT once in command mode.
Serial Port Baud Rate Over-the-Air Baud Rate Receiver Sensitivity
1200 bps 5000 bps -117 dBm
2400 bps 5000 bps -117 dBm
4800 bps 15000 bps -112 dBm
9600 bps 15000 bps -112 dBm
19200 bps 58000 bps -107 dBm
38400 bps 58000 bps -107 dBm
57600 bps 236000 bps -100 dBm
115200 bps 236000 bps -100 dBm

In "HC12 Send/Recieve Example Program 1," the HC-12s are used in their default state
(FU3: 20mW transmit, 9600 bps, Channel 001) to create a wireless bridge between the serial
ports of two computers. The transceivers must be physically separated by at least 1.5
meters to function.

This program will allow messages to be sent between two computers via the HC-12
transmitters. Text typed on one computer will be displayed on the serial monitor of the
second computer.

Begin by connecting the HC-12 transceivers to each Arduino:

 Connect the HC-12 "Set" pin to Arduino pin 6


 Connect the HC-12 "RXD" pin to Arduino pin 4
 Connect the HC-12 "TXD" pin to Arduino pin 5
 Per the datasheet, connect a 22 µF to 1 mF reservoir capacitor in parallel with the HC-
12 "Gnd" and "Vcc" pins
 Connect HC-12 "Gnd" and "Vcc" to a 3.2 V to 5.5V 200mA source. Per the datasheet,
if powering the HC-12 with more than 4.5V, place a 1N4007 diode in series with the
HC-12 "Vcc" pin

Upload the following code and open the serial port monitor in the Arduino IDE to
send/receive messages.

The functions "*.available()" reads the number of bytes stored in the Arduino's Serial or
SoftwareSerial FIFO buffers. As long as there is a non-zero value returned by "*.available()",
the "*.read()" function pulls one byte out of the buffer and the "*.write()" function sends that
byte along to the other serial port to be read by either the computer or the HC-12.

The Arduino UART has a 64-byte receive buffer built into the hardware so any bytes of data
that exceed the 64-byte limit will be discarded. The software serial also has a 64-byte buffer;
however, the SoftwareSerial library can be modified to increase that, if required.

/* HC12 Send/Receive Example Program 1


By Mark J. Hughes
for AllAboutCircuits.com

Connect HC12 "RXD" pin to Arduino Digital Pin 4


Connect HC12 "TXD" pin to Arduino Digital Pin 5
Connect HC12 "Set" pin to Arduino Digital Pin 6

Do not power over USB. Per datasheet,


power HC12 with a supply of at least 100 mA with
a 22 uF - 1000 uF reservoir capacitor.
Upload code to two Arduinos connected to two computers.

Transceivers must be at least several meters apart to work.

*/

#include <SoftwareSerial.h>

const byte HC12RxdPin = 4; // Recieve Pin on HC12


const byte HC12TxdPin = 5; // Transmit Pin on HC12

SoftwareSerial HC12(HC12TxdPin,HC12RxdPin); // Create Software Serial Port

void setup() {
Serial.begin(9600); // Open serial port to computer
HC12.begin(9600); // Open serial port to HC12
}

void loop() {
if(HC12.available()){ // If Arduino's HC12 rx buffer
has data
Serial.write(HC12.read()); // Send the data to the
computer
}
if(Serial.available()){ // If Arduino's computer rx
buffer has data
HC12.write(Serial.read()); // Send that data to serial
}
}

"HC12 Send/Recieve Example Program 2" remains backward-compatible with "HC12


Send/Recieve Example Program 1." However, two significant changes have been made in the
way data is handled by the Arduino.
In the first program, single bytes were detected and read from the serial buffer and software
serial buffer and immediately written to the other serial port. The following program will read
entire strings of data from the serial buffers and store it until a newline character is
detected at which point it will write out the entire buffer.

The first program had no way to enter command mode and change the settings of the HC-12
transceiver. The following program can detect command sequences and change the settings
of remote and local transceivers (provided they are running the newer version of the code).
Note that it is important to change the settings of the remote transceiver first and then change
the settings of the local transceiver to match, as any initial changes to the local transceiver
will interrupt communication between the two.

The Arduino will collect strings from the serial port and software serial port. Once the new
line has been detected, there is a check to confirm if the string is a command sequence
(commands begin with AT+). If a command sequence is present, the local chip executes the
command and transmits the command to the remote chip for execution there. The code
keeps the HC12s on the same channel at same power levels during testing.

Use caution as it is possible to accidentally lower the remote power level to a point that the
remote transceiver can no longer communicate with the local transceiver. This is quickly
fixed by broadcasting a new power level. Changing the baud rate can disable communication
between the HC-12 and the Arduino unless the Arduino baud rate is changed at the same
time.

/* HC12 Send/Receive Example Program 2


By Mark J. Hughes
for AllAboutCircuits.com

This code will automatically detect commands as sentences that begin


with AT and both write them and broadcast them to remote receivers
to be written. Changing settings on a local transceiver will
change settings on a remote receiver.

Connect HC12 "RXD" pin to Arduino Digital Pin 4


Connect HC12 "TXD" pin to Arduino Digital Pin 5
Connect HC12 "Set" pin to Arduino Digital Pin 6

Do not power HC12 via Arduino over USB. Per the data sheet,
power the HC12 with a supply of at least 100 mA with
a 22 uF to 1000 uF reservoir capacitor and connect a 1N4007 diode in
series with the positive supply line if the potential difference
exceeds 4.5 V.

Upload code to two Arduinos connected to two computers


that are separated by at least several meters.

*/

#include <SoftwareSerial.h>

const byte HC12RxdPin = 4; // "RXD" Pin on HC12


const byte HC12TxdPin = 5; // "TXD" Pin on HC12
const byte HC12SetPin = 6; // "SET" Pin on HC12
unsigned long timer = millis(); // Delay Timer

char SerialByteIn; // Temporary variable


char HC12ByteIn; // Temporary variable
String HC12ReadBuffer = ""; // Read/Write Buffer 1 for
HC12
String SerialReadBuffer = ""; // Read/Write Buffer 2 for
Serial
boolean SerialEnd = false; // Flag to indicate End of
Serial String
boolean HC12End = false; // Flag to indiacte End of
HC12 String
boolean commandMode = false; // Send AT commands

// Software Serial ports Rx and Tx are opposite the HC12 Rx and Tx


// Create Software Serial Port for HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin);

void setup() {

HC12ReadBuffer.reserve(64); // Reserve 64 bytes for


Serial message input
SerialReadBuffer.reserve(64); // Reserve 64 bytes for
HC12 message input

pinMode(HC12SetPin, OUTPUT); // Output High for


Transparent / Low for Command
digitalWrite(HC12SetPin, HIGH); // Enter Transparent mode
delay(80); // 80 ms delay before
operation per datasheet
Serial.begin(9600); // Open serial port to
computer
HC12.begin(9600); // Open software serial
port to HC12
}

void loop() {

while (HC12.available()) { // While Arduino's HC12


soft serial rx buffer has data
HC12ByteIn = HC12.read(); // Store each character
from rx buffer in byteIn
HC12ReadBuffer += char(HC12ByteIn); // Write each character of
byteIn to HC12ReadBuffer
if (HC12ByteIn == '\n') { // At the end of the line
HC12End = true; // Set HC12End flag to true
}
}

while (Serial.available()) { // If Arduino's computer rx


buffer has data
SerialByteIn = Serial.read(); // Store each character in
byteIn
SerialReadBuffer += char(SerialByteIn); // Write each character of
byteIn to SerialReadBuffer
if (SerialByteIn == '\n') { // Check to see if at the
end of the line
SerialEnd = true; // Set SerialEnd flag to
indicate end of line
}
}

if (SerialEnd) { // Check to see if


SerialEnd flag is true

if (SerialReadBuffer.startsWith("AT")) { // Has a command been sent


from local computer
HC12.print(SerialReadBuffer); // Send local command to
remote HC12 before changing settings
delay(100); //
digitalWrite(HC12SetPin, LOW); // Enter command mode
delay(100); // Allow chip time to enter
command mode
Serial.print(SerialReadBuffer); // Echo command to serial
HC12.print(SerialReadBuffer); // Send command to local
HC12
delay(500); // Wait 0.5s for a response
digitalWrite(HC12SetPin, HIGH); // Exit command / enter
transparent mode
delay(100); // Delay before proceeding
} else {
HC12.print(SerialReadBuffer); // Transmit non-command
message
}
SerialReadBuffer = ""; // Clear SerialReadBuffer
SerialEnd = false; // Reset serial end of line
flag
}

if (HC12End) { // If HC12End flag is true


if (HC12ReadBuffer.startsWith("AT")) { // Check to see if a
command is received from remote
digitalWrite(HC12SetPin, LOW); // Enter command mode
delay(100); // Delay before sending
command
Serial.print(SerialReadBuffer); // Echo command to serial.
HC12.print(HC12ReadBuffer); // Write command to local
HC12
delay(500); // Wait 0.5 s for reply
digitalWrite(HC12SetPin, HIGH); // Exit command / enter
transparent mode
delay(100); // Delay before proceeding
HC12.println("Remote Command Executed"); // Acknowledge execution
} else {
Serial.print(HC12ReadBuffer); // Send message to screen
}
HC12ReadBuffer = ""; // Empty buffer
HC12End = false; // Reset flag
}
}
Data transmitted by a remote HC-12 transmitter is received and decoded as "AllAboutCircuits.com" by
a local HC-12 receiver. Note the delay before the .com was transmitted, which might be due to the data
handling of the Si4463 (see page 39 of the Si4463 datasheet) or to some aspect of the program running on the
STM8S003FS.

The previous code, if uploaded to both boards, allows you to program both the local and
remote transceiver at the same time.

Here are some other commands for your reference:

Valid Baud Rate Commands: AT+B1200, AT+B2400, AT+B4800, AT+9600, AT+19200,


AT+38400, AT+57600, AT+115200

Valid Channel Commands: AT+C001, AT+C002, AT+C0xx, ... , AT+C099, AT+C100. Per
its datasheet, if using multiple HC-12s on different channels, stagger adjacent channels at
least five apart

40kHz1 channel×5 channels=200kHz

Valid Transmit Power Commands: AT+P1 (-1 dBm), AT+P2 (2 dBm), AT+P3 (5 dBm),
AT+P4 (8 dBm), AT+P5 (11 dBm), AT+P6 (14 dBm), AT+P7 (17 dBm), AT+P8 (20 dBm)

Return to default settings: AT+DEFAULT

Additional commands are available; refer to the user manual for more information.

Conclusion

The HC-12 is a capable transceiver with an impressive range (up to 1 km). It is satisfactory
for most hobby and even some industrial applications. It is an important alternative to the
very inexpensive, low-power, but short-range nRF24L01. Though a bit more expensive than
the nRF24L01, its range and simplicity of use make the HC-12 an excellent choice for
projects involving tracking. In the next article we will explore using the HC-12 in a GPS
(Global Positioning System) application.
Make Your Own GPS Transmitter with the
HC-12 Transceiver
November 10, 2016 by Mark Hughes

The first article in this two-part series, Understanding and Implementing the HC-12 Wireless
Transceiver Module, uses the HC-12 to create long-distance data transmission between two
Arduino Unos. This article uses a pair of HC-12 transceivers, a GPS module, an Arduino, and
Google Maps to create a very simple tracking device.
Item Cost More Information
HC-12 transceiver (x2) $4 Datasheet
GPS Receiver $16 Datasheet
or Adafruit GPS Logger Shield $45 Project Guide
Arduino Uno R3 (or compatible) $45 Reference

Part one of this two-part series discussed the HC-12 transceiver module and described how to
hook it up to an Arduino and a power source.

In this article, we will create a remote GPS receiver that can be used to track nearby items
without using a cellular network.

For further information on the transceiver module, please see the HC-12 datasheet (PDF).

Adding and Transmitting GPS

The Global Positioning System (GPS) allows users to accurately determine the location of
objects on or above the surface of the Earth. Both of the GPS receivers listed at the top of this
article transmit National Marine Electronics Association (NMEA) sentences that provide
information that includes latitude and longitude, altitude, time, bearing, speed, and a great
many other variables at 9600 baud.

The HC-12s can transmit the information from a GPS receiver with no additional
programming or circuitry.

You can transmit GPS coordinates to remote locations with as little as a GPS receiver, an
HC-12 transceiver, and a battery. Remotely transmitted coordinates would have to be
received by another HC-12 transceiver and then processed with a microcontroller or
computer.
A simple setup such as the one above would allow you to create a small remote object
tracker; it will alert you if the object leaves a predefined area, and then you will have a
certain amount of time to track the object before the transmitter goes out of range. You could
use this with a vehicle, a pet, or even—if you are concerned about theft—the giant pumpkin
that you are growing for the state fair.

If you are in an area with clear line of sight, the transmitters will broadcast up to one
kilometer, which is a 15-minute walk (or 5-minute run). The maximum range in urban areas
will decrease but should remain adequate to alert you if your luggage is leaving the train
station without you, or let you know where your dog ventures when he escapes from your
yard.

We can refine this project by passing the GPS data to an Arduino instead of directly to the
HC-12. Then, only selected strings can be transmitted to the HC-12. This is useful if you
want to increase the range of the HC-12 communication by decreasing the over-the-air baud
rate.

The $16 SparkFun GPS module has a default transmission rate of 9600 baud, and this
corresponds to an over-the-air rate of 15000 baud. Sending the 9600 baud GPS data to the
Arduino and then transmitting only selected information to the HC-12 at 2400 baud will
reduce the over-the-air rate to 5000 baud. According to the datasheet, this improves receiver
sensitivity by at most 5 dB, which provides a modest increase in range.

The SparkFun GPS receiver provides six sentences at 9600


baud: GPRMC, GPVTG, GPGGA, GPGSA, GPGSV, and GPGLL.

The GPS shield from Adafruit, which is significantly more expensive, can be programmed to
transmit select sentences at all standard baud rates.

This is an example data transmission from the receiver to an Arduino. You can decode your
own strings with this online tool.

$GPRMC,210154.00,A,3358.88969,N,11756.33387,W,0.824,,200916,,,A*6F
$GPVTG,,T,,M,0.824,N,1.527,K,A*2C
$GPGGA,210154.00,3358.88969,N,11756.33387,W,1,05,1.67,254.3,M,-32.6,M,,*6E
$GPGSA,A,3,13,05,21,18,29,,,,,,,,3.15,1.67,2.66*01
$GPGSV,3,1,11,05,20,044,23,10,10,223,,13,26,083,22,15,37,120,*70
$GPGSV,3,2,11,16,11,322,,18,45,224,23,20,76,043,,21,55,312,22*76
$GPGSV,3,3,11,25,23,195,17,26,27,298,,29,72,108,17*47
$GPGLL,3358.88969,N,11756.33387,W,210154.00,A,A*74

Arduino libraries exist that enable decoding of NMEA sentences into the latitude & longitude
pairs below:
HDOP,
Type UTC Time Position Speed Altitude Satellites
VDOP, PDOP
2016-09- 33°58'53.38''N, 0.824
RMC
20T21:01:54Z 117°56'20.03''W knots
0.824
VTG
knots
2016-09- 33°58'53.38''N,
GGA 254.3 5
20T21:01:54Z 117°56'20.03''W
1.67, 2.66,
GSA 5
3.15
GSV 11
GSV 11
GSV 11
2016-09- 33°58'53.38''N,
GLL
20T21:01:54Z 117°56'20.03''W

RMC (recommended minimum information), GGA (3D location and accuracy), and GLL
(latitude and longitude) all include latitude, longitude, and time. GGA provides altitude, and
GSA provides the dilution of precision of the reading (lower numbers indicate greater
precision).

The following program is backward-compatible with the two programs presented in part one.
It reads the NMEA sentences sent by the GPS to the Arduino, discards all but the selected
sentence, and transmits the selected sentence to a remote Arduino when requested. It works
with either the SparkFun GPS receiver or the Adafruit GPS logger shield, as shown below.
This program allows users to remotely "ping" distant transceivers to determine their location.

GPS data from a remote transmitter received, via a pair of HC-12 transceivers, by a local Arduino

HC-12 transceiver paired with an Adafruit GPS shield

HC-12 transceiver paired with a SparkFun GPS module


Connect the power supply, GPS, Arduino, and HC-12 as shown above.

The SparkFun GPS receiver has only three wires; the fourth signal (GPS RXD) is not needed
for basic functionality and is not made available to the user. However, if you use the Adafruit
shield, the GPS RX pin is enabled, and you can change the refresh rate and which sentences
the GPS transmits, eliminating the need for the portion of the Arduino code at the end of the
file that simply deletes unwanted sentences.

One potential problem with using the Arduino UNO for this program is that the
SoftwareSerial library can only "listen" to one serial port at a time—data sent to a serial port
when the software isn't "listening" on that port will be discarded. The program functions as
intended during testing, but I would not consider it a robust solution. If you need multiple
serial communication ports in your project, consider the Arduino Mega, or a separate chip
such as the ATSAMD21.

If you are tracking a single object near your house, it is sufficient to set upper and lower
limits for expected latitude and longitude values. If you are trying to determine the distance
between two GPS units, you might consider implementing Vincenty's formula on a 16-bit or
32-bit microcontroller.

/* HC12 Send/Receive Example Program 3


By Mark J. Hughes
for AllAboutCircuits.com

This code will automatically detect commands as sentences that begin


with AT and both write them and broadcast them to remote receivers
when requested. Changing settings on a local transceiver will also
change settings on a remote receiver.

Connect HC12 "RXD" pin to Arduino Digital Pin 4


Connect HC12 "TXD" pin to Arduino Digital Pin 5
Connect HC12 "Set" pin to Arduino Digital Pin 6

Connect GPS GND and 3.3V to Arduino or separate supply


Connect GPS "RX" to Arduino Digital Pin 7 (optional)
Connect GPS "TX" to Arduino Digital Pin 8

Do not power over USB. Per datasheet, power the HC12


with a supply of at least 100 mA current capability, and
include a 22 uF - 1000 uF reservoir capacitor.

Upload code to two Arduinos connected to two computers.

Transceivers must be at least several meters apart to work in default


mode.
*/

#include <SoftwareSerial.h>

//--- Begin Pin Declarations ---//


const byte HC12RxdPin = 4; // "RXD" Pin on HC12
const byte HC12TxdPin = 5; // "TXD" Pin on HC12
const byte HC12SetPin = 6; // "SET" Pin on HC12
const byte GPSRxdPin = 7; // "RXD" on GPS (if
available)
const byte GPSTxdPin = 8; // "TXD" on GPS
//--- End Pin Declarations ---//

//--- Begin variable declarations ---//


char byteIn; // Temporary variable
String HC12ReadBuffer = ""; // Read/Write Buffer 1
-- Serial
String SerialReadBuffer = ""; // Read/Write Buffer 2
-- HC12
String GPSReadBuffer = ""; // Read/Write Buffer 3
-- GPS

boolean serialEnd = false; // Flag for End of


Serial String
boolean HC12End = false; // Flag for End of HC12
String
boolean GPSEnd = false; // Flag for End of GPS
String
boolean commandMode = false; // Send AT commands to
remote receivers
boolean GPSLocal = true; // send GPS local or
remote flag
//--- End variable declarations ---//

// Create Software Serial Ports for HC12 & GPS


// Software Serial ports Rx and Tx are opposite the HC12 Rxd and Txd
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin);
SoftwareSerial GPS(GPSTxdPin, GPSRxdPin);

void setup() {

HC12ReadBuffer.reserve(82); // Reserve 82 bytes for


message
SerialReadBuffer.reserve(82); // Reserve 82 bytes for
message
GPSReadBuffer.reserve(82); // Reserve 82 bytes for
longest NMEA sentence

pinMode(HC12SetPin, OUTPUT); // Output High for


Transparent / Low for Command
digitalWrite(HC12SetPin, HIGH); // Enter Transparent
mode
delay(80); // 80 ms delay before
operation per datasheet
Serial.begin(9600); // Open serial port to
computer at 9600 Baud
HC12.begin(9600); // Open software serial
port to HC12 at 9600 Baud
GPS.begin(9600); // Open software serial
port to GPS at 9600 Baud
HC12.listen(); // Listen to HC12
}

void loop() {
while (HC12.available()) { // If Arduino's HC12 rx
buffer has data
byteIn = HC12.read(); // Store each character
in byteIn
HC12ReadBuffer += char(byteIn); // Write each character
of byteIn to HC12ReadBuffer
if (byteIn == '\n') { // At the end of the
line
HC12End = true; // Set HC12End flag to
true.
}
}

while (Serial.available()) { // If Arduino's


computer rx buffer has data
byteIn = Serial.read(); // Store each character
in byteIn
SerialReadBuffer += char(byteIn); // Write each character
of byteIn to SerialReadBuffer
if (byteIn == '\n') { // At the end of the
line
serialEnd = true; // Set serialEnd flag
to true.
}
}

while (GPS.available()) {
byteIn = GPS.read();
GPSReadBuffer += char(byteIn);
if (byteIn == '\n') {
GPSEnd = true;
}
}

if (serialEnd) { // Check to see if


serialEnd flag is true
if (SerialReadBuffer.startsWith("AT")) { // Check to see if a
command has been sent
if (SerialReadBuffer.startsWith("AT+B")) { // If it is a baud
change command, delete it immediately
SerialReadBuffer = "";
Serial.print("Denied: Changing HC12 Baud does not change Arduino
Baudrate");
}
HC12.print(SerialReadBuffer); // Send local command
to remote HC12 before changing settings
delay(100); //
digitalWrite(HC12SetPin, LOW); // If true, enter
command mode
delay(100); // Delay before writing
command
HC12.print(SerialReadBuffer); // Send command to HC12
Serial.print(SerialReadBuffer); // Send command to
serial
delay(500); // Wait 0.5s for reply
digitalWrite(HC12SetPin, HIGH); // Exit command / enter
transparent mode
delay(100); // Delay before
proceeding
}
if (SerialReadBuffer.startsWith("GPS")) {
HC12.print(SerialReadBuffer);
GPS.listen();
GPSLocal = true;
}
HC12.print(SerialReadBuffer); // Send text to HC12 to
be broadcast
SerialReadBuffer = ""; // Clear buffer 2
serialEnd = false; // Reset serialEnd flag
}

if (HC12End) { // If HC12End flag is


true
if (HC12ReadBuffer.startsWith("AT")) { // Check to see if a
command was received
digitalWrite(HC12SetPin, LOW); // If true, enter
command mode
delay(40); // Delay before writing
command
HC12.print(HC12ReadBuffer); // Send incoming
command back to HC12
Serial.println(HC12ReadBuffer); // Send command to
serial
delay(1000); // Wait 0.5s for reply
digitalWrite(HC12SetPin, HIGH); // Exit command / enter
transparent mode
delay(80); // Delay before
proceeding
HC12.println("Remote Command Executed");
}
if (HC12ReadBuffer.startsWith("GPS")) {
GPS.listen();
HC12.print("Remote GPS Command Received");
GPSLocal = false;
}
Serial.print(HC12ReadBuffer); // Send message to
screen
HC12ReadBuffer = ""; // Empty Buffer
HC12End = false; // Reset Flag
}

if (GPSEnd) {
// Options include GPRMC, GPGGA, GPGLL, etc...
if (GPSReadBuffer.startsWith("$GPGGA")) { // Look for target GPS
sentence
if (GPSLocal) {
Serial.print("Local GPS:"); // Send to local serial
port
Serial.print(GPSReadBuffer); // Send local GPS
} else {
HC12.print("Remote GPS:"); // Local Arduino
responds to remote request
HC12.print(GPSReadBuffer); // Sends local GPS to
remote
}
GPSReadBuffer = ""; // Delete target GPS
sentence
HC12.listen(); // Found target GPS
sentence, start listening to HC12 again
} else {
GPSReadBuffer = ""; // Delete unwanted
strings
}
GPSEnd = false; // Reset GPS
}
}

Data that you collect can be converted into KML files for use in Google Maps using one of
many free online converters.

The above image shows variations in the logged GPS coordinates of a stationary object. The
error is rather large, even for the low-cost setup used in this project—the GPS receiver sold
by SparkFun, for example, claims to provide positional accuracy of 2.5 m CEP. It is likely
that multipath interference made a significant contribution to the additional error.

Real-Time GPS Tracking in Google Earth

Now we will create a GPS tracker with the HC-12 and Google Earth Pro. Through
experimentation, I found that tracking worked if at least the $GPGGA, $GPGSA, and
$GPGLL strings were passed along to Google Earth.

The program below transmits GPS data to a remote receiver for tracking of remote objects. It
receives all sentences at 9600 baud from the computer and then transmits just the $GPRMC,
$GPGGA, and $GPGGL sentences at 4800 baud through the HC-12. A separate
HC-12/Arduino pair would be needed to receive the information and transmit it to the
computer.

/* HC12 Send/Receive Example Program 4


By Mark J. Hughes
for AllAboutCircuits.com
Connect HC12 "RXD" pin to Arduino Digital Pin 4
Connect HC12 "TXD" pin to Arduino Digital Pin 5
Connect HC12 "Set" pin to Arduino Digital Pin 6

Connect GPS "TXD" to Arduino Digital Pin 7 (Optional)


Connect GPS "RXD" to Arduino Digital Pin 8

Do not power over USB. Per datasheet, power the HC12


with a supply of at least 100 mA current capability, and
include a 22 uF - 1000 uF reservoir capacitor.

Upload code to two Arduinos connected to two computers.

Transceivers must be at least several meters apart to work in default


mode.

*/

#include &let;SoftwareSerial.h>

//--- Begin Pin Declarations ---//


const byte HC12RxdPin = 4; // "RXD" Pin on HC12
const byte HC12TxdPin = 5; // "TXD" Pin on HC12
const byte HC12SetPin = 6; // "SET" Pin on HC12
const byte GPSTxdPin = 7; // "TXD" on GPS (if available)
const byte GPSRxdPin = 8; // "RXD" on GPS
//--- End Pin Declarations ---//

//--- Begin variable declarations ---//


char GPSbyteIn; // Temporary variable
String GPSBuffer3 = ""; // Read/Write Buffer 3 -- GPS

boolean debug = false;


boolean HC12End = false; // Flag for End of HC12 String
boolean GPSEnd = false; // Flag for End of GPS String
boolean commandMode = false; // Send AT commands to remote
receivers
//--- End variable declarations ---//

// Create Software Serial Ports for HC12 & GPS


// Software Serial ports Rx and Tx are opposite the HC12 Rxd and Txd
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin);
SoftwareSerial GPS(GPSRxdPin, GPSTxdPin);

void setup() {
buffer3.reserve(82); // Reserve 82 bytes for longest
NMEA sentence

pinMode(HC12SetPin, OUTPUT); // Output High for Transparent /


Low for Command
digitalWrite(HC12SetPin, HIGH); // Enter Transparent mode
delay(80); // 80 ms delay before operation
per datasheet
HC12.begin(4800); // Open software serial port to
HC12
GPS.begin(9600); // Open software serial port to
GPS
GPS.listen();
}

void loop() {
while (GPS.available()) {
byteIn = GPS.read();
buffer3 += char(byteIn);
if (byteIn == '\n') {
GPSEnd = true;
}
}

if (GPSEnd) {
// GPRMC, GPVTG, GPGGA, GPGSA, GPGSV, GPGLL
if (buffer3.startsWith("$GPRMC")||buffer3.startsWith("$GPGGA")||
buffer3.startsWith("$GPGLL")) {
HC12.print(buffer3); // Transmit RMC, GGA, and GLL
sentences
buffer3 = ""; // Clear buffer
} else {
buffer3 = ""; // Delete GSA, GSV, VTG sentences
}
GPSEnd = false; // Reset GPS flag
}
}

Here are the steps you'll need to follow:

1. Open Google Earth


2. Select Tools -> GPS
3. Select the Realtime tab and click Start. Google Earth will cycle through available
serial ports looking for NMEA sentences. When NMEA data is found, it will provide
a location on the map.

Three separate screenshots were combined in order to show all the steps simultaneously

Note: An Arduino (or any other microcontroller) is not strictly required for this to work. A
GPS module (such as the Adafruit logger shield) that can be programmed to transmit the
desired sentences at 4800 baud can be connected directly to an HC-12. Data can then be sent
to Google Earth using a separate HC-12 that is connected to a computer's serial port via a
logic-level-to-RS232 converter.

Conclusion

This two-article series demonstrates that the HC-12 is a versatile and easy-to-use RF
transceiver module. It is similar to the nRF24L01, but it offers the important advantage of
longer range. The straightforward UART interface facilitates integration into a wide variety
of systems—microcontrollers and PCs can directly communicate with the HC-12.

As this article has shown, the HC-12 is a simple solution for logging GPS data and for real-
time GPS tracking.

You might also like