Здраствуйте, делаю проект пульта ДУ для FPV самолета из компьютерного джойстика (defender cobra m5) - считывание 5 аналоговых каналов, масштабирование, тримирование, инверсия, экспонента и прочее..., а далее формирование РРМ сигнала прерыванием.
Столкнулся с нехваткой производительности mega2560, если только считывать аналоговые выходы, масштабировать и формировать РРМ сигнал то все отлично, если выполнять остальные функции то цикл loop, насколько я понимаю, не успевает выполниться за цикл РРМ (22,5мс) - получаю один правильный пакет РРМ и 5 пустых..
Решил сильно не упрощать код (наверное зря) и перейть на Due, вот только не знаю как в ней сформировать РРМ сигнал прерываниями. Внизу выкладываю рабочий скетч формирования РРМ для mega2560:
unsigned char outPinPPM = 12; // PPM output pin (do not change - pin 10 tied to ISR)
int pulseMid = 1200;
int PPM_array[9];
int PPMFreq_uS = 22500; // PPM frame length total in uS
int Fixed_uS = 300; // PPM frame padding LOW phase in uS
const int InvertPPM = 0;
void setup() {
// Setup Digital I/O
pinMode(outPinPPM, OUTPUT); // sets as output
// Initialize PPM channel array
char i=0;
for(i=0; i<8; i++) { PPM_array[i] = pulseMid; }
PPM_array[i] = -1; // Mark end
// Initialise ISR Timer 1 - PPM generation
TCCR1A = B00110001; // Compare register B used in mode 3 -Установка выходной линии OC1B (на линии высокий уровень) и Работа таймера/счетчика1 в 8-разрядном ШИМ режиме
TCCR1B = B00010010; // WGM13 & CS11 set to 1 -? и деление частоты на 8
TCCR1C = B00000000; // All set to 0 -принудительно устанавливают значение на выводах OC1A и OC1B =0
TIMSK1 = B00000010; // Interrupt on compare B -OCIE1A разрешают прерывания при совпадении с А и B
TIFR1 = B00000010; // Interrupt on compare B -OCF1A устанавливаются в 1 при совпадение с A, B
OCR1A = PPMFreq_uS; // PPM frequency -регистр сравнения A (22500)
OCR1B = Fixed_uS; // PPM off time (lo padding) -регистр сравнения В (300)
if (InvertPPM == 1) TCCR1A = B00100001;
}
void loop() { // Main loop
int PPM1=1200;
int PPM2=1200;
int PPM3=1200;
int PPM4=1200;
int PPM5=1200;
int PPM6=1200;
int PPM7=1200;
int PPM8=1200;
PPM_array[0] = PPM1 + Fixed_uS;
PPM_array[1] = PPM2 + Fixed_uS;
PPM_array[2] = PPM3 + Fixed_uS;
PPM_array[3] = PPM4 + Fixed_uS;
PPM_array[4] = PPM5 + Fixed_uS;
PPM_array[5] = PPM6 + Fixed_uS;
PPM_array[6] = PPM7 + Fixed_uS;
PPM_array[7] = PPM8 + Fixed_uS;
}
int ACC_PPM_length = 0; // Pulse length current total, used to calculate sync pulse
int *PPM_pointer = PPM_array;
int PPM_len;
// *********************** TIMER 1 **************************
ISR(TIMER1_COMPA_vect) { //-Совпадение A таймера-счётчика 1 и Регистр TCNT1 принял значение, равное регистру OCR1A
PPM_len = *(PPM_pointer++);
if(PPM_len > -1) {
OCR1A = PPM_len; // Set pulse length
ACC_PPM_length += PPM_len; // Add pulse length to accumulator
} else {
PPM_pointer = PPM_array; // Reset table position pointer
OCR1A = PPMFreq_uS - ACC_PPM_length; // Calculate final sync pulse length
ACC_PPM_length = 0; // Reset accumulator
}
}
Решил сильно не упрощать код (наверное зря) и перейть на Due, вот только не знаю как в ней сформировать РРМ сигнал прерываниями. Внизу выкладываю рабочий скетч формирования РРМ для mega2560:
Для начала надо взять даташит на микроконтроллер и читать про аппаратные таймеры, прерывания, их регистры.
Не имею профильного образования в этой области. Поэтому когда делал РРМ на mega2560 взял несколько проектов и построчно их расписал, изучил кучу литературы (как по мне на 2560 ее больше, чем на ARM) и только после этого смог выправить эти проекты под себя. Некоторые моменты по ARM я почитал, боюсь не осилю в ближайшей перспективе. Поэтому и задал вопрос, возможно кто-то уже с этим сталкивался.
И теперь вы предлагаете всем делать то же самое с вашим кодом? Построчно расписывать? Я там них. не могу понять, какие 9 каналов? Почему таймер перезаписыватся, есть же библиотеки для серво моторов, они как раз и формируют PPM. Тот который 50 Гц и 900-2200 микросекунд пульсы?
1. int PPM_array[9] да там должна быть цифра 8
2. есть библиотеки чтобы считать PPM сигнал и сформировать PWM для серв
3. в loop в полной версии кода у меня производится считывание 8 аналоговых каналов масштабирование считаных значений в диапазон 700-1700 (длина импульса РРМ) потом я прибавляю к этому импульсу межканальный интервал 300 мс (в реальном коде я масштабирую в диапазон 1000-2000 чтобы не делать лишних вычислений)
4.Генератор РРМ первые 300мс импульса РРМ находится в "1", потом 700-1700мс в "0" - после значение счетчика перезаписывается и формируется следующие 7 импульсов
5.OCR1A = PPMFreq_uS - ACC_PPM_length - тут вычисляется значение защитного интревала (22500 - PPM_array[i]*8) - чтобы длина пакета РРМ всегда была одинаковой
6. if (InvertPPM == 1) TCCR1A = B00100001 - инвертирует РРМ сигнал (межимпульсный интервал становится "1", испульс РРМ "0")
спасибо большое
Подправил код генератора PPM для Due, может кому пригодится