Вывод данных в обработчике прерывания ардуино

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем siriniti, 26 фев 2016.

  1. siriniti

    siriniti Нуб

    Добрый день! У меня возникла проблема вывода на экран данных,считываемых с акселерометра troyka-модуля. Задача заключается в том чтобы в функции обработки прерывания выводились значения. Вывод значений осуществляется библиотечной функцией accel.readX_G(). Если написать код вывода в сам обработчик прерываний то вывод не происходит. Подскажите, пожалуйста, с чем это может быть связано? Частота датчика 1 кГц, частоту прерывания установила такую же. Код прилагаю. Вывод данных вне обработчика прерываний осуществляется исправно.
    Код (C++):


    #include <Wire.h>
    // библиотека для работы с модулями IMU
    #include <troyka-imu.h>

    unsigned int latency;
    unsigned char timerLoadValue;
    LIS331DLH_TWI accel_1(0x18);
    LIS331DLH_TWI accel_2(0x19);
    float U1;
    float U2;
    float w = 2 * 3.14 * 10.0;
    float t = 0;

    #define TIMER_CLOCK_FREQ 2000000.0 //2MHz for /8 prescale from 16MHz

    unsigned char SetupTimer1(float timeoutFrequency)
    {
      unsigned char result;   //Подсчет начального значения таймера
      result = (int)((65536.0 - (TIMER_CLOCK_FREQ / timeoutFrequency)) + 0.5);
      TCCR1A = 0;
      TCCR1B = 0 << CS12 | 1 << CS11 | 0 << CS10;
      TIMSK1 = 1 << TOIE1; //Подключение прерывания по переполнению Timer1
      TCNT1 = result;//загружает таймер для первого цикла
      return (result);
      sei();
    }

    ISR(TIMER1_OVF_vect)
    {
      if ( millis() < 10000)
      {
        /*  t = t+0.001;
          U1 = sin (w * t);
          U2 = cos (w * t);*/

        Serial.print(accel_1.readX_G());
        Serial.print("\t");

        Serial.print(accel_1.readY_G());
        Serial.print("\t");

        Serial.print(accel_2.readX_G());
        Serial.print("\t");

        Serial.print(accel_2.readY_G());
        Serial.print("\t");

        /* Serial.print(U1);
          Serial.print("\t");

          Serial.print(U2);
          Serial.print("\t");*/

        Serial.println("");
      }
      latency = TCNT1;
      TCNT1 = latency + timerLoadValue;//Перезагрузка таймера и коррекция по задержке
    }

    void setup(void)
    {
      Serial.begin(115200);//Запуск последовательного порта
      Serial.print("Begin...");
      accel_1.begin();
      accel_2.begin();
      accel_1.setRange(RANGE_2);
      accel_2.setRange(RANGE_2);// устанавливаем чувствительность
      timerLoadValue = SetupTimer1(1000.0);//Запускает таймер и получает загружаемое значение таймера.
    }

    void loop(void)
    {
    }

     
     
  2. Spell

    Spell Нерд

    Во-первых. Проверьте настройки порта на компе. По умолчанию он работает на 9600, а у вас настройка на 115200.

    Во-вторых. Если я не ошибаюсь, то UART сам использует прерывания.
    Из-за чего может возникнуть конфликт. Поэтому в прерываниях обмен использовать в принципе не следует.

    В-третьих. Вообще подпрограмма обработки прерывания должна быть как можно короче. И отрабатывать как можно быстрее.
    Вы прикиньте, сколько времени займет вывод данных. А Вы еще и чтение данных из акселерометров делаете. Вы настроили прерывания на 1кГц. Т.е. код подпрограммы должен отработать менее чем за 1 мс.
    Что-то мне подсказывает, что у Вас прерывания накладываются друг на друга. Т.е. первое не успевает отработать, а уже пришло второе.
    Поэтому лучше в прерывании выставлять некий флаг, по которому уже в общем цикле делать что нужно.
    Я тоже пытался делать вывод из прерывания. У меня на прерывания были повешены энкодеры колес робота. Т.е. прерывания отрабатывало не слишком часто. И то в порт выводилась полная белиберда.

    И в-четвертых. В подрограмме обработки прерывания стоит условие
    Код (C++):
    if ( millis() < 10000)
    Т.е. Ваш вывод будет отрабатывать только первые 10 секунд после включения. Это так и надо?
     
    Последнее редактирование: 27 фев 2016
  3. siriniti

    siriniti Нуб

    В настройках порта вроде всё правильно, при других условиях (выводе данных не в обработчике прерываний) порт исправно считывает всё и данные отображаются.
    Насчет третьего Вашего предположения тоже так сама предполагала, но хотелось просто уточнить у знающих людей тут на форуме,может быть просто в программе совсем не верно что-либо, и поэтому хотелось уточнить.
    А условие стоит пока что для удобства, чтобы не было большого набора данных для дальнейшей обработки в матлабе. В дальнейшем программа будет запускаться на считывание в постоянном режиме работы системы.
    Сейчас программа работает, считывание в переменные осуществляются в основном цикле loop, а вывод на экран уже по прерыванию.
    Код (C++):
    ...
    ISR(TIMER1_OVF_vect)
    {
      if ( millis() < 10000)
      {
        /*  t = t+0.001;
          U1 = sin (w * t);
          U2 = cos (w * t);*/

        Serial.print(ax);
        Serial.print("\t");

        Serial.print(ay);
        Serial.print("\t");

        Serial.print(bx);
        Serial.print("\t");

        Serial.print(by);
        Serial.print("\t");

        /* Serial.print(U1);
          Serial.print("\t");

          Serial.print(U2);
          Serial.print("\t");*/

        Serial.println("");
      }
      latency = TCNT1;
      TCNT1 = latency + timerLoadValue;//Перезагрузка таймера и коррекция по задержке

    }

    ....

    void loop(void)
    {
      ax = accel_1.readX_G();
      ay = accel_1.readY_G();
      bx = accel_2.readX_G();
      by = accel_2.readY_G();
    }

     
     
  4. Spell

    Spell Нерд

    Т.е. Вы хотите вывод делать по времени?
    А зачем тогда вообще прерывание насиловать?
    Не проще в основном цикле делать проверку через millis?
    И еще. Допустим вывод заработал. Вам надо чтобы на экране 1000 раз в секунду (так настроен таймер) выскакивали какие-то строки с данными? Вы же просто ничего не увидите, т.к. изображение размажется.
    Может все-таки скорость вывода уменьшить?
    Вам вообще зачем этот вывод? Пытаетесь проверить работу акселерометров?
    Может лучше так:
    Формируете массив измерений и раз в 0.5 сек выводите в порт?
     
  5. siriniti

    siriniti Нуб

    Тут получается вывод не совсем по времени а просто число измерений за определенный отрезок времени. Ставлю это условие чтобы накопить определенный не большой массив данных и потом его обработать. Данные визуально наблюдать мне ни к чему,они записываются в файл другим монитором. потом я их обрабатываю. Пока просто требуется большая частота дискретизации для отладки других алгоритмов на основе считанных данных с акселя, поэтому и стоят такие параметры портов.
     
  6. Spell

    Spell Нерд

    Понятно.
    В таком случае прерывание, видимо, оправдано.
    А чем не устраивает вариант с установкой флага в прерывании?
    Попробуйте ставьте флаг в прерывании, а в основном цикле делайть чтение данных и обмен с компом.
     
  7. siriniti

    siriniti Нуб

    Да, спасибо) будем работать над этим.
     
  8. Unixon

    Unixon Оракул Модератор

    А нужно сделать ровно наоборот. По прерыванию считывание датчиков и запись в кольцевой буфер, в основном цикле чтение из буфера и отправка. Как вариант - в прерывании только установка флага, а в главном цикле и чтение датчиков по флагу и все остальное.
     
  9. Unixon

    Unixon Оракул Модератор

    При таких параметрах вам нужен канал в 50~60kbps если даже просто передавать данные в бинарном виде (3x16bit 1kHz), с протокольными метками и временем как раз все 115kbps съедятся. И это без какого либо текстового представления!
     
  10. siriniti

    siriniti Нуб

    а как быть с прерыванием по флагу? из справочной информации sei(); -флаг разрешения прерывания. не подскажете как правильно его использовать? к нему обращаться через условия? что-то пока с этим вопросом не разобралась. если Вам это будет трудно описать, или объяснение громоздкое тогда разберусь сама с усилиями. а если не затруднит то было бы здорово чтобы на каком нибудь элементарном примере работу с флагами в прерываниях показали.
     
  11. Limoney

    Limoney Гик

    Просто используйте переменную, которая будет изменяться в прерывании.
    с false на true
    В основном цикле в зависимости от состояния переменной выводить буфер
     
  12. Limoney

    Limoney Гик

    Еще настройку на частоту акселерометров нужно производить каждый раз, когда подается питание. Состояние не запоминается
     
  13. Limoney

    Limoney Гик