Solved

Using 2 timer controls on one single form

Posted on 2009-07-10
7
333 Views
Last Modified: 2012-05-07
Hello,

I have a windows form in vb.net 2008. This form has one timer control. This Pc is connected to 2 hardware units. My form reads the data from these 2 hardware units via the serial port. I have set the timer interval to 5 seconds. So after the first 5 seconds, I send request to serial port "1" which means data for hardware unit 1 and then I read receiving data for hardware unit 1 and then after next 5 seconds, I send request to serial port as "2" which means data for hardware unit 2 and I read the receiving data for hardware unit 2 and again after 5 seconds for hardware unit 1 and so on.

Now the client has suggested changes. He wants that I send request for hadware unit 1 after 5 seconds and the request for hardware unit 2 after 30 seconds. But I found that to implement this, I need to keep changing the timer interval after reading the data from serial port and this hangs the PC.

Hence now my question is:
1. Can I use two timer controls on one form with two different timer intervals?

2. If the above is not possible, then can I use two forms with two timer controls - one on each form with different timer internvals? The issue here would be that once I open the serial port in form 1, it may not allow me to open the port in form 2 as the serial port would be in use in form 1.

Any suggestions/solutions?

Regards,
MI
0
Comment
Question by:vj_mi
  • 4
  • 3
7 Comments
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 24829586
Yes, it it possible to use multiple Timers on the same Form but...

There are two ways to interpret your description.

Do you want:
5 secs --> Port 1
30 secs --> Port 2
5 secs --> Port 1
30 secs --? Port 2
etc...

Or?
5 secs --> Port 1
5 secs --> Port 1
5 secs --> Port 1
5 secs --> Port 1
5 secs --> Port 1
5 secs -->  Port 2
(repeat entire sequence)...

I think you want the latter?

I recommend ditching the Timer controls, though, and replacing them with BackgroundWorker controls.

Use SyncLock to prevent them from trying to access the serial port at the same time.

Here is a simplified example:
Public Class Form1
 

    Private PortLock As New Object

    Private WithEvents bgw1 As New System.ComponentModel.BackgroundWorker

    Private WithEvents bgw2 As New System.ComponentModel.BackgroundWorker
 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        bgw1.WorkerReportsProgress = True

        bgw2.WorkerReportsProgress = True

        bgw1.RunWorkerAsync()

        bgw2.RunWorkerAsync()

    End Sub
 

    Private Sub bgw1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw1.DoWork

        While True ' <-- Thread will be killed automatically when app exits

            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5).TotalMilliseconds)
 

            SyncLock PortLock ' <-- Thread will STOP & WAIT here if other thread currently has "PortLock"

                ' send request to Port 1
 

                ' wait for data to come back
 

                ' process data...but do NOT update GUI from in here!
 

                bgw1.ReportProgress(-1) ' causes ProgressChanged() Event below to fire

                ' (you can pass data using a second param if desired)

            End SyncLock

        End While

    End Sub
 

    Private Sub bgw1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw1.ProgressChanged

        ' it is SAFE to update the GUI from in here...

        ' (if you passed data access it with "e.UserState")

        Debug.Print("Port 1 Progress @ " & DateTime.Now)

    End Sub
 

    Private Sub bgw2_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw2.DoWork

        While True ' <-- Thread will be killed automatically when app exits

            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(30).TotalMilliseconds)
 

            SyncLock PortLock ' <-- Thread will STOP & WAIT here if other thread currently has "PortLock"

                ' send request to Port 2
 

                ' wait for data to come back
 

                ' process data...but do NOT update GUI from in here!
 

                bgw2.ReportProgress(-1) ' causes ProgressChanged() Event below to fire

                ' (you can pass data using a second param if desired)

            End SyncLock

        End While

    End Sub
 

    Private Sub bgw2_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw2.ProgressChanged

        ' it is SAFE to update the GUI from in here...

        ' (if you passed data access it with "e.UserState")

        Debug.Print("Port 2 Progress @ " & DateTime.Now)

    End Sub
 

End Class

Open in new window

DualBackgroundWorkerOutput.jpg
0
 

