C#串口每隔10ms发送命令 为什么在10s内接收不到1000条返回数据

ypfsmile 2017-02-05 10:37:28
各位高手,我现在是利用Thread.sleep(10)每隔10ms向我的一个MODBUS协议的采集器发送命令,然后利用datareceived来接受返回的数据,并存储。但发现程序运行10s后,接收到的数据最多只有600多条,这是为什么呢?还有就是我怎么做才能每隔10ms接收到采集器返回的数据呢?请大神们帮助。
...全文
2209 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
时间之外 2017-06-19
  • 打赏
  • 举报
回复
真巧,我最近也遇到这个问题,C#控制每10ms向串口发送102字节,接收端的帧频也是60hz左右,说一下我解决问题的过程吧。 首先楼主开始用的sleep肯定是不行的,我开始用的是System.Timers.Timer,多线程计时器不会影响ui,但测试发现间隔时间最低只能设置15ms,帧频也就60左右,我自己利用stopwatch封装了一个简单的计时器,能达到10ms发送的要求。 此时测试发一个字节帧频达到100,但发102字节时依然帧频只有60,再测试向虚拟串口发和向另一台电脑发送,帧频也能到100,至此基本确定是接收设备的问题,现在做硬件的同事正在找问题。 附上自定义的timer类
   class MyTimer
    {
        private Stopwatch stw = new Stopwatch();
        public delegate void ElapsedHandler();
        public event ElapsedHandler Elapsed;
        
        private static Thread sendThread;
        
        public bool Enabled = false;
        private int _interval;
        /// <summary>
        /// 时间间隔(ms)
        /// </summary>
        public int Interval 
        {
            get
            {
                return _interval;
            }
            set
            {
                _interval = value;
            }
        }
        public void Start()
        {
            Enabled = true;
            stw.Start();
            sendThread = new Thread(new ThreadStart(DoSend));
            sendThread.IsBackground = true;
            sendThread.Start();
        }
        private void DoSend()
        {
            while (Enabled)
            {
                if (stw.ElapsedMilliseconds >= _interval)
                {
                    if (Elapsed != null)
                    {
                        Elapsed();
                        stw.Restart();
                    }
                }
            }
        }
        public void Stop()
        {
            Enabled = false;
            stw.Stop();
            if (sendThread != null && sendThread.IsAlive)
            {
                Thread.Sleep(1);
                sendThread.Abort();
            }
        }
    }
ypfsmile 2017-02-26
  • 打赏
  • 举报
回复
各位,经测试,Thead.sleep()的精度确实不够,最快也只是15ms的频率。后来在网上搜索了一下,偶然发现下面的博客: http://blog.csdn.net/chenyujing1234/article/details/7482464 借鉴这一仁兄(也可能是仁妹)的做法。利用QueryPerformanceFrequency 和QueryPerformanceCounter这两个WIN32API函数。自己实现了一个定时器可以设置为10ms的频率,经测试,在10s内可以收到接近1000条的数据,缺失数据在个位。我的发送数据的代码如下,请各位高手指定。
引用
QueryPerformanceFrequency(out ClockFrequency); IntervalTicks = (long)(9.9965 * (double)ClockFrequency / (double)1000); QueryPerformanceCounter(out CurrTime); //获取当前硬件计数器计数 NextTriggerTime = CurrTime + IntervalTicks; TimeStamps.Add(DateTime.Now); MileagePort.Write(MileageSendOrder, 0, MileageSendOrder.Length); while (Running) { //循环等待间隔时间 while (CurrTime < NextTriggerTime) { QueryPerformanceCounter(out CurrTime); } TimeStamps.Add(DateTime.Now); MileagePort.Write(MileageSendOrder, 0, MileageSendOrder.Length); NextTriggerTime = CurrTime + IntervalTicks; //获取下一次触发的计数器计数
目前是用这种方式解决的,但出现的新的问题时,我每次发送数据前获取了一下系统时间作为时间戳,结束后查看了一下,时间列表里面的系统时间的毫秒部分却不是10ms的间隔,且出现连续几条时间数据的毫秒数不变。现在还不知道原因。 我最初提的问题已经得到了大家的不少帮助,我先结贴了。新出现的问题,如果没人回复了,我再另开帖子问吧。
  • 打赏
  • 举报
回复
你只是10ms发送而已,串口又不一定每次都及时回你,就比如你看上个妹子每个小时给发一条短信,人家不愿搭理你,一次也不回你或者你发了十几条触动了她,她才理你一次
PaulyJiang 2017-02-23
  • 打赏
  • 举报
回复
10 ms 发送你最好1ms监听
海阔天空CE 2017-02-16
  • 打赏
  • 举报
回复
10ms 时间太短了吧,又不是嵌入式系统的中断定时
qq_16997111 2017-02-16
  • 打赏
  • 举报
回复
不看别人的回答,看楼主的标题和内容。只说一句,CPU处理是需要时间的。至于sleep的精度完全不需要管。600条跟999条,若只在楼主的问题中,那么就是同一个概念。
okkk 2017-02-11
  • 打赏
  • 举报
回复
sleep不靠谱的问题: 可以使用 stopwatch 使用 while(true) { stopwatch流失时间 满足条件 发送指令 } ---会独立占用一个CPU,而且 CPU 使用率 永远是100%;
ypfsmile 2017-02-10
  • 打赏
  • 举报
