霸气侧漏 发表于 2017-10-23 11:03:22

怎样提升C#的定时器精度

最近在用C#做串口通信方面的控制,发现一个问题,定时一点不准,我想定时器10ms,发现不行,

有没有办法定时器精度做到20ms,实在不行30ms也可以,好吧40ms也中。

用过的来说说吧,哈哈

-佛听- 发表于 2017-10-23 11:18:49

确实是的c#的定时器不准确

霸气侧漏 发表于 2017-10-23 11:20:39

-佛听- 发表于 2017-10-23 11:18
确实是的c#的定时器不准确

有解决的办法没

rqiang 发表于 2017-10-23 11:24:10

本帖最后由 rqiang 于 2017-10-23 11:25 编辑

https://msdn.microsoft.com/zh-cn/library/system.diagnostics.stopwatch(v=vs.110).aspx
这个可以拿来检测时间,比较准

霸气侧漏 发表于 2017-10-23 11:26:48

rqiang 发表于 2017-10-23 11:24
https://msdn.microsoft.com/zh-cn/library/system.diagnostics.stopwatch(v=vs.110).aspx
这个可以拿来检 ...

这个只能用来检测时间对吧?但是我要的中断触发啊

浮华一生 发表于 2017-10-23 11:27:00

调用C/C++的DLL

浮华一生 发表于 2017-10-23 11:27:31

有内核的定时函数接口   可以有几ms的精度吧

panjun10 发表于 2017-10-23 11:32:00

多媒体定时器1ms精度

rqiang 发表于 2017-10-23 11:32:09

霸气侧漏 发表于 2017-10-23 11:26
这个只能用来检测时间对吧?但是我要的中断触发啊

MS级中断没有用过,估计不行

霸气侧漏 发表于 2017-10-23 11:32:53

panjun10 发表于 2017-10-23 11:32
多媒体定时器1ms精度

多媒体定时器1ms精度

我搜搜看,还有这个定时器,

semonpic 发表于 2017-10-23 11:33:01

Win 就不是一个实时系统,想做的精确定时很困难。
说说我的想法,win系统时间片据说是20ms。非计算密集型的程序,在1ms 只内应该就会因为阻塞或者主动放弃CPU(Sleep(XX))而让出 CPU。计算密集型应该最多20ms 就被强制放弃CPU。

一般合格程序员写的程序(非计算密集型)基本能在1ms 让出CPU。

你能做的是:用户任务近可能少,关闭也行占用CPU比较高的进程和服务
1.使用线程,将优先级调至最高
2.关闭系统不必要服务
3.任务管理器查看那个程序,占用CPU较高,看看是否能优化调或者关了,如杀毒软件。

对操作系统或者.net Framework 内部造成的定时不准确,就没办法了,但是操作系统应该没有啥,计算密集型的任务。至于.net Framework在GC的时候可能会卡一下吧。


霸气侧漏 发表于 2017-10-23 11:40:36

semonpic 发表于 2017-10-23 11:33
Win 就不是一个实时系统,想做的精确定时很困难。
说说我的想法,win系统时间片据说是20ms。非计算密集型的 ...

这样啊,谢谢大神的指点,我去试试看

-佛听- 发表于 2017-10-23 11:56:52

霸气侧漏 发表于 2017-10-23 11:40
这样啊,谢谢大神的指点,我去试试看

或者用那个time watch来做闭环应该可以做到ms级别

q457344370 发表于 2017-10-23 12:01:23

多媒体定时器,或者用线程设置优先级高然后获取系统时间死等我做到了1ms

霸气侧漏 发表于 2017-10-23 12:16:37

q457344370 发表于 2017-10-23 12:01
多媒体定时器,或者用线程设置优先级高然后获取系统时间死等我做到了1ms

来点代码先,哈哈

zyqcome 发表于 2017-10-23 15:48:23

换个想法了,试一试,用
//------独立线程--------
while {
      Thread.Sleep(XX);
      //do something
}

mcu5i51 发表于 2017-10-23 17:41:41

还是多媒体定时器的回调方式吧,等效MCU的中断

uid81 发表于 2017-10-24 13:25:13

.net 有4种定时器,用System.Timers.Timer更精确些,触发间隔要大于16ms

霸气侧漏 发表于 2017-10-24 13:38:55

uid81 发表于 2017-10-24 13:25
.net 有4种定时器,用System.Timers.Timer更精确些,触发间隔要大于16ms

