Добрый день! У меня возникла проблема вывода на экран данных,считываемых с акселерометра 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) { }
Во-первых. Проверьте настройки порта на компе. По умолчанию он работает на 9600, а у вас настройка на 115200. Во-вторых. Если я не ошибаюсь, то UART сам использует прерывания. Из-за чего может возникнуть конфликт. Поэтому в прерываниях обмен использовать в принципе не следует. В-третьих. Вообще подпрограмма обработки прерывания должна быть как можно короче. И отрабатывать как можно быстрее. Вы прикиньте, сколько времени займет вывод данных. А Вы еще и чтение данных из акселерометров делаете. Вы настроили прерывания на 1кГц. Т.е. код подпрограммы должен отработать менее чем за 1 мс. Что-то мне подсказывает, что у Вас прерывания накладываются друг на друга. Т.е. первое не успевает отработать, а уже пришло второе. Поэтому лучше в прерывании выставлять некий флаг, по которому уже в общем цикле делать что нужно. Я тоже пытался делать вывод из прерывания. У меня на прерывания были повешены энкодеры колес робота. Т.е. прерывания отрабатывало не слишком часто. И то в порт выводилась полная белиберда. И в-четвертых. В подрограмме обработки прерывания стоит условие Код (C++): if ( millis() < 10000) Т.е. Ваш вывод будет отрабатывать только первые 10 секунд после включения. Это так и надо?
В настройках порта вроде всё правильно, при других условиях (выводе данных не в обработчике прерываний) порт исправно считывает всё и данные отображаются. Насчет третьего Вашего предположения тоже так сама предполагала, но хотелось просто уточнить у знающих людей тут на форуме,может быть просто в программе совсем не верно что-либо, и поэтому хотелось уточнить. А условие стоит пока что для удобства, чтобы не было большого набора данных для дальнейшей обработки в матлабе. В дальнейшем программа будет запускаться на считывание в постоянном режиме работы системы. Сейчас программа работает, считывание в переменные осуществляются в основном цикле 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(); }
Т.е. Вы хотите вывод делать по времени? А зачем тогда вообще прерывание насиловать? Не проще в основном цикле делать проверку через millis? И еще. Допустим вывод заработал. Вам надо чтобы на экране 1000 раз в секунду (так настроен таймер) выскакивали какие-то строки с данными? Вы же просто ничего не увидите, т.к. изображение размажется. Может все-таки скорость вывода уменьшить? Вам вообще зачем этот вывод? Пытаетесь проверить работу акселерометров? Может лучше так: Формируете массив измерений и раз в 0.5 сек выводите в порт?
Тут получается вывод не совсем по времени а просто число измерений за определенный отрезок времени. Ставлю это условие чтобы накопить определенный не большой массив данных и потом его обработать. Данные визуально наблюдать мне ни к чему,они записываются в файл другим монитором. потом я их обрабатываю. Пока просто требуется большая частота дискретизации для отладки других алгоритмов на основе считанных данных с акселя, поэтому и стоят такие параметры портов.
Понятно. В таком случае прерывание, видимо, оправдано. А чем не устраивает вариант с установкой флага в прерывании? Попробуйте ставьте флаг в прерывании, а в основном цикле делайть чтение данных и обмен с компом.
А нужно сделать ровно наоборот. По прерыванию считывание датчиков и запись в кольцевой буфер, в основном цикле чтение из буфера и отправка. Как вариант - в прерывании только установка флага, а в главном цикле и чтение датчиков по флагу и все остальное.
При таких параметрах вам нужен канал в 50~60kbps если даже просто передавать данные в бинарном виде (3x16bit 1kHz), с протокольными метками и временем как раз все 115kbps съедятся. И это без какого либо текстового представления!
а как быть с прерыванием по флагу? из справочной информации sei(); -флаг разрешения прерывания. не подскажете как правильно его использовать? к нему обращаться через условия? что-то пока с этим вопросом не разобралась. если Вам это будет трудно описать, или объяснение громоздкое тогда разберусь сама с усилиями. а если не затруднит то было бы здорово чтобы на каком нибудь элементарном примере работу с флагами в прерываниях показали.
Просто используйте переменную, которая будет изменяться в прерывании. с false на true В основном цикле в зависимости от состояния переменной выводить буфер
Еще настройку на частоту акселерометров нужно производить каждый раз, когда подается питание. Состояние не запоминается