Помогите подправить код эмулятора датчиков двигателя

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

15 строчку заменить на if ((uint16_t)millis() - phase_start + phase_shift > data[data_pos]) {

А как же

rkit пишет:

Приведенный мной код корректно обрабатывает переполнение переменных

Перестал отрабатывать? :-)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Да ладно Женя, мелкие придирки.

Ты знаешь мою искреннюю "любовь" к пассажиру ;)), но код вполне изящный. Если "доё..ываться" , то до diginalWrite(!digitelRRead(xxx)). И то в тестах все так пишут, из продакшн, конечно убрать надо, но пассажир про продакшн и не говорил.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:
Если "доё..ываться" , то до diginalWrite(!digitelRRead(xxx)).
Да, ладно! К чему тут? Вот сюда посмотри. Во втором коде используется недокументированное значение второго параметра pinMode, загоняющее светодиод в очень интересный режим :-)))

-NMi-
Offline
Зарегистрирован: 20.08.2018

Сколько оборотов/мин получилось в итоге???

MaksVV
Offline
Зарегистрирован: 06.08.2015

-NMi- пишет:

Сколько оборотов/мин получилось в итоге???

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

-NMi- пишет:
ТС - задача твоя решается очень просто. Делаешь процедуру, которая берёт из массива булевы данные с датчиков ( 0 или 1) Это будет единичный квант времени, 360 квантов = одному обороту коленвала. А управлять фазой по распредвалам уже будешь смещением счётчика, бегающего по массива распредвала. Подобная задача уже решалась здесь, несколько месяцев назад. Единственная проблема - не хватает скорости проца, больше 1500 об/мин у меня не получилось сделать. Выход - переход на стм32.