Author Comment

by:vj_mi
ID: 24830291
Hello Idle_Mind,
I want:
5 secs --> Serial Port 1 (Timer 1)
Next 30 secs --> Serial Port 1 (Timer 2)

Again 5 secs --> Serial Port 1 (using Timer 1)
Next 30 secs -- Serial Port 1 (using Timer 2)

So both data is coming from single serial port. So in this case both timer should work independently. This means that first timer can have any interval and must not be dependent and must also not interfere with timer interval of timer 2. Now I cannot remove the timer control because that will affect my complete project which is almost ready. So I appreciate this backgroundworker concept but it may not be feasible to implement at this stage.  Based on your indication that we can use two timer controls on one form, let me try a sample and I will revert back.

Regards,
MI
0
 

Author Comment

by:vj_mi
ID: 24830370
One more point:
My current code is as follows:

Dim sp as new SerialPort.

1. With this declaration, can I still use two timer controls?

2. What happens if code in timer 1 does not get completed and meantime timer2 event gets fired?

Regards,
MI
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24830889
Your Timer diagram and your description contradict each other:

    "...both timer should work independently. This means that first timer can have any interval and must not be dependent and must also not interfere with timer interval of timer 2."

With that statement you would actually have:

    5 secs Timer1 (@5 secs)
    5 secs Timer1 (@10 secs)
    5 secs Timer1 (@15 secs)
    5 secs Timer1 (@20 secs)
    5 secs Timer1 (@25 secs)
    5 secs Timer1 (@30 secs)
  30 secs Timer2 (@30 secs)
    5 secs Timer1 (@35 secs)
    5 secs Timer1 (@40 secs)
    5 secs Timer1 (@45 secs)
    5 secs Timer1 (@50 secs)
    5 secs Timer1 (@55 secs)
    5 secs Timer1 (@60 secs)
  30 secs Timer2 (@60 secs)
    etc...
   
But your diagram is showing:

    5 secs Timer1 (@5 secs)
  30 secs Timer2 (@35 secs)
    5 secs Timer1 (@40 secs)
  30 secs Timer2 (@70 secs)
    5 secs Timer1 (@75 secs)
  30 secs Timer2 (@105 secs)

If you really want the SECOND scenario then just do this:
Public Class Form1
 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Timer1.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds

        Timer2.Interval = TimeSpan.FromSeconds(30).TotalMilliseconds
 

        Timer1.Enabled = True

        Timer2.Enabled = False

    End Sub
 

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        Timer1.Stop()
 

        ' ... code ...
 

        Timer2.Start()

    End Sub
 

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick

        Timer2.Stop()
 

        ' ... code ...
 

        Timer1.Start()

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:vj_mi
ID: 24835107
Sorry ... I think I did not put it correctly, but you understood it well.... I want:
   5 secs Timer1 (@5 secs)
    5 secs Timer1 (@10 secs)
    5 secs Timer1 (@15 secs)
    5 secs Timer1 (@20 secs)
    5 secs Timer1 (@25 secs)
    5 secs Timer1 (@30 secs)
  30 secs Timer2 (@30 secs)
    5 secs Timer1 (@35 secs)
    5 secs Timer1 (@40 secs)
    5 secs Timer1 (@45 secs)
    5 secs Timer1 (@50 secs)
    5 secs Timer1 (@55 secs)
    5 secs Timer1 (@60 secs)
  30 secs Timer2 (@60 secs)
    etc...

This is what I want to have. How to achieve this? Also note that at 30 secs, both timer 1  and timer 2 would be triggered. Will this create any problem since it has to execute two different set of codes for two different timers?

Regards,
MI
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24835164
It really depends on the type of code that is executing in the Tick() events of your Timers.

The Timer control runs in the SAME thread as the form.  So if you have synchronous, non-threaded code AND you are NOT calling Application.DoEvents() inside the Tick() events, then the first Tick() event to fire and be processed will execute and run to completion without interruption.  When it is done, then the second Tick() event will be processed (including any other messages pending in the message queue).
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24835166
*Oh...to achieve this you would simply set the Interval and Enable both Timers...
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now