FEZ Panda II UART with Interrupt

Hello Guys,

I tried to combine some of the FEZ Panda II Functions and I have the following problem: I am using an Interrupt to count a number and I am using an endless loop to scan the analog input.
Now I want to send these informations via UART to the computer when the character “1” is received. But the system is throwing an exception when [quote]UART.open[/quote] is called.

Do you have any ideas?

This is my code. Quite simple but I can’t find the mistake.

 using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
using System.IO.Ports;
using System.Text;

namespace MFConsoleApplication1
{

    public class Program
    {

        public static class GlobalVar
        {
            static int _globalValue;

            public static int GlobalValue
            {
                get
                {
                    return _globalValue;
                }

                set
                {
                    _globalValue = value;
                }
            }
        }

       
        public static void Main()
        {

            GlobalVar.GlobalValue = 0;
            
            // the pin will generate interrupt on high and low edges
            InterruptPort IntButton =
                new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.LDR, true,
                                   Port.ResistorMode.PullUp,
                                   Port.InterruptMode.InterruptEdgeLow);

             

            // add an interrupt handler to the pin
            IntButton.OnInterrupt +=
                new NativeEventHandler(IntButton_OnInterrupt);

            //do anything you like here
            // Thread.Sleep(Timeout.Infinite);

            AnalogIn voltagePort = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An3);
            OutputPort lowPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An0, false);
            OutputPort highPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An2, true);

            const double maxVoltage = 3.3;
            const int maxAdcValue = 1023;


            InterruptPort RX =
                new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di0, true,
                Port.ResistorMode.PullUp,
                Port.InterruptMode.InterruptEdgeLow);

            RX.OnInterrupt +=
                new NativeEventHandler(RX_OnInterrupt);

                        while (true)
            {
                double mess = 0;
                int sample = 10000;
                for (int i = 0; i <= (sample - 1); i++)
                {
                    mess += (double)voltagePort.Read();
                }
                double valueRaw = mess / sample;
                double valueVoltage = (valueRaw * maxVoltage) / maxAdcValue;
                double valuePercent = (valueVoltage / maxVoltage) * 100;

                Debug.Print("Voltage: " + valueVoltage + "V");
                Debug.Print("Percent: " + valuePercent + "%");

                //Thread.Sleep(1000);

            }
        }

        static void IntButton_OnInterrupt(uint port, uint state,
                                          DateTime time)
        {
            GlobalVar.GlobalValue++;
            string zaehler_string = GlobalVar.GlobalValue.ToString();
            Debug.Print(zaehler_string);
        }



        static void RX_OnInterrupt(uint port, uint state,
                                          DateTime time)
        {
            // Initial Daten 
            SerialPort UART = new SerialPort("COM1", 115200);
            int read_count = 0;
            byte[] tx_data;
            byte[] rx_data = new byte[10];
            UART.ReadTimeout = 0;
            UART.Open();

            read_count = UART.Read(rx_data, 0, rx_data.Length);
            string empfangen = rx_data.ToString();
            string zaehler_string = GlobalVar.GlobalValue.ToString();
            if (empfangen == "1")
            {
                tx_data = Encoding.UTF8.GetBytes(zaehler_string);
                UART.Write(tx_data, 0, tx_data.Length);
            }

            
        }
    }
} 

Hi and welcome to the forum.

Using code tags will make your post more readable. This can be done in two ways:[ol]
Click the “101010” icon and paste your code between the

 tags or...
Select the code within your post and click the "101010" icon.[/ol]
(Generated by QuickReply)

Simply your code to only open UART so you are only testing one thing at a time.

I think di0 is first opened as an interrupt port and then opened as com1?

Isn’t the bigger issue that the UART declaration is in the interrupt handler. Once that happens, and the handler exits, it’ll be garbage collected.

You should have one UART object in your code, and it needs to persist across all interactions, so that means a global object. Open it in main(), and send data when you want to.

That’s a good point. I’ll make one UART object in the main(). The reason why I am opening the Interrupt and the UART is simply that I want the UART to react only when there is a signal change on the the pin. So I don’t have to make an endless loop to look every second if there was sent something or not.

Why don’t you subscribe to the OnDataReceived event? Then you don’t need the pin interrupt.

As Eric says, DataRecieved event is exactly so you don’t have to poll the serial port. It has its own peculiarities, but if you just want to figure out when a “1” comes in that’s a snack.

just FYI, even if this did work the way you wanted and not give you pin conflicts, there’s a chance that enabling the UART at that point would be too late, that first character may be missed.

The OnDataReceived event is just what I needed. Thank you, Guys!

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
using System.IO.Ports;
using System.Text;
namespace MFConsoleApplication1
{

