Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
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
 
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 24-Nov-12 0:03am

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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:
using System.ComponentModel;
using System.Threading;
Then you need to do something like this:
        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 | :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 | :laugh:
 
Just put the serial port stuff in there:
        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 | :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:
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! Smile | :)
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...
  Permalink  
v6
Comments
OriginalGriff at 24-Nov-12 5:38am
   
Answer updated
OriginalGriff at 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.
CPallini at 24-Nov-12 5:58am
   
5.
OriginalGriff at 24-Nov-12 6:06am
   
It means he upvoted my answer by giving it a five. Basically he thinks it is a good answer. (Don't worry about it! :laugh:)
OriginalGriff at 24-Nov-12 6:16am
   
Answer updated
OriginalGriff at 24-Nov-12 6:18am
   
Yes - you will. Remember what I said about data not arriving in whole lines?
If the value is 123[Return] and you discard the input buffer, then you could get
 
123[Return]
or
23[Return]
or
3[Return]
or
[Return]
 
depending on what data has arrived so far.
OriginalGriff at 24-Nov-12 7:24am
   
In my original code, where it says
Console.WriteLine(e.ProgressPercentage);
Take that value, and do what you like with it! It is the latest value as reported by the serial port.
You can store it for later use, or process it immediately if you need to.
OriginalGriff at 24-Nov-12 7:52am
   
No - e is a parameter to the Event Handler method, the EventArgs based ProgressChangedEventArgs and it is only available while it is in scope - i.e. within the ProgressChanged event handler method. You can copy it to an external variable (declared outside the Main method).
private static double latestWeight = 0.0;
static void Main(string[] args)
{
...
}

static void work_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lastestWeight = (double) e.ProgressPercentage / 1000.0;
...
}
OriginalGriff at 24-Nov-12 9:37am
   
Answer updated
OriginalGriff at 24-Nov-12 10:12am
   
Answer updated
Nelek at 24-Nov-12 10:53am
   
What an answer... +5

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



Advertise | Privacy | Mobile
Web03 | 2.8.141220.1 | Last Updated 24 Nov 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100