задержка в микросекундах

Тема в разделе "LANGS.C", создана пользователем finger, 16 фев 2012.

  1. finger

    finger New Member

    Публикаций:
    0
    Регистрация:
    16 фев 2012
    Сообщения:
    3
    Трубется сделать задержку в 5-10 мкс. Нашёл такую конструкцию:

    int tkt;
    double PCFreq = 0.0;
    __int64 CounterStart = 0;

    void StartCounter()
    {
    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);

    PCFreq = double(li.QuadPart)/1000000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
    }
    double GetCounter()
    {
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
    }

    int zaderzhka() //функция организующая задержку
    {
    StartCounter();
    do {
    tkt = GetCounter();
    }
    while(tkt <= /" здесь выставляю задержку "/ );
    return 0;
    }

    Всё работает, но задержка не стабильная, прыгает (+-5 мкс) .
    Есть ли ещё какой-нибуль способ организовать задержку в микросекундах?

    Вычитал что можно вставку asm сделать, но я это не в состоянии сделать. (программирую полторы недели, работа требует)
    Есть какие-нибудь предложения?
    Пишу в C++ Buider 6
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    finger
    Данная задача не реализуется на ПК, в виду наличия вытесняющей многозадачности и неизвестных параметров системы. Для этого нужен микроконтроллер с достаточно известными параметрами.
    А зачем вам задержка 5 мкс?
     
  3. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    KeDelayExecutionThread, но это исключительно в ядре, и соответственно в драйвере который должен работать с неким устройством.

    а вообще есть некое извращение с помощью select из винсока
    http://stackoverflow.com/questions/85122/sleep-less-than-one-millisecond

    касаемо асма только это пришло в голову. задержка на приблизительное число тактов проца. чтобы
    это дело перевести в мкс полагаю следует рассчитать время одного такта

    Код (Text):
    1. // писал на визуал студии, хз как там билдер ключевые слова понимает
    2. #include "stdafx.h"
    3.  
    4. __declspec(naked) __forceinline void __fastcall DelayExecutionTicks(unsigned int TickCount)
    5. {
    6.     __asm
    7.     {
    8.         rdtsc
    9.         mov esi, eax
    10.         _loop:
    11.         rdtsc
    12.         sub eax, esi
    13.         cmp eax, ecx
    14.         jbe _loop
    15.         ret
    16.     }
    17. }
    18.  
    19.  
    20. int _tmain(int argc, _TCHAR* argv[])
    21. {
    22.     int i_thpriority;
    23.  
    24.     i_thpriority = GetThreadPriority(GetCurrentThread());
    25.    
    26.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
    27.     DelayExecutionTicks(0x300);
    28.     SetThreadPriority(GetCurrentThread(), i_thpriority);
    29.  
    30.     return 0;
    31. }
     
  4. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    Лет 5-7 назад здесь, на Васме, приводил пример, как можно делать точные маленькие задержки на циклах. Идея такая.

    1. Задержки выполняются в потоках с приоритетом TimeCritical циклами типа:

    for (i=0;i<N;i++) {
    _asm {
    sub eax, eax
    cpuid
    }
    }

    2. Тут надо знать точное значение N. Если просто измерить цикл для какого-нибудь N0, а потом увеличить или уменьшить N в нужное количество раз, то задержки получатся завышенными на несколько мкс. Дело в том, что задержка в цикле состоит из 2 частей, где одна часть С - собственно цикл, а другая D - накладные расходы.
    Поэтому предварительно делаем 2 цикла с разными N (например, N1=10000000 и N2=25000000) и измеряем их времена T1 и T2 при помощи RDTSC. Получаем систему двух уравнений:

    T1 = C*N1 + D
    T2 = C*N2 + D,

    из которой находим C=(T2-T1)/(N2-N1) и D=(T1*N2-T2*N1)/(N2-N1) - это константы для данного процессора с данной частотой. Я все это делал на этапе инициализации 1 раз.

    3. Пусть теперь нужно получить задержку T, имеем уравнение T = D + C*n, из которого находим точное значение n=(T-D)/C, и уже с этим количеством делаем цикл. Он будет продолжительностью T, и погрешности на практике очень хорошие: плюс минус 1 мкс.

    4. Но! Винда - не ось реального времени. Даже если выставить у потока приоритет Time Critcal, раз в 4-5 секунд этот поток все равно будет прерван, причем надолго. То есть, это означает, что такие маленькие точные задержки можно делать не непрерывно, а изредка, и почаще отдыхать - возвращая NormalPriority и делая Sleep(0). Если такой режим работы по условиям задачи не подходит - сорри, ищите другую ось.

    5. На многоядерных не пробовал, т.к. не было необходимости.
     
  5. Malfoy

    Malfoy New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2012
    Сообщения:
    698
    Прерывания маскируйте. Вы же не в досе.
     
  6. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Не проще ли воспользоваться мультимедийными таймерами с колбэком или ивентом? timeSetEvent, разрешение/точность задается timeBeginPeriod.
     
  7. Malfoy

    Malfoy New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2012
    Сообщения:
    698
    Dmitry_Milk
    Длительность кванта больше чем необходимая задержка. Посему планирование не избежно придётся вырубить. Но так как между квантами есчо и прерывания робят, а они не прекращаются принудительно, то и их выключить придётся. Тоесть либо диспатч из ISR, либо лок камня в цикле.