Частота записи меньше, чем указана. Как исправить?
- Войдите на сайт для отправки комментариев
#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 записей в секунду. Речь, разумеется, идет о коротких записях - длиной менее сектора в любом случае. Ну и в условии пренебрежения временем на обработку записи, например, на преобразование числа в текст.