Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi to all i am new here and i have heard a lot about this website that it really helps you out. Hope you will be able to help me out!.

I have a very simple program which its only aim is to read from a serial port and prints it on the console window in C# for 2000 times.

I am just turning a variable resistor on a micro-controller that's all

Here below is the code

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace Testing_serial_v3._0
{
    class Program
    {
        static void Main(string[] args)
        {

            string buff;


            SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
            port.Open();

            for (int i = 0; i < 2000; i++)
            {


                buff = port.ReadLine();
                Console.WriteLine(buff);
                //Console.ReadLine();
            }
        }
    }
}

But there is a funny thing happening in this code. When the console readline is commented as shown in the code above the value from the port changes as i turn the knob of the variable resistor. So this means it is working good. On the other hand if i make the readline happen so that after each value i have to press a key the port reads the current value and even though i change the knob and press enter again the value will remain the first as if it is not resetting at all?

Do you have to include any other command lines so that the port will reset?

Hope you understand my problem and any other questions you need to know please don't hesitate i really need this problem fixed ASAP. Many thanks and regards
Posted

1 solution

The problem is that the serial port is doing something called buffering - it is receiving the data from your microcontroller while your software is waiting for you to press a button on the keyboard. When you press the button, it fetches the next input line - which is the oldest, not the newest - and displays that value before waiting for the key again. All the older versions are still there, waiting for you to read them, so it fetches each old version every time you press a key on the keyboard. There are a number of ways round this, but it all depends on what you want to happen - if you are after the latest version at all times then you do it one way, if you just want to show the current value when you press the button, then I would do it another.


"I would like to do this. When i go read from the serial i want the current value on the variable resistor thats all. My actual project does not require only the press of the enter key this is just a sample program i made to explain.

My project is sort of a balance it goes to get the weight from the variable resistor do some operations and goes to get the weight again (which is continuously changing) and i want the weight at that instant."



OK - your question tags mention Threading, so I take it this is not a total mystery to you?

I would do it by one of two ways: either by setting up a BackgroundWorker thread that handled the serial port, just sitting there reading lines and getting the current value which it passes to the main thread for display (and reports progress when it has changed), or by handling the serial port DataRecieved Event and doing much the same thing there.

The second method could be more complex to code: data does not arrive in neat line based packages, but character by character so each time the event fires you might get a whole line, or you might get the second character in the current value - you would have to sort out what you have yourself.

Which way would you rather go?


"I do not know how to use them that much but i know about threading. I would rather go with the first method that of just background worker thread and just get the change for display or use."

Easy peasy:
Add these two usings:
C#
using System.ComponentModel;
using System.Threading;

Then you need to do something like this:
C#
static void Main(string[] args)
    {
    BackgroundWorker work = new BackgroundWorker();
    work.DoWork += new DoWorkEventHandler(work_DoWork);
    work.ProgressChanged += new ProgressChangedEventHandler(work_ProgressChanged);
    work.WorkerReportsProgress = true;
    work.RunWorkerAsync();
    Console.ReadLine();
    }

static void work_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    Console.WriteLine(e.ProgressPercentage);
    }

static void work_DoWork(object sender, DoWorkEventArgs e)
    {
    BackgroundWorker work = sender as BackgroundWorker;
    int i = 0;
    while (true)
        {
        Thread.Sleep(100);
        i++;
        work.ReportProgress(i);
        }
    }
This just increments a counter, but if you replace the DoWork code with your Serial port stuff then you should get it going pretty simply. I would convert you received data to a numeric value rather than leaving it as a string, and only report progress when the numeric value changes - otherwise you are going to be outputing numbers all the time! :laugh:

