генерация значений от 0 до 360 каждые 10 секунд

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

Есть необходимость в генерации значений от 0 до 360 за 10 секунд и заново. Задержки и ++ не вариант т.к. тормозится вся программа. пробовал с привязкой к переменной millis(); 

void loop() 
{ 
  time = millis();
  if(time%100 == 0)
  { 
    alfa_grad = alfa_grad + 3.6;
  }
  if( time%10000 == 0) alfa_grad = 0;
  

где альфа это угол. Не получается, значения плавают, через монитор порта видно что даже не от 0 до 9 значения в последовательностях. Что можно исправить, или другие способы реализации?

tmr
Offline
Зарегистрирован: 19.05.2014

Не очень понял задачу, если нужно задать значение с высокой точностью интервала, можно воспользоваться прерыванием настроив соответствующий таймер, например:

void setup(){
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  OCR1A = 15624;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS10);
  TCCR1B |= (0 << CS11);
  TCCR1B |= (1 << CS12);
  TIMSK1 |= (1 << OCIE1A);
}

ISR(TIMER1_COMPA_vect){
  if(alfa_grad != 360){
    alfa_grad += 3.6;
  }else{
    alfa_grad = 0;
  }
}

viod loop(){
  //do something;
}

Только нужно правильно установить регистр TCCR1B, и прескалер OCR1A, а то я сейчас на глаз посчитал

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

tmr пишет:

Не очень понял задачу, если нужно задать значение с высокой точностью интервала, можно воспользоваться прерыванием настроив соответствующий таймер, например:

void setup(){
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  OCR1A = 15624;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS10);
  TCCR1B |= (0 << CS11);
  TCCR1B |= (1 << CS12);
  TIMSK1 |= (1 << OCIE1A);
}

ISR(TIMER1_COMPA_vect){
  if(alfa_grad != 360){
    alfa_grad += 3.6;
  }else{
    alfa_grad = 0;
  }
}

viod loop(){
  //do something;
}

Только нужно правильно установить регистр TCCR1B, и прескалер OCR1A, а то я сейчас на глаз посчитал

не могу найти понятного руководства по их настройке.

Вы взяли OCR1A = 15624 это столько отсчетов пройдет за 10 секунд и таймер обнулится, верно?

а растет tcnt1?

как проводить рассчеты?

tmr
Offline
Зарегистрирован: 19.05.2014

15624 это 1 секунда, расчет: 16000000 (16MHz частота) / 1024 (прескалер)/ 15625 (размер счетчика)

TCNT1 это регистр счетчика - да.

Я так понял, что каждую секунду нужно увеличивать значение на +3.6 в течении 10 секунд, затем сбрасывать и по новой.

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

да, верно

tmr
Offline
Зарегистрирован: 19.05.2014

Я там в первом сообщении допустил ошибку, нужно поменять местами слова "регистр" и "прескалер". Прескалер задается битами CS10,CS11,CS12 в регистре TCCR1B, а регистр OCR1A это значение по которому происходит прерывание.

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

спасибо, я догадался когда начал гуглить. Только что то не хочет обнуляться, дальше гонит за 360. Ошибок  что-то не видно

tmr
Offline
Зарегистрирован: 19.05.2014

alfa_grad у вас глобальная volatile?

ilyer
Offline
Зарегистрирован: 28.11.2013
#include <EEPROM.h>/



byte x = 0;
byte x_1 = 0;
byte x_2 = 0;
int ramX_1 = 0; 
int ramX_2 = 0;
int ramX = 0;
int modul;  
int modul_1;
int modul_2;
volatile float alfa_grad = 0;
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
   
   Serial.begin(115200); // connect to the serial port
   Serial.println("PWM Test");
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  OCR1A = 15625; // Верхняя граница счета. Диапазон от 0 до 65535
  // Частота прерываний будет = Fclk/(N*(1+OCR1A)) 
  // где N - коэф. предделителя (1, 8, 64, 256 или 1024)
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS10);
  TCCR1B |= (0 << CS11);
  TCCR1B |= (1 << CS12);
  TIMSK1 |= (1 << OCIE1A); // Разрешить прерывание по совпадению
}

ISR(TIMER1_COMPA_vect){
  if(alfa_grad != 360)
  {
    alfa_grad += 3.6;
  }
  else
  {
    alfa_grad = 0;
  }
}
  

void loop() 
{ 

  alfa_rad = (float)alfa_grad*3.14/180;
  if (x <= 255) 
    {
  x_1 = x + 85;
  x_2 = x + 170;
  
    analogWrite(3, myArray[x]); 
       ramX = myArray[x]-127; 
       ramX_1 = myArray[x_1]-127;
       ramX_2 = myArray[x_2]-127;
       modul = map (((float)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 (3,modul);
       analogWrite (5,modul_1);
       analogWrite (6,modul_2);
       
       x++; 
      Serial.print(modul);
      Serial.print("  ");
      Serial.print(modul_1);
      Serial.print("  ");
      Serial.println(alfa_grad);
    }
    else x=0;

}

весь код, даже когда исправил пишет значения выше 360

tmr
Offline
Зарегистрирован: 19.05.2014

Условие сброса в прерывании нужно переписать, у вас в loop значние a_r меняется произвольно.

Или в loop не нужно переопределять a_r, а использовать для вычислений другую переменную.

И учтите, что loop будет выполнятся со скоростью исполнения кода, а прерывание вызываться строго каждую 1 секунду. То ли это, что вы хотели получить?

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

это как раз то, что надо. Этот код для эмуляции синусоиды. а так на вход напряжение приходит и оцифровывается и скорость там ни к чему.

не добился я пока эффекта

альфа нужен чтобы промодулировать синусоиду

tmr
Offline
Зарегистрирован: 19.05.2014

Ага, я не увидел разницы между alfa_rad и alfa_grad. Теперь вижу что с этим все впорядке.

Думаю тут дело в типе float, который не будет равен точно 360. Попробуйте привести типы перед сравнением, если не поможет можно попробовать округлить или отбросить дробную часть или сравнить не точно а > или <.

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

никакими операторами не обнуляется, либо пишет нули вообще

tmr
Offline
Зарегистрирован: 19.05.2014

Хмм, ну так то полюбому должно сработать: if(alfa_grad > 359 && alfa_grad < 361)... да и даже if(alfa_grad > 359) будет достаточно

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

а не может ли быть дело в том что обработчик запускается и выполняется бесконечно, не может снуляться? луп осуществляет циклы

tmr
Offline
Зарегистрирован: 19.05.2014

Прерывание прерывает исполнение loop на время исполнения обработчика, т.е. если бы обработчки выполнялся бесконечно, то весь loop бы просто завис

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

отставить, 

alfa_grad += 3.6;
  if(alfa_grad > 359 && alfa_grad < 361)
    
{alfa_grad = 0;}

дало эффект.

Бесконечно благодарен за помощь. Знаний как видите маловато еще у меня) 

не исключено что по времени это дольше чем 10 секунд, проверю завтра на реальном железе с осциллографом