I finally found time to address a pending project which had been relegated to the back burner. The original idea was to just substitute the two existing forward and reverse analogue power indicators which I had fitted to my homebrew QO-100 satellite terminal. It quickly became an experimental IOT project opening up many customisable opportunities.
Operating some distance from the ground terminal by ethernet, to curtail coaxial cable losses to the antenna, meant that it was not possible to keep an eye on the SWR meters whilst operating. A more practical remote SWR monitoring solution was needed.
The initial idea was just to remotely read the state of the SWR whilst transmitting from the shack and thus have an immediate warning if something was amiss. This plan quickly avalanched into a bigger project. As well as the state of the SWR, some other equipment parameters could be collected.
The fastest way found to develop a unit to perform this task was to use some already familiar systems. Namely Arduino or ESP32/ESP8266 hardware, C+ coding and then why not incorporate the help of the Internet Of Things.
GUEST DASHBOARDS
Using a dashboard means all types of parameters can be neatly displayed and accessed from the shack operating position. Coupled to an IOT service, a dashboard can be accessed from any location and by other users if desired.
Guest dashboards can be created by the administrator and shared so other users can view certain data. Including for example the Maidenhead grid locator when roving, for any grid hunters following the operation.
Reading SWR
A common type of SWR meter used in amateur radio markets contains a dual directional coupler. Directional couplers sample a small amount of power in one direction. A forward and a reverse (or reflected). Later, a diode is used to rectify it before applying to a meter.
The 2.4GHz power amplifier which I used in the transmitter has feedthrough capacitors to test points reading the forward and reverse voltages. This equates to reading the forward and reflected powers at the PA output to the antenna. Although I don't imagine it to be a precision instrument it is enough to gain an idea of power transfer from the PA to the helix uplink antenna.
In this case, full power from the PA equates to about 3V measured from the directional couplers. Your milage may vary. Plotting the measured values on a graph showed a non linear curve, which tapered slightly towards maximum transmit power. This however is not a problem as we rely more on the relationship between the forward and reverse voltages themselves. Assuming that each side of the directional coupler are reasonably twined with similar components, the two voltage representations will be good enough to derive a basic SWR measurement.
The QO-100 ground station transmits the uplink on 2.4GHz which is an ISM band freely used by many services.
After testing various setups whilst using the narrow band transponder of Oscar 100, no interference was experienced to the Arduino UNO R4 WiFi from the transmitted uplink signal. Your mileage may vary and factors such as uplink power level, device location, distance to router or access point, Tx antenna lobe pattern and signal quality should be considered.
Microcontroller choice.
Does choosing to use the newest Arduino make sense? Well I needed an excuse to try the new UNO R4 board out. Alternatives would have been ESP32, ESP2866 or M5Stack based hardware which I've used in previous projects and were also an option. However the uniformity, availability and cost of the Arduino were advantages. In typical Arduino fashion, online information was abundant even for such a new board. It had a built in display and although this LED matrix was a spartan alternative to an LCD or colour OLED screen, its grid of 12x8 LEDs was enough to show what would be needed. It was clear, bright and already included on the board. It would certainly be a big improvement from my dated needle meters currently being used.
The Internet Of Things.
Since IOT is ideal for monitoring and controlling almost anything, the opportunity here lent itself to adding more sensors to gain more information. Other parameters were experimented with and in so doing, added the possibility to access ambient and location data also. Hence, we are not limited to just the ground station equipment parameters, such as antenna SWR and equipment voltages.
Coupling this new UNO R4 microcontroller board with the possibilities afforded by the Arduino IOT Cloud, a feature set was drawn up.
- Numeric display SWR meter.
- Forward and Reverse analogue LED bargraph.
- High SWR warning buzzer.
- High SWR warning red LED.
- Four individual Voltage measurements.
- Current measurement up to 6.4 Amps.
- Temperature, humidity and pressure measurement.
- Global Navigation Satellite System functionality.
- Scrolling Voltages displayed showing Bus, PA, USB1 and USB2 values.
- Scrolling ambient displayed showing Temp, Humidity, Pressure and Maidenhead Locator grid.
- Connection to the Internet Of Things.
- Dashboard monitoring and control.
- OT dashboard accessible with a computer browser.
- IOT dashboard accessible with a smartphone app.
- Graphical representation of data values.
- Dashboard saved data history.
- Dashboard GPS coordinate mapping.
- Lat/Long coordinates and Maidenhead grid displayed.
- Simple homebrew shield installs neatly atop the UNO R4 WIFI.
- Shield solder pads accommodates both through hole or SMD components.
- Two push buttons on shield to test or control (to dashboard also).
- Two green LEDs on shield to test or monitor (from dashboard also).
- Header pins make available many GPIO pins.
- Jumper pins to set program configurations.
- Arduino Reset pin accessible on upper shield PCB.
- PCB shield can be used with other sketches and for other uses.
- Second I2C port availability as first is used for ADC.
- QWIIC/STEMMA connector on I2C port for neat daisy chaining modules.
- Shield allows for future flexible features for changes and experimentation.
Altough other services exist, I settled for the Arduino IOT Cloud after trying the free plan they offer.
The dashboards may seem simplistic compared to other dashboard offerings (Node-Red for example) but they are sufficient for this application. They have a minimalist design with an agreeable Dieter Rams feel to them. They are intuitively easy to create and modify, which means it can be done with rapidity. I'm sure we would all rather be Dxing and grid chasing, than coding and editing. Actually, behind the apparently subtle dashboard facade, the Arduino Cloud can provide complex functionalities like notifications, data history, OTA updating, advanced charts, synced variables, web editing with worldwide private or public access by web browser or a smartphone app. They can even integrate with Amazon's Alexa to provide voice control to any project.
Coding can be done on the Arduino web editor, which is accessed through any browser. Also, with the UNO R4 WiFi, any new code can be uploaded to it using Over The Air (OTA) as well as the traditional way via the USB port. This means once a project is running in situ, its sketch code can be modified and remotely uploaded to it wirelessly.
Having expanded on the SWR meter project, the monitoring of other parameters was experimented with and displayed by the shield and on the dashboard. In addition to equipment voltages and current parameters, other less important but still relevant parameters can be measured with suitable sensors.
Microcontroller Board - Arduino UNO R4 WiFi:
This microcontroller board (together with the UNO R4 Minima) are the newest additions to the Arduino lineup. It is an UNO R3 on steroids.
The Arduino UNO R4 WiFi merges the RA4M1 48 MHz Arm Cortex-M4 microprocessor from Renesas with the ESP32-S3 from Espressif. This gives it built-in Wi-Fi and Bluetooth capabilities. The UNO R4 WiFi's memory is larger than its predecessors, with 256 kB flash, 32 kB SRAM and 8 kB of EEPROM. It has a rich feature set too big to list here and without doubt is grossly underused in this application.
Be aware that not all UNO R4 WiFi boards are the same. I used the official Arduino version. The shield will of course install in all generic versions but its rectangular cutout, through which we view the display below, lines up perfectly above Arduino's official board and might be offset slightly on generic copies.
The one difference to keep in mind between the new R4 boards and the previous UNO R3 is its pin current limitation.
On the new Arduino Uno R4 boards, the maximum source/sink current is only 8mA. On the older R3 boards, it was 20 mA. This is less than half of the current that the previous version of the UNO could handle and must be kept in mind when designing any circuit to be used with this new R4.
INA219 Current Sensor Module:
This is a DC current sensor module, with a stock maximum limit of 26V and 3.2A which can be read without it overheating. To read the current levels drawn by the ground station it needed modification in hardware and code. This allows me to read double the stock current rating, to 6.4A. This accommodates better the current draw levels which will be read whilst the ground station is in operation.
A 0.1 Ohm 2W shunt is used by the INA219 module. The voltage drop across this resistor is measured for the current flowing through it. The module then calculates the current passing, from the voltage dropped and resistor value (Ohms law). Inevitably, the 12V Bus voltage will drop slightly depending on current draw. More drop when using more current of course.
Since my ground station on transmit can draw more than the maximum 3.2A that the INA219 is capable of safely reading, the module must be modified. Adding a second 0.1 Ohms resistor in parallel will make 0.05 Ohms and allow double the current to be measured. Using a 2W or higher rated resistor will avoid excessive heating and any unpleasantness. After this hardware modification, the code also needs to be edited.
The readINA219() function is updated to reflect the new shunt value by doubling current and power values.
current_mA = 2 * (ina219.getCurrent_mA() );
// Double because of 2nd parallel 0.1 Ohm resistor (making 0.05 Ohms)
power_mW = 2 * ( ina219.getPower_mW() );
// Double because of 2nd parallel 0.1 Ohm resistor (making 0.05 Ohms)
INA219 parameters:
- Load Voltage = Total voltage across both loads (shunt + equipment loads)
- Shunt Voltage = Voltage dropped across shunt resistor
- Bus Voltage = Voltage to load (equipment)
- Current = Current being drawn.
- Power = Bus Voltage x Current
PA1010D GPS Module:
I am using an Adafruit Mini GPS PA1010D having STEMMA QT ports for I2C bus connection. Generic modules are also available but lack the QWIIC/STEMMA QT connectors.
This tiny unit is a surprisingly good GPS receiver. It support GPS, GLONASS, GALILEO and QZSS systems, often locking on to the GNSS constellation in less than ideal settings. I was very surprised by its sensibility and resistance to interference. During the project development, a fast lock was consistently acquired with the module just sitting on my desk with no need to be up against a window. It comes with an optional CR1220 coin cell holder to solder on if required. This keeps the internal RTC running and allows warm starts for faster GPS locking. Although, I never found the need for this as locking was pretty fast anyway. The board shows when it has reached aquisition of satellites as next to a green power LED there is a tiny red PPS LED. The LED blinks discretely when a fix is found and provides an instantaneous way of knowing if the module has locked, without having to wait for the sketch to do it at timed intervals.
BME280 Ambient Sensor Module:
A digital sensor module measuring temperature, humidity and barometric pressure, with I2C and in the 3.3V supply version
I'm using a cheap version of this module which is made in China as I already had a few. Since it doesn't follow the QWIIC/STEMMA QT layout, to allow daisy chaining the I2C, this module was left at the end of the bus and attached with normal header (DuPont) connectors. Otherwise another, but more messy way, would be to just attach the I2C modules in parallel to the same module header.
Monitor & Control Shield:
My homebrew interface shield which piggybacks onto the Arduino board. This has analogue and digital input/output header connectors. The analog inputs each have noise filtering capacitors. An input and selection jumper routes either the 3.3V or an external analogue voltage reference. Another header is meant for CAN Bus and UART access. A second jumper can control configuration or program flow. A buzzer and red alarm LED warns of any high SWR. A pair of input push switches and green output LEDs are also available.
The rectangular cutout allows viewing of the 12x8 LED matrix of the UNO R4 WiFi board beneath it. The shield provides a perfect viewing bezel to the matrix of LEDs below on the official Arduino UNO R4 WiFi board. Be aware that some generic copies of the UNO R4 have the LED matrix placement shifted slightly on their board, so the view may not align perfectly with the shield's cutout. The main reset switch is made accessible on the shield PCB, as the R4 UNO's reset switch is now covered.
Since the shield makes available many of the microcontroller board's GPIO pins, it is very flexible and can be used with different code and for other purposes.
STEMMA QT, QWIIC and the second I2C busThese I2C connections are essentially the same. STEMMA QT (Cutie) is used on Adafruit modules. QUIIC is used on Sparkfun modules. They are actually just small JST SH, 1.0mm pitch connectors. Two of these on each module allows them to be neatly daisy chained along the I2C bus to the microcontroller.
By convention each module has a specific address depending on its use. This avoids I2C address conflicts. Nevertheless, conflicts could happen if using multiple boards. Espeacially when using multiple modules of the same type. In this case some boards have solder pads that should be bridged to select another address.
The usual Arduino I2C lines on pins D18 and D19 are not available here. Because almost all the analogue ADC inputs are being used there is no I2C bus access. Since digital pins D18 and D19 connect I2C lines IIC_SDA1 and IIC_SCL1 and shared with analogue inputs A4 and A5.
Conveniently on the UNO R4, Arduino gives us a second I2C bus (IIC0_SDA and IIC0_SCL) by way of the QWIIC/STEMMA QT connection. This can be persuaded to work using Wire1 instead of Wire when coding. From this connector, various I2C sensors and actuators can then be linked together in a neat chain.
All the sketch code can be found in my GitHub repository. See the Code section at the end of this article.
A direct link to the main code is here: QO100-GS-MONITOR-AND-CONTROL
I am not a programmer and there is undoubtedly some unneeded complexity in program flow. This code was built up and added to with features and functions, over time and as I felt the need. No fancy code or clever statements were employed. This makes it easy to read, understand and modify. Perhaps in a future rewrite employing separate timing threads, using interrupts and reducing the global variable count would be an idea. It is what it is. It serves my purposes and doesn't visibly slow down the operation in any way.
On powering up or booting, the hardware jumper J2 will select which one of two programs will run. The first is a normal operating mode to be used with IOT access. The second was intended to be a local operating mode, without needing IOT.
However, currently with the jumper to the left on LOCal, a placeholder test program is run. This just checks all of the shield's buttons, LEDs and the sounder. Future plans would be to replace the code here to run the unit locally without the use of an IOT connection.
Whilst still in the setup(), the code checks that all the sensor modules are available. If there is an issue then an error tone will emanate from the buzzer, the red alarm LED will light and the program will effectively freeze. Connecting to the serial debug port will show what the issue is.
NORMAL OPERATING MODE AT BOOT
With the jumper J2 to the right, normal program flow will be chosen to be run at boot up.
Whilst still setting things up, the variable triggerGS state is toggled. The dashboard has been configured to send a notification when this variable changes state. A timestamped text informs of a ground station switch on and this notification is pushed to the mobile phone dashboard app. An email can also be chosen to be sent if desired.
If all is well the LED matrix shows a splash text followed by both voltage and ambient parameters, whilst the sounder beeps a countdown towards normal operation. The BUS (12V), PA (28V), USB1 (5V), USB2 (5V), Temperature (degC), Relative Humidity (%RH), Atmospheric Pressure (hPa), GPS (Searching) will scroll past.
Scrolling parameters
Once this scrolling countdown of initial parameters is finished, the unit settles into its normal cycle of operation. Scrolling either voltage parameters or ambient parameters. Currently this is set by grounding or not GPIO D0. Done with an optional jumper on the first two pins of the header H3 (between pins 1, GND and 2, D0).
This is actually a last minute improvisation because of a circuit design error and actually means the UART connection is unavailable. The H3 header is intended for CAN Bus or UART access but which is not required for my ground station application. With suitable code changes, another option would have been to use either SW1 or SW2 push buttons to change the scrolling display on the fly. This is convenient but would occupy one of the digital input pins of course. Using the a pin from header H3 seemed a less evasive ad-hoc workaround.
The LED matrix will then scroll through the chosen data values cyclically:
- It will show the voltage parameters (if H3 pins 1 and 2 closed).
BUS(12V), PA(28V), USB1(5V), USB2(5V), Temperature(degC).
OR
- It will show ambient parameters (if H3 pins 1 and 2 open).
Temperature/degC, Humidity%RH, Pressure/hPa, Maidenhead Grid or No Fix.
Occasionally the scrolling will stop for a few seconds, whilst the sketch retrieves the current NMEA data from the PA1010D GPS module. A recycle icon is shown on the display whilst the module is being briefly accessed. The time interval at which this happens is defined in the sketch and should be set to more than a few minutes to maintain smooth program flow. A searchFixMinutes value of 5 or more minutes is adequate.
const unsigned int searchFixMinutes = 10; //Minutes between reading GPS
Reading antenna SWR
Parameter scrolling continues until a transmission is sensed. By regularly pooling the forward voltage we can detect the power amplifier's output power and switch to measuring and displaying the antenna SWR. This SWR measurement is shown by a two digit display on the LED matrix, allowing a reading of up to 9.9 of SWR.
In addition to this numeric synoptic of SWR, the lower two rows of LEDs of the 12x8 matrix show an analogue representation of forward and reverse power. They change in tandem with the calculated SWR shown numerically above them and provide a horizontal LED bargraph of transmitted and reflected power.
Whilst transmitting, if the high SWR limit has been surpassed the red warning LED will light on the shield and the buzzer will sound. A small delay has been defined in the code before this warning happens to prevent constant toggling during transmit fluctuations (SSB). The SWR limit threshold value is also defined and can be changed during operation from the dashboard or disabled (set to zero).
When no forward voltage is detected it means that any transmission has ended and we can leave SWR measuring mode and switch back to scrolling voltages or ambient parameters. This does not happen instantly. It occurs only after a few seconds to avoid constant to and throw toggling of SWR measuring and parameter scrolling.
LOCAL (TEST) MODE AT BOOT
With the jumper J2 to the left (bridging the pins marked LOC), a simple test program flow will be run at boot up.
Placeholder
For the moment this code is just used for testing of the shield. It is more of a placeholder for future sketch code which will run without IOT connectivity.
The code will simply test the shield hardware by sounding the buzzer and lighting all three LEDs. Then pressing push buttons SW1 or SW2 should extinguish LED1 and LED2 respectively.
FUNCTIONS
- loopIOT()
This is the path running in a loop for normal operation and executes when the J2 jumper is selected appropriately. It does the heavy lifting by calling all the appropriate functions which are explained below. The dashboard is constantly updated here by calling ArduinoCloud.update(). Program flow is controlled by using the flag displaySWRenable, to switch from either measuring SWR or scrolling the display. - loopLocal()
A placeholder function intended for a second sketch booting choice when jumper J2 is to the left, on LOC. Initially intended for running a similar sketch to the normal loopIOT but running locally independant of the IOT cloud. Currently it contains code to test the shield's hardware. - readINA219()
Reads INA219 module so we can retrieve shuntVoltage (in Volts), busVoltage (in Volts), values current_mA (in milliAmps) and power_mW (in milliWatts) to then give us Bus Voltage (in Volts), Input Current (in Amps) and Input Power (in Watts).
Bus Voltage: Voltage to load (equipment)
Shunt Voltage: Voltage dropped across shunt resistor
Load Voltage: Total voltage across both loads (shunt + equipment load)
Current: Current being drawn.
Power: Bus Voltage x Current
- checkInputSwitches()
Checks the state of the two inputs available on header port H2. The state of peripheral equipment can be recovered here. These are also connected to our test buttons inputSW1 and inputSW2, which can be used not only for testing but for controlling program functions if needed. - getMaidenhead()
This short routine converts the current latitude and longitude position values to the Maidenhead Grid Locator reference. - flushGPS()
When locked the GPS will constantly receive NMEA data and if not emptied regularly will soon fill up its serial buffer. To avoid reading old data each time the module is periodically accessed every few minutes, its buffer is emptied beforehand. - roundUpTo1dp(float valEntry)
This takes the floating values of voltages, current, power, temperature, humidity and pressure and rounds their value up to 1 decimal point. This is enough required precision and displaying them like this on the dashboard reduces constant updating. - readGPS()
This function is used to fetch the NMEA data from the PA1010D mini GPS module. - showGPSstats()
Used to show the NMEA data we fetched from the PA1010D. This information will appear on the debugging serial port. The gpsFix flag is also set to true if the GPS has locked. - convertLatLong()
The latitude and longitude values from the GPS are converted here to the more standard format of degrees, minutes with North, South, East or West. - readBME280()
Reads the BME280 environmental sensor and retrieves the current temperature, humidity and pressure values. Temperature is in degrees Centigrade but Fahrenheit is possible too. The barometric pressure value is in hectoPascals after conversion here. - scrollAmbient(int poolAmbient)
Reads the ambient parameters of temperature, humidity and pressure and scrolls them sequentially followed by the Maidenhead grid locator if the GPS is locked. If no lock has been achieved a NO FIX will be scrolled instead. - scrollVoltages(int poolDVM)
Scrolls each of the four voltage readings sequentially across the LED matrix display. - readAnalogInput1()
Reads the 12V Bus voltage measured by the INA219 module and rounds it up, ready to be updated to the dashboard. - readAnalogInput2()
readAnalogInput3()
readAnalogInput4()
Each of these functions are used to measure the PA (28V), USB1 (5V) and USB2 (5V) supplies. They read the analogue input then calculate and correct for the individual resistor tolerances of their respective potential dividers. - scrollMessageText(char messageToScroll[])
This function will scroll any text it receives across the 12x8 LED matrix display. - scrollVoltageText(float voltageValueToScroll)
This function will scroll the voltage values across the matrix display, after suitably formatting and adding the Volts unit to it correctly. - scrollSensorText(float sensorValueToScroll, int unitOfSensor)
Used to scroll the three ambient data values, after suitably formatting and adding the correct unit of measurement. - buzzNow(int freq, int buzzTime)
The function which sounds the buzzer after being passed the tone and duration information. - readAnalogFwdRevInputs()
Here we read the forward and reverse analogue input pins and calculate the voltages measured. These will equate to a rough power measurement. The code here also uses the displaySWRenable boolean variable to either stay in SWR measuring mode, or return to scrolling after timing out some seconds after the last measurement. - plotFWD()
This code will plot the forward voltage measured as a horizontal LED bargraph (equating to forward power), along the penultimate row of 12 LEDS on the matrix. - plotREV()
This code will plot the reverse voltage measured as a horizontal LED bargraph, (equating to reflected power), along the last row of 12 LEDS on the matrix. - highSWRalert()
This function controls what happens when the previously set highSWRlimit value is exceeded. Sounding the warning buzzer and lighting the red LED only if this functionality has been enabled from the dashboard (To disabled alarm set High SWR Limit to zero). Alarms only after a predetermined delay defined by buzzerDelayCount to avoid constant toggling. - SWR_Calc()
This is a simple function to derive SWR from the voltage values measured at the dual directional coupler's forward and reverse outputs. - SWR_seperateIntDec()
Used to round up and separate the SWR value into its integer and decimal digits. This simplifies displaying SWR as a numeric value on the LED matrix. - add1stDigit_to_frame(char c, int pos)
add2ndDigit_to_frame(char c, int pos)
These two functions use the numerical characters I have defined in the fonts.h file to make up both digits of the SWR meter display. A decimal point between these digits is added at the calling function afterwards. - fsdMeter()
Keeps the meter to below a full scale deflection SWR value of 10 as defined by the constant fsdSWR. - convertDigits()
Converts each SWR digit to its numerical character by adding 48 to its value. - clear_frame()
Fills the array of the 12x8 LED matrix display with zeroes. - display_frame()
Displays the frame to the LED matrix.
The following functions use read/write variables which can be accessed by the dashboard. The sketch can alter these variables also but will be overwritten by the dashboard settings each time it is updated by the ArduinoCloud.update statement:
- onOutputLED1Change()
onOutputLED2Change()
These functions are called to turn either of the shield's green LEDs on or off. - onHighSWRlimitIOTChange()
This function is called to set the High SWR Limit value, which dictates when the warning buzzer and red LED activate.
CUSTOM CODE CONSTANTS
The following constants should be set for specific hardware and desired preferences.
- const float maxFWDvoltsReading = 3.0;
// Maximum FWD voltage measured from directional coupler. - const float maxREVvoltsReading = 3.0;
// Maximum REV voltage measured from directional coupler. - const float ref_voltage = 3.28;
// Measure the exact value of the stable '3.3V' reference and then specify here. - const float R1ohms28V = 46900.0;
const float R2ohms28V = 5570.0;
// Measure and then set here R1 and R2 for potential divider. - const float R1ohms5V1 = 2680.0;
const float R2ohms5V1 = 3270.0;
// measure and then set here R1 and R2 for potential divider. - const float R1ohms5V2 = 2680.0;
const float R2ohms5V2 = 3270.0;
// Measure and then set here R1 and R2 for potential divider. - const unsigned int displayTimeout = 6000;
// Period of time after no SWR measured that the display will return to scrolling. - const unsigned int refreshSWR = 300;
// Slows update rate of SWR measurement to avoid decimals flickering too fast. - const unsigned int buzzerDelay = 20;
// Delays buzzer sounding until set number of high SWR violations have occurred. - const unsigned int searchFixMinutes = 5;
// Interval between reading GPS data (in mins). Set to more than a few minutes...for program flow and to avoid too many GPS updates.
LIBRARIES AND HEADERS
All the following should be included and made available.
- #include "fonts.h"
A file that contains the frames for each 5x3 numeric font and is used when displaying SWR. - #include "frames.h"
A file that contains the recycle2 frame used to indicate when the program is collecting NMEA data from the GPS. I have also created some other display frames (clockWait, recycle, exclamationMark). - #include "thingProperties.h"
This is generated automatically when creating variables in the Arduino Thing interface. It should not be modified. - #include "ArduinoGraphics.h"
A graphics library used by the Arduino_LED_Matrix LED matrix driver. - #include "Arduino_LED_Matrix.h"
A driver for the Arduino UNO R4 WiFi 12x8 LED matrix display. - #include "Wire.h"
A popular library needed to communicate with two-wire class I2C devices. For the UNO R4's second I2C port on the QWIIC/STEMMA QT connection Wire1 should be specified in the code. - #include "SparkFunBME280.h"
A library to drive the Bosch BME280 temperature, humidity and pressure sensor. - #include "Adafruit_GPS.h"
This is the Adafruit GPS library which is used to read and parse NMEA data from the PD1010D module. - #include "maidenhead.h"
A handy library by Mateusz Salwach SP6Q which without doubt saved me hours of research and coding. It converts latitude and longitude coordinates to their Maidenhead locator grid counterparts. - #include "Adafruit_INA219.h"
This is a library for the Adafruit INA219 high side DC current sensor module. It works with the 0.1 Ohm 2W on board resistor allowing up to 3.2A to be safely measured. After modification it can read up to 6.4A (0.05 Ohm) with the sketch needing modification also.
CONFIGURATION JUMPERS*
Three configuration jumpers exist (plus an ad-hoc jumper made to work with header H3):
- J1
Choose between the currently used 3.3V voltage reference or an EXTernal voltage reference which can be fed in through pin 3 of header H1. - J2
Choose between normal operation or another sketch operation. Shield testing code is coded currently. - J3
Hardware facility to mute the buzzer. - H3*
Header pins 1 and 2 are also being used currently as a jumper setting to configure which parameters are scrolled.
The shield PCB has been designed to take either through hole or SMD components. The schematic diagram (from which the PCB is generated) reflects this by showing pairs of resistors and capacitors.
Only one of each should be considered on the circuit and installed of course.
Referring to the circuit diagram, we see how the Arduino shield is connected straight atop the main Arduino UNO R4 WiFi microcontroller board.
The circuit's main task is to aquire the voltage levels we wish to measure for the code to then work on. Since the directional coupler produces voltages of up to about 3V, an analogue voltage reference of 3.3V is used. The default 5V reference is somewhat high and would waste a lot of ADC precision.
- The UNO R4 also has an internal bandgap reference voltage of 1.5V available by setting AR_INTERNAL but although very stable, another potential divider resistor pair would be needed.
- Defining AR_INTERNAL as DEFAULT or indeed not at all, will have the ADC use the UNO's 5V as the analogue voltage reference.
The UNO's available 3.3V voltage was nearer the mark and after measuring proved to be stable enough, despite changes in input supply voltage and temperature. Its exact value needs to be accurately measured and edited in the code to define the constant ref_voltage. To avoid any unpleasantness, the ADC analogue voltage inputs should not go above this 3.3V reference.
For other uses the circuit makes provisions for accepting an off board external voltage reference of choice at pin 3 of header H2. This can then be selected through jumper J1. With this application it is kept on 3.3V to route the 3.3V UNO board's voltage to the Analogue Voltage Reference pin.
The 6 analogue inputs, A0 to A5, are made available at header H1 to inject individual voltage levels to be read by the ADC. Initially designed to take the 12V Bus, 28V PA, 5V USB1, 5V USB2 as well as the 3V FWD and 3V REV voltages. However later, by using an INA219 module, the 12V Bus voltage is retrieved in I2C and so is not measured by the UNO R4's ADC directly. This leaves a spare analogue input available at pin A0 for future use.
- Input pin A1 accepts the 28V from a DC booster feeding the power amplifier, through its R1/R2 potential divider pair of resistors R11 (or SMD R3) and R12 (or SMD R4). The values shown were calculated to top out at 31V input for 3.3V to the ADC at pin A1.
- Input pin A2 accepts the 5V from a first USB PSU, through its R1/R2 potential divider pair of resistors R13 (or SMD R5) and R14 (or SMD R6). The values shown were calculated to top out at about 6V input for 3.3V to the ADC at pin A2.
- Input pin A3 accepts the 5V from a second USB PSU, through its R1/R2 potential divider pair of resistors R15 (or SMD R7) and R16 (or SMD R8). The values shown were calculated to top out at about 6V input for 3.3V to the ADC at pin A2.
Because of component tolerances, the exact value of the resistors used should be measured. Then each R1/R2 pair's exact value must be hard coded into the sketch by defining the constants R1ohms28V, R2ohms28V, R1ohms5V1, R2ohms5V1, R1ohms5V2 and R2ohms5V1.
- Input pin A4 accepts the 0 to 3V from the PA's forward directional coupler. With the voltage reference at 3.3V no potential divider is needed.
- Input pin A5 accepts the 0 to 3V from the PA's reverse directional coupler. With the voltage reference at 3.3V no potential divider is needed.
Once again dealing with the high amount of noise that these analogue lines can pick up has been an issue. Each input pin has had a 100nF capacitor placed close by, to act as a low pass filter and get rid of any noise picked up. A further filter capacitor is also included at the external reference input for the same reason.
To reiterate, for improved accuracy:
- It is most important to measure and define in the code the exact external voltage reference in use.
- It is most important to measure and define in the code the exact resistor values which make up the potential dividers for each ADC input.
- It is most important to reduce noise by filtering, use of a PCB ground plane, careful design and general layout.
As well as the default ADC 10 bit (0-1023) the UNO R4 also has 12 bit (0-4096) and 14 bit (0-16383) resolutions, which would give even more accuracy on analog readings. This is easily done using analogReadResolution(12) or analogReadResolution(14) at setup at may be justified depending on individual application requirements.
Continuing our circuit walkthrough, we refer to the output LEDs and input push buttons.
Output LED1 and LED2 show the state of GPIO pins D10 and pin D9 respectively. These outputs are made available at header H2 pins 6 and 7 and can be controlled by the sketch or from the dashboard. Connecting these header pins through a MOSFET (and relay or opto-coupler if necessary), peripheral equipment like fans, power supplies, motors etc. can be controlled.
Each green LED has its current limiting resistor R22 (or SMD R17) and R23 (or SMD R18). A value of about 1.2K gave a comfortable light level for my particular green LEDs and kept the current well below the 8mA maximum allowed from any GPIO on this new UNO R4 board.
Alarm LED4 shows the state of GPIO pin D8 and warns of any anomaly. Here a current limiting resistor R24 (or SMD R19) of 3K is used for this red LED.
Different coloured LEDs, even of the same type, will show different light intensities for equal amount of current flowing through them. I've found that red and white LEDs are particularly bright whilst green LEDs are dimmer. Testing how bright they shine for different currents is useful for finding suitable resistor values so all colours illuminate with the same intensity on the board.
Input switches SW1 and SW2 connect to GPIO pins D7 and D6 respectively. These inputs are also made available at header H2 pins 4 and 5 and can be used to control the sketch or dashboard. Connecting these header pins to external lines means the state of peripheral equipment can be retrieved. The GPIOs have internal pull up resistors defined so take low to activate. Used by themselves the push buttons can also control the code flow and update the dashboard.
Passive buzzer SG2 on pin D3 is used to signal a high SWR in this application. It passes through a limiting resistor R20 (SMD R21) to keep the GPIO current drawn below 8ma. It is not loud. A method for muting the sound in hardware by using a jumper J3, is always good in case the unthinkable happens.
Jumper J2 straddles pins D12 and D13 with ground at its centre. It is handy to have for program configuration options at booting. Placed to the left marked LOC will run a parallel program in the sketch called Local. Intended for running the unit without needing WiFi and the IOT cloud. Currently the sketch only runs a board testing program.
Header H3 provides access to the UART and CAN Bus pins of the UNO R4. However there is an error regarding the CAN Bus pins (swap of Can Bus UNO R4 Minima pins) which needs correction. If not intending to use CAN Bus then this is of no consequence. As a stopgap solution the sketch is using header H3 pin 2 (GPIO D0) jumped (or not) to header pin 1 (ground) to choose which set of scrolling messages will be displayed.
Reset Switch push button of the UNO R4 is included on the shield for easier access, as the original is now covered by the shield itself.
PCB DESIGN AND CONSTRUCTIONA double layer board was designed, sufficient for the simple circuit and to keep fab house costs down. Provision was made for using either through hole or surface mount components. The circuit diagram (which is used to generate the PCB) has a doubling up of the resistors and capacitors. Only one component should be considered of course.
The PCB design follows the Arduino shield format. It fits perfectly on top of the UNO microcontroller board and is just slightly longer at the lower edge. A rectangular cutout above the LED matrix forms a display viewing window and bezel of sorts.
The shield will of course install on all versions of the UNO R4 WiFi but its rectangular cutout, through which we view the display below, lines up perfectly above Arduino's official board LED matrix. Some generic versions of the UNO board have shifted the placement of the LED matrix slightly but should still be viewable through the shield's cutout.
The board presents no significant build challenges. It is easy to put together and the component count ensures a quick assembly time.
POWERING
The new UNO R4 board can be powered through the USB 5V socket or DC barrel jack (also Vin pin). The latter uses a beefier onboard regulator supporting a range from 6 to 24V, which is more than the previous UNO R3 recommendation of 7 to 12V.
For the ground station I can use 5V from one of the buck converters directly to the R4's USB-C socket or perhaps more conveniently use 12V (13.8V) from the main supply to the DC barrel jack.
CAVEATS- There is an error on the schematic and subsequent PCB board which affects anyone planning on using the UNO R4 WiFi's CAN Bus. Pins D4 and D5 are made available for CAN Bus use on header H3. These pins assignments however are for the UNO R4 Minima board. The UNO R4 WiFi's CAN Bus pins are on D10 and D13. If not intending to use CAN Bus this minor blunder is irrelevant.
- An important difference to keep in mind between the new R4 boards and the previous UNO R3 is its GPIO pin current limitation. On the new Arduino Uno R4 boards, the maximum source/sink current is only 8mA. On the older R3 boards, it was 20 mA.
- The QO-100 ground station transmits the uplink on 2.4GHz which is an ISM band freely used by other services. No interference was experienced to the Arduino UNO R4 WiFi from the transmitted uplink signal when operating on the NB transponder. Your mileage may vary.
- A seperate switch to control program flow would be nice. Maybe by way of a touch pad on the PCB. Similar to the Love Heart capacitive touch pad that exists on the bottom of the UNO R4 but more practically placed.
- On the next iteration of this project the error relevant to the CAN Bus pins should be corrected and the matching PCB regenerated. However, as stated before, this will only be relevant for persons intending to make use of the CAN Bus facility.
- Improvements to the code could be made by using timed action threads, interrupts and reducing the amount of global variables.
- To keep GPIO current below the safe level of 8mA means the buzzer volume is not loud. Increasing the sounder volume by employing a transistor driver for the buzzer might be justified
Comments