MP3 speech files for use in clock projects

In recent post I’ve posted about Using Text to Speech online tools to create audio files for Arduino projects and Batch processing files with Audacity. I have a couple of projects that use speech alerts and one of those is a speaking clock. It announces the time at the press of a button, but more helpfully announces the hour, when it is time to get up and when to have morning tea and lunch.

While I don’t think the Arduino code is in a fit state to share I’ve uploaded the audio files to Github for anyone to use in their projects. There are two versions of of the files:

  1. French Celine created with Online Tone Generator. These are the files I am currently using in my clock.
  2. British Amy created with TTSMP3. An alternative set I made to test TTSMP3

I use French Celine in my project. Here are a couple of examples of what they can do when joined:

French Celine

British Amy

I have uploaded the mp3 files to my Github for anyone to freely use. They are available here. This is a list of the files:

000 zero.mp3
001 one.mp3
002 two.mp3
003 three.mp3
004 four.mp3
005 five.mp3
006 six.mp3
007 seven.mp3
008 eight.mp3
009 nine.mp3
010 ten.mp3
011 eleven.mp3
012 twelve.mp3
013 thirteen.mp3
014 fourteen.mp3
015 fifteen.mp3
016 sixteen.mp3
017 seventeen.mp3
018 eighteen.mp3
019 nineteen.mp3
020 twenty.mp3
021 twenty one.mp3
022 twenty two.mp3
023 twenty three.mp3
024 twenty four.mp3
025 twenty five.mp3
026 twenty six.mp3
027 twenty seven.mp3
028 twenty eight.mp3
029 twenty nine.mp3
030 thirty.mp3
031 thirty one.mp3
032 thirty two.mp3
033 thirty three.mp3
034 thirty four.mp3
035 thirty five.mp3
036 thirty six.mp3
037 thirty seven.mp3
038 thirty eight.mp3
039 thirty nine.mp3
040 forty.mp3
041 forty one.mp3
042 forty two.mp3
043 forty three.mp3
044 forty four.mp3
045 forty five.mp3
046 forty six.mp3
047 forty seven.mp3
048 forty eight.mp3
049 forty nine.mp3
050 fifty.mp3
051 fifty one.mp3
052 fifty two.mp3
053 fifty three.mp3
054 fifty four.mp3
055 fifty five.mp3
056 fifty six.mp3
057 fifty seven.mp3
058 fifty eight.mp3
059 fifty nine.mp3
060 sixty.mp3
061 one oclock.mp3
062 two oclock.mp3
063 three oclock.mp3
064 four oclock.mp3
065 five oclock.mp3
066 six oclock.mp3
067 seven oclock.mp3
068 eight oclock.mp3
069 nine oclock.mp3
070 ten oclock.mp3
071 eleven oclock.mp3
072 twelve oclock.mp3
073 noon.mp3
074 twelve noon.mp3
075 midnight.mp3
076 the time is.mp3
077 it is.mp3
078 it is time to wake up.mp3
079 it is morning tea time.mp3
080 it is lunch time.mp3
081 am.mp3
082 pm.mp3
083 I was sleeping.mp3
084 good morning.mp3
085 good day.mp3
086 good afternoon.mp3
087 good evening.mp3
088 at the third stoke.mp3
089 beep beep beep.mp3
090 exactly.mp3
092 its time to do something.mp3
094 or there abouts.mp3
095 precisely.mp3

Batch processing files with Audacity

In my last post Using Text to Speech online tools to create audio files for Arduino projects I had some info about online text to audio sites I have been using to create audio alert files for projects. The files produced by ttsmp3.com seemed to have a lower audio level than I expected. I found I could run all the files through a batch process in Audacity to normalize them. I spent a lot more time trying to find out how to do it so I’m making this quick post so I have the info for next time.

I was running Audacity 2.1.3 which is now an old version. The terminology and location of the feature changed in 2.3.0. Essentially the pre 2.3 version seems to call it ‘chains’ whereas it became ‘macros’ in 2.3. I’ll include info for both as I made notes for the older versions first.

The relevant info is available on the Audacitiy site.

There are two parts to the process

  1. Create a chain/macro with the processes that will be run during the batch process. This only needs to be set up once.
  2. Select files and run the task.

There are a lot of other changes that can be included. I’ve also added Mono to one as I found some of my files created another way were stereo and others mono. My project only had a single speaker so I converted them all to mono for consistancy.

Pre 2.3 version

In these versions the batch process is referred to as a chain.

To create a chain

  • Go to File
  • Select Edit chains…
  • Add button
  • Set a name, e.g. Normalize to -0.1dB
  • Insert Normalize – Tweak settings if desired. I didn’t
  • Insert ExportMP3 – This is required otherwise the files are not saved
The chain should look something like this

To use the chain

  • Go to File
  • Select Apply chains…
  • Select the chain, in my case ‘Normalize to -0.1dB’
  • Select Apply to files
  • Browse to the file folder and choose files
  • Select Open
  • Converted files will be placed in a folder called cleaned inside the folder of the selected files

Current version

In later versions it is called a macro.

To create a macro

  • Go to Tools
  • Select Macros…
  • New button
  • Set a name, e.g. Normalize
  • Insert Normalize. There is also an option ‘Normalize (Macro_Normalize)’ that I have not tried

  • Insert Export as MP3 – This is required otherwise the files are not saved

To use the macro

  • Go to Tools
  • Select Macros…
  • Select the macro, in my case Normalize
  • Select Files
  • Browse to the file folder and choose files
  • Select Open
  • Converted files will be placed in a folder called macro-output inside the folder of the selected files

Before and after

Here is a before and after shot. The before is the one at the top.

