повысить частоту записи analogwrite

ilyer
Offline
Зарегистрирован: 28.11.2013

 по умолчанию пишет на 490 гц. можно ли как то повысить частоту записи?

написал код генерации синусоиды на основе предрассчитаных 256 значений. при 490 можно макчимум на 50гц вырулить с помошью задержек delay, а надо бы 400. Может по сигналу синхронизации как то завести

ilyer
Offline
Зарегистрирован: 28.11.2013

или как то с таймерами 0 , 1 или 2. но как их увязать?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012
Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013
ilyer
Offline
Зарегистрирован: 28.11.2013

насколько я понял вписав в setup

 
#define PWM_1 1 - будет включать предделитель = 8 (~3,9 KHz)

// 3,922 KHz
TCCR1B = _BV(CS11);

 

 я получу на 4 и 5 ноге 3,9кгц?

беда в том что генерится опорная синусоида, со входа берется сигнал, который влияет на амплитуду. и на выходе три синусоиды со смещением на 120 градусов. Выходит у меня без вариантов?

 

ilyer
Offline
Зарегистрирован: 28.11.2013

спасибо

видел эту статью, но не понял как это что-то изменит

int PWM_time=32; //Число, которое мы как бы хотим записать в analogWrite(PIN, 32)
for (int k=0;k<PWM_time) PORTA=B00000001;
for (int k=0;k<256-PWM_time) PORTA=B00000000;

форы в сетапе или лупе? что за переменная к?

могу выложить код

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

ilyer пишет:

насколько я понял вписав в setup

 
#define PWM_1 1 - будет включать предделитель = 8 (~3,9 KHz)

// 3,922 KHz
TCCR1B = _BV(CS11);

 

 я получу на 4 и 5 ноге 3,9кгц?

беда в том что генерится опорная синусоида, со входа берется сигнал, который влияет на амплитуду. и на выходе три синусоиды со смещением на 120 градусов. Выходит у меня без вариантов?

 

Не понял вообще ничего. Сколько Вам нужно PWM выходов? Я правильно понял, что три? Если так, то нужно сделать аналогично для еще одного таймера и будет нормально.

С какого входа берется сигнал? ПРи чем тут амплитуда? На каком выходе три синусоиды?

Опять же ни слова, какой у Вас МК или Ардуино. Я не телепат.

Если хотите адекватного ответа, задайте вопрос еще раз, объяснив задачу.

UPD: Вы думаете, что на 4,5 выходах буду синусоиды? А частота - это частота синуса? Частота - это частота PWM, боюсь, что мы друг друга не понимаем.

UPD2: http://arduino.ru/Reference/AnalogWrite

 

ilyer
Offline
Зарегистрирован: 28.11.2013

моя задача. Сделать устройство которое генерировало бы 3 фазы. тоесть 3 синусоиды со сдвигом на 120. Синусоиду я реализовал с помощью массива из 256 значений, в которых прорисован весь период. смещаю "х" и вывожу в analogwrite

analogWrite(3, myArray[x]);

а смещение на 120 градусов

 x_1 = x + 120;
  x_2 = x + 240;

такого типа. и теперь когда все работает я столкнулся с проблемой, что нужна частота самой синусоиды - 400гц. осциллографом проверял, шим сжимается разжимается синхронно, все красиво

com
Offline
Зарегистрирован: 06.09.2013

а что такое "x"? то ли  индекс элемента массива, то ли угол сдвига фазы....

ilyer
Offline
Зарегистрирован: 28.11.2013

Индекс элемента. Ноль синусоиды 127, единица 255, минус единица 0. сдвиг фазы реализован сдвигом элемента массива.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

В такой постановке, нужно скорей всего делать на прерываниях, использовать для этого 0 таймер (не знаю какая у Вас Ардуино) и в обработчике прерывания выводить все три значения, т.е. программировать сразу порты PWM таймера (т.е. 1 и 2 таймеры). Частоту прерываний рассчитать в зависимости от частоты синусоиды. Возможно получится то, что нужно. Правда при этом нельзя будет пользоваться функциями millis, micros и т.п. Возможно проблемой будет то, что частота 400Гц точно не получится, нужно считать. А если Вам нужно менять частоту, тогда этот способ может не подойти совсем.

 

