Почему нельзя использовать Systick и Timer1 одновременно - PullRequest
1 голос
/ 27 мая 2020

Я использую таймер Systick для создания задержки, обработчик systick происходит раз в микросекунду (1 мкс).

Кроме того, я использую TIM1, его обработчик выполняется раз в секунду (1 с). Внутри обработчика timer1 я переключаю светодиод.

В основной функции внутри while l oop я переключаю другой светодиод (другой, чем в обработчике timer1), здесь функция задержки использует Systick.

Обработчик timer1 выполняется, как ожидалось, но проблема в том, что while l oop в основной функции никогда не выполняется.

Любая помощь?

volatile uint32_t i=0;

void TIM1_UP_TIM10_IRQHandler(void)
{
    NVIC_ClearPendingIRQ(TIM1_UP_TIM10_IRQn);   
    i ^= 1;
    if(i == 1)
        LED_On(0);
    else
        LED_Off(0);
    TIM1->SR &= ~(1 << 0); 
}

int main(void)
{
    NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 32);
    NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

    LED_Initialize();
    RCC->APB2ENR |= (1 << 0); // Enable Timer1 clock

    TIM1->CR1 &= ~(1 << 4);  // Set the direction of timer to be upcounter
    TIM1->DIER |= (1 << 0);  // Enable tim1 interrupt request

    TIM1->PSC = 15999;  // each count takes 1 msec 
    TIM1->ARR = 1000;   //each 1 sec an overflow update event occurs
    TIM1->CR1 |= (1 << 0);

    SysTick_Init(16000000/1000000);

    while(1)
    {       
        LED_On(1);
        Delay_MS(5000);
        LED_Off(1);
        Delay_MS(5000);
    }

    return 0;
}

Ответы [ 3 ]

3 голосов
/ 27 мая 2020

Одна микросекунда неоправданно быстро для прерывания SYSTICK, особенно при работе на частоте всего 16 МГц. Вероятно, ваша система тратит почти 100% своего времени на подсчет тиков обработчика прерываний.

Даже если она может поддерживать частоту прерываний 1 МГц, если Delay_MS(5000) - это задержка в 5000 периодов SYSTICK, тогда вы будет переключать светодиод и 100 Гц и не будет воспринимать мигание, только более тусклое освещение. *

SysTick_Init( 16000000 / 1000 ) ;

Хотя я бы предложил на самом деле:

SysTick_Init( SystemCoreClock / 1000 ) ;

, чтобы ваш код адаптировался к изменениям тактовой частоты - поскольку 16 МГц - довольно скромная скорость для запуска STM32.

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

3 голосов
/ 27 мая 2020
  1. если ваши часы 16 МГц и вы хотите, чтобы прерывания происходили каждые 16 часов, теперь он будет работать. В лучшем сценарии прекращения (запуск кода из RAM et c) вам потребуется как минимум 11 тактов для входа в обработчик прерывания и 6 тактов для выхода из него, что больше, чем время между прерываниями.

  2. Перебивать каждого нас - плохая идея, даже если ты бежишь быстрее. Устройство с частотой 168 МГц будет иметь только 168 тактов между прерываниями. Допустим, ваш обработчик будет работать в течение 20 часов + 11 + 6 = ~ 40 часов. Это значит, что 25% процессорного времени уйдет на увеличение переменной !!! Не делать это. На многих других (макс. Тактовая частота 72 или 80 МГц) будет еще хуже.

  3. Если вы хотите, чтобы задержка от США, сделайте что-то вроде этого (если вы перезагрузите счетчик, вам нужно принять это во внимание ). Код предназначен только для демонстрации идеи

#define TICKSPER_uS 80

void delay_us(uint32_t uS)
{
    uint32_t endCnt = SysTick -> VAL + uS * TICKSPER_uS;
    while(SysTick -> VAL < endCNT);
}   
0 голосов
/ 27 мая 2020

Это моя функция задержки для использования c

//==============================================================================
static  uint32_t    timeMicroSecDivider = 0;
extern  uint32_t    uwTick;

//==============================================================================
//  The SysTick->LOAD match the uC Speed / 1000.
//  If the uC clock is 80MHz, the the LOAD is 80000
//  The SysTick->VAL is the decrement counter from (LOAD-1) to 0
//==============================================================================
uint64_t getTimeMicroSec()
{
  if ( timeMicroSecDivider == 0)
  {
    //  Number of clock by micro second
    timeMicroSecDivider = SysTick->LOAD  / 1000;
  }
  return( (uwTick * 1000) + ((SysTick->LOAD - SysTick->VAL) / timeMicroSecDivider));
}

//==============================================================================
void delayTimeMicroSec(uint32_t delay)
{
  uint64_t tickstart = getTimeMicroSec();

  while ((getTimeMicroSec() - tickstart) < delay)
    ;
}
...