Notes About Working with Various Arduino & Netduino Microcontroller Boards

Sunday, April 21, 2013

Emic 2 Text-to-Speech Module & the Arduino Due

The Emic 2 text-to-speech module is a 5 volt serial device, but the Arduino Due's I/O pins don't tolerate more than 3.3 volts. The serial connection requires a logic level converter, such as the Sparkfun Logic Level Converter (BOB-08745). For me experiments with the Emic 2, I am using a cheap, thin 8 Ohm speaker without amplification.

On the Arduino Due, there are three serial ports available for use with the Emic 2 (since the first Serial device is used for the serial console).  The example below uses Serial1 (pins RX1 & TX1). You could also use  Serial2  (RX2 & TX2), or Serial3 (RX3 & TX3).


Connections



Arduino Due Logic Level Conv Emic 2
TX1 (D18)   LV TXI - HV TXO  SIN
RX1 (D19)   LV RXO - HV RXI  SOUT
GND         LV GND
GND         HV GND           GND
5V          HV HV            5V
3.3V        LV LV    

SP+ and SP- on the Emic 2 are connected to the speaker.


Code


The code below doesn't do anything special  it's just the usual "Hello world." 


void setup() {
  Serial1.begin(9600);
  // Check for response from Emic 2
  Serial1.print('\n');
  // Emic 2 returns ':' if ready for command
  while (Serial1.read() != ':'); 
  // Set volume to maximum
  Serial1.print('V18\n');
  delay(10);
  Serial1.flush();  
}

void loop() {
  Serial1.print('\n');
  while (Serial1.read() != ':');
  // 'S' command = say 
  String cmd = "S"; 
  String text = "hello world";
  Serial1.print(cmd + text + "\n");
  while(1) { ; } 
}

Note that each command ends with a new line character ('\n'). Here is the list of available commands for the Emic 2 taken from its User Manual -


Sx  Convert text-to-speech: x = message (1023 characters maximum)
Dx  Play demonstration message: x = 0 (Speaking), 1 (Singing), 2 (Spanish)
X   Stop playback (while message is playing)
Z   Pause/un-pause playback (while message is playing)
Nx  Select voice: x = 0 to 8
Vx  Set audio volume (dB): x = -48 to 18
Wx  Set speaking rate (words/minute): x = 75 to 600
Lx  Select language: x = 0 (US English), 1 (Castilian Spanish), 2 (Latin Spanish)
Px  Select parser: x = 0 (DECtalk), 1 (Epson) 
R   Revert to default text-to-speech settings 
C   Print current text-to-speech settings
I   Print version information
H   Print list of available commands

The manual contains additional information about these commands. 

Saturday, April 13, 2013

Serial (UART) Communication between a Netduino Plus 2 & a Raspberry Pi

The following basic example shows how to use a serial (UART) connection to send data back and forth between a Netduino Plus 2 and a Raspberry Pi using a serial connection.

In this demonstration, the two devices are connected at 115200 baud. The Netduino sends different 1 byte commands to the Raspberry Pi. These commands are just arbitrary; the programmer needs to work out how commands are sent and how responses are evaluated (including how to tell if you have received the full response or not). The Raspberry Pi then returns the full current time and date, just the date, or just the time, depending on which command byte was received.

The Python code for the Raspberry Pi part of the operation is on my Raspberry Pi blog.


Connections


Netduino Plus 2  Raspberry Pi
Digital 0        TXD
Digital 1        RXD
GND              GND

Digital pins 0 and 1 are used with the COM1 serial port. You could connect using the other COM ports available on the Netduino.  See the board's product page for information on which pins are associated with the COM ports.

Note that both must have a common ground. This example prints to the Visual Studio debug console, so I am using the current provided by the USB connection.

Both devices are 3.3 volt, so no logic level converter is needed for the serial connection.


Code


Here is the C# code for the Netduino. See my Raspberry Pi blog for the Python code for the RPi.

My code uses the following characters to represent commands: @, $, and #. As indicated above, these are just arbitrary symbols/bytes. You could certainly use multibyte commands, but then you would need to add a loop to write the commands one byte at a time to the Pi and work out a way to tell when each command transmission was finished.

using System;
using System.Threading;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.Netduino;
using System.IO.Ports;

namespace RPiSerial
{
    public class Program
    {
        public static void Main()
        {
            SerialPort serial = new SerialPort(SerialPorts.COM1,
                  115200, Parity.None, 8, StopBits.One);
            serial.Open();
            while(true)
            {
                // Get full date & time
                serial.WriteByte((byte)'@');
                getResponse(serial);
                // Get date only
                serial.WriteByte((byte)'$');
                getResponse(serial);
                // Get time of day only
                serial.WriteByte((byte)'#');
                getResponse(serial);
                Thread.Sleep(1000);
            }
        }

        private static void getResponse(SerialPort serial)
        {
            String response = "";
            while (serial.BytesToRead > 0)
            {
                byte[] buf = new byte[1];
                serial.Read(buf, 0, 1);
                // Line feed - 0x0A - marks end of data.
                // Append each byte read until end of data.
                if (buf[0] != 0x0A)
                {
                    response += (char)buf[0];
                }
                else
                {
                    Debug.Print(response);
                    break;
                }
            }
        }
    }
}

Saturday, April 6, 2013

Telling the Time with Text to Speech Using a Netduino Plus 2 & EMIC 2 Module

