Christophe Gerbier
Published © Apache-2.0

Serial And Events With nanoFramework

This project demonstrates GPIO events and serial communications with nanoFramework.

IntermediateShowcase (no instructions)1 hour1,599
Serial And Events With nanoFramework

Things used in this project

Hardware components

MIKROE Quail board
×1
Adafruit Membrane 3x4 Matrix Keypad
×1
Devantech LCD03
×1

Software apps and online services

Visual Studio extension
.NET nanoFramework Visual Studio extension
.NET nanoFramework nanoFramework GPIO package
.NET nanoFramework nanoFramework Serial package

Story

Read more

Code

Gpio events and Serial communication

C#
Main source code
using System;
using System.Threading;
using Windows.Devices.Gpio;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;

namespace GpioEventSerial
{
    public class Program
    {
        private static Keypad4X3 _keypad;
        private static GpioPin Led1;
        private static DevantechLcd03 _lcd;

        public static void Main()
        {
            try
            {
                // Set up the green led on Quail
                Led1 = GpioController.GetDefault().OpenPin(4 * 16 + 15);    // Green led on Quail (PE15)
                Led1.SetDriveMode(GpioPinDriveMode.Output);

                // Create an instance of the Devantech LCD display in serial mode
                _lcd = new DevantechLcd03()
                {
                    BackLight = true,
                    Cursor = DevantechLcd03.Cursors.Hide
                };
                _lcd.ClearScreen();
                _lcd.Write(1, 1, "Starting scan");

                // Create an instance of the keypad
                _keypad = new Keypad4X3(3 * 16 + 14, 0 * 16 + 14, 0 * 16 + 10, 0 * 16 + 9, 0 * 16 + 5, 3 * 16 + 0, 3 * 16 + 1);
                _keypad.KeyPressed += _keypad_KeyPressed;
                _keypad.KeyReleased += _keypad_KeyReleased;

                _keypad.StartScan();
            }
            catch (Exception ex)
            {
                // Do whatever please you with the exception caught
            }
            finally    // Enter the infinite loop in all cases
            {
                while (true)
                {
                    Thread.Sleep(100);
                }
            }
        }

        private static void _keypad_KeyReleased(Object sender, Keypad4X3.KeyReleasedEventArgs e)
        {
            _lcd.Write(1, 3, "Key : " + e.KeyChar);
            Led1.Write(GpioPinValue.Low);
        }

        private static void _keypad_KeyPressed(Object sender, Keypad4X3.KeyPressedEventArgs e)
        {
            Led1.Write(GpioPinValue.High);
        }
    }

    public class Keypad4X3
    {
        public event KeyPressedEventHandler KeyPressed = delegate { };
        public event KeyReleasedEventHandler KeyReleased = delegate { };

        private static GpioPin[] _rows;
        private static GpioPin[] _columns;
        private Thread _scanThread;
        private Boolean _scanThreadActive;

        public Keypad4X3(int row1, int row2, int row3, int row4, int column1, int column2, int column3)
        {
            var controller = GpioController.GetDefault();
            var Row1 = controller.OpenPin(row1);
            Row1.SetDriveMode(GpioPinDriveMode.Output);
            Row1.Write(GpioPinValue.Low);

            var Row2 = controller.OpenPin(row2);
            Row2.SetDriveMode(GpioPinDriveMode.Output);
            Row2.Write(GpioPinValue.Low);

            var Row3 = controller.OpenPin(row3);
            Row3.SetDriveMode(GpioPinDriveMode.Output);
            Row3.Write(GpioPinValue.Low);

            var Row4 = controller.OpenPin(row4);
            Row4.SetDriveMode(GpioPinDriveMode.Output);
            Row4.Write(GpioPinValue.Low);

            var Col1 = controller.OpenPin(column1);
            Col1.SetDriveMode(GpioPinDriveMode.InputPullDown);

            var Col2 = controller.OpenPin(column2);
            Col2.SetDriveMode(GpioPinDriveMode.InputPullDown);

            var Col3 = controller.OpenPin(column3);
            Col3.SetDriveMode(GpioPinDriveMode.InputPullDown);

            _rows = new[] { Row1, Row2, Row3, Row4 };

            _columns = new[] { Col1, Col2, Col3 };
        }

        public void StartScan()
        {
            if (_scanThreadActive) { return; }
            _scanThreadActive = true;
            _scanThread = new Thread(ScanThreadMethod);
            _scanThread.Start();
        }

        public void StopScan()
        {
            _scanThreadActive = false;
        }

