Tuesday, September 2, 2025

How to Build an Automatic Station Identification using Arduino and DF Player

 


One of my recent weekend project  is the automatic station identifier using Arduino Nano, DFPlayer and DS1307 RTC module. These three modules were integrated on a compact 2 x 3 inch printed circuit board with the addition of a general-purpose transistor to reliably key the transmitter at pre-programmed intervals.

The code for this project was initially generated with the assistance of ChatGPT. Subsequent  refinements included the incorporation of additional libraries  and code modifications to ensure proper functionality. 

Below is the code.

.......................................................................................................................................................................

#include <Wire.h>

#include "Arduino.h"

#include "SoftwareSerial.h"

#include "DFRobotDFPlayerMini.h"

#include "uRTCLib.h"


uRTCLib rtc(0x68);


SoftwareSerial mySerial(10, 11); // D10 = TX, D11 = RX

DFRobotDFPlayerMini myDFPlayer;


const int busyPin = 7;   // DFPlayer BUSY pin

const int playLed = 5;   // Indicator output (HIGH while playing)


int lastMinute = -1;


void setup() {

  

  delay (1000);  //This is included to allow the reset of arduino.

  pinMode(busyPin, INPUT);   

  pinMode(playLed, OUTPUT);  

  digitalWrite(playLed, LOW);


  Serial.begin(9600);

  mySerial.begin(9600);


#ifdef ARDUINO_ARCH_ESP8266

URTCLIB_WIRE.begin(0, 2); // D3 and D4 on ESP8266


  #else

   URTCLIB_WIRE.begin();

  #endif


//rtc.set(45, 29, 19, 6, 23, 8, 25);

//  RTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)



  if (!myDFPlayer.begin(mySerial)) {

    Serial.println("Unable to begin DFPlayer Mini");

    while (1);

  }


 myDFPlayer.volume(23);  // set volume (0–30)

  

  }


void loop() {

  


  rtc.refresh();


  // --- Show realtime clock every second ---

  Serial.print(rtc.year());

  Serial.print('/');

  Serial.print(rtc.month());

  Serial.print('/');

  Serial.print(rtc.day());

  Serial.print(" ");

  Serial.print(rtc.hour());

  Serial.print(':');

  Serial.print(rtc.minute());

  Serial.print(':');

  Serial.println(rtc.second());


  // --- Every 30 minutes playback trigger ---

  if (rtc.minute() % 15 == 0 && rtc.minute() != lastMinute && rtc.second() == 0) {

    lastMinute = rtc.minute();

    Serial.println("Playing MP3...");

    myDFPlayer.play(1);   // Play first MP3 file (0001.mp3 on SD card)

  }


  // --- Monitor DFPlayer BUSY line ---

  if (digitalRead(busyPin) == LOW) {

    digitalWrite(playLed, HIGH);  // Playing

  } else {

    digitalWrite(playLed, LOW);   // Idle

  }


  delay(1000);

}

.......................................................................................................................................................................


The program is configured to trigger the DFPlayer module at 15 minute interval throughout the hour. During idle periods, the system continuously outputs real-time clock data via the Arduino serial interface. This feature provides an external monitoring capability and allows RTC calibration when necessary.

When the scheduled event occurs, the Arduino simultaneously initiates audio playback on the DFPlayer and signal digital pin 5 to key the transmitter PTT. The Arduino also monitors the busy pin of the DFPlayer via digital pin 7, enabling the microcontroller to accurately determine the end of the audio playback. This ensures that the transmitter's PTT is released in precise synchronization with the termination of the station identification message.




The video below demonstrates the project in operation, keying an Icom IC-2200H radio transceiver. In the future, I am planning to modify the code to include automated time announcement in addition to the station identification feature.   ---73 de du1vss




Sunday, August 10, 2025

How to build a programmable Buck Converter XY6020L

 




Another find from the Chinese market is this XY6020L DIY programmable buck converter.  I bought mine from Lazada for about 21 USD and the kit comes into two modules. One of the module is the main buck converter unit while the other one serves as the display keypad unit.


 

My programmable buck converter uses a salvaged old PSU aluminum case and  connected the module to a 10amps, 24V switching power supply.


 With this combination, my working DIY power supply is now capable delivering 0 to 24V volts and 0-10Amps of current. The front knob and buttons provides access to adjust the CV and CC and the small back lit LCD provides visual indication of my set points and real-time voltage/current output of the converter.


Why need to buy expensive PSU when you can make one. ---73 de du1vss.













