14 Replies - 1256 Views - Last Post: 18 December 2013 - 05:15 AM Rate Topic: -----

#1 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 26 November 2013 - 12:33 AM

Hello everybody, for some time now i've been strugling with a code for counting frequency from a pulse generator and it don't want to work as I would like it to. I wrote a very simple program using serial port component, pin change event and stopwatch but I can see some variations in frequency. What I do is simply connect the signal from pulse generator to RS232 (pin 1 and 5) and I am looking for Carrier Detect signal and it works more less ok up until 15 Hz (~66ms) but when I am trying to speed up the generator to ~30Hz the frequency read is not stable, it varies ~3Hz.

My question is: Is it even possible to count the frequency in a way I am trying now?

private void serialPort1_PinChanged(object sender, SerialPinChangedEventArgs e)
        {

            if (serialPort1.CDHolding == true)
            {
                res = (1000 / st.Elapsed.TotalMilliseconds); // for Hz calculation
                label2.Text = st.Elapsed.TotalMilliseconds.ToString() + " ms";
                label3.Text = res.ToString("#") + " Hz";
                st.Restart();
            }
            
        }


Is This A Good Question/Topic? 0
  • +

Replies To: Realtime 'pulse' frequency counter through RS232 Carrier Detec

#2 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 26 November 2013 - 07:03 AM

Did you set your PC's power profile to High Performance? If not, you maybe seeing the effects of your CPU stepping down.

Do you have other processes running on your machine that maybe hogging the CPU? (Some AV software, or SQL server can be bad about this.)

Your use of multiple calls to ToString() maybe setting you up for quickly using up heap space, and the lagging you maybe seeing maybe due to garbage collection. Unfortunately, I have no recommendations on how to avoid calling ToString() without having to roll your own integer to string function.
Was This Post Helpful? 0
  • +
  • -

#3 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5631
  • View blog
  • Posts: 12,078
  • Joined: 02-June 10

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 27 November 2013 - 07:04 AM

I think Skydiver is really on to the real issue: The GUI in general.

You're not going to get accurate info when you have the gui and the serial port handler on the same thread. Especially in winforms.

You need to put the serial handler on its own thread, have it raise events for the pin change, then have the GUI listen to those events and report the information.
Was This Post Helpful? 1
  • +
  • -

#4 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 03 December 2013 - 04:44 AM

Thank you guys for your help.

What I did here is to change the approach to the problem. I discovered (or maybe I am wrong) that the best results I can get comes from DataRecieved event while serial cable has 2 and 5 pin connected (2 pin for +3VDC and 5 for GND). What I do right now is creating arrays upon application startup then openinig port and count impulses from DataRecieved event:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            
            {
                    res[g] = (st.Elapsed.TotalMilliseconds);
                    time_tot[g] = st_total.Elapsed.TotalMilliseconds;
                    g = g + 1;
                   st.Restart();
            
                    if (g == max)
                    {
                        label8.Text = "Finished";
                        tt1 = st_total.Elapsed.TotalMilliseconds;
                        serialPort1.Close();
                    }
            }

            
        } 



Before openinig a serial port I need to decide how many pick of voltage I want it to collect and once it is done I list those results in a listview and plot them on a chart. Using this method I managed to get down to 0,5ms variation between picks. Since my laptop does not have a serial port build in I have to use a USB->RS232 adapter which is a no name poor adapter. I did my tests on a different laptop with built in RS232 and the variation dropped down to 0,2ms which is not that bad.

The other thing I noticed is that no matter the frequency of the generator 20Hz or 200Hz I always get a ~0,5ms variation.

Is it possible to get my results even better than this?
I have 2 FTDI chipped USB->Serial adapters on order (they should be in any day now) do you think it will help me lose some precious microseconds?
Was This Post Helpful? 0
  • +
  • -

#5 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 03 December 2013 - 06:51 AM

On both machines, is the IsHighResolution property of the Stopwatch returning true?

Are the laptops plugged in or running on battery? Are their power schemes set for High Performance?
Was This Post Helpful? 0
  • +
  • -

#6 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 03 December 2013 - 08:00 AM

On both machines Stopwatch is high resolution.
Both machines are running on cable with High Performance power scheme.

The only difference is that one is connected via USB->Serial and the other via RS232 built in port.
The computer that is connected through USB->RS232 is way faster than the other one but I don't know if that matters.
Was This Post Helpful? 0
  • +
  • -

#7 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 03 December 2013 - 08:29 AM

You may have hit the limits of what managed wrapper for the serial port can give you. This is what it says in MSDN about the events fired:

Quote

PinChanged, DataReceived, and ErrorReceived events may be called out of order, and there may be a slight delay between when the underlying stream reports the error and when the event handler is executed. Only one event handler can execute at a time.

The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.


Or it may truly be the hardware...