        private void ScanThreadMethod()
        {
            var prevKey = -1;
            while (_scanThreadActive)
            {
                var nbKey = 0;
                // Scans the matrix
                for (var i = 0; i < 4; i++)
                {
                    for (var j = 0; j < 3; j++)
                    {
                        if (ReadMatrix(i, j) == GpioPinValue.Low) continue;
                        // A key has been pressed
                        var keyNum = (i * 3) + j + 1;
                        nbKey += keyNum;
                        if ((prevKey != keyNum) && (prevKey == -1))  // A key has been pressed and no other is currently pressed (avoids dealing with multiple keys at the same time)
                        {
                            prevKey = keyNum;
                            var tempEvent = KeyPressed;
                            tempEvent(this, new KeyPressedEventArgs(keyNum, KeytoChar(keyNum)));
                        }
                        break;
                    }
                }
                if (nbKey == 0)  // No key pressed in this pass
                {
                    // Was there a key pressed before ?
                    if (prevKey != -1)
                    {
                        var tempEvent = KeyReleased;
                        tempEvent(this, new KeyReleasedEventArgs(prevKey, KeytoChar(prevKey)));
                    }
                    prevKey = -1;
                }
                // Leave time for other processes
                Thread.Sleep(100);
            }
        }

        private GpioPinValue ReadMatrix(int row, int column)
        {
            _rows[row].Write(GpioPinValue.High);
            var colState = _columns[column].Read();
            _rows[row].Write(GpioPinValue.Low);

            return colState;
        }

        private char KeytoChar(int keyValue)
        {
            char c;
            if (keyValue < 10) { c = (char)(keyValue + 48); }
            else
            {
                switch (keyValue)
                {
                    case 10:
                        c = '*';
                        break;
                    case 11:
                        c = '0';
                        break;
                    case 12:
                        c = '#';
                        break;
                    default:
                        c = ' ';   // Should never happen
                        break;
                }
            }

            return c;
        }

        public delegate void KeyPressedEventHandler(object sender, KeyPressedEventArgs e);
        public delegate void KeyReleasedEventHandler(object sender, KeyReleasedEventArgs e);

        public class KeyPressedEventArgs
        {
            public KeyPressedEventArgs(int pKeyValue, char pKeyChar)
            {
                KeyValue = pKeyValue;
                KeyChar = pKeyChar;
            }

            public int KeyValue { get; private set; }
            public char KeyChar { get; private set; }
        }

        public class KeyReleasedEventArgs
        {
            public KeyReleasedEventArgs(int pKeyValue, char pKeyChar)
            {
                KeyValue = pKeyValue;
                KeyChar = pKeyChar;
            }

            public int KeyValue { get; private set; }
            public char KeyChar { get; private set; }
        }
    }

    public class DevantechLcd03
    {
        public enum Cursors
        {
            Hide,
            Underline,
            Blink
        };

        private readonly SerialDevice _lcdSerial;
        private DataWriter outputDataWriter;
        private Cursors _cursor;
        private Boolean _backLight;

        public DevantechLcd03()
        {
            try
            {
                _lcdSerial = SerialDevice.FromId("COM3");
                _lcdSerial.BaudRate = 9600;
                _lcdSerial.Parity = SerialParity.None;
                _lcdSerial.StopBits = SerialStopBitCount.Two;
                _lcdSerial.Handshake = SerialHandshake.None;
                _lcdSerial.DataBits = 8;

                outputDataWriter = new DataWriter(_lcdSerial.OutputStream);

                Init();
            }
            catch {  }
        }

        private void Init()
        {
            _backLight = false;
            _cursor = Cursors.Blink;
        }

        public Cursors Cursor
        {
            get { return _cursor; }
            set
            {
                outputDataWriter.WriteBytes(new[] { (byte)(4 + value) });
                outputDataWriter.Store();
                Thread.Sleep(1);
                _cursor = value;
            }
        }

        public Boolean BackLight
        {
            get { return _backLight; }
            set
            {
                outputDataWriter.WriteBytes(new[] { value ? (Byte)19 : (Byte)20 });
                outputDataWriter.Store();
                Thread.Sleep(1);
                _backLight = value;
            }
        }

        public void SetCursor(byte x, byte y)
        {
            if (x <= 0 || x > 20 || y <= 0 || y > 4) { return; }
            outputDataWriter.WriteBytes(new byte[] { 3, y, x });
            outputDataWriter.Store();
            Thread.Sleep(1);
        }

        public void Write(string text)
        {
            outputDataWriter.WriteString(text);
            outputDataWriter.Store();
            Thread.Sleep(1);
        }

        public void Write(byte x, byte y, string text)
        {
            if (x <= 0 || x > 20 || y <= 0 || y > 4) { return; }
            SetCursor(x, y);
            Write(text);
        }

        public void ClearScreen()
        {
            outputDataWriter.WriteBytes(new byte[] { 12 });
            outputDataWriter.Store();
            Thread.Sleep(1);
        }
    }
}

Credits

Christophe Gerbier
3 projects • 8 followers

Comments