    public class Program
    {

        public static class GlobalVar
        {
            static int _globalValue;

            public static int GlobalValue
            {
                get
                {
                    return _globalValue;
                }

                set
                {
                    _globalValue = value;
                }
            }
        }

        public static void Main()
        {

            SerialPort mySerialPort = new SerialPort("COM1", 115200);

            //mySerialPort.BaudRate = 9600;
            //mySerialPort.Parity = Parity.None;
            //mySerialPort.StopBits = StopBits.One;
            //mySerialPort.DataBits = 8;
            //mySerialPort.Handshake = Handshake.None;

            
            mySerialPort.Open();
            mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            
            int read_count = 0;
            byte[] tx_data;
            byte[] rx_data = new byte[1];
            //mySerialPort.ReadTimeout = 0;
            

            read_count = mySerialPort.Read(rx_data, 0, rx_data.Length);
            if (read_count != 3)
            {
                // we sent 3 so we should have 3 back
                Debug.Print("Wrong size: " + read_count.ToString());
            }
            string empfangen = rx_data.ToString();
            string zaehler_string = GlobalVar.GlobalValue.ToString();
            // Um 1hochzählen und in string wandeln (zeichenkette) 
            //if (empfangen == "1")
            {
                tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString());
                mySerialPort.Write(tx_data, 0, tx_data.Length);

            }
            

            //Console.WriteLine("Press any key to continue...");
            //Console.WriteLine();
            //Console.ReadKey();
            //mySerialPort.Close();

            GlobalVar.GlobalValue = 0;

            // the pin will generate interrupt on high and low edges
            InterruptPort IntButton =
                new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.LDR, true,
                                   Port.ResistorMode.PullUp,
                                   Port.InterruptMode.InterruptEdgeLow);

            // add an interrupt handler to the pin
            IntButton.OnInterrupt +=
                new NativeEventHandler(IntButton_OnInterrupt);

            //do anything you like here
            // Thread.Sleep(Timeout.Infinite);

            AnalogIn voltagePort = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An3);
            OutputPort lowPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An0, false);
            OutputPort highPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An2, true);

            const double maxVoltage = 3.3;
            const int maxAdcValue = 1023;

            while (true)
            {
                double mess = 0;
                int sample = 10000;
                for (int i = 0; i <= (sample - 1); i++)
                {
                    mess += (double)voltagePort.Read();
                }
                double valueRaw = mess / sample;
                double valueVoltage = (valueRaw * maxVoltage) / maxAdcValue;
                double valuePercent = (valueVoltage / maxVoltage) * 100;

                Debug.Print("Voltage: " + valueVoltage + "V");
                Debug.Print("Percent: " + valuePercent + "%");

                //Thread.Sleep(1000);
            }
        }




        static void IntButton_OnInterrupt(uint port, uint state,
        DateTime time)
        {
            GlobalVar.GlobalValue++;
            string zaehler_string = GlobalVar.GlobalValue.ToString();
            Debug.Print(zaehler_string);
        }


            private static void DataReceivedHandler(
                                object sender,
                                SerialDataReceivedEventArgs e)
            {

                    
                byte[] tx_data;
                byte[] rx_data = new byte[1];
                
                //mySerialPort.Write(tx_data, 0, tx_data.Length);
                SerialPort sp = (SerialPort)sender;
                //GlobalVar.GlobalValue++;
                //string zaehler_string = GlobalVar.GlobalValue.ToString();
                //Debug.Print(zaehler_string);
                //string indata = sp.ReadExisting();
                Debug.Print("Data Received:");
                sp.Read(rx_data, 0, rx_data.Length);
                //rx_buff = System.Text.Encoding
                if (rx_data[0] == 115)
                {
                    tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString());
                    sp.Write(tx_data, 0, tx_data.Length);
                }
                else
                {
                    tx_data = rx_data;
                    sp.Write(tx_data, 0, tx_data.Length);
                    //Console.Write(indata);
                }
            }
        
        }
    }


Evereything is working now. But: When the program jumps to the DataReceivedHandler, it doesn’t jump to the main Thread any more. I can send Data with HyperTerminal and ithe DataReceivedHandler is working. But the the interrupt and the voltage measurement aren’t working anymore.
Do I have to quit the thread manually?

Hi Rog, Welcome (or re-welcome if this was your thread from before :slight_smile: )

You’re mis-using the DataRecieved event. You use either a polling construct, or the DataRecievedEvent. You don’t use them both.

Your DataRecieved event needs to just pull data out of the port and put it in a global buffer. Your main() needs to NOT read from the port but read from the buffer instead.

