Страница 1 из 1

Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 13:44:30
sheffline_85
Добрый день форумчане, написал код для Atmega 48 трехфазного частотника
Листинг

Код: Выделить всё

volatile char i; 
 
volatile unsigned char b_sin; // Индекс фазы B в таблице синуса
volatile unsigned char c_sin; // Индекс фазы C в таблице синуса
 
volatile unsigned char temp_a; // временное хранение значения фазы A
volatile unsigned char temp_b; // временное хранение значения фазы B
volatile unsigned char temp_c; // временное хранение значения фазы C
 
volatile unsigned int freq_inv=31250; // задает период прерывания
volatile unsigned int freq=83; // задает частоту
 
volatile unsigned char amp_sin = 255; // амплитуда синуса. 255 это максимум.   
 
#include <mega48.h>
#include <delay.h>
#include <stdio.h> 
#include <sin256.h> 
 
interrupt [EXT_INT0] void ext_int0_isr(void)
{
 
}
 
 
interrupt [EXT_INT1] void ext_int1_isr(void)
{
 
}
 
 
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
 
ADCSRB = sin[i];
                   
temp_a=((unsigned int)amp_sin*(unsigned int)sin[i])>>8;
 
OCR0A = temp_a;
     
b_sin=i+85;
 
ADCSRB = sin[b_sin];
 
temp_b=((unsigned int)amp_sin*(unsigned int)sin[b_sin])>>8;
 
OCR0B = temp_b; 
 
c_sin=i+170;
 
ADCSRB = sin[c_sin];
 
temp_c=((unsigned int)amp_sin*(unsigned int)sin[c_sin])>>8;
 
OCR2A = temp_c;
 
i++;
if (i>255) i=0;
 
b_sin++;
if (b_sin>255) b_sin=0;
 
c_sin++;
if (c_sin>255) c_sin=0;
 
}
 
 
void main(void)
{
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
 
PORTD=0x0C;
DDRD=0x00;
TCCR0A=0xA3;
TCCR0B=0x01;
TCNT0=0x00;
ASSR=0x00;
TCCR2A=0x83;
TCCR2B=0x01;
TCNT2=0x00;
 
 
DDRD|=(1<<5)|(1<<6); // PD5 PD6  выходы ШИМ Таймер0
DDRB|=(1<<3);        // PB3      выход  ШИМ Таймер2
 
 
OCR1AH = ((unsigned int)freq_inv/(unsigned int)freq)>>8;
OCR1AL = ((unsigned int)freq_inv/(unsigned int)freq);
 
OCR1BH=0x00;
OCR1BL=0x00;
 
TCCR1A = 0x00;
TCCR1B = 0x09;
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
 
 
TIMSK0=0x00;
   
TIMSK1=0x02;
 
TIMSK2=0x00;
   
UCSR0A=0x00;
UCSR0B=0x08;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x0C;
 
ACSR=0x80;
ADCSRB=0x00;
 
// Global enable interrupts
#asm("sei")
 
while (1)
      {
 
      }
}


Я новичок, не пинайте сильно, что в данном коде не так?
Попытка выставить любую частоту выше 83 заканчивается одним и тем же, работой на частоте 50 Гц.
компилятор CodevisionAVR, проверяю в протеусе.

Код естественно будет доработан плюшками, но пока хоть разобраться с частотой, она регулируется только в диапазоне 0-83 Гц

Попытка производить вычисления в теле прерывания таймера 1 приводит вообще к околесице, к тому же самому только в 30 Гц.

в синусе 256 значений, для целого числа сдвига фаз.

потолком является величина 2-значная.
Регистр OCR1A как и таймер 1 16 битный.
Число 8000000/(256*freq) в любом случае меньше 2 байт.
Процедура деления выполняется нацело, т.е. без плавающей точки, т.е. те же 100 Гц будут в регистре OCR1A числом 138 или же OCR1AH=0x01 OCR1AL=0x38, при попытке прописать эти значения в лоб, то же самое происходит что при вычислении (естественно вычисление закоменчивается при этом).

Что за затык может быть такой искусственный?

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 14:03:55
ARV
unsigned char i;

фазаА = sin[i];
фазаВ = sin[(i+85) & 0xFF];
фазаС = sin[(i+170) & 0xFF];
i++;

это и весь обработчик прерывания. не нужно 3 разных индекса, не нужно проверять индексы на переполнение... как-то так.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 14:57:57
sheffline_85
переписал код как вы посоветовали

Код: Выделить всё

interrupt [EXT_INT1] void ext_int1_isr(void)
{

}


interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
                 
