谢谢这位兄弟提醒。但多媒体定时器精度很高
windows定时器精度都不高,要看主机,每个主机延时不一样,还有界面的一些操作占用时间比较多,都有影响

解决方案 »

  1.   

    这位兄弟,我就是用Remon的串口类,他是开辟一个线程,然后发数据,

    m_hComm = CreateFile(szPort,                   // communication port string (COMX)
    GENERIC_READ | GENERIC_WRITE,  // read/write types
    0,                             // comm devices must be opened with exclusive access
    NULL,                          // no security attributes
    OPEN_EXISTING,                 // comm devices must use OPEN_EXISTING
    FILE_FLAG_OVERLAPPED,          // Async I/O
    0);                            // template must be 0 for comm devices可以看到他用的也是重叠IO
      

  2.   

    谢谢这位兄弟提醒。但多媒体定时器精度很高
    windows定时器精度都不高,要看主机,每个主机延时不一样,还有界面的一些操作占用时间比较多,都有影响
    谢谢这位兄弟,你的话里界面操作用时比较多,这点到时提醒我,我思考思考。
      

  3.   

    之前我分析下可能有三个原因:一个是串口发送的时候开辟了一个线程,这个线程用到临界区,有可能这个线程和定时器在某一时刻冲突;一个可能是MFC消息机制,消息级别比较低,经常要等消息队列中级别高的先执行,然后才执行;一个可能是ontimer本身精度比较低,所以出现问题,但这个问题在使用高精度定时器--多媒体定时器中还出现这个问题,说明不是最后这个原因,多媒体定时器中有发送消息,所以前两个的可能性比较大。通过不间断几个小时的串口监视,发现定时500ms时数据发送是没问题(至少现在没有),但是还是偶尔出现定时延迟100ms或提前几十ms的,平时的话定时器还是可以做到1ms精度的。这时定时器采用多媒体定时器,多媒体定时器中有发送消息。我自己觉着第二个原因比较大
      

  4.   

    windows 定时器 就是 dos 的 定时 中断 18/每秒。
    因为优先度比较 低 ,所以 总是有 误差 的,但 不 会 几百 ms。
      

  5.   

    上面的图片是昨天用AccessPort137监视串口数据的,计算553-130=423ms,当时定时器是200ms,下一条数据没截出来,记得是567吧,与553相差14ms,所以接收到的数据乱码。
      

  6.   

    最新截图,定时也是200ms,用多媒体定时器,计算前面两条数据间隔469-54=415ms,后面两条数据间隔481-469=12ms,郁闷中if ((TimerID = timeSetEvent(SENDTIME, 1, (LPTIMECALLBACK)TimerProc, (DWORD)this, TIME_PERIODIC)) == 0)
    {
    MessageBox(_T("定时器启动失败"), _T("错误"), MB_OK|MB_ICONWARNING);
    }#define SENDTIME                    200          //间隔时间郁闷中
      

  7.   

    “AccessPort137”会不会有别的问题。
    会不会 过度 包装。
      

  8.   

    schlafenhamster兄弟你的回复真是太及时了,这个论坛不能连续发3次,昨天还想加上我的测试呢。AccessPort137包装肯定是有的,而且它计字节数不准。 不过还是可以用的。下面是我昨天的测试。
    void CALLBACK TimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
    {
    static bool bBenginEnd = false;
    if (QueryPerformanceFrequency(&Frequency))
    {
    //*
    bBenginEnd = !bBenginEnd;
    if (bBenginEnd)
    {
    QueryPerformanceCounter(&BeginTime);
    }
    else
    {
    QueryPerformanceCounter(&EndTime);
    }
    //*/ /*
    QueryPerformanceCounter(&BeginTime);
    //*/ CtestDlg* testdlg = (CtestDlg*)dwUser;
    testdlg->SendMessage(MYTIMER_MSG, (WPARAM)uID, (LPARAM)0); /*
    QueryPerformanceCounter(&EndTime);
    //*/ if (EndTime.QuadPart > BeginTime.QuadPart)
    {
    TRACE("using time is %lu us\n", ((1000000*(EndTime.QuadPart - BeginTime.QuadPart))/ Frequency.QuadPart));
    }
    }
    }
    根据woshi_hujunjun的思路,在多媒体定时器回调函数TimerProc中进行两项简单测试,一个测试TimerProc函数被调用的时间间隔;一个测试自定义定时消息MYTIMER_MSG的处理时间(详细代码如上),两项测试分别单独进行直到检测到数据错误。经几个小时测试发现回调函数TimerProc函数被调用的时间间隔一直在200ms左右,自定义定时消息MYTIMER_MSG的处理时间不超过10ms,SendMessage发送消息之后要等待消息返回才进行下一步操作,所以可以粗略测试,在测试过程中还发现鼠标点击最小化、最大化网页,数据发送都会有一定的延迟。因此我怀疑我用的串口类有问题,我用的串口类是Remon Spekreijse的串口类(刚学串口,不会写,网上有源码,所以..),可能是在设置写事件(SetEvent(m_hWriteEvent);)之后,由于某个原因串口类没收到这个写事件,所以就有了如标题一样的结果。这是我的猜测,我感觉一个人的脑袋瓜不够,各位兄弟给点思路或见解啊,求解求指导。(顺便说下我用这个串口类遇到一个比较郁闷的问题,就是它在win7下定时发送数据不行,但在window xp却可以,后来弄了好久才解决这个问题,求吐血)。以下是部分测试数据
    1、TimerProc函数被调用的时间间隔
    using time is 200005 us
    using time is 200061 us
    using time is 200054 us
    using time is 200011 us
    using time is 200070 us
    using time is 200130 us
    using time is 200074 us
    using time is 199945 us
    using time is 200003 us2、定时消息MYTIMER_MSG的处理时间
    using time is 4540 us
    using time is 3540 us
    using time is 4418 us
    using time is 3476 us
    using time is 4061 us
    using time is 4621 us
    using time is 7818 us
    using time is 4457 us
    using time is 2843 us3、点击IE网页最大化按钮时数据发送的延迟时间(捕捉到一组数据)
    16:07:56.432(时间格式:分:秒:毫秒)
    16:07:56.632
    16:07:56.953
    16:07:57.114
    16:07:57.233
    16:07:57.433
    16: 07:57.632
      

  9.   

    微软自带的 MScomm 不能用 ?
      

  10.   

    当初选择的时候听说MScomn使用的时候有bug多多,就没考虑了。
      

  11.   

    我是 不喜欢用 串口控件的 , 从 CreateFile 起 就可以了。
      

  12.   

    这位兄弟,我就是用Remon的串口类,他是开辟一个线程,然后发数据,

    m_hComm = CreateFile(szPort,                   // communication port string (COMX)
    GENERIC_READ | GENERIC_WRITE,  // read/write types
    0,                             // comm devices must be opened with exclusive access
    NULL,                          // no security attributes
    OPEN_EXISTING,                 // comm devices must use OPEN_EXISTING
    FILE_FLAG_OVERLAPPED,          // Async I/O
    0);                            // template must be 0 for comm devices可以看到他用的也是重叠IO
    虽然还不清楚阻塞是不是导致你的问题的原因,不过单纯就上面这个问题,打开串口时使用OVERLAPPED(话说WindowsNT以后都不支持非OL了)不一定意味着操作过程的效果是非阻塞的。比如要是LastError是IOPending时就一直while下去的话、或者WaitForXXXObject里用了INFINATE,这种跟阻塞比起来没太大优势。
    个人理解哈,学习关注中...
      

  13.   

    这位兄弟,我就是用Remon的串口类,他是开辟一个线程,然后发数据,

    m_hComm = CreateFile(szPort,                   // communication port string (COMX)
    GENERIC_READ | GENERIC_WRITE,  // read/write types
    0,                             // comm devices must be opened with exclusive access
    NULL,                          // no security attributes
    OPEN_EXISTING,                 // comm devices must use OPEN_EXISTING
    FILE_FLAG_OVERLAPPED,          // Async I/O
    0);                            // template must be 0 for comm devices可以看到他用的也是重叠IO
    虽然还不清楚阻塞是不是导致你的问题的原因,不过单纯就上面这个问题,打开串口时使用OVERLAPPED(话说WindowsNT以后都不支持非OL了)不一定意味着操作过程的效果是非阻塞的。比如要是LastError是IOPending时就一直while下去的话、或者WaitForXXXObject里用了INFINATE,这种跟阻塞比起来没太大优势。
    个人理解哈,学习关注中...嗯!兄弟,照你这样说,不用while,不用INFINATE,如何实现非阻塞式操作?定期检测?超时设定或其他?我现在使用的CSerialPort串口类就是设定超时的方式。有没有在串口接收到数据之后有个回调函数通知我们,这样的话我们就不必等了。
      

  14.   

    这位兄弟,我就是用Remon的串口类,他是开辟一个线程,然后发数据,

    m_hComm = CreateFile(szPort,                   // communication port string (COMX)
    GENERIC_READ | GENERIC_WRITE,  // read/write types
    0,                             // comm devices must be opened with exclusive access
    NULL,                          // no security attributes
    OPEN_EXISTING,                 // comm devices must use OPEN_EXISTING
    FILE_FLAG_OVERLAPPED,          // Async I/O
    0);                            // template must be 0 for comm devices可以看到他用的也是重叠IO
    虽然还不清楚阻塞是不是导致你的问题的原因,不过单纯就上面这个问题,打开串口时使用OVERLAPPED(话说WindowsNT以后都不支持非OL了)不一定意味着操作过程的效果是非阻塞的。比如要是LastError是IOPending时就一直while下去的话、或者WaitForXXXObject里用了INFINATE,这种跟阻塞比起来没太大优势。
    个人理解哈,学习关注中...嗯!兄弟,照你这样说,不用while,不用INFINATE,如何实现非阻塞式操作?定期检测?超时设定或其他?我现在使用的CSerialPort串口类就是设定超时的方式。有没有在串口接收到数据之后有个回调函数通知我们,这样的话我们就不必等了。这个,咱还真不知道。
    话说咱其实水平也低——看咱滴等级就知道菜鸟跟菜鸟——但也干脆直接用WinAPI(这样才会经常出现各种意想不到的问题,但反过来想想也能多锻炼些吧),读数据的话然后开个线程死循环定期readfile到一个有临界区的buffer里,主线程需要时到临界区里取这个buffer。贼原始的法子。那个死循环的线程本身readfile是相当于阻塞的(Pending了就Sleep一小下,OVERLAPPED里的hEvent等到了就continue,超时则放弃)。这个笨方法我还想找机会看看咋改进的说
      

  15.   

    thundersung兄弟的思路很不错。也许有另外一种方法可以改进,那就是使用hook api,启用钩子,提升权限,监听串口,也许这样的方式能够在第一时间内发送或接收数据,不会有现在的问题出现,表示这个方法没试过。话说一个帖子最高才100分,有点少。苦恼郁闷中!走过路过不要错过,求有用过Remon Spekreijse编写的CSerialPort串口类来发送接收数据的兄弟、前辈,或者串口这方面的大牛指点迷津。我自己也改改代码,分析分析。也许这个过程很痛苦,但我会坚持!
      

  16.   

    串口助手CommAssist
    http://www.cnblogs.com/EdmundDwyane/p/3443074.html
      

  17.   


    串口助手这个对我来说没多大用,试了一下,貌似很多bug。而且同样出现如标题描述一样的现象。以下是捕捉到的一组数据。
    早上看了你写的那个CxComm类,个人感觉要是同一时刻同一串口有读写操作那就悲剧了。你能写出这串口类很不错,还是感谢你的帮助。
      

  18.   

    我使用CSerialPort类每个350ms发送一条报文,接收都没问题,发送报文我是重新开辟一条线程的。
    我的从站也是一个表计,350ms是我测试出来大致较小的时间,在小可能会出现报文不完整等情况
    部分代码:
    while(m_bSend==TRUE)
    {
      
    for(int i=0;i<IEDCount;i++)
    {
     
          Send_Yc(i+1);
      //  long t1,t2,t;
         long t1=GetTickCount();//程序段开始前取得系统运行时间(ms)
     while(1)
     {
     long t2=GetTickCount();//程序段结束后取得系统运行时间(ms)
         long t=t2-t1;//前后之差即 程序运行时间 (ms)
     if(t>350) 
     {
     Send_Yx(i+1);//发送报文
     break;
     }
     }
     Sleep(350);
    }
    }
      

  19.   

    350ms吗!如果是350毫秒可以测试一下,非常感谢兄弟你提供的这个数据,500是我测试出来比较小的,不知道350能不能通过,期待中。话说你已经用了GetTickCount为啥还要Sleep?不解。
      

  20.   

    Sleep是为了使不同从站地址发报文的时间间隔,其实使用GetTickCount再得个350ms间隔也行,当时为了方便就写了个Sleep。
      

  21.   

    for循环为了发不同的从站地址的报文,Send_Yc(i+1)和Send_Yx(i+1)为了发送不同种类的报文
      

  22.   

    不是定时器的问题,是串口发送速度不够。你让它200MS发送一次,可是发送数据本身需要400MS,不就延时了吗。要是用SetTimer还好,系统会移除多余的WM_TIMER消息,只留一个在消息队列。要是用timeSetEvent,那就完了,随时间推迟越来越堵。
    你不妨把缓冲区大小、波特率等等增大或缩小试试,或者设法提高发送数据本身的速度。
      

  23.   


    串口助手这个对我来说没多大用,试了一下,貌似很多bug。而且同样出现如标题描述一样的现象。以下是捕捉到的一组数据。
    早上看了你写的那个CxComm类,个人感觉要是同一时刻同一串口有读写操作那就悲剧了。你能写出这串口类很不错,还是感谢你的帮助。把你发现的BUG都告诉我,谢了。
      

  24.   

    350ms貌似不行了。还得改改这个问题还没解决啊不应该是发送时间的问题吧,哪里需要那么长时间啊,最多也就是发几十个字节的数据。比如波特率是9600,那1ms都要发1.2个字节,你这里才发14个字节,能耗多少时间啊 这个发送速度不会错的看看 ontimer 里面哪里耗时多了吧,还是
      

  25.   

    如果不是 ontimer里面耗时过多的话 ,就是你的串口类有问题。
      

  26.   


    发送数据本身不需要400ms,看我之前贴的截图,正常情况下从发送数据到接收第一个数据之间都没有超过50ms的,非正常情况下就是我现在的问题。关于settimer和timeSetEvent没像你研究那么深,学习了。
    关于bug,没有打开串口就点击自动发送会弹出提示,但是没有关闭定时器,所以提示就有N多个,关都来不及,只能杀进程。在200ms下发送数据,接收丢字节很多(用其他的串口调试助手没发现这种情况或一天丢一两个字节)。
      

  27.   

    多媒体定时器timeSetEvent()函数,定时精度为ms级。
    对于精确度要求更高的定时操作,可以试试QueryPerformanceFrequency()
    和 QueryPerformanceCounter()函数。
      

  28.   

    兄弟我这问题一测试就要好几个小时,程序改改,拖拖拉拉,一天测试最多也就两回。你串口中断的问题我之前看了,我也不知道怎么弄。ontimer现在不用了。到底哪里出问题,现在我也不敢下定论。刚才仔细看代码的时候发现之前测试TimerProc函数被调用的时间间隔有问题(详细代码请看17楼),就是当EndTime.QuadPart < BeginTime.QuadPart的情况没写出来。这样的话实际有两个时间间隔,而我只写出其中一个时间间隔。
      

  29.   

    兄弟我这问题一测试就要好几个小时,程序改改,拖拖拉拉,一天测试最多也就两回。你串口中断的问题我之前看了,我也不知道怎么弄。ontimer现在不用了。到底哪里出问题,现在我也不敢下定论。刚才仔细看代码的时候发现之前测试TimerProc函数被调用的时间间隔有问题(详细代码请看17楼),就是当EndTime.QuadPart < BeginTime.QuadPart的情况没写出来。这样的话实际有两个时间间隔,而我只写出其中一个时间间隔。你不如先把循环中的其它代码全部注释掉,再一段一段的添加上,看看添上哪段后出问题,这样还可能快一点。或者 
     一段 接一段的注释掉,看看注释掉哪一段就正常了,都可以尝试一下这样也不用该代码什么的,不停的测试就好了
      

  30.   

     在接收完一帧报文立即使用:PurgeComm(mycom.m_hComm, PURGE_RXCLEAR);//清空接收缓冲区,
      我就是这么干的 
      

  31.   

    我搜索了一下“Remon的串口”
    好像 有 好多年了 反应也 可以。
    那就 重起炉灶 搞一个 最简单的 程序 试试。
      

  32.   

    woshi_hujunjun兄弟你说一段一段注释不停的测试,这个方法最费时。老实说吃力不讨好,事倍功半。
      

  33.   

    “PC用cserialport类setTimer定时200ms发送数据给MCU,有时定时混乱,不是200ms而是420ms,下一个数据又间隔十几毫秒发送,导致数据接收出现乱码,选用多媒体定时器一样出现此问题。”总觉得 windows 下 ,要 按时 做些事是困难的,定时器 误差 不是 问题, 问题是 定时器 消息 可能 丢失, 200ms 定时, 丢一个 ,就是 200 到 400 ms。提高 线程的 优先度 到 ‘实时’级, 可能 会 解决这个问题, 但 别的程序 的 响应 就会 有问题。
      

  34.   

    即:
    m_pThread->SetThreadPriority(THREAD_PRIORITY_TIME_CRITICAL);//
    发送完毕后,在线程中 Sleep(200);