Нужна идея (распараллеливание процессов)

ustas
Offline
Зарегистрирован: 12.03.2012

Делаю вот такую штуку (уже текущее состояние): http://www.youtube.com/watch?v=2uaoDtSHL4Y

Все работает... почти.

Работа с дисплеем построена достаточно просто - есть массив, описывающий текущее состояние каждого "пиксела" и есть прерывания - по прерыванию считывается инфомрация о следующей строке и она отображается и т.п.

Чтобы с дисплеем было удобно работать - написал библиотекчку и несколько "простых" функций. К примеру, вывод "бегущей строки" делается одной строчкой:

matrix.printRunningString(string, color, font6x8, FAST);

Девайс оснащен ИК-приемником и модулем RF24L01 и вот тут "подкрался незаметно". 

Когда на экране что-то статичное (отображение часов на видео) - тут все происходит быстро - функция "статичной" печати быстренько правильно заполняет массив и МК спокойно получает и обрабатывает команды от ИК и принимает от RF24, а вот когда работает функция бегущей строки - мы из основного цикла уходим в обработку функции "сдвигов" и пока вся анимация не пройдет - в основной цикл не возвращаемся и, соответственно, пропускаем все, что только можно.

Чтобы было более понятно - приведу структуру "базовой" функции, которая занимается "печатью" строки и анимацией:


// печатаем строку
void Matrix::printString(String s, byte pos, byte color, unsigned char *Font, char effect, int speed) {
  // ..............
  // инициаизация и подготовка
  // ..............

  if (effect==1) {	// сдвижка вверх
    for (i=0; i<8; i++){

      // ..............
      // что-то тут делаем
      // ..............
    }
    ready=millis()+speed;
    while(millis()<ready);
  }
  else if (effect==2) {	// сдвижка вниз 
    for (i=0; i<8; i++){

      // ..............
      // что-то тут делаем
      // ..............
    }
    ready=millis()+speed;
    while(millis()<ready);
  }

  else if (effect==3) {	// сдвиг влево 

    for(k=0; k<(32-empty*longStringFlag); k++){	// проходим 32 шага - чтобы самый крайний правый пиксель уехал влево до конца

      // ..............
      // что-то тут делаем
      // ..............
    }

    ready=millis()+speed;
    while(millis()<ready);
  }
}

Очевидно, что проблема в том, что когда ждем следующую итерацию для сдвига - крутимся в пустом цикле (и сюда бы как раз включить "прослушивание" ИК и RF24), но вот как это корректно сделать, особенно с учетом того, что управление экраном вынесено в библиотеку и эта библиотека о своем "окружении" вообще ничего не знает?

Или как вместо этого "пустого цикла" возвращаться на время в loop, а потом - снова вернуться в "анимационную" функцию да еще и в нужном состоянии?