Я тоже когда то пытался такую задачу решить, но тогда ещё знаний не было((

было время на работе, решил по упражняться. Вот что получилось. Луп в формировании сигнала не участвует, всё на таймере 1 и низкоуровневое руление ногами. 9000 об/мин (можно и выше) - картинка вроде красивая. Так что 328 мега вполне себе... Фазы распредвалов двигаются с шагом 1 градус. В лупе принимаются настройки по оборотам и смещению фаз. 

скетч 

//--------------------------------------------
uint16_t rpm_D = 1000;    // по дефолту  1000 об/мин 
int phaseEX_D = 75;       // смещение вып вала по дефолту , градусов 
int phaseIN_D = 75;       // смещение вп вала по дефолту , градусов 

volatile int ExTooths[] =   {3};                 // здесь задаем количество зубов вып распреда и их длительность (соответствующую зубам колена)
volatile int InTooths[] =   {8,6,24,6,24,22,8};  // здесь задаем количество зубов вп распреда и их длительность (соответствующую зубам колена)

bool CKPbeginLogic = 1; // логика начала сигнала колена
bool EXbeginLogic =  1; // логика начала сигнала выпуска
bool INbeginLogic =  1; // логика начала сигнала впуска

#define CKPpin PB0      // пин коленвала 
#define EXpin  PB1      // пин вып распредвала 
#define INpin  PB5      // пин вп  распредвала 
//--------------------------------------------


volatile int ExToothsG[sizeof(ExTooths)/2+1];
volatile byte countEX = 0;
volatile byte NumbcountEX = 0;
volatile int InToothsG[sizeof(InTooths)/2+1];
volatile byte countIN = 0;
volatile byte NumbcountIN = 0;
volatile uint16_t countgrad = 1; 
volatile byte countT = 1; 
volatile byte counttooth = 1; 
volatile uint16_t rpm;     
volatile int phaseEX;      
volatile int phaseIN;      

void Default () 
{
rpm = rpm_D;
phaseEX = phaseEX_D;
phaseIN = phaseIN_D;
Serial.println ("Default settings:");
Serial.print (rpm); Serial.println (" rpm");
Serial.print("Ex: ");  Serial.print (phaseEX); Serial.println(" grad"); 
Serial.print("In: ");  Serial.print (phaseIN); Serial.println(" grad"); 
Serial.println();
}

void setup() {
Serial.begin(115200);
 Default () ;
  DDRB|= _BV(CKPpin);
  DDRB|= _BV(EXpin);
  DDRB|= _BV(INpin);
 if (!CKPbeginLogic)PORTB |=_BV(CKPpin);
 if (!EXbeginLogic) PORTB |=_BV(EXpin);
 if (!INbeginLogic) PORTB |=_BV(INpin);
  TCCR1A = 0;
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm;  
  TIMSK1 |= (1<<OCIE1A);
for (int i=0; i<sizeof(ExToothsG)/2 ; i++) 
      {   if (i==0) ExToothsG[i]= phaseEX;
         else  ExToothsG[i] = ExToothsG[i-1]+ (6*ExTooths[i-1]);
      }
for (int i=0; i<sizeof(InToothsG)/2 ; i++) 
      {   if (i==0) InToothsG[i]= phaseIN;
         else  InToothsG[i] = InToothsG[i-1]+ (6*InTooths[i-1]);         
      }
NumbcountEX = sizeof(ExTooths)/2+1;
NumbcountIN = sizeof(InTooths)/2+1;

}


void loop() {
if (Serial.available() )
  {
    static int mode = 0; 
    
    int in = Serial.read();
if (in >='0' && in <='9' && mode ==0)
    {int rpm = (in-'0')*1000;
Serial.print (rpm); Serial.println (" rpm");
OCR1A = 2666666UL/rpm;}

else if (in=='+'&& mode==1) {phaseEX++; Serial.print("Ex: ");  Serial.print (phaseEX); Serial.println(" grad");  }
else if (in=='-'&& mode==1) {phaseEX--; Serial.print("Ex: "); Serial.print (phaseEX); Serial.println(" grad"); }

else if (in=='+'&& mode==2) {phaseIN++; Serial.print("In: ");  Serial.print (phaseIN); Serial.println(" grad");  }
else if (in=='-'&& mode==2) {phaseIN--; Serial.print("In: "); Serial.print (phaseIN); Serial.println(" grad"); }

else if (in=='r'){mode = 0; Serial.println ("RPM input");}           // настройка оборотов ДВС
else if (in=='e'){mode = 1; Serial.println ("EX Phase  input");}     // режим смещения фазы выпуска 
else if (in=='i'){mode = 2; Serial.println ("IN Phase  input");}     // режим смещения фазы впуска 
else if (in=='d'){Default () ; } // настройки по умолчанию



for (int i=0; i<sizeof(ExToothsG)/2 ; i++) 
      {   if (i==0) ExToothsG[i]= phaseEX;
         else  ExToothsG[i] = ExToothsG[i-1]+ (6*ExTooths[i-1]);
      }
for (int i=0; i<sizeof(InToothsG)/2 ; i++) 
      {   if (i==0) InToothsG[i]= phaseIN;
         else  InToothsG[i] = InToothsG[i-1]+ (6*InTooths[i-1]);         
      }
Serial.println();
}

}
ISR (TIMER1_COMPA_vect)

{
  
  countgrad++;
  countT++;
  if (countT>=3){
    countT = 0;
    counttooth++; 
    if (counttooth>120) counttooth =1;
    if (counttooth!=117 && counttooth!=118 && counttooth!=119 && counttooth!=120)  PORTB ^= _BV(CKPpin);
    }
  
  if (countgrad>720) countgrad=1;
  
  if (countgrad==ExToothsG[countEX]){ PORTB ^=( _BV(EXpin)); countEX++; if (countEX>=NumbcountEX) countEX=0; }
  if (countgrad==InToothsG[countIN]){ PORTB ^=( _BV(INpin)); countIN++; if (countIN>=NumbcountIN) countIN=0; }
    
  

}

9000rpm крупно

9000rpm

2000rpm

ну и ТСа картинка для сравнения

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

//--------------------------------------------
uint16_t rpm_D = 1000;    // по дефолту  1000 об/мин 
int phaseEX_D = 80;       // смещение вып вала по дефолту , градусов 
int phaseIN_D = 80;       // смещение вп вала по дефолту , градусов 

volatile int ExTooths[] =   {3};                 // здесь задаем количество зубов вып распреда и их длительность (соответствующую зубам колена)
volatile int InTooths[] =   {8,6,24,6,24,22,8};  // здесь задаем количество зубов вп распреда и их длительность (соответствующую зубам колена)

bool CKPbeginLogic = 1; // логика начала сигнала колена
bool EXbeginLogic =  1; // логика начала сигнала выпуска
bool INbeginLogic =  1; // логика начала сигнала впуска

#define CKPpin PB0      // пин коленвала 
#define EXpin  PB1      // пин вып распредвала 
#define INpin  PB5      // пин вп  распредвала 
//--------------------------------------------


volatile int ExToothsG[sizeof(ExTooths)/2+1];
volatile byte countEX = 0;
volatile byte NumbcountEX = 0;
volatile int InToothsG[sizeof(InTooths)/2+1];
volatile byte countIN = 0;
volatile byte NumbcountIN = 0;
volatile uint16_t countgrad = 1; 
volatile byte countT = 1; 
volatile byte counttooth = 1; 
volatile uint16_t rpm;     
volatile int phaseEX;      
volatile int phaseIN;     
volatile bool tooth_or_hole = 1; 

void Default () 
{
rpm = rpm_D;
phaseEX = phaseEX_D;
phaseIN = phaseIN_D;
Serial.println ("Default settings:");
Serial.print (rpm); Serial.println (" rpm");
Serial.print("Ex: ");  Serial.print (phaseEX); Serial.println(" grad"); 
Serial.print("In: ");  Serial.print (phaseIN); Serial.println(" grad"); 
Serial.println();
}

void setup() {
Serial.begin(115200);
 Default () ;
  DDRB|= _BV(CKPpin);
  DDRB|= _BV(EXpin);
  DDRB|= _BV(INpin);
 if (!CKPbeginLogic)PORTB |=_BV(CKPpin);
 if (!EXbeginLogic) PORTB |=_BV(EXpin);
 if (!INbeginLogic) PORTB |=_BV(INpin);
  TCCR1A = 0;
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm;  
  TIMSK1 |= (1<<OCIE1A);
for (int i=0; i<sizeof(ExToothsG)/2 ; i++) 
      {   if (i==0) ExToothsG[i]= phaseEX;
         else  ExToothsG[i] = ExToothsG[i-1]+ (6*ExTooths[i-1]);
      }
for (int i=0; i<sizeof(InToothsG)/2 ; i++) 
      {   if (i==0) InToothsG[i]= phaseIN;
         else  InToothsG[i] = InToothsG[i-1]+ (6*InTooths[i-1]);         
      }
NumbcountEX = sizeof(ExTooths)/2+1;
NumbcountIN = sizeof(InTooths)/2+1;

}


void loop() {
if (Serial.available() )
  {
    static int mode = 0; 
    
    int in = Serial.read();
if (in >='0' && in <='9' && mode ==0)
    {int rpm = (in-'0')*1000;
Serial.print (rpm); Serial.println (" rpm");
OCR1A = 2666666UL/rpm;}

else if (in=='+'&& mode==1) {phaseEX++; Serial.print("Ex: ");  Serial.print (phaseEX); Serial.println(" grad");  }
else if (in=='-'&& mode==1) {phaseEX--; Serial.print("Ex: "); Serial.print (phaseEX); Serial.println(" grad"); }

else if (in=='+'&& mode==2) {phaseIN++; Serial.print("In: ");  Serial.print (phaseIN); Serial.println(" grad");  }
else if (in=='-'&& mode==2) {phaseIN--; Serial.print("In: "); Serial.print (phaseIN); Serial.println(" grad"); }

else if (in=='r'){mode = 0; Serial.println ("RPM input");}           // настройка оборотов ДВС
else if (in=='e'){mode = 1; Serial.println ("EX Phase  input");}     // режим смещения фазы выпуска 
else if (in=='i'){mode = 2; Serial.println ("IN Phase  input");}     // режим смещения фазы впуска 
else if (in=='d'){Default () ; } // настройки по умолчанию



for (int i=0; i<sizeof(ExToothsG)/2 ; i++) 
      {   if (i==0) ExToothsG[i]= phaseEX;
         else  ExToothsG[i] = ExToothsG[i-1]+ (6*ExTooths[i-1]);
      }
for (int i=0; i<sizeof(InToothsG)/2 ; i++) 
      {   if (i==0) InToothsG[i]= phaseIN;
         else  InToothsG[i] = InToothsG[i-1]+ (6*InTooths[i-1]);         
      }
Serial.println();
}

}
ISR (TIMER1_COMPA_vect)

{
  
  countgrad++;
  countT++;
  
  if ((tooth_or_hole && countT>=1) || (!tooth_or_hole && countT>=5) ) // основные зубья дпкв (зубы 1гр, впадины 5гр.)
  
  {
    tooth_or_hole = !tooth_or_hole;
    countT = 0;
    counttooth++; 
    if (counttooth>120) counttooth =1;
    if (counttooth!=117 && counttooth!=118 && counttooth!=119 && counttooth!=120) PORTB ^= _BV(CKPpin);
  }
  
    
  if (countgrad>720) countgrad=1;
  
  if (countgrad==ExToothsG[countEX]){ PORTB ^=( _BV(EXpin)); countEX++; if (countEX>=NumbcountEX) countEX=0; }
  if (countgrad==InToothsG[countIN]){ PORTB ^=( _BV(INpin)); countIN++; if (countIN>=NumbcountIN) countIN=0; }
    
  

}