Tuesday, July 8, 2025

Programming my Arduino Industrial Board




 

I 'm excited to start testing my newly acquired Arduino Industrial 101 board for potential R&D in Internet of Things (IOT) applications. Thanks to the help of various AI tools, programming microcontrollers has become much easier and faster, making the learning more efficient.

Upon inspecting the board, I can see that this board has 3 digital pins and 4 analog input channels. For my first project, I 'm using the digital pins 5, 6 and 13 each connected to a differently colored LED. Based on  ChatGPT,'s suggestion, activating these LEDs requires the use of Bridge library, and is recommended the following code as a starting point.

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

YunServer server;

void setup() {
  Bridge.begin();      // Start Bridge
  server.listenOnLocalhost();
  server.begin();

  pinMode(5, OUTPUT);   // Set pin 5 as output
  pinMode(6, OUTPUT);   // Set pin 6 as output
  pinMode(13, OUTPUT);  // Set pin 13 as output
}

void loop() {
  YunClient client = server.accept();

  if (client) {
    process(client);
    client.stop();
  }

  delay(50);
}

void process(YunClient client) {
  String command = client.readStringUntil('/');

  if (command == "digital") {
    int pin = client.readStringUntil('/').toInt();
    int value = client.readStringUntil('\r').toInt();

    if (pin == 5 || pin == 6 || pin == 13) {
      digitalWrite(pin, value);
      client.print(F("Pin "));
      client.print(pin);
      client.print(F(" set to "));
      client.print(value);
    } else {
      client.print(F("Invalid pin."));
    }
  } else {
    client.print(F("Invalid command."));
  }
}

After compiling the code and programming it to the board, the 3 LEDs can be tested by the following http commands.

Activate pin 5: http://arduino.local/arduino/digital/5/1
Deactivate pin 5: http://arduino.local/arduino/digital/5/0

Activate pin 6: http://arduino.local/arduino/digital/6/1
Deactivate pin6: http://arduino.local/arduino/digital/6/0

Activate pin 13: http://arduino.local/arduino/digital/13/1
Deactivate pin 13: http://arduino.local/arduino/digital/13/0





Using ChatGPT again, I was able to create an HTML interface with 3 buttons corresponding to each LED. With this dashboard, I can now control all the 3 LEDs remotely. Below is the HTML code used to control the LEDs. 


<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Arduino Pin Control</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      margin-top: 50px;
    }
    .button {
      display: inline-block;
      width: 140px;
      padding: 15px;
      margin: 10px;
      font-size: 18px;
      border: none;
      border-radius: 10px;
      cursor: pointer;
      background-color: #ccc;
    }
    .button.on {
      background-color: #4CAF50;
      color: white;
    }
  </style>
</head>
<body>

  <h1>Arduino Control Panel</h1>

  <button class="button" id="pin5" onclick="togglePin(5)">Pin 5 OFF</button>
  <button class="button" id="pin6" onclick="togglePin(6)">Pin 6 OFF</button>
  <button class="button" id="pin13" onclick="togglePin(13)">Pin 13 OFF</button>

  <script>
    const arduinoIP = "192.168.8.238";  // ✅ Your Arduino IP
    const pinStates = { 5: 0, 6: 0, 13: 0 };

    function togglePin(pin) {
      // Toggle internal state
      pinStates[pin] = pinStates[pin] ? 0 : 1;

      // Build URL
      const url = `http://${arduinoIP}/arduino/digital/${pin}/${pinStates[pin]}`;

      // Use Image to send GET request (avoids CORS)
      const img = new Image();
      img.src = url;

      // Update button UI
      const btn = document.getElementById(`pin${pin}`);
      if (pinStates[pin]) {
        btn.classList.add("on");
        btn.textContent = `Pin ${pin} ON`;
      } else {
        btn.classList.remove("on");
        btn.textContent = `Pin ${pin} OFF`;
      }
    }
  </script>

</body>
</html> 

Before uploading the code to Arduino, make sure to connect the board to your local WIFI network. Once connected, take note of the IP address assigned to the board, and update your HTML code accordingly to ensure proper communication.   --- 73 de du1vss
 

Thursday, September 12, 2024

Antenna Analyzer Impedance Calculations


I just found this valuable information on the mathematics behind the modern antenna analyzer. The diagram was part of the May 2005 issue of Amateur Radio magazine..



 

Friday, August 9, 2024

How to repair defective Met One MSO Weather Sensor board

 

We have three defective MSO weather sensors from Met One Instruments that have been sitting in the junk box for over 7 years. Upon checking the Met One Instruments website, we found that this product has long been discontinued and replaced by Met One AIO weather sensor. Both models are identical except the AIO weather sensor now using an ultrasonic wind speed and wind direction sensor. 

These three MSO units suffered a common failure-- the board's microcontroller was damaged by an electrical surge, rendering the entire unit useless. For those unfamiliar with the MSO, let me give a short description about the instrument. It is a compact weather instrument made by Met One Instruments. The MSO includes an anemometer for measuring wind speed, a vane for measuring wind direction, a digital pressure sensor for atmospheric pressure and lastly it has a temperature/humidity sensor for measuring ambient temperature and relative humidity. That's 5 weather sensors combined in a small package.


For this project, I plan to reuse the potentiometer in the wind direction since it is still functional. The MSO uses a 360-degree 10K potentiometer and a reed switch for the anemometer assembly. 

For the ambient temperature, humidity and barometric pressure, I decided to use the new BME280 digital sensor from Adafruit. All these sensors can be easily integrated and processed by an Arduino microcontroller.



I built my prototype board on a single PCB measuring (2.5in x 2.5in) in size. The Arduino nano and the LM2596 buck converter are all mounted on the top. The buck converter is more convenient than the typical 7805 regulator since in can handle up to 35V of input without heating. Another important module in the project is the RS232 to TTL converter. It is mounted at the back of the pcb so only the 4 pins are visible on the surface. The converter is responsible for interfacing the Arduino to the outside world!

The MSO weather sensor sends a serial data every second. There are 5 parameters separated by a comma and terminated by a carriage return (cr) and line feed (lf). The format is:

Temp,Humidity,Pressure,Wind Speed,Wind Direction(cr)(lf)




We can use a datalogger or a serial data terminal program such as the RealTerm to display the real-time readings of the MSO weather sensor.  Below is the code used by the Arduino to integrate all the 5 sensors!


/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor
  This example shows how to take Sensor Events instead of direct readings
  
  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2652

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BME280.h>



Adafruit_BME280 bme; // use I2C interface
Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();


const int pulsePin = 7; // Pin where the pulse signal is connected
unsigned long duration; // Duration of the pulse in microseconds
int frequency; // Frequency of the pulse in Hertz

void setup() {
  pinMode(pulsePin, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println(F("BME280 Sensor event test"));

  if (!bme.begin()) {
    Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
    while (1) delay(10);
  }
  
  //bme_temp->printSensorDetails();
  //bme_pressure->printSensorDetails();
  //bme_humidity->printSensorDetails();

  Serial.println();
  Serial.println("Multi Parameter Weather Sensor");
  Serial.println("Developed by Hevir, DU1VSS, 8/8/24");
  Serial.println();
  Serial.println("AT,RH,BP,WS,WD");
  Serial.println();


}

void loop() {

  ///   code for bme280   ///
  sensors_event_t temp_event, pressure_event, humidity_event;
  bme_temp->getEvent(&temp_event);
  bme_pressure->getEvent(&pressure_event);
  bme_humidity->getEvent(&humidity_event);

  ///   code for frequency counter   ///
    
    duration = pulseIn(pulsePin, LOW); //measure the duration of the pulse.
    frequency = 1000000.0 / duration; // Frequency = 1 / period, period = duration in microseconds
    float ws = ((frequency * 0.805) + 0.1748);


  ///   code for wind direction   ///

  int raw = analogRead(A2);
  int wd = (raw * (5.0 / 1023.0) * 72);



  Serial.print(temp_event.temperature);
  Serial.print(",");

  Serial.print(humidity_event.relative_humidity);
  Serial.print(",");

  Serial.print(pressure_event.pressure);
  Serial.print(",");

  Serial.print(ws);
  Serial.print(",");

  Serial.print (wd);
  Serial.print(",");

  Serial.print ("000"); //This extra line is included for siap+micros to parse the data correctly.
  Serial.println();

  delay(1000);
}






---73 de du1vss


Tuesday, July 9, 2024

Measuring the Impedance of a UHF Quadloop

 


Quad loop antenna is indeed has a 100ohms impedance at the feed point. I tried to build a UHF version of the quad and sweep its frequency response using my handy antenna analyzer. 


Quad loop needs a quarter wavelength of 75 ohm cable in order to transform its impedance from 100ohms to 50ohms.


---73 de du1vss