OCR0A = ((unsigned int)amp_sin*(unsigned int)sin[i])>>8;
     
OCR0B = ((unsigned int)amp_sin*(unsigned int)sin[(i+85)&0xFF])>>8; 

OCR2A = ((unsigned int)amp_sin*(unsigned int)sin[(i+170)&0xFF])>>8; 

i++;

}


Диапазон расширился до 115 Гц, в принципе теперь мне его за глаза и за уши.
Я так понимаю данное ограничение вызвано размером ОЗУ МК?
т.е. если применить 128 атмегу с 4кБ ОЗУ то вполне себе влезет 460 Гц 256 точеченого синуса?
а с проверкой по переполнению это я да, перемудрил, сам выбрал режим очистки OCR0A/B и OCR2A по переполнению и зачем-то продублировал это в преывании, сожрав дополнительно процессорное время.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:01:02
mail_robot
прока проц будет считать синус, я успею глотнуть пива и покурить сходить.

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

ваш кэп

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:06:30
ARV
где вы увидели связь объема ОЗУ с частотой генерации синуса?!

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

от чего зависит частота прерываний? от настроек вашего таймера и от длительности кода, исполняемого в прерывании. отсюда и пляшите.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:08:05
sheffline_85
Ну так она заготовлена и объявлено место ее хранения в начале кода
#include <mega48.h>
#include <delay.h>
#include <stdio.h>
#include <sin256.h>


Или вы предлагаете на каждое значение амплитуды отдельную таблицу бахать? :shock:
Проц не считает синус, он берет готовые значения из таблицы, пихает их в регистр сравнения с кратным частоте синуса периодом катается по таблице.
Единственное сто проц считает это амплитуду данного синуса и его частоту, последнее сделано для лианеризации, чтобы можно было плавно разгонять или кратно по кнопке менять частоту.

Синус проц не считает в данном коде.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:22:07
mail_robot
аааа, ну ладна :tea:

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:23:53
sheffline_85
ARV
понял вас, спасибо, т.е. нужно максимально оптимизировать процессы внутри прерывания?
единственное что я вижу целесообразным это вынесение расчета амплитуды за пределы прерывания, куда ее лучше пихнуть в бесконечный цикл или в майн?
Проверил ограничив код вашим первоначальным вариантом, потолком стала частота 200 Гц

Код: Выделить всё

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
                 
OCR0A = sin[i];
     
OCR0B = sin[(i+85)&0xFF]; 

OCR2A = sin[(i+170)&0xFF]; 

i++;

}


я так понял чтобы поднятся выше придется уже резать таблицу с 256 до 128/64/32 значений?

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 15:41:07
sheffline_85
попробовал делать обсчет амплитуды вне тела прерывания получается чехарда с кучей шума на вершинах.
Видимо все же придется оставить как есть, на месте, а для желающих получить 400 гц привод посоветовать высокочастотные Атмеги.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 16:44:52
uk8amk
Для этого делают пинг-понг буфер. Пока первый обсчитывается, воспроизводится второй. Потом они меняются местами. Никакого шума и чехарды.

И это, ваш мотор даже не заметит разницу между таблицей на 256 и 32 точки. Ну разве что жужжать чуть по другому будет.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 18:31:37
Kavka
Что-то думается, что volatile там не нужен.
Спойлер

Код: Выделить всё

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{

static unsigned char i=0;
                 
OCR0A = sin[i];
     
OCR0B = sin[(i+85)&0xFF];

OCR2A = sin[(i+170)&0xFF];

i++;

}

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 20:26:36
COKPOWEHEU
Можно добавить множитель частоты

Код: Выделить всё

volatile freq_mult=1;
...
static unsigned char i=0;
i+=freq_mult;
Да, будет пропуск какого-то количества значений, но при 256 значениях в таблице будет не слишком заметно.

Re: Недоступна генерация синуса выше 83 Гц (ATMega48)

Добавлено: Пт ноя 07, 2014 22:33:41
vdavid
sheffline_85 Асинхронная загрузка OCRx на частотах близких к частоте ШИМ приводит к полному безобразию. Загружайте в прерывании переполнения таймера ШИМ. Это раз. Максимальная частота синуса на 256 точках может быть 20 000 000/256/256=305 Гц. Для дальнейшего повышения частоты уменьшаем число точек. Ну, и, наконец, для нормального формирования сигналов для управления мостом все равно нужно переходить на Phase correct PWM. При этом частота (или число точек синусоиды) еще уменьшится вдвое Посмотрите на апликейшены Атмел. Там все просто и доходчиво.