As always if let me know if you find inaccuracies in my info.

Using Text to Speech online tools to create audio files for Arduino projects

I’ve made a couple of projects that play audio alerts using a dfplayer and MP3 files. One in a clock that plays announcements and the other a countdown timer. When I did those, I used onlinetonegenerator.com to convert text to speech. I liked the voices but it doesn’t have an option to save the audio as an MP3 file. I ended up using Audacity to record the computers audio. It worked but was very tedious. Since then, I’ve been looking for a simpler way.

The important criteria in a text to speech service for me is:

  • Ability to enter text, listen to the converted audio in the browser and then download it as an mp3 file.
  • Sufficient audio quality.
  • Volume level ok.
  • Suitable lead in and end dead time to allow multiple files to be played in sequence with the  result sounding as a smooth sentence. For example these four files together; “The time is”, “eleven”, “thirty two”, “am”.
  • A suitable voice. They don’t all have the same voices. I prefer some more than others.
  • Free or good value.
  • Ability to change speed, pitch and emphasis a bonus.

Here are a few I’ve looked at.

Online Tone Generator (onlinetonegenerator.com/voice-generator.html)

This is the first one I used. Its:

  • Free.
  • Has a good range of voices; mostly Google, plus a few Microsoft ones I presume are built into my Windows PC. I particularly like Google français.
  • Lots of other audio tools, including; noise generator, sweep generator, DTMF signals.
  • But, no MP3 download.

From Text To Speech (fromtexttospeech.com)

I briefly looked at this one. It is:

  • Free.
  • Has a 50 000 character limit per file.
  • I’m unable to listen in browser. No play button displays until a file is created and then the player presented appears to use flash and is blocked by my browser. The file can be downloaded and used.
  • MP3 download.
  • Different speed and voices.

TTSMP3 (ttsmp3.com)

This is the one that I am intending to use in my next project. Lots of features, MP3 file output and a fair amount of free usage. It is:

  • Free for 3,000 characters (~375 words) per day.
  • Lots of different voices.
  • Supports speed, pitch and other effects using tags.
  • Multiple voices can be used in the one piece of text by using tags.
  • MP3 file download.

TTSMP3 uses Amazon Polly and comes with quite a few voices and features. Additional effects can be used by using tags in your text. More info about tags is available on this Amazon page.

Here is an example of the voices.

That audio file was created by pasting the text below into the converter. Beware if you do this it will use up most of your daily 3000 word limit.

[speaker:Zeina] Hi, I'm Arabic Zeina
[speaker:Russell] Hi, I'm Russell Australian English Russell
[speaker:Nicole] Hi, I'm Australian English Nicole
[speaker:Camila] Hi, I'm Brazilian Portuguese Camila
[speaker:Ricardo] Hi, I'm Brazilian Portuguese Ricardo
[speaker:Vitória] Hi, I'm Brazilian Portuguese Vitória
[speaker:Emma] Hi, I'm British English Emma
[speaker:Amy] Hi, I'm British English Amy
[speaker:Brian] Hi, I'm British English Brian
[speaker:Chantal] Hi, I'm Canadian French Chantal
[speaker:Enrique] Hi, I'm Castilian Spanish Enrique
[speaker:Lucia] Hi, I'm Castilian Spanish Lucia
[speaker:Conchita] Hi, I'm Castilian Spanish Conchita
[speaker:Zhiyu] Hi, I'm Chinese Mandarin Zhiyu
[speaker:Mads] Hi, I'm Danish Mads
[speaker:Naja] Hi, I'm Danish Naja
[speaker:Ruben] Hi, I'm Dutch Ruben
[speaker:Lotte] Hi, I'm Dutch Lotte
[speaker:Céline] Hi, I'm French Céline
[speaker:Léa] Hi, I'm French Léa
[speaker:Mathieu] Hi, I'm French Mathieu
[speaker:Vicki] Hi, I'm German Vicki
[speaker:Marlene] Hi, I'm German Marlene
[speaker:Hans] Hi, I'm German Hans
[speaker:Karl] Hi, I'm Icelandic Karl
[speaker:Dóra] Hi, I'm Icelandic Dóra
[speaker:Aditi] Hi, I'm Indian English Aditi
[speaker:Raveena] Hi, I'm Indian English Raveena
[speaker:Carla] Hi, I'm Italian Carla
[speaker:Giorgio] Hi, I'm Italian Giorgio
[speaker:Bianca] Hi, I'm Italian Bianca
[speaker:Takumi] Hi, I'm Japanese Takumi
[speaker:Mizuki] Hi, I'm Japanese Mizuki
[speaker:Seoyeon] Hi, I'm Korean Seoyeon
[speaker:Mia] Hi, I'm Mexican Spanish Mia
[speaker:Liv] Hi, I'm Norwegian Liv
[speaker:Ewa] Hi, I'm Polish Ewa
[speaker:Jan] Hi, I'm Polish Jan
[speaker:Maja] Hi, I'm Polish Maja
[speaker:Jacek] Hi, I'm Polish Jacek
[speaker:Inês] Hi, I'm Portuguese Inês
[speaker:Cristiano] Hi, I'm Portuguese Cristiano
[speaker:Carmen] Hi, I'm Romanian Carmen
[speaker:Maxim] Hi, I'm Russian Maxim
[speaker:Tatyana] Hi, I'm Russian Tatyana
[speaker:Astrid] Hi, I'm Swedish Astrid
[speaker:Filiz] Hi, I'm Turkish Filiz
[speaker:Joey] Hi, I'm US English Joey
[speaker:Kimberly] Hi, I'm US English Kimberly
[speaker:Salli] Hi, I'm US English Salli
[speaker:Ivy] Hi, I'm US English Ivy
[speaker:Matthew] Hi, I'm US English Matthew
[speaker:Kendra] Hi, I'm US English Kendra
[speaker:Joanna] Hi, I'm US English Joanna
[speaker:Justin] Hi, I'm US English Justin
[speaker:Miguel] Hi, I'm US Spanish Miguel
[speaker:Lupe] Hi, I'm US Spanish Lupe
[speaker:Penélope] Hi, I'm US Spanish Penélope
[speaker:Gwyneth] Hi, I'm Welsh Gwyneth
[speaker:Geraint] Hi, I'm Welsh English Geraint

Comparisons

Compared with the original audio files that I created by using Audacity to record the PC audio and onlinetonegenerator.com, ttsmp3.com had lower volume. I may have had the record level a bit high when I used Audacity so not sure that the ttsmp3 level is too low.

The bit rate is also different, with the Audacity ones higher. That’s probably because I unnecessarily chose a higher bitrate in Audacity. TTSMP3 was 48kbs.

And that affected the file size. The TTSMP3 is much smaller.

Here are a couple of examples for comparison. For each I created four separate files and then joined them together to see how smooth the transition was. The four files were “The time is”, “11”, “32”, “AM”. I had to be a bit creative with the AM for French Celine as it was pronounced as “am”.

onlinetonegenerator.com Voice is Google français. I like this voice. It has added a lot of character to my speaking clock.

ttsmp3.com Voice is French Celine. It was much easier to create and the timing between files is ok, but the voice doesn’t have the same character to the one above in my opinion

ttsmp3.com This is British Amy. This was just for comparison to see how the same text would sound with an English voice.

Do you have other methods? Let me know.

Update 13/4/2021: I have added a post with info about how to increase the audio level in a batch of files Batch processing files with Audacity

Reliably debouncing rotary encoders with Arduino and ESP32

I love those simple cheap rotary encoders as used in the KY-040 modules as a method of getting user input with Arduino and ESP32 projects. The issue of bounce with them is significant and for years I’ve been looking a reliable method of dealing with it. I thought I had it figured out by either using a couple of 100nF capacitors or by using code ignore quick changes but this was not always reliable and sometimes missed legitimate changes when rotating at speed. In forums I read people recommending to use a lookup table, but not me. I persevered with what I knew, at least until my methods didn’t work.

I’ve only recently started using ESP32s. The first time I started using one with an encoder the bouncing was terrible. Turning a single indent resulted in a large number of false increments. I assumed that this was because the ESP32 was so running much faster than the Nanos I’ve been using and triggering on even quicker bounces. I don’t know if that is a possibility, but I now believe that the encoder I was using was extremely noisy. I thought it was time to revisit debouncing. After all a reliable encoder will not necessarily stay reliable forever.

An alternative solution

In some forums I read there was sometimes a comment saying there was a more reliable way. That is to use a table to compare the previous state with the new state and using a lookup table to ignore those changes that are not valid for a legitimate change. I decided to investigate. I came across this page Rotary Encoder : How to use the Keys KY-040 Encoder on the Arduino. I recommend reading it if you want to learn more about it.

I tried the Code For Improved Table Decode and was really surprised just how well it worked without any hardware filtering. There were only two things missing that I wanted. Firstly, it uses polling and I wanted to use interrupts and secondly it has a copyright notice and I respect that. However, I want to use code that I can include in projects that I can place online to share with others. It’s still a great read and I am grateful for Best Microcontroller Projects for providing the resource.

Next I came across code by Oleg Mazurov’s pages Reading rotary encoder on Arduino and Rotary encoder interrupt service routine for AVR micros

I also found these to be very helpful. I found some others had similar code that I believe is based on the code by Oleg. Oleg’s code worked well too, but I couldn’t get it to work on the ESP32 without a couple of changes. It uses port read to read the value of the encoder pins, which I expect is a very efficient thing to do, but didn’t work with the ESP32. Also, the interrupt version uses PROGMEM that also appears to be incompatible with the ESP32, or at least as it is done in the example.

However, you can stop here and use Oleg’s code if you are using a Nano or Uno, or use the Best-Microcontroller-Projects.com version. To get Oleg’s version working on the ESP32 I made these changes.

Port read

Olig’s code reads the ports directly without using Arduino’s digitalRead. I had a go at using digitalRead, which I hoped would allow it to work on the ESP32 and perhaps other microcontrollers. To do that I:

Removed this define

define ENC_PORT PINC

And changed this:

old_AB |= ( ENC_PORT & 0x03 ); // Add current state 

to this to use digitalRead:

if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B

Progmem

I’m not sure why program memory is used instead of SRAM, only that I couldn’t get it to work on the ESP32 so I removed the reference to it making it the same as Oleg’s polling version. So from this:

static const int8_t enc_states [] PROGMEM = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

To this:

static const int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

Changed versions

I confess to not fully understanding the code, so I can’t be sure that there are not issues with it. I have made some other tweaks too, but those are mainly just the addition of comments. These are the two versions that I am currently using.

Polling version

/* Based on Oleg Mazurov's code for Reading rotary encoder on Arduino, here   
   https://chome.nerpa.tech/mcu/reading-rotary-encoder-on-arduino/ and here
   https://chome.nerpa.tech/mcu/rotary-encoder-interrupt-service-routine-for-avr-micros/

   This example does not use the port read method. Tested with Nano and ESP32

   Connections
   ===========
   Encoder | ESP32 |  Nano
   --------------------------
     A     |  D5   |  Nano D2
     B     |  D21  |  Nano D3
     GND   |  GND  |  GND
*/

// Define rotary encoder pins
#define ENC_A 21
#define ENC_B 5