ilyer
Offline
Зарегистрирован: 28.11.2013

А где по таймерам можно найти примеры и толковые обяснения? Пытался разобраться но регистры так и не осилил...

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013
kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

А еще есть смысл посмотреть исходники, а именно файл wiring_analog.c, там есть исходник analogWrite. Это чтобы не использовать analogWrite, а напрямую программировать таймеры. Конечно придется покопаться, но иначе и браться не стоит, если не хочется копаться. В любом случае сначала надо рассчитать частоту вывода данных, чтобы понять, есть ли смысл браться за прерывания

ilyer
Offline
Зарегистрирован: 28.11.2013

а если воспользоваться таймером0 для перебора значений 0-256? ведь он генерит 256 и сбрасывается в ноль, а это то что надо. только я пока не понял как так модифицировать код. значения брать из массива[256]

ilyer
Offline
Зарегистрирован: 28.11.2013

kisoft пишет:

В такой постановке, нужно скорей всего делать на прерываниях, использовать для этого 0 таймер (не знаю какая у Вас Ардуино) и в обработчике прерывания выводить все три значения, т.е. программировать сразу порты PWM таймера (т.е. 1 и 2 таймеры). Частоту прерываний рассчитать в зависимости от частоты синусоиды. Возможно получится то, что нужно. Правда при этом нельзя будет пользоваться функциями millis, micros и т.п. Возможно проблемой будет то, что частота 400Гц точно не получится, нужно считать. А если Вам нужно менять частоту, тогда этот способ может не подойти совсем.

 

написал тоже что скказали и Вы. дошло. как правильно описать таймер?

в секунду нужно выводить 400гц*256=102400 значений //256 это период синусоиды эт частота вывода значений

Период тактового сигнала таймера Т0 равен Tt0 = (1/Fcpu)/k = k/Fcpu -    подберем коэффициент, допустим 64:

64/8мгц=0,000008 

сравним ее с требуемым периодом:

1/102400=0,000009.  

из этого следует, что коэффициент делителя нужен 64. в ту сторону мыслю?

ilyer
Offline
Зарегистрирован: 28.11.2013
#include <EEPROM.h>//подключаем библиотеку
int x = 0;// переменная для хранения значения из массива
int x_1 = 0;// переменная для хранения смещенного 120 значения из массива
int x_2 = 0;// переменная для хранения смещенного 240 значения из массива
int ramX_1 = 0; //переменная с нормированным относительно нуля
int ramX_2 = 0;
int ramX = 0;
int modul; // переменная с вычислением сдвига по фазе и нормирование на положительный уровень
int modul_1;
int modul_2;
int alfa_grad = 270; //переменная для хранения значения угла в градусах
float alfa_rad = 0; //переменная для хранения значения угла в радианах

  int myArray[256] = {127,130,133,136,140,143,146,149,152,155,158,
                    161,164,167,170,173,176,179,182,185,187,190,
                    193,195,198,201,203,206,208,211,213,215,217,
                    220,222,224,226,228,230,232,233,235,237,238,
                    240,241,242,244,245,246,247,248,249,250,251,
                    252,252,253,253,254,254,254,254,254,254,254,
                    254,254,254,253,253,252,252,251,250,250,249,
                    248,247,246,244,243,242,240,239,237,236,234,
                    232,231,229,227,225,223,221,219,216,214,212,
                    209,207,204,202,199,197,194,191,189,186,183,
                    180,177,175,172,169,166,163,160,157,154,150,
                    147,144,141,138,135,132,129,125,122,119,116,
                    113,110,107,104,100,97,94,91,88,85,82,79,77,
                    74,71,68,65,63,60,57,55,52,50,47,45,42,40,38,
                    35,33,31,29,27,25,23,22,20,18,17,15,14,12,11,
                    10,8,7,6,5,4,4,3,2,2,1,1,0,0,0,0,0,0,0,0,0,0,
                    1,1,2,2,3,4,5,6,7,8,9,10,12,13,14,16,17,19,21,
                    22,24,26,28,30,32,34,37,39,41,43,46,48,51,53,
                    56,59,61,64,67,69,72,75,78,81,84,87,90,93,96,
                    99,102,105,108,111,114,118,121,124,127}; 

