串口C#控制台读取 [英] Serial Port C# Console Read

查看:291
本文介绍了串口C#控制台读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,我是新来的,我听说过很多有关此网站的信息,它确实可以为您提供帮助.希望你能帮助我!.

我有一个非常简单的程序,它的唯一目的是从串行端口读取并在C#的控制台窗口中打印2000次.

我只是在一个微控制器上打开一个可变电阻器

下面是代码

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();
            }
        }
    }
}


但是这段代码中发生了一件有趣的事情.如上面的代码所示,对控制台读数线进行注释时,当我旋转可变电阻器的旋钮时,端口的值会发生变化.因此,这意味着它工作正常.另一方面,如果我使readline发生,以便在每个值之后我都必须按一个键,端口将读取当前值,即使我更改了旋钮并再次按Enter,该值仍将是第一个,就好像它没有在重置一样.完全没有?

您是否需要包括任何其他命令行以使端口重置?

希望您了解我的问题以及您需要知道的其他任何问题,请不要犹豫,我真的需要尽快解决此问题.非常感谢和问候.


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

推荐答案

问题是串行端口正在执行名为缓冲的操作-它在接收来自微控制器的数据的同时您的软件正在等待您按键盘上的按钮.当您按下按钮时,它将获取下一个输入行-最旧的而不是最新的-并在再次等待按键之前显示该值.所有较旧的版本仍然存在,等待您阅读它们,因此,每当您按键盘上的一个键时,它都会获取每个旧版本.有多种方法可以解决此问题,但这都取决于您要发生的事情-如果您一直都在使用最新版本,那么您只需要按一种方式就可以显示当前值,如果您一直在使用最新版本,就可以这样做.按钮,那么我会再做一次.


我想这样做.当我从串行中读取数据时,我想要可变电阻器上的当前值,这就是全部.我的实际项目并不需要仅按Enter键,这只是一个示例程序进行解释.

我的项目是一个平衡点,它需要从可变电阻器获得重量以执行一些操作,然后再次获得重量(该数值不断变化),我希望在那一刻获得重量."



好的-您的问题标签中提到了Threading,所以我认为这对您来说不是一个谜吗?

我可以通过以下两种方式之一来实现:要么通过设置处理串行端口的BackgroundWorker线程,要么坐在那里读取行并获取将其传递给主线程以进行显示的当前值(并在更改后报告进度) ),或者通过处理串行端口DataRecieved Event并在那里执行相同的操作.

第二种方法的代码可能更复杂:数据不是以整齐的行为基础的包中到达的,而是逐个字符地到达的,因此每次事件触发时,您可能会得到整行,或者您可能会在当前值中得到第二个字符-将不得不理清自己拥有的东西.

您想走哪条路?


我不怎么知道如何使用它们,但是我对线程非常了解.我宁愿采用第一种方法,即仅后台工作线程并只获取更改以供显示或使用."

轻松轻松:
添加这两个用法:
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);
        }
    }

这只会增加一个计数器,但是如果您用串行端口的东西替换DoWork代码,则应该使它运行起来非常简单.我会将您收到的数据转换为数字值,而不是将其保留为字符串,并且仅在数字值更改时报告进度-否则,您将一直在输出数字! :laugh:

(您不需要睡眠-当没有可用数据时,您的ReadLine将暂停线程)


哦,对不起.

但是我无法使其正常工作,因为当我将程序放入do work函数时,它将无法识别端口".


那不要把整个程序放在那里! :laugh:

只需将串行端口的东西放在那里:

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:

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);
           }
        }
    }




我尝试过,但是返回0

我在main之前完成了此操作:
私有静态int val = 0;

比下班后的主要工作要多.我要求它(只是为了测试)
console.writeline(val)

在工作进度中,我删除了编写行并得到了以下内容:
val = e.ProgressPercentage;

我有一个小问题,如果我想平均说10个值怎么办?"


好的,请耐心等待,因为这听起来与您的问题无关,但说实话!

初始值始终很痛苦-因此请尝试使用它们.而不是从初始值0开始,而是从负值开始-忽略它,直到得到正值为止(我假设您的天平不适用于比空气轻的物体-如果可以,则从Double开始最小值(它是最大的负范围),并忽略所有值,直到它改变为止.然后,尽早启动后台工作程序-串行通讯(尤其是9600波特)是 慢速 ,这将需要一些时间来从您的微控制器接收数据.

完成此操作后,请更改后台工作人员.进入循环之前:
1)从串行端口读取一条线
2)丢弃!这很重要-串行端口随时可能在来自uProcessor的数据流中打开,因此,如果您丢弃第一个读数,则您的代码将与uProc保持同步.
3)读取另一个,并将其设置为grams值.这是从uProc读取的初始值.
4)立即将进度报告为克值-这告诉主线程初始值是什么.
5)您现在可以进入循环.

您的平均数很容易做到-但是您想要移动平均数还是10个值的平均数?它们都很简单,但是它们可以给出不同的结果.
无论哪种情况,您都希望从ProgressChanged事件中获取十个值并使用它们.对于移动平均线,您将需要一个数组或一个列表;对于静态平均线,您将需要一个计数和总计.


对不起,但是我真的不知道如何执行第1步到第5步,您可以编辑我们拥有的代码吗?对不起:/"

:laugh:是的!您需要对自己的能力有更多的信心...

1)从串行端口读取一行
您要做的就是从port.Open行之后开始,然后添加:




"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:

port.ReadLine();

这会从uPorcessor和...读取行. 2)丢弃!这很重要-串行端口打开随时可能会出现在来自uProcessor的数据流中,因此,如果您放弃第一次读取,则代码将与uProc保持同步.
由于您没有将其保存在任何地方,因此将其丢弃.完成.
3)读取另一个,并为其设置grams值.这是从uProc读取的初始值.
现在,我知道您知道如何阅读一行,所以我就把那一点留给您! :)
int.TryParse位进行转换,因此您只需复制并修改为正确的变量即可. (如果不确定函数的功能,请在Google上进行搜索:在方法名称上添加"MSDN",它将立即找到该页面)

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...


这篇关于串口C#控制台读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