30ms也是没问题的

立创商城-技术 发表于 2017-10-24 13:52:00

霸气侧漏 发表于 2017-10-24 13:53:19

立创商城-技术 发表于 2017-10-24 13:52
做个外置硬件的计时单元也不错吧!
比如 用CH9326 (USB HID 免驱)+ RTC芯片或MCU,轻松实现一个USB RTC。 ...

这个不现实,虽然也能解决问题,还是软件级别的解决方案比较好

立创商城-技术 发表于 2017-10-24 16:26:30

霸气侧漏 发表于 2017-10-24 21:42:13

立创商城-技术 发表于 2017-10-24 16:26
用软件也可以,比如用VC做一个DLL,精度其实很高,延时xx微秒(uS) 都可以。 然后C#调用DLL。...

没这样搞过,有例程没有,

ordinary 发表于 2017-10-24 22:04:28

延时uS是可以,但不能稳定的延时。

ordinary 发表于 2017-10-24 22:05:30

Win 就不是一个实时系统,想做的精确定时很困难。

霸气侧漏 发表于 2017-10-24 22:20:54

ordinary 发表于 2017-10-24 22:05
Win 就不是一个实时系统,想做的精确定时很困难。

这个我知道,就是不太清楚怎么搞定,很少用C#

Error.Dan 发表于 2017-10-25 00:45:26

用C#做10ms级别的精确控制不是一件容易的事情,因为包括.NET framework在内的整个系统不是给强实时应用准备的.
但是大部分情况下,解决问题不是只有一种方法的,比如LZ的串口应用,在合理设置串口buffer threshold的情况下是完全可以用事件响应的方式做到很高的实时性的.实在不行,就用最基本的字节中断,自己去拼数据,灵活且响应快.
同时多线程环境下,如果os的负担不重每个线程的轮询比例比较均匀也是可以获得比较好的实时性的.(我一般都这么搞,本身C#写这一类应用就超级方便,而且大部分时候响应速度都够用,毕竟系统跑满的情况比较少)

tangnyzl 发表于 2017-10-25 07:25:30

开个线程,用gettickcount计数,这个本来就不是实时操作糸统

redroof 发表于 2017-10-25 07:34:06

semonpic 发表于 2017-10-23 11:33
Win 就不是一个实时系统,想做的精确定时很困难。
说说我的想法,win系统时间片据说是20ms。非计算密集型的 ...

操作系统的计算密集型任务也有哦,常见的杀毒软件360防火墙之类都是。它是驱动层的比你优先级高,想干啥都行。
哈哈… 你程序写的再好,遇到客户装上全套这种东西,包你卡的跟啥一样!

霸气侧漏 发表于 2017-10-25 09:10:01

redroof 发表于 2017-10-25 07:34
操作系统的计算密集型任务也有哦,常见的杀毒软件360防火墙之类都是。它是驱动层的比你优先级高,想干啥 ...

这他妈就尴尬了,目前只给公司内部测试用,应该没问题

huangqi412 发表于 2017-10-25 10:01:27

以前测试,VC多媒体定时器,关掉别的乱七八糟软件,定时1MS,99%以上周期准确,偶有跳到几个MS到10多个MS时候
如果开了别的乱七八糟软件,那就无法预测了,至少你不可能比杀毒软件之类更优先,马云马化腾360之类全家桶也是牛逼哄哄,神仙也无招。
-----------结论:电脑高精度定时只能在理想环境下保证基本正确的ms级别,不具有广泛性(你不能保证运行环境)。

huangqi412 发表于 2017-10-25 10:04:48

不会有谁为了运行你的软件把浏览器扣扣淘宝等等等等神马统统统统杀掉进程。 什么都不干光看着屏幕界面。

redroof 发表于 2017-10-25 10:12:44

huangqi412 发表于 2017-10-25 10:04
不会有谁为了运行你的软件把浏览器扣扣淘宝等等等等神马统统统统杀掉进程。 什么都不干光看着屏幕界面。 ...

做工业自动化监控的机器,你或许可以这么要求客户。
当然如果有笨蛋非要在控制着价值几百万的生产线的电脑上安装360全家桶之类,那么神仙也帮不了你{:titter:}
在大部分管理正确的这种机器上,你安装任何软件都要跟他们管理员申请的。

rainbow 发表于 2017-10-25 23:20:34

霸气侧漏 发表于 2017-10-23 11:20
有解决的办法没

运行程序后,在任务管理器中找到进程,点鼠标右键,设置优先级,改为“实时“,看看有没有效果。

霸气侧漏 发表于 2017-10-25 23:38:08

rainbow 发表于 2017-10-25 23:20
运行程序后,在任务管理器中找到进程,点鼠标右键,设置优先级,改为“实时“,看看有没有效果。 ...

我试试看,嘿嘿

rainbow 发表于 2017-10-26 00:46:07

霸气侧漏 发表于 2017-10-25 23:38
我试试看,嘿嘿

有区别吗?

marshallemon 发表于 2017-10-26 10:58:51

使用串口通讯,需要1mS定时的精度 意义何在?串口本来就很慢,实时性要求这么高有意义?

q457344370 发表于 2017-10-26 13:44:44

霸气侧漏 发表于 2017-10-23 12:16
来点代码先,哈哈

多媒体定时器MmTimer的网上例子很多,你自己找吧,
下边是用线程死等的,可以做到很小的周期,但是比较耗资源,且周期不太稳定
int pengding = 0;
Thread trans_thread;
private void CanTrans_Thread()
{
    while (true)
    {
      int id;
      int dlc;
      long oldTime = DateTime.Now.Ticks;
      long nowTime;
      long time;
      long cnt;
      byte[] dat = new byte;
      bool rx_frame = false;
      int idle_counter = 0;
      while (true)
      {
            rx_frame = false;
            while (ReadData != null && ReadData(out id, ref dat, out dlc, out time) == true)
            {
                if (id == rx_id && dlc == 8)
                {
                  /*
                  ** Response Pending
                  */
                  if (dat == 0x03
                        && dat == 0x7F
                        && dat == 0x78)
                  {
                        pengding = 5000;
                        RxFrameEvent(id, dat, dlc, time);
                        break;
                  }
                  pengding = 0;
                  RxFrameEvent(id, dat, dlc, time);
                  Array.Copy(dat, can_rx_info.frame, SF_DL_MAX_BYTES + 1);
                  break;
                }
            }
            nowTime = DateTime.Now.Ticks;
            cnt = nowTime - oldTime;
            if (cnt >= 5000 || rx_frame)
            {
                oldTime = nowTime;
                if (pengding == 0)
                {
                  CanTrans_Counter((int)(cnt + 5000) / 10000);
                }
                else
                {
                  pengding--;
                }
            }

            if (pengding == 0)
            {
                CanTrans_Manage();
            }

            if (can_rx_info.rx_in_progress || can_tx_info.tx_in_progress || rx_frame)
            {
                idle_counter = 0;
            }
            else
            {
                if (idle_counter >= 100)
                {
                  Thread.Sleep(5);
                }
                else
                {
                  idle_counter++;
                }
            }
      }
    }
}

/// <summary>
/// 传输层开启
/// </summary>
public void Start()
{
    pengding = 0;
    can_tx_info = new tx_info();
    can_rx_info = new rx_info();

    trans_thread = new Thread(new ThreadStart(CanTrans_Thread));
    trans_thread.IsBackground = true;
    trans_thread.Priority = ThreadPriority.Highest;
    trans_thread.Start();

    testerPresentStart();
}

1a2b3c 发表于 2017-10-26 15:25:54

晕,原来这里也有这个讨论,
昨天我还在另外一个帖子里面问呢,
https://www.amobbs.com/forum.php?mod=viewthread&tid=5682473&page=1#pid9960896

我不是搞上位机软件的,但是实际中发现的确好多情况下每个sleep()就是15.625ms的感觉,
然后不知道有没有usleep()函数,

1a2b3c 发表于 2017-10-26 15:30:15

marshallemon 发表于 2017-10-26 10:58
使用串口通讯,需要1mS定时的精度 意义何在?串口本来就很慢,实时性要求这么高有意义? ...

比如说一秒钟发1000帧信息,那么基本上就是1ms一次了,即使不用均匀分布的绝对1ms一次,但是平均下来是也可以,问题是现在简单方式就做不到1ms的定时,就如楼主所说的一样。

然后一毫秒钟以内发一帧信息的话,115200应该发几个字节也是可以的,在退步,楼主说的那样,哪怕10ms也行,这样很多通信帧就可以完成了

Yawgmoth 发表于 2017-10-27 00:17:07

通过结果可以看出Sleep, GetTickCount都是10~35ms左右的时间跳跃,timeGetTime为1ms,QueryPerformanceCounter和QueryPerformanceFrequency根据CPU频率计时,可以到100ns。

takashiki 发表于 2017-10-27 07:06:29

立创商城-技术 发表于 2017-10-24 16:26
用软件也可以,比如用VC做一个DLL,精度其实很高,延时xx微秒(uS) 都可以。 然后C#调用DLL。...

精度高有个蛋用,进程一切换就煞笔了。vc嵌入汇编还能搞到ns级定时呢,然并卵。应用又没办法关中断

takashiki 发表于 2017-10-27 07:15:47

huangqi412 发表于 2017-10-25 10:01
以前测试,VC多媒体定时器,关掉别的乱七八糟软件,定时1MS,99%以上周期准确,偶有跳到几个MS到10多个MS时 ...

所以要保证精确度,只能是驱动,或者换系统,比如wince,对付1ms还算可以的。我测试过usb的sof包,真的是1ms一次哪怕电脑CPU占用100%了,要不然usb就掉了。而高精度定时器其实是高精度计时器,能保证啥时开启,却无法保证啥时关闭,这就悲剧了

霸气侧漏 发表于 2017-10-27 12:23:30

takashiki 发表于 2017-10-27 07:15
所以要保证精确度,只能是驱动,或者换系统,比如wince,对付1ms还算可以的。我测试过usb的sof包,真的是 ...

应该是这样的

marshallemon 发表于 2017-10-27 12:41:21

1a2b3c 发表于 2017-10-26 15:30
比如说一秒钟发1000帧信息,那么基本上就是1ms一次了,即使不用均匀分布的绝对1ms一次,但是平均下来是也 ...



我比较好奇的是,哪种场合需要这种机制?难道准备使用串口搞高速运动控制?为了弥补win的实时性的缺陷,把这1000帧拆分成多帧,下位机使用FIFO不行吗?非要1mS发送一帧?而且对于下位机来说实现高波特率貌似是通过降低采样率来实现的,这样用可靠性值得怀疑

1a2b3c 发表于 2017-10-27 12:48:54

marshallemon 发表于 2017-10-27 12:41
我比较好奇的是,哪种场合需要这种机制?难道准备使用串口搞高速运动控制?为了弥补win的实时性的缺陷 ...

千奇百怪的应用太多了,所以实际中完全存在我说的这个情况,因为我做的一个东西恰好就是要这样,而且还是国际标准...哈哈,

霸气侧漏 发表于 2017-11-14 14:15:21

rqiang 发表于 2017-10-23 11:24
https://msdn.microsoft.com/zh-cn/library/system.diagnostics.stopwatch(v=vs.110).aspx
这个可以拿来检 ...

再请教C#精度定时问题
https://www.amobbs.com/thread-5683320-1-1.html
(出处: amoBBS 阿莫电子论坛)


请看看这个帖子,谢谢

霸气侧漏 发表于 2017-11-14 14:16:04

1a2b3c 发表于 2017-10-26 15:25
晕,原来这里也有这个讨论,
昨天我还在另外一个帖子里面问呢,
https://www.amobbs.com/forum.php?mod=vie ...

再请教C#精度定时问题
https://www.amobbs.com/thread-5683320-1-1.html
(出处: amoBBS 阿莫电子论坛)


最新成果,但是精度还是有问题

霸气侧漏 发表于 2017-11-29 08:39:33

浮华一生 发表于 2017-10-23 11:27
有内核的定时函数接口   可以有几ms的精度吧

那个函数,指点一下先

霸气侧漏 发表于 2017-11-29 08:41:10

q457344370 发表于 2017-10-26 13:44
多媒体定时器MmTimer的网上例子很多,你自己找吧,
下边是用线程死等的,可以做到很小的周期,但是比较耗 ...

谢谢,我现在用多媒体定时器

霸气侧漏 发表于 2017-11-29 08:41:44

q457344370 发表于 2017-10-26 13:44
多媒体定时器MmTimer的网上例子很多,你自己找吧,
下边是用线程死等的,可以做到很小的周期,但是比较耗 ...

谢谢,我现在用多媒体定时器

Stm32Motor 发表于 2023-6-6 15:12:58

DPC定时器,我测试1MS的周期,最大抖动 +-0.2ms
页: [1]
查看完整版本: 怎样提升C#的定时器精度