Perhaps talk to the serial port directly using the unmanaged APIs, or roll your own device driver?
Was This Post Helpful? 2
  • +
  • -

#8 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 07 December 2013 - 08:35 AM

The new FTDI adapters got me down to 0,3ms which is still to high for me. I tried the software also at a stationary PC with built in RS232 and the results were close to 0,1ms.

I tried my best with Unmanaged API but unfortunately my knowlage of C# is very poor even with a ready to go class.
I found something interesting online:

http://www.hanselman...alPortCode.aspx

but I have no idea how to use this class in my soft. Could anyone give me an example on how to utilize this class for my purpose. What I am looking from it is a pin change event (high and low state) or maybe even data_recieve event like in IO.Ports and a way to display a timestamp results like I do in my SerialPort_DataRecieved event.

Thanks in advance
Was This Post Helpful? 0
  • +
  • -

#9 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4559
  • View blog
  • Posts: 7,980
  • Joined: 08-June 10

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 07 December 2013 - 09:01 AM

The unmanaged APIs are C/C++. You can leverage them in C# by using [DllImport]. It's not trivial if you're not already familiar with how to use them. To be honest, it requires some studying and practice to get it right. However, the linked article has examples of how Scott did what he did, so you can look at those for guidance.
Was This Post Helpful? 0
  • +
  • -

#10 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 07 December 2013 - 01:45 PM

You can't use Scott Hanselman's code because his code is driving the pin instead of listening to it. You can learn from his findings which was essentially: use the unmanaged APIs for less overhead.
Was This Post Helpful? 0
  • +
  • -

#11 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 09 December 2013 - 08:19 AM

Ok, I changed the approach once more and my final results in variation are 0,1 - 0,2ms using USB-RS232 adapter.
I read a ton of articles about unmanaged API and learned alot but decided not to use that. What I did instead is to create an infinite loop and check the state of CD, RTS and CTS signals. This way I can read 3 sources using one RS232:

for (; ; )
                {

                    if (current_state == 0 && serialPort1.DsrHolding == true)
                    {
                        result[k] = st_watch.Elapsed.TotalMilliseconds;
                        st_watch.Restart();
                        current_state = 1;
                        k++;

                    }

                    if (current_state == 1 && serialPort1.DsrHolding == false)
                    {
                        current_state = 0;
                    }

                    if (k == 500)
                    {
                        break;
                    }

                }



I know that this is probably not the best way to do it but the results are satisfying. This solution is way faster and more accurate than the Pin_Changed event. If anyone have any insights on this or maybe have a different (better) proposal on how to solve this other than using infinite loop (or maybe a different one) I would really appriciate it.
Was This Post Helpful? 0
  • +
  • -

#12 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 09 December 2013 - 08:29 AM

Be aware that tight loop will eat batteries on laptops.

Code wise, though, it maybe more descriptive to rename current_state to something else like collecting_data or something more reflective of what the current state is.

Additionally, using a bool or enum instead of an integer may make the code self documenting and more legible.
Was This Post Helpful? 0
  • +
  • -

#13 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4559
  • View blog
  • Posts: 7,980
  • Joined: 08-June 10

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 09 December 2013 - 09:52 AM

Also, you can switch to a do-while loop. Won't make a difference performance-wise, but for readability it would be good:

do{
  ...
} while (k != 500);


It also might be smart to change that to k < 500, just for getting into the habit. It's better to not leave possible bounds errors, even if your current program can't create them.
Was This Post Helpful? 0
  • +
  • -

#14 cqcx  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 26-November 13

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 17 December 2013 - 03:07 AM

Thank you guys for your help, I have one more question though. After a data has been taken and I list my results every several measurements I have 2 measures +0,1ms and next -0,1ms and after that everything is stabilizing for next 20-30 mesures and then the variation appears again. My question is where is it comming from? I tried to implement additional timers to measure lost time (speed of each loop, delay in saving variable) but those do not compensate the 0,1ms I am losing during measurement. Does that come from system interrupts?
I understand that system is doing a lot of things while I am taking the measurement but all I am looking for is to somehow measure that time.
I also need to add that those 0,1ms variations are very random and not equally spaced between each other.
Was This Post Helpful? 0
  • +
  • -

#15 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3650
  • View blog
  • Posts: 11,420
  • Joined: 05-May 12

Re: Realtime 'pulse' frequency counter through RS232 Carrier Detec

Posted 18 December 2013 - 05:15 AM

Those could be system interrupts, or delays from garbage collection, or a host of other things. Can you verify with an oscilloscope that those variations do not exist in the source signal?

If you are expending this much time on a software solution, perhaps taking some time to do build a custom circuit that measures the pulses maybe worth exploring. You can have dedicated hardware to measure the pulses, buffer the results, and then let your program get the data at your leisure.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1