Link to home
Start Free TrialLog in
Avatar of borntofly
borntofly

asked on

serialport datareceived activating a timer

Hello,

I have a problem in the attached code.

I need my software to send some commands on serialport2 for x times every y seconds if a message is received on serialport1.

With this code the actions in the timer are never executed if the timere is activated by the datareceived fuction, but every thing works fine if it is activated by the button1. Moreover once the datarecived fuction is trigged the button stops to work.

Any ideas?



int n_timrs = 10, n_sent=0;
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.Open();
            serialPort2.Open();
            timer1.Enabled = false;
            timer1.Interval = 1000;
            serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(datareceived);
        }
        void datareceived(object s, SerialDataReceivedEventArgs e)
        {
            timer1.Enabled = true;
            serialPort2.Write("test" + Environment.NewLine);
            
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            serialPort2.Write("test" + Environment.NewLine);
            n_sent++;
            if (n_sent > n_timrs)
            {
                n_sent = 0;
                timer1.Enabled = false;
                MessageBox.Show(n_sent.ToString());
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
            serialPort2.Write("test" + Environment.NewLine);
        }

Open in new window

Avatar of alex_paven
alex_paven
Flag of Romania image

For the dataReceived event to be triggered, you need to set the ReceivedBytesThreshold property of the serial port class to a non-zero value. Note that the DataReceived event will be triggered when a number of bytes are received, so if you receive twice as many bytes, the event will be triggered again. So for instance if you set ReceivedBytesThreshold = 2 and you receive 4 bytes (2 bytes and \r\n for instance), the event may be triggered twice. There is no guarrantee however that the number of bytes will correspond exactly to the number of times the event will be triggered.
To clarify: in my example, with ReceivedBytesThreshold = 2 and 4 bytes received, the DataReceived event will be triggered at least once, but there is no guarrantee that it will be triggered a second time or not.
Avatar of borntofly
borntofly

ASKER

Hello,

thanks for your reply.

The DataReceived event is trigged (serialPort2.Write("test" + Environment.NewLine); is correctly executed). The problem is in the timer actions that are never executed.

I tried to put a MessageBox.Show at the end of the DataReceived event. If I do not close the MessageBox every thing works fine, but as soon as I close it the timer stops to execute.
Oh. Then I think the problem is that the DataReceived event is executed on a different thread. The best way would be to create a delegate and invoke it so that the timer runs on the form's thread. If you need specific code to help you out, ask further.
Of course, I'm assuming the timer's Tick event is correctly bound to timer1_Tick.
Yes, please.

My brain is gone. I've been trying to solve it for 2 days now...:)

Thank you very much
Actually I solved it with a workaround, but it isn't really a proper solution.
I could not use the timer and trigger this fuction

private void test()
        {
           bool stop = false;
            do
            {
                if (DateTime.Now >= start.AddSeconds(freq))
                {
                    start = DateTime.Now;
                    serialPort2.Write("test" + Environment.NewLine);
                    n_sent++;
                    if (n_sent > n_timrs)
                    {
                        n_sent = 0;
                        stop = true;
                    }
 
                }
            } while (!stop);
        }

Open in new window

But I would prefer to use a timer.....
Can you explain me how to create and ivoke a delegate for the timer???

Thank you
ASKER CERTIFIED SOLUTION
Avatar of alex_paven
alex_paven
Flag of Romania image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you so much.

You saved me.
If you want a detailed explanation of what happened, feel free to ask, it would be my pleasure :)
Actually I understud that the problem was that the datareceived event was executed in a different thread. What i do not undestend is why.

Thank you again
The serial port is designed like that, so that when data is received you immediately get notified (I think because often synchronization is crucial when working with the serial port). With this code, the Invoke may introduce a delay of up to 10-15 milliseconds, I think.
The Windows.Forms.Timer however is very restrictive and only works on the thread that called it. You could have used a different kind of timer (System.Timers.Timer, or System.Threading.Timer) but those also fire their Tick (Elapsed) events on a different thread for greater precision, so depending on exactly what you needed to do when the timer fires, you may have needed Invoke in that case too.