Ардуино не правильно вычисляет. (баг?)

Euronimus
Offline
Зарегистрирован: 18.12.2016

Здравствуйте.

При расчете времени поворота синусоиды на 1гр. по формуле: ( t / f ) / 360, где t - 1 сек в микросекундах, f - задаваемая частота в Гц, 360 - период синуса в углах, столкнулся с интересным моментом:

если расчет вести по выделенной формуле, то при задаваемых частотах f < 185 ардуино вычисляет значения верно:

но, если значение задаваемых частот f > 185, то начинается что-то для меня не понятное (должно получиться 14,62, с округлением до 15):

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

Весь код скетча:

byte mask_p = (1 << 7) | (1 << 4) | (1 <<2); //маска пинов фаз 2, 4, 7
const uint8_t deg_max=90, //угол первого максимума
              deg=120,    //угол сдвига фаз
              p_value=75, //длительность 1/4 периода фазы в эл.углах
              motor_deg=4;//4 периода синуса = 1 обороту
const uint32_t sec=1000000;//сек в микросек
unsigned long _time,      //время работы ардуино
  p1_str, p1_stp, p2_str, //время начала и конца 
  p2_stp, p3_str, p3_stp; //положительного полупериаода фаз
uint16_t      f,          //частота фазы
              deg_val;    //1 эл.гр. в мкс
uint8_t       p_rise,     //угол начала фазы
              p_dawn;     //угол конца фазы

void setup() {
  Serial.begin(9600);
  DDRD |= mask_p;         //пины 2, 4, 7 OUTPUT
  PORTD &= ~mask_p;        //пины 2, 4, 7 LOW
  f = 190;
  _time = micros();
  /*deg_val = (sec/f)/360;*/  deg_val = sec/(f*360);
  Serial.println(deg_val);
  p_rise = 90-p_value;
  p_dawn = 90+p_value;
  p1_str = _time + deg_val*p_rise;
  p1_stp = p1_str + deg_val*p_value*2;
  p2_str = _time + deg_val*(p_rise+120);
  p2_stp = p2_str + deg_val*p_value*2;
  p3_str = _time + deg_val*(p_rise+240);
  p3_stp = _time + deg_val*((330+p_value)-360);
}

void loop() {
  while (1) {
    _time = micros();
    if (_time>=p1_str) {      //ждем время нарастания фазы 1
      PORTD |= (1<<2);
      p1_str = p3_str + deg_val*120;} 
      else {
        if (_time>=p3_stp) {      //ждем время спада фазы 3
          PORTD &= ~(1<<7);
          p3_stp = p3_str + deg_val*p_value*2;}
          else {
            if (_time>=p2_str) {      //ждем время нарастания фазы 2
             PORTD |= (1<<4);
             p2_str = p1_str + deg_val*120;}
              else {
                if (_time>=p1_stp) {      //ждем время спада фазы 1
                  PORTD &= ~(1<<2);
                  p1_stp = p1_str + deg_val*p_value*2;}
                  else {               
                    if (_time>=p3_str) {      //ждем время нарастания фазы 3
                      PORTD |= (1<<7);
                      p3_str = p2_str + deg_val*120;}
                      else {
                        if (_time>=p2_stp) {      //ждем время спада фазы 2
                          PORTD &= ~(1<<4);
                          p2_stp = p2_str + deg_val*p_value*2;}
                      }
                  }
              } 
          }
      }
  }
   
}

 

kalapanga
Онлайн
Зарегистрирован: 23.10.2016

Ваша f имеет тип uint16_t, произведение f*360 будет такого же типа. Переполнение случилось, и Ваши секунды делятся уже совсем не на то, что Вы думаете.

Euronimus
Offline
Зарегистрирован: 18.12.2016

Не знал о такой особенности, спасибо

Euronimus
Offline
Зарегистрирован: 18.12.2016

Мне Ваш комментарий очень помог в дальнейших расчетах =) еще раз спасибо

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Не по теме, но ник больно уж у автора прикольный.

https://ru.wikipedia.org/wiki/Викернес,_Варг

Euronimus
Offline
Зарегистрирован: 18.12.2016

Я уже думал о манхейм забыли =) да и ссылку тогда уж на Эйстейна Ошета надо был давать ;-)