1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
|
|
1 | |
Массив с помощью формулы05.01.2017, 14:11. Показов 5452. Ответов 9
Метки нет (Все метки)
Всем привет. Написал программу для трехфазного ШИМ на микроконтроллере Атмега2560. Сначала попробовал заранее мной рассчитанный массив синуса. Все получилось, но впоследствии убедился, что трудновато будет осуществить сдвиг фаз. Поэтому решил рассчитывать массив формулой прямо в программе.
Программа: Длинный код прячем под спойлеры!!! Код
#include <avr/io.h> #include <avr/interrupt.h> #include <stdlib.h> #include <math.h> ftoot fa=1; //Амплитуда фазы А ftoot fb=1; //Амплитуда фазы В ftoot fc=1; //Амплитуда фазы C /*Функция прерывания*/ ISR (TIMER2_COMPB_vect) { int x={0}; ftoot p = {3.14}; int z={254}; ftoot sin_table[254] = {sin(2*p*x/z)*254}; x++; OCR1A = sin_table[x]; } int main (void) { /*Настраиваем выходы счетчиков для ШИМ*/ PORTG=0x00; //Установили на всех выводах порта G лог "0" DDRG=0xFF; // Настроили все ноги порта G как выходы (Это ноги таймера "0") PORTB=0x00; //Установили на всех выводах порта B лог "0" DDRB=0xFF; // Настроили все ноги порта B как выходы (Это ноги таймера "1") PORTH=0x00; //Установили на всех выводах порта H лог "0" DDRH=0xFF; // Настроили все ноги порта H как выходы (Это ноги таймера "2 и 4") PORTE=0x00; //Установили на всех выводах порта E лог "0" DDRE=0xFF; // Настроили все ноги порта E как выходы (Это ноги таймера "3") PORTL=0x00; //Установили на всех выводах порта L лог "0" DDRL=0xFF; // Настроили все ноги порта L как выходы (Это ноги таймера "5") /*Настраиваем канал OC0 для прохода по массиву. Нужно задать режим без предделителя, СТС*/ TCCR2A = (1<<WGM21) | (1<<COM2A0) | (1<<COM2A1); TCCR2B = (1<<COM2B0) | (1<<COM2B1) | (1<<CS21); // Настроили T2 СТС с PSC = 8 TCNT2 = 0x00; OCR2A = 0x9D; // В регистр сравнения запихали число 157. На 157--м тике таймера TCNT2 сработает прерывание по СТС OCR2B = 0x00; ASSR=0x00; // Тактируемся от внутреннего источника частоты /*Настраиваем T1. Пускай генерирует положительные полуволны для напряжения - Фаза А полож полуволна. Нам нужен режим FAST PWM, не инверт ШИМ, без предделителя*/ TCCR1A = (1<<WGM00) | (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<COM1C1) | (0<<COM1C0); // Режим без предделителя, FAST PWM TCCR1B = (1<<WGM12) | (1<<CS11); // TCCR1C = 0x00; TCNT1=0x00; // счетный регистр = 0 /*Настраиваем T3. Пускай генерирует отрицательные полуволны для напряжения - Фаза В отриц полуволна. Нам нужен режим FAST PWM, не инверт ШИМ, без предделителя*/ TCCR3A = (1<<WGM30) | (1<<COM3A1) | (0<<COM3A0) | (1<<COM3B1) | (0<<COM3B0) | (1<<COM3C1) | (0<<COM3C0); // Режим без предделителя, FAST PWM TCCR3B = (1<<WGM32) | (1<<CS31); // TCCR3C = 0x00; TCNT3=0x00; // счетный регистр = 0 OCR1AH=0x00;OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; OCR1CH = 0x00; OCR1CL = 0x00; OCR3AH=0x00;OCR3AL=0x00; OCR3BH=0x00; OCR3BL=0x00; OCR3CH = 0x00; OCR3CL = 0x00; TIMSK2 = (1<<OCIE2B); // Прерывание сработает при совпадении OC2B и счетного регистра. OCIE2B = 1 sei(); // Разрешаем прерывание. Тут программа сигает вверх на ISR while (1) { // Бесконечный цикл. Если выполняется прерывание, то программа в цикл не заходит } ;} Меняю фигурные скобки Код
{sin(2*p*x/z)*254}
0
|
05.01.2017, 14:11 | |
Ответы с готовыми решениями:
9
Заполнить массив a[n] с помощью данной формулы Как с помощью формулы заполнить массив Сформировать двумерный массив X (2,4) с помощью формулы X[I, J]=4X 2J С помощью цикла пересчитать формулы |
0 / 0 / 0
Регистрация: 11.12.2011
Сообщений: 789
|
|
05.01.2017, 14:26 | 2 |
Ну правильно все: нулевой элемент массива ftoot sin_table[254] получает значение sin(0)*254, остальные получают значения 0, потом в OCR1A загружается первый элемент массива, равный 0. При следующем входе в прерывание эта ересь повторяется. Мега делает именно то, что вы ей приказываете.
0
|
0 / 0 / 0
Регистрация: 10.04.2014
Сообщений: 879
|
|
05.01.2017, 14:29 | 3 |
Это ж какие накладные расходы, каждый раз считать!
А в чём сложность с массивом? Массив по сути нужен один. Массив - кольцо. Сдвиг фаз - сдвигом начала массива
0
|
0 / 0 / 0
Регистрация: 20.07.2012
Сообщений: 620
|
|
05.01.2017, 14:31 | 4 |
А если вы всё же генерируете синус на лету, то зачем вам вообще массив?
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
|
|
05.01.2017, 14:38 | 5 |
ПлакалЪ.
У вас не матлаб и даже не фортран - тут нельзя так запросто инициализировать массив чем-то кроме массива. Делайте массив глобальным и в начале проги пишите for(int x=0; x<254; x++) sin_table[x]=... (Заодно уберёте вычисление синуса из прерывания) Но вообще я вам рекомендую таблицу синусов рассчитать заранее и сформировать исходник с ней. Во первых, не будет тормозов на старте, во вторых - можно разместить во флеше, а не в ценной ram. Да, насчёт сдвига фаз - двигайте на целое число и не парьтесь. Массив синусов всё тот же, только число из другого места брать.
0
|
0 / 0 / 0
Регистрация: 10.04.2014
Сообщений: 879
|
|
05.01.2017, 17:00 | 6 |
Сообщение от oomomstir
0
|
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
|
|
05.01.2017, 18:39 | 7 |
Сообщение от Vozz
int x={0}; ftoot p = {3.14}; int z={254}; ftoot sin_table[254] = {sin(2*p*x/z)*254}; x++; OCR1A = sin_table[x]; } Интересно, а что в функции прерываний делается-то?
0
|
0 / 0 / 0
Регистрация: 31.01.2013
Сообщений: 1,625
|
|
05.01.2017, 19:09 | 8 |
Смысл аппаратного ШИМа в том и состоит, что он работает сам по себе, выдавая импульс с заполнением OCR аппаратно и не требует вычислительных ресурсов вообще. Закидываем значение OCR и занимаемся своими делами. Прерывание OCR не нужно задействовать. Нужно в ините подготовить таблицу синусов, как вам уже посоветовали, и записать ее в массив. Затем в прерывании ТАЙМЕРА вы меняете индекс массива, который в этом случае будет иметь значение "фаза", и тогда на выходе сгенерится прямоугольник, меняющийся по закону синуса. Частота прерывания таймера рассчитывается как F*256, для трехфазного сигнала 50 Гц это будет 12800 раз в секунду. В этом прерывании надо выдать в значения OCR три числа, сдвинутые на треть длины массива, например, OCR1A=sin_table[0], OCR1B=sin_table[85], OCR2=sin_table[170]. В следующий раз это будут числа 1, 86, 171. и т.д. Когда переваливает за 255, делать 0. На практике 12 кГц это слишком часто, достаточно 2-4 кГц, и таблицу можно сделать меньше, не 256 значений, а например 64. А если подумать, то и обойтись кусочком синусоиды в четверть периода.
И немного подтянуть синтаксис языка С - скобки, объявление, инициализация, вычисление.
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
|
|
05.01.2017, 19:13 | 9 |
Sthuthu, да я из размера массива в первом посте верхнюю границу скопипастил. Сам бы тоже взял массив на 256 элементов.
0
|
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
|
|
07.01.2017, 22:51 | 10 |
Спасибо всем за советы! Наконец то получилось собрать в протеусе схемку. Сигналы с МК усиливаются через IR2130 а затем уже на IGBT
IRG4BC40W. Для прохода по массиву использовал счетчик T2 а для записи в OCRnA, OCRnB, OCRnC - вот такую вот конструкцию: Код
ISR (TIMER2_COMPA_vect) { /*Фаза А*/ OCR1A = sin_OBS[phA1++]; OCR3A = sin_OBS[phA2++]; /*Фаза B*/ OCR1B = sin_OBS[phB1++];OCR3B = sin_OBS[phB2++]; /*Фаза C*/ OCR1C = sin_OBS[phC1++];OCR3C = sin_OBS[phC2++]; }
0
|
07.01.2017, 22:51 | |
07.01.2017, 22:51 | |
Помогаю со студенческими работами здесь
10
Решение формулы с помощью стека Провести интерполяцию с помощью формулы Ньютона Найти предел с помощью формулы Тейлора Изменить значение формулы с помощью макроса Вычислить площади треугольников с помощью формулы Герона Проверить верность гипотезы с помощью рекурсивной формулы Вычислить площади треугольников с помощью формулы Герона Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |