Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Микроконтроллеры (MCU) и микропроцессоры (MPU) > простая и надёжная организация временных задержек


Автор: supercelt 23.6.2016, 17:58
Простите, если тема уже поднималась. Очень требуется решить вопрос.

Инициализирую LCD, в даташите оговорено, поставьте тут задержку 37 микросекунд, там 20 милисекунд и ещё вот тут 200 микросекунд. Реализацию задержки на милисекунды нашёл на систике. 

Код

static __IO uint32_t TimingDelay;


// Time dalay-----------------------------------------------------------------
void Delay_ms(__IO uint32_t nTime)

  TimingDelay = nTime;
  while(TimingDelay != 0);
}

void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  { 
    TimingDelay--;
  }
}

//Time delay handler interrupt systick
void SysTick_Handler(void)
{
  TimingDelay_Decrement();
}


Всё работает. Задерживает точно. А вот задержка на микросекунды - там мнения
расходятся. Кто-то говорит сделать на таймере, кто-то ещё на чём-то. Но неужели нет какого-нибудь очень простого и надёжного способа? Конечно если речь идёт о точности, то таймер скорее всего единственное решение. А если этот таймер, последний понадобится для другого? 
У меня мысль возникла, может сделать в цикле for, только вот как узнать сколько времени занимает 1 итерация цикла, что бы точно выставить число, до которого считать


Автор: Romikgy 23.6.2016, 19:47
все данные в даташите на проц.... а если время вывода не критично , все микросекунды замени задержкой в 1 мс

Автор: baldman88 24.6.2016, 08:08
Все зависит от используемого контроллера. Точнее от его частоты. Организация задержек с микросекундной длительностью с помощью SysTick возможна на контроллерах с частотой от 72 МГц. Все дело в том, что в таком случае используются прерывания. А на вход в прерывание нужно 14 тактов. Плюс декремент счетчика и выход из прерывания. В общем получаем около 20 тактов. Если контроллер работает на 24 МГц, то из 24 тактов в микросекунду, около 20 (возможно даже больше 24) будут уходить на обработку прерывания SysTick. А когда работать остальному коду? На 48 МГц на обработку прерывания будет уходить половина процессорного времени. А вот на 72 МГц уже можно себе это позволить.
Но перед тем, как делать микросекундные задержки нужно настроить SysTick. Я, обычно, делаю так:
Код
static __IO uint32_t TimingDelay;

void Delay_Init(void)
{
    SystemCoreClockUpdate();
    /* Set SysTick interrupts once in us */
    if (SysTick_Config(SystemCoreClock / 1000000))
    {
        while(1);
    }
    NVIC_SetPriority(SysTick_IRQn, 0x00);
}

void Delay_us(uint32_t delay)
{
    TimingDelay = delay;
    while (TimingDelay > 0);
}

void Delay_ms(uint32_t delay)
{
    TimingDelay = delay * 1000;
    while (TimingDelay > 0);
}

void SysTick_Handler(void)
{
    if (TimingDelay > 0)
    {
        TimingDelay--;
    }
}

Автор: supercelt 24.6.2016, 20:38
У меня 24 мГц ((. Придётся делать 1 милисекундную задержку(

Автор: baldman88 24.6.2016, 22:08
Если не нужна супер точность, то можно сделать проще. Каждая итерация (инкремент или декремент) цикла while занимает 4 такта. Поэтому можно сделать так (для 24 МГц -- 1 микросекунда = 24 такта, а так как итерация занимает 4 такта, то значение задержки нужно умножато на 6):
Код
void Delay_us(uint32_t delay)
{
    uint32_t counter = delay * 6;
    while (counter > 0)
    {
        counter--;
    }
}

Учитывая что еще будут затрачиваться такты на вход и выход из функции (около 10-ти тактов), а так же на расчет переменной counter, задержка будет, примерно, на пол микросекунды больше. Хотя можно это учесть отняв эти расходы от counter. Возьмем в сумме 12 тактов накладных расходов, тогда нужно будет отнять 3 (12 / 4 = 3). Получится как-то так:
Код
void Delay_us(uint32_t delay)
{
    uint32_t counter = delay * 6 - 3;
    while (counter > 0)
    {
        counter--;
    }
}

Сам не пробовал, но, по идее, должно получиться.

Автор: Курсант 19.7.2016, 14:01
Здравствуйте!
Обычно я для таких целей использую метки времени и измерение временных интервалов между метками времени. Сейчас я использую 64-разрядные метки времени, которые не переполняются более 100 лет smile Если все временные интервалы будут небольшими, можно использовать и 32-разрядные метки времени. Нужно запустить таймер. Ещё нужна функция получения метки времени:
Код

uint32_t GetTimeStamp ( void ) {
return Timer1->Value;
}

После этого необходимы функции определения временных интервалов.
Код

uint32_t GetIntervalFrom ( uint32_t FromTimeStamp ) {
return ( GetTimeStamp () - FromTimeStamp );
}

uint32_t GetIntervalFromTo ( uint32_t FromTimeStamp, uint32_t ToTimeStamp ) {
return ( ToTimeStamp - FromTimeStamp );
}

uint32_t IsIntervalOverFrom ( uint32_t Interval, uint32_t FromTimeStamp ) {
return ( Interval < GetIntervalFrom ( FromTimeStamp ) );
}

uint32_t IsIntervalOverFromTo ( uint32_t Interval, uint32_t FromTimeStamp, uint32_t ToTimeStamp ) {
return ( Interval < GetIntervalFromTo ( FromTimeStamp, ToTimeStamp ) );
}


Теперь отсчёт требуемого интервала будет выглядеть так:
Код

void WaitForInterval ( uint32_t Interval ) {
uint32_t tmpTimeStamp = GetTimeStamp ();
while ( !IsIntervalOverFrom ( Interval, tmpTimeStamp ) );
}


Т.е. где-то у себя в коде можно записать так:
Код

int main ( void ) {
blah
blah
blah
WaitForInterval ( 1000 );   // Интервал в тиках таймера
blah
blah
blah
}


ИМХО. Пишу по памяти, без контрольной компиляции и на ходу улучшая когда-то работавший код. Ногами не пинайте если что.

Автор: supercelt 19.7.2016, 15:20
Спасибо! Это очень интересный вариант.

Автор: Crystaly 18.5.2018, 09:55
Цитата(supercelt @ 23.6.2016,  17:58)
Простите, если тема уже поднималась. Очень требуется решить вопрос.

Инициализирую LCD, в даташите оговорено, поставьте тут задержку 37 микросекунд, там 20 милисекунд и ещё вот тут 200 микросекунд. Реализацию задержки на милисекунды нашёл на систике. 


Эти микросекунды, которые вы указываете, скорее всего МИНИМАЛЬНЫЕ значения задержек. Реально можно больше. Программно делать такие задержки (имхо) бред. (но не все делается программно, есть еще направление аппаратных разработок ПЛИС и т.п. вот там это важно соблюдать)

Автор: Queenswu666 15.9.2020, 10:06
Модератор: Сообщение скрыто.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)