回复
感谢各位的回答,我在工控机上运行了同样的代码,然后出现了 wanghui0380 讲解的情况,我对返回数据进行解析后,发现发出1000条指令最终是可以得到1000返回数据的。但由于发送数据需要一定的时间,所以在10ms这个频率下,10s中只能获得900多条数据。接下来可能会参考
引用
、解决,通过异步发送数据,timer控制每10ms驱动一次,这样10s 1000条应该问题不大,缺少数应该能控制在个位。
这个方法尝试一下,目前先不急着结贴,因为还有一些问题没有解决,还需各位的帮助。
卧_槽 2017-02-08
  • 打赏
  • 举报
回复
1、sleep自身并不能保证时间精确度,尤其是到了10ms这个级别。 2、发送任务自身也需要时间。这样每个周期肯定是要超过10ms的。 3、解决,通过异步发送数据,timer控制每10ms驱动一次,这样10s 1000条应该问题不大,缺少数应该能控制在个位。
wingwf2000New 2017-02-07
  • 打赏
  • 举报
回复
也可能发的太快,而下位机反应不过来而导致没有反应或收到多个命令但只对某个命令有反应,这些只是猜测,你把速度放慢点再试试
绿领巾童鞋 2017-02-07
  • 打赏
  • 举报
回复
你确定,一个周期10MS,10S内能顺利发送1000次吗? 你上面的现象,明显出现粘包的情况,就是你多次发送后,接收不及时,导致上一次返回数据还在缓冲区。 设计方面,要不做 异步解析,你这种一条一定要多少字节的玩意是不通用的,如果一定要做同步,发送和接收部分一定要有时间间隔,接收完成后要校验接收情况后 再发送下一次,这样 肯定明显 达不到你的10s 1000次的要求。 你们老大叫你再改一下~
  • 打赏
  • 举报
回复
应该是的在家里 都忘了怎么弄的了明天看看先
  • 打赏
  • 举报
回复
引用 24 楼 ypfsmile 的回复:
引用
System.Threading.Timer TimerItem; System.Threading.TimerCallback TimerDelegate = new System.Threading.TimerCallback(timerRead); TimerItem = new System.Threading.Timer(TimerDelegate, null, 0, 2000); 线程做循环 别用Timer 不然 你界面还有其他功能会 程序停止运行
那么请问serialPort.write部分要怎么做呢?新开辟线程一直循环发送吗?
发送不用, 接收用。
ypfsmile 2017-02-06
  • 打赏
  • 举报
回复
引用
sleep精读非常低的,再加上多线程调度的时间误差,收到600次很正常。
引用
Thread.sleep(10)的意思是10Ms内不在接受系统优先级调度 10Ms以后才再次接受系统优先级分配 而10Ms以后 再系统再次重新分配也不一定有最高优先级立刻执行
谢谢答复,那么我怎么样才能每隔10ms采集一次数据呢?用timer吗?
tcmakebest 2017-02-06
  • 打赏
  • 举报
回复
发送速度这么快,串口估计要用坏了吧.
591320277 2017-02-06
  • 打赏
  • 举报
回复
Thread.sleep(10)的意思是10Ms内不在接受系统优先级调度 10Ms以后才再次接受系统优先级分配 而10Ms以后 再系统再次重新分配也不一定有最高优先级立刻执行 所以等待时间是不确定的 百度会有更详细的说明
xuggzu 2017-02-06
  • 打赏
  • 举报
回复
sleep精读非常低的,再加上多线程调度的时间误差,收到600次很正常。
ypfsmile 2017-02-06
  • 打赏
  • 举报
回复
引用
ps:上面你自己也说了,你们的协议规定是modbus,那么我告诉你你到底差在啥地方,你差在把从连续的byte[]里把modbus协议的具体一条解析出来。还是那个比方:“水流”,一个modbus桶200字节,现在你一次触发涌过来500字节的水流,那么理论上他包含3个桶的数据(有完整的,有部分的,有头没尾,有尾没头),你应该根据modbus协议把他具体解析出来,而不是messages.Add(message)
我返回的数据标准应该是21个字节,有头部标识和尾部校验码。我看了一下我messages里接收到的值,都是有头和尾的完整的数据。只是有些是42个字节也就是两条数据。但是加起来也不够1000条。我目前希望的就是发送1000条指令,就接收到1000条数据,这能做到吗? 再次感谢你的细心解答,我会去看你推荐的博客的。
ypfsmile 2017-02-06
  • 打赏
  • 举报
回复
引用
System.Threading.Timer TimerItem; System.Threading.TimerCallback TimerDelegate = new System.Threading.TimerCallback(timerRead); TimerItem = new System.Threading.Timer(TimerDelegate, null, 0, 2000); 线程做循环 别用Timer 不然 你界面还有其他功能会 程序停止运行
那么请问serialPort.write部分要怎么做呢?新开辟线程一直循环发送吗?
shenyi0106 2017-02-06
  • 打赏
  • 举报
回复
引用 21 楼 sp1234 的回复:
[quote=引用 10 楼 ypfsmile 的回复:]
引用
sleep精读非常低的,再加上多线程调度的时间误差,收到600次很正常。
引用
Thread.sleep(10)的意思是10Ms内不在接受系统优先级调度 10Ms以后才再次接受系统优先级分配 而10Ms以后 再系统再次重新分配也不一定有最高优先级立刻执行
谢谢答复,那么我怎么样才能每隔10ms采集一次数据呢?用timer吗?
桌面windows 根本做不到。桌面 windows 是应用系统操作系统。 你如果要做工控,需要专门的操作系统、比较简单的操作系统,甚至是无操作系统(直接用c或者汇编语言)的裸机上写程序,才能做底层控制。[/quote] VxWork似乎可以,它是实时操作系统,不过搞起来难度挺大
加载更多回复(18)

111,126

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