Ты знаешь мою искреннюю "любовь" к пассажиру ;)), но код вполне изящный. Если "доё..ываться" , то до diginalWrite(!digitelRRead(xxx)). И то в тестах все так пишут, из продакшн, конечно убрать надо, но пассажир про продакшн и не говорил.
Если "доё..ываться" , то до diginalWrite(!digitelRRead(xxx)).
Да, ладно! К чему тут? Вот сюда посмотри. Во втором коде используется недокументированное значение второго параметра pinMode, загоняющее светодиод в очень интересный режим :-)))
ТС - задача твоя решается очень просто. Делаешь процедуру, которая берёт из массива булевы данные с датчиков ( 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; }
}
15 строчку заменить на if ((uint16_t)millis() - phase_start + phase_shift > data[data_pos]) {
А как же
Приведенный мной код корректно обрабатывает переполнение переменных
Перестал отрабатывать? :-)
Да ладно Женя, мелкие придирки.
Ты знаешь мою искреннюю "любовь" к пассажиру ;)), но код вполне изящный. Если "доё..ываться" , то до diginalWrite(!digitelRRead(xxx)). И то в тестах все так пишут, из продакшн, конечно убрать надо, но пассажир про продакшн и не говорил.
Сколько оборотов/мин получилось в итоге???
Сколько оборотов/мин получилось в итоге???
+1 на миллис и дигиталврайт будет коряво работать на больших скоростях. только на таймерах, луп должен быть пустой
Я тоже когда то пытался такую задачу решить, но тогда ещё знаний не было((
было время на работе, решил по упражняться. Вот что получилось. Луп в формировании сигнала не участвует, всё на таймере 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
ну и ТСа картинка для сравнения
постом выше скетч немного неточен в плане сигнала датчика коленвала. Вот более правильный скетч.
//-------------------------------------------- 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; } }