If you tell us actually what you’re trying to achieve or emulate, then we might find the best way to construct this. Tell us about how you want the communication to work, what kind of data you’re passing etc. and how you would see the transmission working.

Yes it’s me :-). Thank you very much!

That’s what I want to do:

I am counting pulses on an interrupt Pin. This value is saved in the globalValue. Also I am measureing a voltage on the ADC.
I want these two values to be send via comPort when for example [quote]s[/quote] is sent or any other keyword.
That’s why I am comparing the RX Array with [quote]115[/quote].

if (rx_data[0] == 115)

115 is the [quote]s[/quote].

So every time I send a keyword I want the program to send me the the values. But in the meantime the main procedure should be done.

Rog, then welcome again :slight_smile: Glad to meet the name behind the anonymous name ! :wink:

So let me get this straight.

Your device will be connected to another device via the serial port (you don’t say what that is; shouldn’t matter )

At some point in time, you expect the INPUT over the serial port, that says “S”.

When you get that, you want to OUTPUT the current values you have stored for some measurements.

Does that sound right? Anything else you’re expecting from the serial port?

In that case, I’d do two things. First, you have to remove this block:

 read_count = mySerialPort.Read(rx_data, 0, rx_data.Length);
            if (read_count != 3)
            {
                // we sent 3 so we should have 3 back
                Debug.Print("Wrong size: " + read_count.ToString());
            }
            string empfangen = rx_data.ToString();
            string zaehler_string = GlobalVar.GlobalValue.ToString();
            // Um 1hochzählen und in string wandeln (zeichenkette) 
            //if (empfangen == "1")
            {
                tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString());
                mySerialPort.Write(tx_data, 0, tx_data.Length);
 
            }
 
 

it’s redundant; you can’t read things from the serial port here and expect it to work.

Next, I’d structure a MAIN loop that simply loops around and does the following things:
Check a new global flag, call it GotAnS, and when it is set, output the necessary values, then clear the flag.
Do your averaging work as you want

Then, in your datarecievedevent, I’d check each character that comes in and if it’s ‘S’ then set the global flag; that way you get “notified” in the next cycle through the loop in MAIN(). Since you don’t care about the actual characters, you don’t need to buffer them you can just read them in the handler and discard them.

Simple, I hope !

Brett, thank you very much!
It’s working! :smiley: Impossible!!!
That’s the final version:

//Verweise in der Bibliothek
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
using System.IO.Ports;
using System.Text;

//Namespace Deklaration
namespace DataLogger
{
    //Programmklasse
    public class Program
    {

        public static class GlobalVar
        {
            static int _globalValue;

            public static int GlobalValue
            {
                get
                {
                    return _globalValue;
                }

                set
                {
                    _globalValue = value;
                }
            }
        }

        public static class GlobalVol
        {
            static double _globalVoltage;

            public static double GlobalVoltage
            {
                get
                {
                    return _globalVoltage;
                }

                set
                {
                    _globalVoltage = value;
                }
            }
        }
 
        public static void Main()
        {

            SerialPort mySerialPort = new SerialPort("COM1", 115200);
            mySerialPort.Open();
            mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            GlobalVar.GlobalValue = 0; //Zählwert wird auf 0 gesetzt
 
            InterruptPort IntButton =
                new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.LDR, true,
                                   Port.ResistorMode.PullUp,
                                   Port.InterruptMode.InterruptEdgeLow);
            IntButton.OnInterrupt +=
            new NativeEventHandler(IntButton_OnInterrupt);

            AnalogIn voltagePort = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An3);
            OutputPort lowPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An0, false);
            OutputPort highPort = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.An2, true);


            const double maxVoltage = 3.3;
            const int maxAdcValue = 1023; //Auflösung 1024bit = 3.3/1024


            while (true)
            {
                double mess = 0;
                int sample = 10000;
                for (int i = 0; i <= (sample - 1); i++)
                {
                    mess += (double)voltagePort.Read();
                }
                double valueRaw = mess / sample;
                double valueVoltage = (valueRaw * maxVoltage) / maxAdcValue;
                double valuePercent = (valueVoltage / maxVoltage) * 100;
                GlobalVol.GlobalVoltage = valueVoltage;

                Debug.Print("Voltage: " + valueVoltage + "V");
                Debug.Print("Percent: " + valuePercent + "%");


            }
        }

        static void IntButton_OnInterrupt(uint port, uint state,
            DateTime time)
        {
            GlobalVar.GlobalValue++; //GlobalValue wird bei ausgelöstem Interrupt hochgezählt
            string zaehler_string = GlobalVar.GlobalValue.ToString(); // Wert in String gewandelt
            Debug.Print(zaehler_string); //Im Debug Fenster ausgegeben
        }


        private static void DataReceivedHandler(
                            object sender,
                            SerialDataReceivedEventArgs e)
        {
            byte[] tx_data;
            byte[] tx_data2;
            byte[] tx_data3;

            byte[] rx_data = new byte[1];

            SerialPort sp = (SerialPort)sender;

            sp.Read(rx_data, 0, rx_data.Length);

                if (rx_data[0] == 115) //Asci-Zeichen 115 = "s"
                    {
                        Debug.Print("Data Received:");

                        tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString());
                        tx_data2 = Encoding.UTF8.GetBytes("\r\n");
                        tx_data3 = Encoding.UTF8.GetBytes(GlobalVol.GlobalVoltage.ToString());

                        sp.Write(tx_data, 0, tx_data.Length);
                        sp.Write(tx_data2, 0, tx_data2.Length);
                        sp.Write(tx_data3, 0, tx_data3.Length);
                        sp.Write(tx_data2, 0, tx_data2.Length);
                    }

                else
                    {
                        tx_data = rx_data;
                        sp.Write(tx_data, 0, tx_data.Length);
                    }
        }
    }
}      
      

