Частота записи меньше, чем указана. Как исправить?
- Войдите на сайт для отправки комментариев
#include <SPI.h> #include <SdFat.h> #include <TimerFreeTone.h> #include "GyverButton.h" #include <TM1637.h> #include "I2Cdev.h" //Библиотека для работы с I2C устройствами #include "MPU6050.h" //Библиотека для работы с MPU6050 #include <Wire.h> #include <Adafruit_BMP085.h> #include <DS3231.h> DS3231 rtc(SDA, SCL); SdFat SD; Time t; File ECG; File BUT_GREEN; File BUT_BLUE; File MPU_6050; File BMP_180; MPU6050 accelgyro(0x69); GButton buttG(2); GButton buttB(3); TM1637 disp(9, 10); Adafruit_BMP085 bmp; volatile int16_t ax, ay, az; //Переменная для хранения значений полученных с акселерометра bool flag_menu; bool flag_hold; bool flag_bmp180; unsigned long timer_bmp180; unsigned long timer_mpu6050; unsigned long timer_ECG; unsigned long timer_disp; bool disp_on; void setup() { Serial.begin (2000000); #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif rtc.begin(); pinMode (2, INPUT_PULLUP); pinMode (3, INPUT_PULLUP); pinMode (A3, OUTPUT); pinMode (5, OUTPUT); pinMode (6, OUTPUT); analogReference(EXTERNAL); accelgyro.initialize(); disp.Clear(); disp.SetBrightness(7); // яркость, 0 - 7 (минимум - максимум) if (!accelgyro.testConnection()) { disp << "Err1"; delay (3000); disp.Clear (); } if (!bmp.begin(1)) { disp << "Err2"; delay (3000); disp.Clear (); flag_bmp180 = false; } else { flag_bmp180 = true; } if (!SD.begin(4)) { disp << "noSd"; while (1); } ECG = SD.open(("ECG_320.txt"), FILE_WRITE); BUT_GREEN = SD.open(("BUTTON_GREEN.txt"), FILE_WRITE); BUT_BLUE = SD.open(("BUTTON_BLUE.txt"), FILE_WRITE); MPU_6050 = SD.open (("MPU6050.txt"), FILE_WRITE); BMP_180 = SD.open (("BMP180.txt"), FILE_WRITE); } unsigned long test; int buf_ECG; byte buf_pos; void loop() { test = millis (); while (millis () - test < 10000) { buttG.tick (); buttB.tick (); if (millis () - timer_ECG >= 10) { timer_ECG = millis (); ECG.println (analogRead (A0)); } if (millis () - timer_mpu6050 >= 100) { timer_mpu6050 = millis (); accelgyro.getAcceleration(&ax, &ay, &az); MPU_6050.print (ax); MPU_6050.print (F(" ")); MPU_6050.print (ay); MPU_6050.print (F(" ")); MPU_6050.println (az); } if ((millis () - timer_bmp180 >= 50) && flag_bmp180) { timer_bmp180 = millis (); BMP_180.println (bmp.readPressure()); } if (buttB.isSingle () || buttG.isSingle ()) { Serial.println (2); t = rtc.getTime(); disp.PrintTime (t.hour, t.min); disp_on = true; timer_disp = millis (); } if (disp_on && (millis () - timer_disp >= 3000)) { disp_on = false; disp.Clear (); } if (buttB.isHold() && buttG.isHold() && !flag_hold) { flag_menu = !flag_menu; flag_hold = true; } else if (!(buttB.isHold() && buttG.isHold())) { flag_hold = false; } } ECG.close (); BUT_GREEN.close (); BUT_BLUE.close (); MPU_6050.close (); BMP_180.close (); while (1) {}; }
Это должен быть прибор, записывающий физиологические показатели на SD карту с последующим анализом моей программой на компьютере. Записываться будут значения с акселерометра, ЭКГ, дыхание (BMP180). Частота ЭКГ чем выше, тем лучше. Сейчас, как видно в коде, частота записи ЭКГ стоит раз в 10 мс (100 Гц), что совсем не много, хотелось бы герц 300. Но, записав запись длительностью 10 сек (программа выше как раз делает запись 10 секунд) я увидел, что в файл ЭКГ записалось всего ~700 строк, что соответствует частоте записи 70 Гц. Почему так мало и как это исправить? Хватит ли мощности ардуино чтобы записывать ЭКГ с частотой 320 Гц (раз в 3125 микросекунд), параллельно записывая значения с других датчиков? Если да то как это сделать? Заранее спасибо за ответы!
А если все лишнее убрать и писать только значения ?
Сдается мне узкое место тут не Ардуино , а карта памяти с ее библиотекой
Вообще-то, чтобы не писать вслепую, есть такие функции, как milllis и micros.
...
Нет, не так.
Первую строчку своего сообщения я написал ДО того, как заглянул в исходник. А как заглянул - немного офонарел. Вы всерьез хотите на Ардуино писать одновременно в 5 файлов с частотой 100 раз в секунду?
В общем, для начала озвучте, какой именно разновидностью Ардуино Вы пользуетесь.
А по поводу исходника - в процессе логирования пишите в файл не только величину параметра, но время, (в мс или мкс), когда этот параметр измерен. Сразу будет информация к размышлению, какая операция какое время занимает. (ну а отсюда и некоторое впечатление, что на Ардуино сделать возможно, а что - нет).
Причем судя по результатам, сама то карта вполне успевает.
Но в ряде случаев: когда совпадает по времени, опрос гироскопа, датчика давления и тд, уже не очень успевает.
И некорректно поставлен вопрос в шапке.
По коду все нормально выдает, а именно: не "ЧАЩЕ ЧЕМ РАЗ В 10мс"
arduino nano
И что, Ардуино Нано позволяет открыть одновременно 5 файлов?
Чудеса!
Сообщите заодно отчет об использованной памяти в конце компиляции.
Ну и после того, как добавите в файлы время записи, выложите эти файлы сюда. В самом деле интересно.
И что, Ардуино Нано позволяет открыть одновременно 5 файлов?
Чудеса!
Сообщите заодно отчет об использованной памяти в конце компиляции.
Ну и после того, как добавите в файлы время записи, выложите эти файлы сюда. В самом деле интересно.
Эмм... а в чем скрытый смысл писания в 5 файлов? чем хуже один log, в который последовательно пишется время+код_параметра+значение_параметра?
Скрытый смысл в том что у всех датчиков разная частота опроса.
Скрытый смысл в том что у всех датчиков разная частота опроса.
И что?
Вы сделали то, что я просил: добавить в каждую запись время и выложить на форум результат?
Эмм... а в чем скрытый смысл писания в 5 файлов? чем хуже один log, в который последовательно пишется время+код_параметра+значение_параметра?
Скрытый смысл в том что у всех датчиков разная частота опроса.
andriano не зря спрашивает про пожирание памяти.
andriano не зря спрашивает про пожирание памяти.
Я не шутил, я действительно удивлен.
Если программа с пятью открытыми файлами работает на Нано, значит, библиотека использует единственный буфер для всех файлов. А это - просто катастрофический удар по производительности. В принципе - логично: лучше пусть работает чудовищно медленно, чем совсем не работает. С другой стороны, в программировании есть все таки традиция - предпочитать отказ от возможностей (например, открытия одновременно нескольких файлов) вместо чудовищно медленной реализации этих возможностей.
Но в любом случае хотелось бы запрошенной информации от ТС для ее анализа и выработки оптимальной стратегии. Хотя, вполне вероятно, что сокращение числа файлов до одного решит проблему, но все равно хотелось бы разобраться.
Что-то ТС куда-то исчез из темы. Подозреваю, что воспользовался советом писать в единственный файл и утратил интерес к предмету обсуждения.
Попытался немножечко посмотреть, как оно работает. Честно говоря - жуть.
Смотрел на примере стандартной SD. Если бы как следует разобрался, сравнил бы с SdFat, но не судьба. SD описана весьма обильно, но из рук вон плохо: даже в "родных" примерах (которых всего 6 штук) вовсю используются недокументированные вещи. С описанием SdFat все намного печальнее.
Итак, что удалось выяснить (для платы Arduino Uno).
- SPI работает на частоте 4 МГц. Казалось бы, частота обмена может достигать 500 кБайт/с, но не тут-то было.
- между передачей отдельных байтов существуют паузы, в результате чего максимальный темп передачи составляет 296.3 кБайт/с.
- при указанных условиях время передачи одного сектора (512 байт) могло бы составить 1.728 мс + накладные расходы на передачу служебной информации. Но, увы, при обмене встречаются и гораздо более длительные паузы.
- в результате на запись одного сектора уходит в среднем 4-6 мс. Это в случае, когда мы открыли файл и пишем в него, не закрывая. Это время затрачивается не каждый вызов функций записи, а только тогда, когда в буфере записи накопились 512 байт. В остальных случаях функции "записи" отрабатывают гораздо быстрее.
- по достижении гарнцы кластера время записи увеличивается до 17-18 мс. Очевидно, в это время, помимо прочего, входит работа с самой FAT, которая также расположена в секторах на карте. В памяти ее копии в случае с Ардуино не предусмотрено.
- хотя в документации указано, что библиотека, якобы, может работать с несколькими одновременно открытыми файлами, это неправда.
- собственно, в описании прямо предлагается открывать файл непосредственно перед записью и закрывать сразу после. В таком режиме на запись в файл одного сектора информации уходит уже 15-24 мс. Причем, меньшим величинам (15-18 мс) соответствует случай не до конца заполненного буфера, а большим (22-24 мс) - когда буфер (512 байт) заполняется полностью. В последнем случае, очевидно, запись происходит одновременно в два сектора - конец предыдущего и начало следующего.
- на границе кластера время записи сектора с переоткрытием файла увеличивается до 37-44 мс.
Итого получается, что писать в темпе порядка 100 записей в секунду можно в одном единственно случае - если мы один раз открыли файл и не закрываем его до того, как не запишем в него самую последнюю запись. И то такая периодичность будет нарушаться каждый раз при пересечении границы кластера (для 2Gb карты FAT16 - это 32к). Не следует забывать, что в этом случае необходимо закрыть файл по окончании записи. Если не сделать этого, вся информация будет потеряна. Ну и, естественно, такая работа возможна при наличии единственного файла.
В режиме с переоткрытием максимальный темп записи снижаться примерно до 40 записей в секунду, и то время от времени од будет прерываться по мере пересечения границы кластера. Правда, можно одновременно работать с несколькими файлами. При этом указанные 40 записей - это суммарное количество по всем файлам.
Ну чтобы более или менее выдерживать равномерный темп, этот темп не должен превышать примерно 20 записей в секунду. Речь, разумеется, идет о коротких записях - длиной менее сектора в любом случае. Ну и в условии пренебрежения временем на обработку записи, например, на преобразование числа в текст.