Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/27: Рейтинг темы: голосов - 27, средняя оценка - 4.89
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 96
1

Массив с помощью формулы

05.01.2017, 14:11. Показов 5453. Ответов 9
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет. Написал программу для трехфазного ШИМ на микроконтроллере Атмега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)
{

// Бесконечный цикл. Если выполняется прерывание, то программа в цикл не заходит

}

;}
Все это дело заливаю в атмегу в протеусе. На OC1A атмеги тишина. Что не так?

Меняю фигурные скобки

Код
{sin(2*p*x/z)*254}
на круглые (как и должно быть по идее) - появляется ошибка "invotyd initiotyzer"
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.01.2017, 14:11
Ответы с готовыми решениями:

Заполнить массив a[n] с помощью данной формулы
привет всем! пожалуйста помогите решить кто может!)))))) заполнить массив a с помощью формулы ...

Как с помощью формулы заполнить массив
Xk =Xk-1 +(1/2)Xk-2 x1=3 x2=0.2 Не могу понять как с помощью формулы заполнить массив

Сформировать двумерный массив X (2,4) с помощью формулы X[I, J]=4X 2J
сформировать двумерный массив X(2,4) с помощью формулы X=4X+2J

С помощью цикла пересчитать формулы
есть значения x1:=1; y1:=1; x2:=2; y2:=2; x3:=3; y3:=3; x4:=4; y4:=4; необходимо с помощью...

9
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
ПлакалЪ.
... в начале проги пишите for(int x=0; x<254; x++) sin_table[x]=...
а при x=254 и x=255 откуда потом значения брать?
0
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
05.01.2017, 18:39 7
Цитата Сообщение от Vozz
Код:
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];
}
Интересно, а что в функции прерываний делается-то?
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++];

}
Не подскажете в чем суть 9-ти и 10-ти битного ШИМ? Я сейчас использую 8-битный. Еще бы очень пригодился пример расчета защиты каналов транзисторов на драйвере IR
0
07.01.2017, 22:51
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.01.2017, 22:51
Помогаю со студенческими работами здесь

Решение формулы с помощью стека
Помогите с программой,пожалуйста. Или хотя бы посоветуйте литературу или дайте ссылки на сайт, где...

Провести интерполяцию с помощью формулы Ньютона
Друзья, помогите. Не могу провести интерполяцию с помощью формулы Ньютона. Точнее интерполяцию...

Найти предел с помощью формулы Тейлора
Здравствуйте, очень нужно решение данного предела... Найти предел с помощью формулы Тейлора:

Изменить значение формулы с помощью макроса
Работаю с большим штатом, после добавлено в штат еще 1 позиции вся таблица считаеться неправильно,...

Вычислить площади треугольников с помощью формулы Герона
два треугольника заданы координатами своих вершин A, B и C.вычислить площади треугольников с...

Проверить верность гипотезы с помощью рекурсивной формулы
проверить с помощью рекурсивной функции , верна гипотеза...

Вычислить площади треугольников с помощью формулы Герона
Два треугольника заданы координатами своих вершин. Вычислить площади треугольников с помощью...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru