Управляемая ШИМ - синусоида

questioner
Offline
Зарегистрирован: 10.06.2016

Всем привет. Очередной новичек с кучей вопросов. Для управления мосфетом нужна шим-синусоида с управляемой частотой (потенциометр).

Нашел статью с готовы кодом http://cxem.net/arduino/arduino16.php , решение мне подходит, но компилятор выдает ошибку:

Arduino: 1.6.9 (Windows 7), Плата:"Arduino Nano, ATmega328"

sketch_jun11a:15: error: 'prog_uchar' does not name a type
 
 PROGMEM  prog_uchar sine256[]  = {
 
          ^
 
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:28:0,
 
                 from sketch\sketch_jun11a.ino.cpp:1:
 
C:\Users\1\Documents\Arduino\sketch_jun11a\sketch_jun11a.ino: In function 'void __vector_9()':
 
sketch_jun11a:113: error: 'sine256' was not declared in this scope
 
   OCR2A=pgm_read_byte_near(sine256 + icnt);    
 
                Код:
/*
 *
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int ledPin = 13;                 // LED pin 7
int testPin = 7;
int t2Pin = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile byte icnt;              // var inside interrupt
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  Setup_timer2();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() {

// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);

  sbi (TCCR2A, WGM20);  // Mode 1  / Phase Correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  OCR2A=pgm_read_byte_near(sine256 + icnt);    

  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
}

 

 
dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

там сразу 2 ошибки. 15 строка должна быть такой: uint8_t const  PROGMEM  sine256[]  = {

questioner
Offline
Зарегистрирован: 10.06.2016

Спасибо - сработало.

Один вопрос: что нужно прочитать, чтобы самому видеть такие ошибки?

П.с. Еще у американцев нашел исправление - тоже компилятор не ругается, но оно другое:

const PROGMEM unsigned char sine256[]  = {

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

questioner, в принципе это не ошибка. Там написано всё правильно, просто последние версии ардуины кишат багами. В данном случае не подгружается инклюд из 12 строки скетча в нужный момент времени.

questioner
Offline
Зарегистрирован: 10.06.2016

Как в этом коде поменять диапазон регулировки частоты скажем в 10 раз?

Сам спросил - сам отвечаю :

 67     dfreq=analogRead(0)/10; 

Обожаю Ардуино !!! Я знаком с ним всего 4 дня (вечера), а уже управляю оборотами однофазного двигателя собственной конструкции !!! Мечта инженера "непрограммиста"

Lion777
Offline
Зарегистрирован: 20.05.2016

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

a5021
Offline
Зарегистрирован: 07.07.2013

Еще хорошо, что есть чужие готовые буквы. Если бы буквы каждому самому пришлось изобретать, до сих пор бы за мамонтом бегали с каменными молотками.

questioner
Offline
Зарегистрирован: 10.06.2016

С обоими комментаторами согласен на 100%. Вот только с ардуиной месяцок нужно посидеть, чтобы свой код написать, а с авр-ом или пик-ом - годик.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

questioner, как вы просто и оптимистично всё измеряете :)  Всё от способностей человека  зависит, и от желания учиться.  Код из верхнего поста среднестатический пользователь ардуины вообще вряд ли напишет сам, хоть за месяц хоть за год. Даже что-б просто разобрать и понять как всё там работает -и то нужны  знания и опыт работы с аналогичными программами.

questioner
Offline
Зарегистрирован: 10.06.2016

А возможно ли сделать "разбор" этого кода? Очень нужно, т.к планирую контроллер для трехфазного двигателя, да еще и с датчиками.. Ох и тяжело будет с нуля, но мне деваться некуда. Для меня было сюрпризом, что двигатель моей конструкции заработал с первого раза, да еще и хорошо. Теперь заднюю не включить ))

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

questioner, там есть специфика, без знаний которой бессмысленно начинать разбирать этот скетч. Предварительно необходимо изучить до полного понимания как минимум 2 важных составляющих этой программы  -это знать как работают таймеры (режимы, прерывания, настройка). И знать как работает DDS с аккумулятором фазы.  Остальное уже мелочи.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

a5021 пишет:

Еще хорошо, что есть чужие готовые буквы. Если бы буквы каждому самому пришлось изобретать, до сих пор бы за мамонтом бегали с каменными молотками.

всем сброситься по одному доллару - молотки мой дид придумал.

questioner
Offline
Зарегистрирован: 10.06.2016

dimax, ткните носом, что необходимо прочесть?

Если возможно, на русском.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

questioner, а вот тут проблемка -я не встречал таких книг, статей на эти темы, что б можно было сказать что там всё изложено просто и в доходчивой форме. Обычно это скупой пересказ даташита, а даташиты как известно пишут не для чайников, а для уже специалистов в данном вопросе.  Читайте всё подряд, что найдёте. Я помню читал книгу Евстифеева про микроконтроллеры avr, она легко находится поиском. Про DDS чтива почти нет. Впрочем есть неплохая статья Л.Ридико про DDS. Ну а в общем как говорится гугль вам в помощь :)

 

 

a5021
Offline
Зарегистрирован: 07.07.2013

Я или не въехал в суть вопроса или не вижу сложности. Для генерации синусоидальных колебаний посредством ШИМ-выхода МК (+ интегрирующая цепочка), всего и нужно, лишь в необходимом темпе подкидывать в регистр сравнения значения синуса, вычисленные или табличные.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

a5021, совершенно верно, с одним только нюансом - темп всегда один для любой частоты, в данном случае 31кГц. Функция  DDS имея на входе требуемое значение частоты определяет какие значения таблицы пропустить, а какие нет что б выдать требуемую частоту.

questioner
Offline
Зарегистрирован: 10.06.2016

dimax пишет:

a5021, совершенно верно, с одним только нюансом - темп всегда один для любой частоты, в данном случае 31кГц. Функция  DDS имея на входе требуемое значение частоты определяет какие значения таблицы пропустить, а какие нет что б выдать требуемую частоту.

Я вот из этого поста понял больше, чем из статьи, на которую вы дали ссылку! А не проще было сразу так сказать? Принцип достаточно прост, а вот объяснение в источниках "мозгодробильное". Все можно объяснить гораздо проще.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

questioner, не проще. Вернее это слишком поверхностно, и понимания работы всё равно не даст. Например с пониманием как это работает можно рассчитать для каждой конкретной генерируемой частоты разрядность выдаваемой синусоиды. Она же 8-битная только до определённой частоты, а выше разрядность начинает падать.

questioner
Offline
Зарегистрирован: 10.06.2016

Насколько сложно теперь переделать этот код под трехфазный? Смещение, естесственно 120 градусов и чтобы частота также регулировалась?

a5021
Offline
Зарегистрирован: 07.07.2013

Потребуется три таблицы, три шим канала и управление этим хозяйством. Теоретически это возможно.

questioner
Offline
Зарегистрирован: 10.06.2016

Ресурса железа хватит?

a5021
Offline
Зарегистрирован: 07.07.2013

У атмеги328 шесть шим-каналов. Были бы еще три из них на одном таймере, так совсем бы хорошо было. Но в принципе, и так наверное прокатит.

nevkon
Offline
Зарегистрирован: 20.01.2015

Может я буду не прав, но достаточно будет сделать еще 2 переменные PROGMEM в которых будет смещение на 120 и 240 градусов и вызываться они будут рядом с первой, но для других ног. Если я правильно понимаю там идут значения в равных участках времени и этих значений 256 (раз пишут про 8 бит), а значит 256/3=85. Так вот первые 85 значений перекидываем в конец для второй переменной и 170 или 171 значение перекидываем в конец для третьей переменной.

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

genadii
Offline
Зарегистрирован: 30.03.2016

  Дима здравствуйте тема похожая я задался целью управлять сигналом HCR 04 переменной  длительности  шим портом ардуино для получения тонального сигнела пропорционально длительности входного в аудио диапазоне. подскажете можно ли использовать analogWrite () и нужент скетч.

Petropavel
Offline
Зарегистрирован: 27.04.2017

Приветствую всех, что ни правил - не идет компиляция (ошибка в строке 024 , впрочем я человек в этих делах новый - учусь только), не мог бы кто-нибудь  разместить  здесь, либо отоcлать мне вышеуказаный рабочий скетч (.ino) на      vip.petropavel@mail.ru  . Заранее Вам благодарен.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Petropavel, это 100% рабочий скетч.

Lion777
Offline
Зарегистрирован: 20.05.2016

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

bwn
Offline
Зарегистрирован: 25.08.2014

Lion777 пишет:

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

А в чем такое преимущество новых? У меня например, еще 0023 не снесена.))))

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Да, особенно учитывая, что скетч 2009 года :) А тот товарищ скорее всего про всплывающую кнопку "скопировать код" не знает, и накосячил с вставкой кода.

Ruslani4
Offline
Зарегистрирован: 20.05.2017

Здравствуйте, когда выводил этот сигнал через нч получил синусойду, но частота менялась сама, с определённой переодичностью( т.е. секунду 1 частота, секунду другая, секунду 3я, секунду 4я, и так по кругу), я только только осваиваю ардуин, и не понимаю что сделать чтобы частота не скакала, а была 1ой заданной, как в примере 1000гц, и регулировалась через А0, стоит убрать 85-99 строки или 106-121, а может их оба, или убрать  tword_m, а вместо него ставить dfreq, хотя мне кажется что мы так изменяем частотк через А0, подскажите пожалуйста, что нужно сделать

kerpi4
Offline
Зарегистрирован: 18.03.2018

Добрый день! Видел, писал про то, что хочешь на трехфазный двигатель сделать управление. Получилось? Стоит подобная задача, если увидишь, отзовись, пожалуйста.

andryn
Offline
Зарегистрирован: 08.06.2018

kerpi4 пишет:

Добрый день! Видел, писал про то, что хочешь на трехфазный двигатель сделать управление. Получилось? Стоит подобная задача, если увидишь, отзовись, пожалуйста.

Если еще актуально, то тут: http://arduino.ru/forum/programmirovanie/preobrazovatel-chastoty-dlya-3kh-fazovogo-asinkhronnogo-dvigatelya-na-arduino попытался это сделать.