volatile int counter = 0;

void setup() {

  // Set encoder pins
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);

  // Start the serial monitor to show output
  Serial.begin(115200); // Change to 9600 for Nano, 115200 for ESP32
  delay(500);           // Wait for serial to start  
  Serial.println("Start");
}

void loop() {
  static int lastCounter = 0;
  
  read_encoder();

  // If count has changed print the new value to serial
  if(counter != lastCounter){
    Serial.println(counter);
    lastCounter = counter;
  }
}

void read_encoder() {
  // Encoder routine. Updates counter if they are valid
  // and if rotated a full indent
 
  static uint8_t old_AB = 3;  // Lookup table index
  static int8_t encval = 0;   // Encoder value  
  static const int8_t enc_states[]  = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table

  old_AB <<=2;  // Remember previous state  

  if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
  if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
  
  encval += enc_states[( old_AB & 0x0f )];

  // Update counter if encoder has rotated a full indent, that is at least 4 steps
  if( encval > 3 ) {        // Four steps forward
    counter++;              // Increase counter
    encval = 0;
  }
  else if( encval < -3 ) {  // Four steps backwards
   counter--;               // Decrease counter
   encval = 0;
  }
}

Interrupt version

/* Based on Oleg Mazurov's code for rotary encoder interrupt service routines for AVR micros
   here https://chome.nerpa.tech/mcu/reading-rotary-encoder-on-arduino/
   and using interrupts https://chome.nerpa.tech/mcu/rotary-encoder-interrupt-service-routine-for-avr-micros/


   This example does not use the port read method. Tested with Nano and ESP32
   both encoder A and B pins must be connected to interrupt enabled pins
   

   Connections
   ===========
   Encoder | ESP32 |  Nano
   --------------------------
     A     |  D5   |  Nano D2
     B     |  D21  |  Nano D3
     GND   |  GND  |  GND
*/

// Define rotary encoder pins
#define ENC_A 21
#define ENC_B 5

volatile int counter = 0;

void setup() {

  // Set encoder pins and attach interrupts
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, CHANGE);

  // Start the serial monitor to show output
  Serial.begin(115200); // Change to 9600 for Nano, 115200 for ESP32
  delay(500);           // Wait for serial to start  
  Serial.println("Start");
}

void loop() {
  static int lastCounter = 0;

  // If count has changed print the new value to serial
  if(counter != lastCounter){
    Serial.println(counter);
    lastCounter = counter;
  }
}

void read_encoder() {
  // Encoder interrupt routine for both pins. Updates counter
  // if they are valid and have rotated a full indent
 
  static uint8_t old_AB = 3;  // Lookup table index
  static int8_t encval = 0;   // Encoder value  
  static const int8_t enc_states[]  = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table

  old_AB <<=2;  // Remember previous state

  if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
  if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
  
  encval += enc_states[( old_AB & 0x0f )];

  // Update counter if encoder has rotated a full indent, that is at least 4 steps
  if( encval > 3 ) {        // Four steps forward
    counter++;              // Increase counter
    encval = 0;
  }
  else if( encval < -3 ) {  // Four steps backwards
   counter--;               // Decrease counter
   encval = 0;
  }
}

Downsides of this method

While it is working well in tests, I have not used it in a permanent project yet. The only downside I can find so far is that if using interrupts instead of polling it requires two interrupt pins. Other methods I’ve used only need one. I don’t expect this will be an issue of the ESP32 but it may be with the Nano.

Finally, a decent quality prototype breadboard for a reasonable cost

Getting decent quality prototype breadboards for a reasonable cost is something that has eluded me for years. I think I have finally found a reliable source. Those advertised on eBay or at least the cheaper ones seem that I have previously purchased too often have poor metal connectors inside. It can be difficult to insert pins in and if the pin is thick the contacts don’t completely spring back. I have not found a way to determine which of these are ok as just looking at the breadboard doesn’t seem to be reliable method.

The new ones I’ve got are BB830 by BusBoard. I found out about them by Ben Eaters in this video. Skip to about 1:18 if you want to hear him talk about them.

Ben sells them and has more information about them on his breadboard page, however I must confess I got them from Mouser as I am outside of the US and was preparing an order with Mouser anyway. Here is a shot of a bread board fastened to a cheese board.

The breadboard on the bottom is the new one. Those little ones at the top are just old ones that have been cut.

I’m very happy with them. They cost more than those I’ve previously purchased on eBay but if they don’t work then any price is too much. Also, I want to support producers of decent quality items. So far, I’m very happy with the BusBoard ones.

IR remote control mute button

I recently built a simple one button Arduino based IR remote control to mute our TV and Computer amp. I am quite happy with the results. The idea to use half a stress ball for the mute button I thought was inspired. The timber case built using with the aid of some jigs I made for my old saw bench came out better than expected.

To save power the voltage regulator and the current limiting resistor to the power LED were removed. The other onboard LED was left connected and ended up using it to flash with the IR LED just for diagnostics. As the case doesn’t have a bottom it displays a nice red flash in use. I decided to be a bit naughty and drive the IR LED without a limiting resistor through a transistor to drive it hard and get a bit more range. I thought the quick pulses would mean the LED should probably survive, but I ended up adding the resistor back in.

As is often the case, at least with my projects much time was spent trying to determine what was causing some unexpected behaviour. While it often worked correctly. Sometimes pressing the button didn’t seem to do anything. I used a number of different batteries I had laying around. I eventually discovered the IR LED was staying on, this was with some old batteries. My current assumption is that when the voltage drops too far the processor stops and the LED pin either goes high or it is stopping when it is high. As I don’t have a proper solution, I added the resistor back in series with the IR LED to at least reduce the current flow if it does happen again. With the resistor out I didn’t find the range was improved very much anyway.

The code

The code is fairly simple and is really designed to be able to support multi button remotes. After completing it I read that the TV begone just uses the reset button to wake up the processor, it then sends out it’s codes and then goes back to sleep. That’s an interesting way to do it that never occurred to me. I went with the traditional method of using a button and interrupt.

I mentioned earlier that it was designed to mute both a TV and a computer amp. These are in different rooms. The button simply sends out the mute pulses for one after the other. It could mute both at the same time, but due to location of the amp and TV that doesn’t happen in practice.

The code really needs further work to resolve the case where the LED stays on, but if you are interested you can check it out on my Github garrysblog/IR-Remote-Mute-Button

The circuit

Here is the circuit diagram. I used a PN2222A transistor, but that was because I have a lot of those. I presume it would work with a lot of other types. Other than that it is fairly simple

The case and button

The case was made mostly from a pine timber lining board. Like many of the reasons for my choices I did it this way as another project was to create some jigs to create clean precise 45 degree cuts on an old table saw. I don’t think I could have made it this way without the jigs. While most of the joints were glued using PVA glue the piece that holds in the switch and spring was glued in using hot melt glue to allow a about the right amount of time for jiggling before it hardened.

I needed a couple of thin discs to mount to the top and bottom of the ball that holds the ball. I tried some ply first but my results weren’t great. I had an old circuit board from a project that I abandoned years ago and after scraping off the old tracks found that it works well. See it’s worth hanging on to some things for 20+ years and now it is bringing me joy 🙂

Final results

It has been in use for a couple of months now. It’s still going well but I’m not sure how long the batteries will last. I still don’t haven’t fixed the issue with the LED, but other projects are calling. Maybe one day I’ll come back to it. I hope it gives you some inspiration.

Timber breadboards and serving boards with Arduino

Originally, according to Wikipedia and other articles I’ve read wooden kitchen breadboards were used for electronics, which is where the term started. I’ve started using them too. I had a couple of accidents where they magic smoke was released from a couple of Arduino boards when an Arduino module was bumped and moved over a screwdriver in one case and a piece of metal in another. That smoke can escape pretty quickly. I also got tired of connections coming loose when moving the project between sessions. I thought I would share some of my results as they may help someone.

I started by trying to make my own boards, but found I didn’t really have any suitable timber, but I may come back and look at options later.

I found our local Kmart had suitable items. The first is a beautiful acacia serving board. Originally it had a timber handle. I cut that off as it made it a bit long and awkward. It’s not the easiest timber to cut, but I do have some good tools for that and the results were ok. For this one I attached a 20×4 LCD display, battery holder, rotary encoder and joystick. I tried to include items that wouldn’t plug into the solderless breadboard, but adding all these may have been a mistake. I doubt I will use the joystick, but that’s ok. The dark timber looks great. What I hadn’t expected was how much more pleasing it made working on a project when everything is held together on such a beautiful piece of timber.

Acacia serving board with handle removed

Kmart no longer have the exact same board but they did get these Anko bamboo serving boards. They came in a pack of 3 boards for $6, so the price was right. They are not as beautiful as the first board and they are smaller, but they are made of bamboo which I presume is more environmentally friendly and their size and thickness make them ideal for smaller projects. I made up several with solderless breadboards attached. This one includes a 16×2 LCD display.

Smaller bamboo serving board

I like these LCD displays a lot so I included one on this board. I bought the I2C board and LCDs separately as I didn’t want them pre-soldered together. This allowed me to solder them together with greater distance between the LCD and backpack module. I could then carefully bend the pins so that the LCD sat at a useful angle and the I2 C board was easily accessible for adjusting the contrast and reading the pin connections.

LCD is held down with two screws. The plastic tube spacers are used to get the height at the front correct.

To mount modules to the board I’ve found a couple of different sized plastic tubing. It’s easy to cut to different lengths. There are probably lots of tools to cut it with but I usually use a pair of heavy duty wire strippers, not because it requires a lot of force, but as it has just the right sized cutter that makes it easy to do a neat cut. The tubing can squash a bit so if their lengths are not identical it doesn’t really matter.

Plastic tube and wire strippers

Overall, this has made tinkering much more enjoyable. I’m still looking out for improvements.

Using the DS3231 Real Time Clock alarm with the Adafruit RTClib library

I love the DS3231 RTC module and have used it in a couple of projects without a library using code based on Ralph Bacon’s example. It worked well, but I wanted to use the alarm and working out how to do that was a step too far for me. There doesn’t seem to be a shortage of libraries and I found it challenging to choose one.

I tried the Adafruit RTClib library which I liked but the documentation I looked at didn’t mention support for the alarm, but I found this closed issue in the libraries Github repository Add support for Alarm on DS3231 #94, so it seems it does have support for it. After many hours of twiddling and tweaking here are some notes and example from my experiments of what I believe is correct info. I’m not an expert so let me know if you believe any of it is incorrect or can be improved.

Setting the alarm

This is what I had most trouble with. There are two alarms. The commands to set the alarms time are:
setAlarm1(DateTime, alarm_mode)
setAlarm2(DateTime, alarm_mode)

The alarms can be set to a specific time using DateTime or to a set amount from the current time using TimeSpan. Some formats I used are:

For a specific time use DateTime:
DateTime(Year, Month, Day, Hour, Minute, Second)

For a number of seconds, minutes, hours, etc from the current time:
now + TimeSpan:now + TimeSpan(days, hours, minutes, seconds)

Using unixtime:
now.unixtime() + seconds

