Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: tiny2313. приостановить таймер
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
tazik
Друг попросил сделать генератор синусоидального сигнала частотой примерно от 3 до 15 Гц. Соственно, это сделал. Загвоздка в том, как изменять генерируемую частоту с дискретностью, скажем 0.1 Гц. Синус генерирую с помощью таймера Т1 в режиме PWM. Значение PWM беру из таблицы и обновляю в обработчике прерывания при каждом достижении пилой вершины. Для уменьшения частоты генерируемого сигнала пытаюсь останавливать таймер Т1 в каждом прерывании на некоторое время. При этом, почему-то искажается форма сигнала.
Вопросы:
1. как правильно регулировать частоту генерируемого сигнала?
2. почему форма сигнала так искажается?

Нажмите для просмотра прикрепленного файла

код (tiny2313, тактовая частота 8МГц):

CODE
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "sine_table.h"

static uint16_t step_counter;
uint8_t kvadrant;
uint8_t time_delay;

void IOInit(void){
DDRB=(1<<PB3);
}

void Timer1Init(void){
ICR1=0x01FF;
TCCR1A=(1<<COM1A1);
TCCR1B=(1<<WGM13)|(1<<CS10);
TIMSK=(1<<TOV1);
}

ISR(TIMER1_OVF_vect){

TCCR1B&=~(1<<CS10); //останавливаю таймер
_delay_us(20); //пытаюсь сделать задержку, если нулевая, то искажений нет
TCCR1B|=(1<<CS10); //запускаю таймер вновь

switch(kvadrant){
case 1:{
OCR1A=pgm_read_word(pSine+step_counter);
step_counter++;
if (step_counter==511) kvadrant=2;
break;
};
case 2:{
OCR1A=pgm_read_word(pSine+step_counter);
step_counter--;
if (step_counter==0) kvadrant=3;
break;
};
case 3:{
OCR1A=0x1FF-pgm_read_word(pSine+step_counter);
step_counter++;
if (step_counter==511) kvadrant=4;
break;
};
case 4:{
OCR1A=0x1FF-pgm_read_word(pSine+step_counter);
step_counter--;
if (step_counter==0) kvadrant=1;
break;
};
};
};

int main(void){

OCR1A=0x10;
IOInit();
Timer1Init();
sei();
step_counter=511;
kvadrant=4;

while(1){

_delay_ms(500);
};
}
SasaVitebsk
Непонятно зачем что-то останавливать?

Частота определяется делителем таймера с учётом квантования. Ну например вы хотите запустить мегу на 8МГц, получить 16 ступенек на синус. Для этого вы должны создать таблицу из 16 значений определяющих значение сигнала с шагом Pi/8. Значения в таблице - процентные. Далее для получения нужной частоты Fi надо Fclk/(Fi*16). То есть получить делитель периода ступеньки. Значение ШИМа - есть значение периода * соответствующий процент из таблицы.

Есть соответствующий режим таймера.
tazik
ок, то есть предлагаете использовать делитель тактовой частоты? Дело в том, что частоту генерируемого сигнала хочется менять плавно. А делителем получится только дискретно: CLK, CLK/2, CLK/4.... Отсюда и мои выкрутасы с задержкой.
rezident
Цитата(tazik @ Nov 29 2009, 15:50) *
Дело в том, что частоту генерируемого сигнала хочется менять плавно. А делителем получится только дискретно: CLK, CLK/2, CLK/4.... Отсюда и мои выкрутасы с задержкой.
Почитайте статью Леонида Ивановича DDS: прямой цифровой синтез частоты. Все проще, нужно только вникнуть.
tazik
Цитата(rezident @ Nov 29 2009, 19:25) *
Почитайте статью Леонида Ивановича DDS: прямой цифровой синтез частоты. Все проще, нужно только вникнуть.


Ага, спасибо! Как сам не додумался, ужос (
defunct
Цитата(tazik @ Nov 29 2009, 12:50) *
Дело в том, что частоту генерируемого сигнала хочется менять плавно.

Не изменяя алгоритма, можете попробовать плавно изменять значение регистра OSCCAL.
tazik
Да, действительно, спасибо!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.