2016-06-20 3 views
0

Я пытаюсь создать несколько PWM-волн, используя таймер TC в Arduino Due. Моя проблема в том, что я не могу генерировать точные частоты, используя такие таймеры.Как создать точный таймер в Arduino Due

Вот простой код для того, что я пытаюсь сделать:

static void setupTimer(uint32_t freq_desired) 
{ 

uint32_t ul_div; 
uint32_t ul_tcclks; 
uint32_t ul_sysclk = sysclk_get_cpu_hz(); 
uint32_t counts; 

// Configure PMC 
pmc_enable_periph_clk(ID_TC); 

// Configure TC for the given frequency and trigger on RC compare. 
tc_find_mck_divisor(
    (uint32_t)freq_desired, // The desired frequency as a uint32. 
    ul_sysclk,    // Master clock freq in Hz. 
    &ul_div,    // Pointer to register where divisor will be stored. 
    &ul_tcclks,    // Pointer to reg where clock selection number is stored. 
    ul_sysclk);    // Board clock freq in Hz. 

tc_init(TC0, CHANNEL, ul_tcclks | TC_CMR_CPCTRG); 

// Find the best estimate of counts, then write it to TC register C. 
counts = (ul_sysclk/ul_div)/freq_desired; 

tc_write_rc(TC0, 0, counts); 

// Enable interrupts for this TC, and start the TC. 
tc_enable_interrupt(TC0, CHANNEL0, TC_IER_CPCS);    // Enable interrupt. 

tc_start(TC0,CHANNEL0);   // Start the TC. 

NVIC_DisableIRQ(TC_IRQn); 
NVIC_ClearPendingIRQ(TC_IRQn); 
NVIC_SetPriority(TC_IRQn,configMAX_PRIORITIES); 
NVIC_EnableIRQ(TC_IRQn); 
} 

Тогда на ручки таймера все, что я делаю, спровоцировав выходной контакт с:

ioport_toggle_pin_level(OUT_PIN); 

Проблема заключается в том что когда я пытаюсь, например, генерировать волну 1000 Гц (давая, конечно, 2000 Гц для таймера), он отлично работает. Но когда я пытаюсь, например, 3427 Гц, тогда он генерирует только 3420 Гц или что-то в этом роде.

Есть ли у вас какие-либо идеи, как это исправить? Я попытался добавить round() для вычисления значения «counts» , это помогло немного, но все же не очень точно.

Заранее спасибо.

+0

Не думаю, что вы можете сделать это точным, потому что 16 000 000 (системная тактовая частота) неразделимо на 3427. – MikeCAT

+0

Подумайте, как @MikeCAT. Вероятно, проблема заключается в множественности с 16 МГц ... – jabujavi

+0

Да, это то, о чем я тоже думал (я использую Due, поэтому часы составляют 84 МГц). Так есть ли другой способ получить эту точность с использованием других механизмов, чем таймеры TC? –

ответ

0

Я предполагаю, что TC0 является 8-разрядным таймером? Вы не получите хорошую точность в «необычных» интервалах с 256 вариантами.

Попробуйте использовать 16-разрядный таймер. Я видел несколько «Due Timer» на GitHub, если они вам понадобятся.

Из моих расчетов:

Получить 8-разрядный делитель с Prescale 256:

84MHz/3427/256 = 95.75 divisor, round to 96 

, который генерирует

84MHz/256/96 = 3,417.96 Hz 

Но с 16 бит без Prescale:

84MHz/3427 = 24,511.23 divisor, truncate to 24511 

, который генерирует

84MHz/24511 = 3,427.03 Hz 

Поскольку вычисленный делитель 24511 соответствует в 16-битное значение, вы получили много ближе к выбранной скорости.

И, конечно же, если TC0 на самом деле является 16-разрядным таймером, то есть что-то еще не так! ;-) Удачи!

0

TC0 - 24 бит. все регистры периода таймера по истечении 24 бит. при использовании pwm регистры счетчика периода 16 бит

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