The second part of setAlarm is alarm_mode. This sets what needs to match for the alarm to trigger. The modes are:

Alarm modes for alarm 1
DS3231_A1_PerSecond     Once per second
DS3231_A1_Second        When seconds match
DS3231_A1_Minute        When minutes and seconds match
DS3231_A1_Hour          When hours, minutes, and seconds match
DS3231_A1_Date          When date, hours, minutes, and seconds match (day of month)
DS3231_A1_Day           When day, hours, minutes, and seconds match (day of week)

Alarm modes for alarm 2
DS3231_A2_PerMinute     Once per minute (00 seconds of every minute)
DS3231_A2_Minute        When minutes and seconds match
DS3231_A2_Hour          When hours, minutes, and seconds match
DS3231_A2_Date          When date, hours, minutes, and seconds
match
DS3231_A2_Day           When day, hours, minutes, and seconds match

Alarm 2 is slightly different in that it can’t be set to trigger on anything smaller other than 00 seconds, that is triggering on the minute is the smallest amount.

The trick for me was working out what how the relationship between time and mode. If a suitable mode is not chosen it can (and did) result in unexpected results. For example setting the time for 7:00am the next day, but choosing DS3231_A1_Minute will result in the alarm triggering on the next hour after setting as only minutes and seconds are being used in the mode. Hours and days are ignored.

Examples

Set to an explicit time

setAlarm1(DateTime(2020, 6, 25, 15, 34, 0), DS3231_A1_Hour)

The alarm will trigger when seconds, minutes and hours match, resulting in triggering once per day, every day at (15:34:00). The date, month and year are all ignored.

Using TimeSpan or unixtime to set to an amount from the current time

The current time needs to be called before setting the remaining examples as it is needed to calculate the end time. These examples set the alarm to 10 seconds from the current time.

setAlarm1(now + TimeSpan(0, 0, 0, 10), DS3231_A1_Second)
setAlarm1(now.unixtime() + 10, DS3231_A1_Second)

Monitoring the alarm

So now it can be set, how do we know it has activated? There seems to be two ways to do this.

Using alarmFired

alarmFired() will return true if the alarm is firing and will continue to do so for at least some minutes(?) unless it is cleared. However, while the alarm can be cleared, it doesn’t appear that it can be disabled, so it will fire again when the alarm setting criteria is met again. So that needs to be considered in code. Also, I could only see how to do this by polling alarmFired, which if true looks like this method rules it out for use with sleep modes that I want to use.

Using the SQW pin

This SQW pin can be used to output square waves. It can also be used by the alarm. Its output goes low when the alarm is triggered. This opens up the possibility of using it for use with an interrupt so can be used to wake an Arduino from sleep.

Examples

My Github repository has a few examples:

Setting an alarm and polling the SQW pin – DS3231-RTClib-Adafruit-Alarm-Poll-SQW.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-RTClib-Adafruit-Alarm-Poll-SQW/DS3231-RTClib-Adafruit-Alarm-Poll-SQW.ino

Setting an alarm and polling using alarmFired – DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired/DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired.ino

Sending the Arduino to sleep and waking it using the alarm and SQW pin – DS3231-_RTClib-Adafruit-Alarm-Sleep.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-_RTClib-Adafruit-Alarm-Sleep/DS3231-_RTClib-Adafruit-Alarm-Sleep.ino

I hope this is useful and doesn’t have too much incorrect info. Let me know your feedback.

Measuring audio frequency with an Arduino

When I was working on the Morse Code Decoder project I got unexpected results from the output of of the KY-037 audio module. The output was being monitored by an interrupt in the Arduino Nano. It was triggering far more than I expected. I wondered if it was triggering at the frequency of the audio tone of the Morse code being received.

Rather than research it online I decided to have a go at investigating it myself. I wrote a simple sketch that counts the number of times the interrupt is triggered and at regular intervals does a simple calculation and displays the results as Hz. I’m sure this is all widely known, but it was enjoyable working it out for myself.

It’s a simple setup. Just a Nano on a breakout board and the Audio module

It is triggering once per wave of the tone it hears. While monitoring a steady tone I found it to be reasonable at displaying the frequency. I used this online tone generator for testing. Results were fairly consistent from below 100Hz up to 20kHz. I had to crank the volume up a bit and hold it close to the speaker for 20kHz, I presume because the speakers I have don’t work well at that frequency.

It had to be held close for 20kHz, but not as close for lower audible frequencies.

Here is a closeup of the audio module. It is a cheap one from ebay.

Audio module. The digital output was used.

I’ve uploaded the code for anyone interested to by GitHub repository https://github.com/garrysblog/Audio-Frequency-Measurement-Test

Morse Code Decoder using an Arduino Nano

Decoding recreated Morse code from the Titanic

I find the history of Morse code fascinating. I admire those that are able to send and interpret Morse code messages at high speed.

Some time ago I saw a YouTube video about a Morse Code decoder that was based on a micro controller. I didn’t see the schematic or the code but I was very impressed that it was possible with relatively few components. I didn’t know how it was achieved but the puzzle of the design continued to percolate away in the back of my mind.

A Morse code decoder has a lot of elements that interest me. It covers radio history, codes, electronics and programming. Attempting to design one was an opportunity to learn about detecting data patterns, try out some case build ideas I had as well as learn a bit more about Morse Code.

I had an idea that it may be possible using an interrupt routine and using it to look at the time between triggered interrupts. I set myself a challenge to design one. Soon I would be hearing messages by spies in exotic locations, possibly in an attic, wearing trench coats and fedoras tapping out their secret messages to their HQ, or more likely not.

