2015-03-12 4 views
0

Я пытаюсь реализовать протокол Dallas OneWire, но у меня возникли проблемы с созданием микросекундной задержки на STM32l-Discovery.Как сделать микросекундный точный таймер на плате ARM STM32L-Discovery?

Как реализовать таймер, достаточно точный, чтобы задержать программу для микросекунд?

ответ

3

Для начала я должен сказать вам, что нет возможности выполнить точную задержку использования usec с помощью программного обеспечения. Даже если вы используете систему на основе прерываний, у вас будут задержки. Конечно, вы можете добиться большей точности с более высокими частотами процессора.

Для подключения с 1-Wire устройства вы можете использовать:

  • внешний интерфейс, как DS2482-100
  • Программное обеспечение реализации 1-проводный с использованием пин-опроса.

Для второго решения вам необходимо вызвать задержку на основе программного обеспечения. Вы можете сделать задержку опроса флагов или задержку опроса флагов на основе прерываний. В обоих случаях у вас будет , и убедитесь, что прошло определенное количество времени, но вы не можете быть уверены, насколько подходит больше времени. Это связано с задержкой процессора, тактами CPU и т. Д.

Например, рассмотрим следующую реализацию. Мы программируем HW TIMER для непрерывного подсчета и проверяем значение TIMER. Мы называем «Jiffy» время между клещами и тиков каждого таймера таймерами максимальное значение:

Низкий уровень водителя часть (например: driver.h)

// ... 
#define JF_TIM_VALUE   (TIM7->CNT) 
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies); 
// ... 

Низкий уровень водителя часть (например: driver.c)

// ... 
#include <stm32l1xx.h> 
#include <misc.h> 
#include <stm32l1xx_rcc.h> 
#include <stm32l1xx_tim.h> 
/* 
* Time base configuration using the TIM7 
* \param jf_freq The TIMER's frequency 
* \param jiffies The TIMER's max count value 
*/ 
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) { 
    uint32_t psc=0; 

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); 
    SystemCoreClockUpdate(); 

    if (jf_freq) 
     psc = (SystemCoreClock/jf_freq) - 1; 

    if (psc < 0xFFFF)  TIM7->PSC = psc; 
    else     return 1; 

    if (jiffies < 0xFFFF) TIM7->ARR = jiffies; 
    else     return 1; 
    TIM7->CR1 |= TIM_CR1_CEN; 
    return 0; 
} 
// ... 

система Промежуточное Jiffy с некоторыми реализациями задержки jiffy.h:

#include "string.h" 

typedef int32_t jiffy_t; // Jiffy type 4 byte integer 
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //Pointer to setfreq function 

typedef volatile struct { 
    jf_setfreq_pt setfreq;  // Pointer to driver's timer set freq function 
    jiffy_t  *value;  // Pointer to timers current value 
    uint32_t  freq;   // timer's frequency 
    uint32_t  jiffies;  // jiffies max value (timer's max value) 
    jiffy_t  jpus;   // Variable for the delay function 
}jf_t; 


/* 
* ============= PUBLIC jiffy API ============= 
*/ 

/* 
* Link functions 
*/ 
void jf_link_setfreq (jf_setfreq_pt pfun); 
void jf_link_value (jiffy_t* v); 

/* 
* User Functions 
*/ 
void jf_deinit (void); 
int jf_init (uint32_t jf_freq, uint32_t jiffies); 

jiffy_t jf_per_usec (void); 
void jf_delay_us (int32_t usec); 
int jf_check_usec (int32_t usec); 

jiffy.c:

#include "jiffy.h" 

static jf_t _jf; 
#define JF_MAX_TIM_VALUE  (0xFFFF) // 16bit counters 

//Connect the Driver's Set frequency function 
void jf_link_setfreq (jf_setfreq_pt pfun) { 
    _jf.setfreq = pfun; 
} 

// Connect the timer's value to jiffy struct 
void jf_link_value (jiffy_t* v) { 
    _jf.value = v; 
} 

// De-Initialize the jf data and un-connect the functions 
// from the driver 
void jf_deinit (void) { 
    memset ((void*)&_jf, 0, sizeof (jf_t)); 
} 

// Initialise the jf to a desired jiffy frequency f 
int jf_init (uint32_t jf_freq, uint32_t jiffies) { 
    if (_jf.setfreq) { 
     if (_jf.setfreq (jf_freq, jiffies)) 
     return 1; 
     _jf.jiffies = jiffies; 
     _jf.freq = jf_freq; 
     _jf.jpus = jf_per_usec(); 
     return 0; 
    } 
    return 1; 
} 

// Return the systems best approximation for jiffies per usec 
jiffy_t jf_per_usec (void) { 
    jiffy_t jf = _jf.freq/1000000; 

    if (jf <= _jf.jiffies) 
     return jf; 
    else 
     // We can not count beyond timer's reload 
     return 0; 
} 

/*! 
* \brief 
* A code based delay implementation, using jiffies for timing. 
* This is NOT accurate but it ensures that the time passed is always 
* more than the requested value. 
* The delay values are multiplications of 1 usec. 
* \param 
* usec  Time in usec for delay 
*/ 
void jf_delay_us (int32_t usec) { 
    jiffy_t m, m2, m1 = *_jf.value; 

    usec *= _jf.jpus; 
    if (*_jf.value - m1 > usec) // Very small delays will return here. 
     return; 

    // Delay loop: Eat the time difference from usec value. 
    while (usec>0) { 
     m2 = *_jf.value; 
     m = m2 - m1; 
     usec -= (m>0) ? m : _jf.jiffies + m; 
     m1 = m2; 
    } 
} 

/*! 
* \brief 
* A code based polling version delay implementation, using jiffies for timing. 
* This is NOT accurate but it ensures that the time passed is always 
* more than the requested value. 
* The delay values are multiplications of 1 usec. 
* \param 
* usec  Time in usec for delay 
*/ 
int jf_check_usec (int32_t usec) { 
    static jiffy_t m1=-1, cnt; 
    jiffy_t m, m2; 

    if (m1 == -1) { 
     m1 = *_jf.value; 
     cnt = _jf.jpus * usec; 
    } 

    if (cnt>0) { 
     m2 = *_jf.value; 
     m = m2-m1; 
     cnt-= (m>0) ? m : _jf.jiffies + m; 
     m1 = m2; 
     return 1; // wait 
    } 
    else { 
     m1 = -1; 
     return 0; // do not wait any more 
    } 
} 

Хммм вы сделали это до здесь. Nice

Итак, теперь вы можете использовать его в своем приложении, как это: main.c:

#include "driver.h" 
#include "jiffy.h" 

void do_some_job1 (void) { 
    // job 1 
} 
void do_some_job2 (void) { 
    // job 2 
} 
int main (void) { 
    jf_link_setfreq ((jf_setfreq_pt)JF_setfreq); // link with driver 
    jf_link_value ((jiffy_t*)&JF_TIM_VALUE); 
    jf_init (1000000, 1000); // 1MHz timer, 1000 counts, 1 usec per count 

    // use delay version 
    do_some_job1(); 
    jf_delay_us (300); // wait for at least 300 usec 
    do_some_job1(); 

    // use polling version 
    do_some_job1(); 
    while (jf_check_usec (300)) { 
     do_some_job2(); // keep calling for at least 300 usec 
    } 
} 
+0

Спасибо за этот удивительный и экспансивный ответ. –

Смежные вопросы