great, glad to hear it’s working. But I can tell you it’s not reliable as-is. If you get two characters at once, and S is the second character in the buffer, then this block (below) won’t handle that. (it will however catch up, later down the track, when another character pops in, but it too may be an ignored character). Also, you may need to process more iterations through the loop to handle all the data you get. Can you confirm that you intend to echo characters back to the sender when they don’t match your pattern?

if (rx_data[0] == 115) //Asci-Zeichen 115 = "s"
                    {
                        Debug.Print("Data Received:");
 
                        tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString());
                        tx_data2 = Encoding.UTF8.GetBytes("\r\n");
                        tx_data3 = Encoding.UTF8.GetBytes(GlobalVol.GlobalVoltage.ToString());
 
                        sp.Write(tx_data, 0, tx_data.Length);
                        sp.Write(tx_data2, 0, tx_data2.Length);
                        sp.Write(tx_data3, 0, tx_data3.Length);
                        sp.Write(tx_data2, 0, tx_data2.Length);
                    }
 
                else
                    {
                        tx_data = rx_data;
                        sp.Write(tx_data, 0, tx_data.Length);
                    }

My suggestion (note: coded here, not syntax checked or tested in any way) is:

 
for (int i = sp.BytesToRead;i>0;i--)
{
          sp.Read(rx_data, 0, 1);
          if (rx_data[0] == 's') //Asci-Zeichen 115 = "s"  Brett: no need for ASCII foo, just put it in there!
                    {
                        Debug.Print("Data Received:");
                        // this doesn't do less actual string churn operations, but it does look cleaner and has less variables
                        tx_data = Encoding.UTF8.GetBytes(GlobalVar.GlobalValue.ToString() + "\r\n" + GlobalVol.GlobalVoltage.ToString());  //Brett: Do you want \r\n at the end too?
 
                        sp.Write(tx_data, 0, tx_data.Length);
                 }
 
                else
                    {
                       sp.Write(rx_data[0], 0, 1);
                    }
}

If it can help, here’s how I deal with serial (or even network) communications if I can manage both sides (sender/receiver) :

public class Program
    {
        static SerialPort SP;
        static char SerialStart, SerialEnd;
        private static string SerialString = string.Empty;
        private static bool BufferingSerial = true;

        public static void Main()
        {
            SerialStart = '#';
            SerialEnd = '$';

            SP = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One);
            SP.DataReceived += SP_DataReceived;
            SP.Open();

            Thread.Sleep(Timeout.Infinite);
        }

        private static void SP_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int Nb = SP.BytesToRead;
            byte[] Buf = new byte[Nb];
            SP.Read(Buf, 0, Nb);
            char[] ReceivedChars = Encoding.UTF8.GetChars(Buf);
            foreach (char c in ReceivedChars)
            {
                if (BufferingSerial && c != SerialEnd) { SerialString = string.Concat(SerialString, c); }
                if (c == SerialStart)
                {
                    BufferingSerial = true;
                    SerialString = string.Empty;
                }
                if (c == SerialEnd && BufferingSerial)
                {
                    BufferingSerial = false;
                    Debug.Print("Serial string = " + SerialString);
                    SerialString = string.Empty;
                }
            }
        }

    }

Every command is sent or received as “#command_or_text$” (without the quotes). You could use whatever start/end char you decide.
The principle here is to “buffer” chars received until it encounters a “SerialEnd” char, which is ‘$’ in my example.
Buffering starts only when the SerialStart char is received (’#’ in my example). Every other char is discarded if not buffering.