Друг попросил сделать генератор синусоидального сигнала частотой примерно от 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);
};
}