I’ll say straight up that I am not a developer or have electronics training. This is just a hobby and I have not written a lot of code for the Arduino. This design is unlikely to be the best out there. It’s just a result of the result of the challenge I set myself. I’m just documenting the project for fun and maybe inspire others to design their own projects.

Goal

In designing the decoder I wanted to achieve:

  • The decoder to use a microphone as the input. Any Morse it hears is displayed as plain text on a display.
  • Convert text from a clear source with little noise that is sent at speeds in excess of 20 wpm
  • Use an Arduino Nano as the microcontroller, not because it is the best, but because it is the only one that I am familiar with and I don’t have a desire to learn others at the moment.
  • Other parts should be common components or modules and not many of them.
  • Use a 20 x 4 LCD for simplicity. I really like these displays even though they are a bit old school. In my opinion, the glowing backlight seems to have the right aesthetic for the project.
  • Display to show
    • Top line: The length of the latest received dot and the speed set and speed received
    • Middle two lines: Plain text of the latest received message
    • Bottom line: The latest received dots and dashes
  • Manual mode allows user to set speed using a potentiometer
  • Auto mode that automatically tracks sending speed.
  • Potentiometer to set the input sensitivity
  • An LED that lights when the microphone module activates, that is it is receiving a dot or dash. There is one already on the microphone module I used.
  • An LED that illuminates when the processor believes it is receiving a dot or dash. I started with D13 as it was already on the module.
  • Build into a wooden box made from old timber I had. Part of the build was trying to come up with a simple to build and interesting project enclosures.
  • Paint the front and back panels black.

The project was partly about trying out some ideas with the case as well as the actual unit.

While it could do with a bit more development and tweaking, it is now at a point that it works reasonably well, at least where the audio doesn’t have too much background static and hiss. It decodes the Morse of this recreation of the messages from the Titanic on this YouTube video fairly reliably.

The prototype

I started with a simple Morse key that I made from a piece of scrap timber, bending a piece of metal strapping from around the packing of some large item we had purchased, a few screws and an old knob. Added a pulldown resistor and capacitor to reduce bouncing. I connected it to an LCD module and an Arduino Nano. After quite a bit of coding, well lots more thinking than coding, I was able to get it display a single character on the screen with input from the Morse key. Sending Morse using appropriate timing, even slowly is much harder than I expected. With that working I was encouraged and then added a standard audio module and gave up on the key. It was some time before I got any success with that, which brings me to an unexpected feature of the audio module.

The digital output of the audio module wasn’t what I expected

The audio module has two output pins; an audio output and a digital output. I was expecting the digital output would change when the audio tone of a beep was detected and change back when the tone ended. That’s not quite what I found. I have one of those really cheap data analysers that plug into my laptop. This is what I saw when I connected it up.

This is the word YOU -.– — ..-

There are lots of ups and downs… a real lot. Perhaps it is changing at the frequency of the tone playing or at least at a ratio of the tone. If so that opens up further questions and ideas for exploration in the future. Meanwhile how do I get rid of those? I also had a look on the oscilloscope.

Not good here either

I tried adding a smoothing capacitor as they have in power supplies. I found 22uF worked but sometimes affected the first mark in a word resulting in the wrong character being displayed. What about a low pass filter? I don’t know much about them and I’ve never made one before. I found several sites that calculate the values of a resistor and capacitor for a low pass filter, but what frequency should I be aiming for? In the end I experimented with the output connected to an oscilloscope and Morse playing into the mic. The result is based on one of a few different capacitors I had and by tweaking a variable resistor. The waveform on the oscilloscope looks far from square, in fact it looks really bad.

It looks better on the data analyzer.

The word YOU with filtering. The first dash is not quite right but others are

The text on the display Morse decoder was surprisingly accurate.

Prosigns. What are prosigns?

I was not aware of prosigns, but soon came across them on the Wikipedia Morse Code page. Prosigns are characters that have a value that is has a text equivalent that is more than one character. The most well known one outside of Morse operators is probably SOS. It is not designed to be sent as three different characters, rather as one long character, that is …—… The spacing between the S and O bits is the same spacing as the within the S and O bits. It seemed like a good idea to support SOS and if I was going to do that I may as well cover as many prosigns as possible. SOS also has the most marks (dots and dashes) of any I found, so the sketch supports up to 9 bit characters.

Wait, some characters can be a prosign or another character?

Yes they can. It looks like there have been different standards used that has resulted in some Morse patterns set to different characters or prosigns, for example -.–. can be KN or (

So far I have not been able to work out which is the best to use so I’ve taken the easy way out and display both. In this example <KN/(> is displayed.

Display update speed was important

When dots can be as short as 20-30 milliseconds the time to update the display becomes significant. Well the speed of the whole sketch probably becomes significant. I tried to improve the speed in the rest of the sketch as best I could, but I’m sure it could be improved further. Updating the display was definitely slow. I decided to try two methods to speed it up.

The first was to remove the I2C backpack from the display and connect it up directly to the Arduino. This meant more wiring and required another pot for the contrast and resistor for the backlight, but it was not that difficult. The display updated in about half the time. A good result.

The other idea was to try a different library. After reading this forum post I decided to give the hd44780 library a go. I was expecting significant code changes to get it to work, but instead I only needed to change a few lines at the start of the sketch. The result was another three times faster. That’s about 6 times faster with both changes. Not only that but the display seemed clearer. I suspect there is less clearing and overwriting text. This should make up for some of my less efficient code J

How do you calculate speed? Surely there is a single standard

To assist in setting the morse speed to ensure the timing is correct I’ve used the dot length in milliseconds to convert to words per minute. I based the conversion on the PARIS

Number of dot lengths per second = 1000 / dot length in ms

W = 1200 / T (ms)

Where: T is the unit time, or dot duration in milliseconds, W is the speed in wpm

Examples:  150ms = 8wpm, 100ms = 12wpm, 50ms = 24wpm, 20ms = 60wpm

It sounded simple enough but while there is standard timing, e.g. gaps between marks should be one dot length and dashes should be three dot lengths but that’s not always what is being sent. So the dot length may not reliably indicate how many words would actually be sent in a minute. I don’t know that it matters, but don’t know that it doesn’t.

A few notes about the code

The code is available in my Github repository https://github.com/garrysblog/Arduino-Morse-Code-Decoder

What could be improved?

Its structure could be improved. I am trying to write well structured code, but I’m not there yet.

It does not support some characters with homoglyphic diacritical marks, for example ä.

The automatic setting could be improved. If follows along with changing speeds ok, but it sometimes adds spaces when it shouldn’t, it also has trouble if it quickly changes for example when it switches between to senders that are using very different speeds.

The speed potentiometer can be set on the border of different speeds and the display flickers between two different speed numbers. Perhaps it would be better with a rotary encoder with the speed could be saved in EPROM memory so the setting is the same next time it is turned on. However, I do like the simplicity and usability of a potentiometer.

Auto speed sensing and noise handling also could be improved.

The hardware could be improved too. That method of filtering the incoming audio is not ideal.

Operation – twiddling the knobs

This is how I operate it:

  1. Place the microphone in front of the speaker sounding the Morse
  2. Adjust the input sensitivity so that the audio LED flashes in time with the sound of the Morse
  3. For manual operation, set the function to Manual
  4. Look at bottom line of the display and adjust the speed pot so that it is displaying both dots and dashes in the pattern I hear
  5. Look at the received and set speed numbers on the top line of the display and adjust so the set number is similar to the received number
  6. Look at the text being received. If necessary, tweak the speed setting to get spacing correct.
  7. For auto mode, simply set the function to Auto.

Switching to auto sets the speed to the current set speed and then tries to track the received speed by averaging the length of recent received dots. While it works ok, manual mode holds the speed to a more stable setting.

The case

The case has built from some old timber. Originally destined for wooden crates it had been sitting in a shed since the 1960s or 70s.

Simple butt joints were used
The front view. Those LEDs may look like they are in a good position, but after drilling the holes I discovered that area is covered by the LCD.
Back view. Knob for display contrast. Small hole to insert USB for power or update code. Barrel jack for power. Mic. Large hole to assist removing the back. The back is a friction fit.

The electronics

There is a description of the wiring in the code, but I intend to also create a diagram that I will upload with the files in the Github repository.

Parts list

  • KY-037 Audio module to Detects sound. Digital output pin goes low when the sound level exceeds set threshold.
  • Arduino Nano
  • 20×4 LCD display. I like green best, but most YouTubers seem to prefer blue.
  • 10K linear pot to adjust contrast of the display.
  • 150 – 270 ohm resistor to limit the current of the display backlight.
  • 1 x LED to replace the one on the audio module. This was only needed to make the status visible on the front panel of the case.
  • 1 x LED to display the status of the Arduino. The built-in LED on the Arduino can be used instead of this LED and resistor below.
  • 1 x resistor to limit current to the LED above.
  • Pot to adjust the audio threshold. The Audio module has a pot built onto the module and that can be used for testing. It is fiddly to use so adding one in parallel makes it much easier to use.
  • 10K linear pot to adjust the speed of the incoming transmission.
  • 6.8 uF tantalum capacitor for low pass audio filter.
  • 270 ohm resistor for low pass audio filter.
  • SPST switch for power on/off. Not used if powering by USB.
  • SPDT switch to switch between manual and auto mode.
  • I started with an I2C backpack on the LCD but it was not able to handle faster Morse. If a backpack is used the contrast pot and backlight resistor are not needed.

The circuit

The workings. Messier on the inside than the outside.
The main board

Audio module

The Audio module I have does not have any markings but it appears to be a KY-037. I found a circuit diagram for it here http://arduinolearning.com/code/ky038-microphone-module-and-arduino-example.php. Other microphone modules may also work.

The audio sensitivity trimmer pot

The KY-037 has a 100K potentiometer to adjust the threshold where the output triggers from high (nothing detected) to low (sound detected). I found this potentiometer to be very difficult to adjust. I removed the potentiometer and replaced it with an 10K pot and 22K resistor in series. That made it far easier to use and placed the threshold setting at about the midway point. It’s tricky to remove the built-in pot. If I was doing it again I would try soldering a 10k pot and another resistor (maybe 39K) in series with the onboard pot as that would be much easier to wire up.

Audio module LED

There is an LED on the audio module that lights when the output goes low (receive). This is very useful for both testing and adjusting the sensitivity while in operation. When I installed it in the case, I removed the existing LED on the audio module and replaced it with an ordinary 5mm red LED mounted on the front panel.

Filtering the output

The best results I have got is by connecting a resistor between the audio out and Arduino input and a capacitor from the input to ground. The input to the Arduino looks a bit ugly on the oscilloscope but was the best for operation that I tried.

The received status LED

I added this LED as a way to diagnose issues, but found it to be very useful in operation. This LED lights when the interrupt is triggered and the code believes there is a dot/dash being sent. Under ideal conditions, both LEDs should be flashing at the same time and both only when there is sound from the speaker being monitored. It’s a good indicator that something is not set or working correctly.

The speed pot

I used a standard 10K linear pot. This is only used for manual mode.

Should you build it?

Well that’s up to you, but I’ll repeat what I said early on. Building projects is just a hobby for me. I’m not a professional or have professional experience. Keep that in mind. At the very least I hope the project gives you inspiration.