P.S. пример blink без delay освоен, но вот как его применить конкретно тут - ума не приложу :(

P.P.S. RF24 я могу повесить на прерывание и это закроет часть проблемы.. с ИК я так сделать точно не смогу.

maksim
Offline
Зарегистрирован: 12.02.2012

Почему с ИК не сможете? библиотеку маленько покурите на второе прерывание сожайте и все будет работать.

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

как я понял, вы получаете строку и пока она вся не выведется, у вас контроллер тупит  с ИК...

тогда напрашивается все красивости не сразу делать, а разбить на отдельные шаги, т.е сдвигать не все 8 строк или 32 столбца в цикле, а за раз на 1 строку/столбец(уменьшится время прерывания, больше отойдет на выполнение основной программы)

ustas
Offline
Зарегистрирован: 12.03.2012

с прерываниями тоже не все так гладко, как ожидалось.

При "отрисовке" прерывание предельно короткое и работаем вообще с минимальным "квантом" изображения - одной строкой. 

По срабатыванию прерывания вызывается функция, которая гасит текущую строку, записывает в регистры состояние следующей строки, зажигает новую строку и возврат. Еще больше укоротить это прерывание - не представляется возможным :(

ustas
Offline
Зарегистрирован: 12.03.2012

Оппа.. взлетело. 

Сделал так.. в основном скетче создал функцию:

void code(){
  listenRF24();
  listenIR();
}

В соответствующих функциях как раз работа с ИК и RF

Эта же функция включена в основном цикле.

В файл объявления библиотеки (lib.h) тоже добавил описание этой функции

void code();

чтобы можно было ее вызывать, и дальше в базовой функции, что упоминалась выше, "пустые" циклы поправил на:

		ready=millis()+speed;
		while(millis()<ready) code();

И это сработало... 

Теперь и радио работает, и ик-команды принимаются, даже если строка движется. Результат достигнут, но, конечно, это "костыль".

И никаких "визуальных эффектов".

ales2k
Offline
Зарегистрирован: 25.02.2013

Я шел более простым путем, без прерываний

Все действия с датчиками, матрицами, радио, экраном и т.п. описал отдельными функциями и каждой позволяю выполнять по одному действию не менее чем через ххх миллисекунд (конечно никаких delay нигде). Например бегущая строка, если есть что показывать, то выполняет по одному действию каждые 60 мс (),не чаще,датчики и радио по пол секунды, и т.п.

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

ну  для распараллеливания(запарился выписывать :) ) можно вообще прикрутить RTOS какой нить, вроде как для мег есть куцая версия

alex_r61
Offline
Зарегистрирован: 20.06.2012

Я делал табло на двух мк. Один работал с матрицей и принимал команды и данные через последовательный порт,

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

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

ustas
Offline
Зарегистрирован: 12.03.2012

alex_r61 пишет:

Я делал табло на двух мк. Один работал с матрицей и принимал команды и данные через последовательный порт,

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

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

Это было бы уже просто.

Сейчас есть желание обойтись одним МК и вроде как мега должна справиться (и, как оказалось, это правда, но я узнал много нового и выкрутился "костылями"), но дальше потенциально подключение LAN-модуля (или даже WiFi) - чувствую, что это еще не все "грабли" на которые я наступил...

Теперь буду знать, что динамическая индикация - это задача для отдельного МК, и если задачи только этим не ограничиваются - лучше использовать специализированый контроллер (чтобы этот контроллер "рулил" матрицами) и для остальных задач - мега (или что-то там, что есть в наличии).

alex_r61
Offline
Зарегистрирован: 20.06.2012

С одним можно, но надо всё правильно разрулить. И работать через прерывания, основной приоритет матрице.

Сделать вывод для неё в прерывании и с минимальным числом команд, используя или "чистый C" или asm.

А остальные пп разделить по приоритету и минимизировать время их выполнения.

Или как вариант табло со статической индикацией.

ustas
Offline
Зарегистрирован: 12.03.2012

Для работы с отображением на матрице используется вот такая функция (обработчик прерывания):

// отображение дисплея
ISR(TIMER1_COMPA_vect)          
{
  if (row++ == 8) row = 0;
  PORTL&=~(1<<7); // установили 7 бит в 0 (начинаем передачу SPI)
  PORTL|=(1<<6); // установили 6 бит в 1 (погасили строку)
  // передаем последовательно данные
  for(char i=0; i < 8; i++) SPI.transfer(~array[7-row][i]);
  PORTL = (PORTL & ~addrmask) | (row) | (1<<7); // формируем адрес новой строки
  PORTL&=~(1<<6); // установили 6 бит в 1 (зажгли строку)
}

Вот как этой фукнции назначить максимальный приоритет? "Визуальные эффекты" начинаются из-за того, что другое прерывание "смещает" по времени исполенине этой функции. А сделать это другое прерывание "короче" - уже тоже не получается - упираюсь в модуль RF24

alex_r61
Offline
Зарегистрирован: 20.06.2012

В Mega невозможно назначить приоритет событию, как в XMega или 51. Поэтому

лучше или не использовать прерывания с большим приоритетом или в какие то 

моменты их запрещать. Сколько ещё и какие прерывания используете?

toc
Offline
Зарегистрирован: 09.02.2013

>> сделать это другое прерывание "короче" - уже тоже не получается - упираюсь в модуль RF24

ustas, вероятно, можно в обработчике прерывания только поставить флаг, типа  "радио модуль просит обратить на него внимание"=true.

А чуть позже, в основном loop, если true сделать listenRF24();

 

 

ustas
Offline
Зарегистрирован: 12.03.2012

toc пишет:

ustas, вероятно, можно в обработчике прерывания только поставить флаг, типа  "радио модуль просит обратить на него внимание"=true.

Супер, спасибо! Это тоже сработало (возвращаюсь к работе на прерываниях - ничего не пропускаем через RF и зазря не используем машинное время). Еще раз спасибо!