(You don't need the Sleep - your ReadLine will suspend the thread when there is no data available)


"Oh ok sorry.

But i cant get it to work because when i put the program in the do work function it then does not recognize the port"


Don't put the whole program in there then! :laugh:

Just put the serial port stuff in there:
C#
static void work_DoWork(object sender, DoWorkEventArgs e)
    {
    BackgroundWorker work = sender as BackgroundWorker;
    int grams = -1;
    SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
    port.Open();
    while (true)
        {
        string buff = port.ReadLine();
        int value;
        if (int.TryParse(buff, out value) && value != grams)
           {
           grams = value;
           work.ReportProgress(grams);
           }
        }
    }



"I tried it but it is returning a 0

i did this before main:
private static int val = 0;

than in the main after work.RunWorkerAsync(); i called for it (just to test)
console.writeline(val)

and in the work progress i removed the writeline and got this:
val = e.ProgressPercentage;

And i small question, what if i want to get an average of say 10 values"


OK, bear with me, because this is going to sound like nothing to do with your problem - but it is, honest!

Initial values are always a pain - so try to deal with them. Instead of starting with an initial value of 0, start with a negative value - and ignore it until you have a positive (I am assuming your scale does not work for lightler-than-air objects - if it does, then start with the Double.Min value (it's largest negative extent) and ignore all values until it has changed. Then, start the background worker as early as you can - serial communications (especially at 9600 baud) are slow and it will take time to receive data from your microcontroller.

When you have done that, change the background worker. Before you enter the loop:
1) Read a line from the serial port
2) Discard it! This is important - your serial port open can occur at any time in the stream of data from your uProcessor, so if you discard the first reading, then you get your code in synch with the uProc.
3) Read another, and set the grams value to it. This is the initial value read from the uProc.
4) Immediately report progress as the grams value - this tells the main thread what the initial value is.
5) You can now enter the loop.

Your average is easy to do - but do you want a moving average, or a grab-ten-values average? They are both pretty easy, but they can give different results.
In either case, you want to grab ten values from the ProgressChanged event and work with them. For a moving average, you will want an array, or a list - for a static average, you will want an count, and a total.


"sorry but i really dont know how to do step 1 to 5 can you just edit the code we have. sorry :/"

:laugh: Yes you do! You need to have more confidence in your own abilities...

1) Read a line from the serial port
All you have to do is start after the port.Open line, and add:
C#
port.ReadLine();
This read a line from the uPorcessor and...
2) Discard it! This is important - your serial port open can occur at any time in the stream of data from your uProcessor, so if you discard the first reading, then you get your code in synch with the uProc.
Because you didn't save it anywhere, it was discarded. Done.
3) Read another, and set the grams value to it. This is the initial value read from the uProc.
Now, I know you know how to read a line, so I'll leave that bit to you! :)
The int.TryParse bit does the conversion, so all you need to do is copy that and modify it for the correct variable. (If you aren't sure what a function does, google it: Add "MSDN" on to the method name, and it'll find the page straight away)
int.TryParse MSDN[^] - the first link will take you straight there.
4) Immediately report progress as the grams value - this tells the main thread what the initial value is.
You know how to do that, as well - it's just the work.ReportProgress call we used before!
5) You can now enter the loop.

See? You did know how to do it - or you could easily work it out! Please, have a little faith in yourself: all it takes is a little thinking sometimes...
 
Share this answer
 
v6
Comments
[no name] 24-Nov-12 5:21am    
I would like to do this. When i go read from the serial i want the current value on the variable resistor thats all. My actual project does not require only the press of the enter key this is just a sample program i made to explain.

My project is sort of a balance it goes to get the weight from the variable resistor do some operations and goes to get the weight again (which is continuously changing) and i want the weight at that instant.
OriginalGriff 24-Nov-12 5:38am    
Answer updated
[no name] 24-Nov-12 5:41am    
I do not know how to use them that much but i know about threading. I would rather go with the first method that of just background worker thread and just get the change for display or use.
[no name] 24-Nov-12 5:58am    
But i dont need the progress i need the actual change for example first it was 1kg than it becomes 5kg which is the reading from the variable resistor
OriginalGriff 24-Nov-12 6:05am    
The Progress is just a way of reporting a value in a thread safe way - you could use a variable instead, but then you have to either using locking every time you access it from either thread, or be very, very careful how you do things.
"Percentage" is just a name - you can treat it as a "Grams" value and return 5000 for 5Kg, or 4234 for 4.234Kg.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900