void setup() 
  {
   pinMode(3, OUTPUT); //pcint19
   pinMode(5, OUTPUT); //pcint21
   pinMode(6, OUTPUT); //pcint22
   pinMode(9, OUTPUT); //pcint1
   Serial.begin(115200);        // connect to the serial port
   Serial.println("PWM Test");
   
  }

void loop() 
{
  alfa_rad = alfa_grad*3.14/180; // перевести градусы в радианы,
  if (x <= 255) //если значение угла в пределах 360-ти градусов,
    {//то...
  x_1 = x + 85;
  x_2 = x + 170;
   if (x_1 >= 255) //если значение x  в пределах 255
    {//то...
    x_1 -= 255;         
    }
    if (x_2 >= 255)
    {
      x_2 -= 255;
    }
    
    analogWrite(3, myArray[x]); // выводим на 3 вывод несущую
       ramX = myArray[x]-127; //нормируем относительно ноля синусоиду
       ramX_1 = myArray[x_1]-127;
       ramX_2 = myArray[x_2]-127;
       modul = map ((ramX*sin(alfa_rad))*100,-12700,12700,-127,127) + 127;
       modul_1 = map ((ramX_1*sin(alfa_rad))*100,-12700,12700,-127,127) + 127;
       modul_2 = map ((ramX_2*sin(alfa_rad))*100,-12700,12700,-127,127) + 127;
       analogWrite (5,modul);
       analogWrite (6,modul_1);
       analogWrite (9,modul_2); 
       x++; 
      Serial.print(myArray[x]);
      Serial.print("  ");
      Serial.println(modul);
    }
    else x=0;
delay(10);
}

тот код, который есть на данный момент

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Да уж, что то слишком тяжелый расчет.

x, x_1, x_2 можно сделать тип - байт и не париться, поскольку больше 255 они не будут никогда и добавлять константу и не проверять. byte x_1 = x + 185; никогда не будет больше 255.

alfa_grad нигде не меняется, соответственно alfa_rad всегда одно и тоже значение.

Не помню как правильно, но строку 48 я бы записал как:

alfa_rad = (float)alfa_grad*3.14/180;

иначе может некорректно рассчитать - лучше результат вывести в монитор и проверить.

(ramX*sin(alfa_rad))*100 - аналогично, ramX - целое, умножается на float и округляется. Так что тут тоже лучше написать как

((float)ramX*sin(alfa_rad))*100.

В общем эти места лучше проверить.

На счет таймера:

1/400 = 2,5мс это один период, т.е. за это время надо вывести 256 отсчетов, т.е. если я не ошибся, это 102,4 КГц - частота прерываний. Много это или мало, не знаю, разумеется зависит от частоты МК.

А дальше сегодня уже голова не варит. Может кто из практиков подскажет, а то я в этом вопросе - теоретик.

Подозреваю, что нужно, если использовать прерывания, выкинуть все расчеты и тупо оставить таблицу и выводить из неё данные без каких либо пересчетов, иначе не успеет отработать.

И еще, не понял, зачем на синус из таблицы (Array[x]) накладывать еще один синус (sin(alfa_rad)), непонятно.

 

ilyer
Offline
Зарегистрирован: 28.11.2013

спасибо, поправил, все работает. Дело в том, что на вход будет выдаваться сигнал угла и он будет меняться.

В проекте моделируется алгоритм поворота высотомера на азимут. Дается код угла и трехфазый движок выворачивается на угол.

нашел в сети библиотеку, для первого таймера  http://robocraft.ru/blog/arduino/614.html

попробую разобраться

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Удачи, впрочем, думаю Вы еще не уходите :) Да и поделиться с сообществом тоже не помешает.

Если использовать таймер1, будет пересечение по прерываниям с таймером0, не забывайте про это, если увидите неравномерность на выходе.

 

ilyer
Offline
Зарегистрирован: 28.11.2013

будут успехи отпишусь, но пока что то нет идей... на осциллографе ши почемуто тоже модулирован синусоидой...

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

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