The EMIC 2 text to speech module connects to a microcontroller via a serial connection. It does not require any special libraries, and I have found it is easy to get it working with a Netduino Plus 2. The following example uses the EMIC 2 to announce the time when the button on the Netduino board is pressed. This code connects to a network time server and sets the Netduino's clock when the program starts, so it is assumed that the Netduino is connected to the Internet. Getting the time from an NTP server takes a moment at startup. After the time is set, you could disconnect the Netduino from the network. You could also use a real-time click chip to set the Netduino's internal clock.

For my testing, I have just used an inexpensive, thin 8 Ohm speaker from Sparkfun without any amplification.

Connections


EMIC 2  Netduino Plus 2
GND     GND
5V      5V
SOUT    Digital 0
SIN     Digital 1

SP- & SP+ on the EMIC 2 connect to the speaker.


C# Code

namespace EMIC2
{
    public class Program
    {
        const int DELAY = 1000;
        const String NTP = "time.nist.gov"; // NTP server
        const int TZ = -5;                  // Offset from GMT

        static SerialPort serial;
        public static void Main()
        {
            // Sync clock to current time
            UpdateTimeFromNtpServer(NTP, TZ);

            // Use interrupt to handle button presses
            InterruptPort button = new InterruptPort(Pins.ONBOARD_SW1, true, 
                Port.ResistorMode.Disabled, 
                Port.InterruptMode.InterruptEdgeBoth);
            button.OnInterrupt += new NativeEventHandler(button_OnInterrupt);

            // Connect to EMIC2 via SerialPort
            serial = new SerialPort(SerialPorts.COM1,
                  9600, Parity.None, 8, StopBits.One);
            serial.Open();
            Thread.Sleep(100);
            serial.WriteByte(10);
            String volCmd = "V15\n";
            sendCommand(volCmd);
            Thread.Sleep(-1);
        }

        static void sendCommand(String cmd)
        {
            byte[] cmdArray = new byte[cmd.Length];
            int i = 0;
            foreach (char a in cmd.ToCharArray())
            {
                cmdArray[i++] = (byte)a;
            }
            serial.Write(cmdArray, 0, cmd.Length);
        }

        static void button_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            if (serial.BytesToRead > 0)
            {
                byte[] buf = new byte[1];
                serial.Read(buf, 0, 1);
                if (buf[0] == ':')
                {
                    DateTime now = DateTime.Now;
                    String countCmd = "STime is " + now.Hour.ToString() + " " + 
                        now.Minute.ToString() + "\n";
                    sendCommand(countCmd);
                }
            }
        }
        //============================================================================
        //
        // Code for synchronizing time to NTP server
        //
        //============================================================================ 
        // Network time update code from 
        // http://www.jaypm.com/2011/09/setting-the-netduinos-datetime-automatically/
        public static bool UpdateTimeFromNtpServer(string server, 
            int timeZoneOffset)
        {
            try
            {
                var currentTime = GetNtpTime(server, timeZoneOffset);
                Microsoft.SPOT.Hardware.Utility.SetLocalTime(currentTime);
                return true;
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
                return false;
            }
        }

        private static DateTime GetNtpTime(String timeServer, int timeZoneOffset)
        {
            // Find endpoint for TimeServer
            var ep = new IPEndPoint(Dns.GetHostEntry(timeServer).AddressList[0], 123);

            // Make send/receive buffer
            var ntpData = new byte[48];

            // Connect to TimeServer
            using (var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 
                ProtocolType.Udp))
            {
                // Set 20s send/receive timeout and connect
                s.SendTimeout = s.ReceiveTimeout = 20000;
                s.Connect(ep);
                ntpData[0] = 0x1B;   // Set protocol version
                s.Send(ntpData);     // Send Request
                s.Receive(ntpData);  // Receive Time
                s.Close();
            }

            const byte offsetTransmitTime = 40;
            ulong intpart = 0;
            ulong fractpart = 0;

            for (var i = 0; i <= 3; i++)
                intpart = (intpart << 8) | ntpData[offsetTransmitTime + i];

            for (var i = 4; i <= 7; i++)
                fractpart = (fractpart << 8) | ntpData[offsetTransmitTime + i];

            ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);

            var timeSpan = TimeSpan.FromTicks((long)milliseconds * 
                TimeSpan.TicksPerMillisecond);
            var dateTime = new DateTime(1900, 1, 1);
            dateTime += timeSpan;

            var offsetAmount = new TimeSpan(timeZoneOffset, 0, 0);
            var networkDateTime = (dateTime + offsetAmount);

            return networkDateTime;
        }
    }
}

I need to work more on the way the time is read out to handle time on the hour and minutes less than ten after the hour.

The EMIC 2 is very versatile. Have a look at the product page and  manual to get an idea of what you can do with it and how its command language works. 

Monday, April 1, 2013

IR Codes for Adafruit Mini Remote Control

Adafruit offers an inexpensive infrared remote that they describe only as "Mini Remote Control." The control is intended for an audio device. Mine does not have the "Car" brand label, but the keypad is identical. Using a Sparkfun IR Receiver Breakout (TSOP85), here is a list of the NEC IR codes used by this device.  I have collected the codes using the IRrecvDump sketch included in examples Ken Shirriff's Arduino IRremote library.

Remote Key        Hex Code (NEC)
VOL-              FD00FF
Play / Pause      FD807F
VOL+              FD40BF
SETUP             FD20DF
Up Arrow / PREV   FDA05F
STOP / MODE       FD609F
Left Arrow / CH-  FD10EF 
ENTER / SAVE      FD906F
Right Arrow / CH+ FD50AF
0 10+             FD30CF
Down Arrow / NEXT FDB04F
Repeat            FD708F
1                 FD08F7
2                 FD8877
3                 FD48B7
4                 FD28D7
5                 FDA857
6                 FD6897
7                 FD18E7
8                 FD9867
9                 FD58A7