Подключиться к YouTube? Подключиться к YouTube? Подключиться к YouTube? Подключиться к YouTube? Подключиться к YouTube? Подключиться к YouTube? Bluetooth-акселерометрBluetooth-акселерометр делается на основе платформы Arduino Nano, модуля акселерометра ADXL335 и bluetooth-модуля HM-10 поддерживающего Bluetooth 4.0 LE (НЕЛЬЗЯ использовать модули HC-06, HC-05). Даже если Вы никогда не слышали об Arduino, то это будет отличный повод с ней познакомиться. Здесь не будет подробного описания Arduino, но в Интернете про это есть огромное количество информации, и на наиболее важную информацию будут ссылки. Главным преимуществом Bluetooth по сравнению с Wi-Fi является очень маленькое потребление энергии. Однако Bluetooth-модуль имеет очень маленькую скорость передачи дынных, и поэтому нужно тщательно оптимизировать передаваемые данные. Сжатие данных основывается на расчете разницы между соседними значениями и передаче по Bluetooth только этой разницы. Благодаря этому для передачи значения хватает одного байта. Это позволяет обеспечить максимальную частоту дискретизации около 1870 Hz (при измерении 1 оси). Преимущества подключения акселерометра через bluetooth в сравнении с подключением через гнездо для наушников: • Измерение не только колебаний но и абсолютных значений. Недостатки: • Чувствительность меньше (к цифровым акселерометрам (BMA180, LSM9DS1) это не относится). Может быть увеличена в 100 раз. Подключение Arduino Nano к компьютеру и загрузка скетчаDownload the Arduino IDE Скетч 1: /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue = 0; int LastAccelValue = 0; int dValue = 0; void setup() { //Put your setup code here, to run once: //Открывает последовательный порт, устанавливает скорость передачи данных. Serial.begin(9600); //Serial.begin(115200); //A5 => Высокоимпедансное состояние pinMode(A5, INPUT); digitalWrite(A5, LOW); //A5 => (+) //pinMode(A5, OUTPUT); //digitalWrite(A5, HIGH); //A1 => GND pinMode(A1, OUTPUT); digitalWrite(A1, LOW); //A0 => Высокоимпедансное состояние //pinMode(A0, INPUT); //digitalWrite(A0, LOW); //Настраивает опорное напряжение, используемое для аналогового входа. analogReference(EXTERNAL); //EXTERNAL: Напряжение подаваемое на вывод AREF (только 0-5 В) используется как опорное напряжение. //D4 => (+) pinMode(4, OUTPUT); digitalWrite(4, HIGH); //D5 => GND pinMode(5, OUTPUT); digitalWrite(5, LOW); delay(500); //Пауза в миллисекундах. } void loop() { //Put your main code here, to run repeatedly: AccelValue = analogRead(A3); //Напряжение поданное на аналоговый вход (от 0В до опорного напряжения) будет преобразовано в значение от 0 до 1023. if (i < 3) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue); i++; ii++; ByteArr[ii] = lowByte(AccelValue); } else { dValue = AccelValue - LastAccelValue; if (abs(dValue) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue); } else { ByteArr[ii] = char(dValue); } } LastAccelValue = AccelValue; i++; ii++; WriteFunction(); //delay(3); //~319 Hz. delayMicroseconds(1000); //~880 Hz. MAX для Serial.begin(9600). delayMicroseconds(1000) = delay(1) //delayMicroseconds(400); //Serial.begin(115200), ~1867 Hz. MAX } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 200) { i = 0; } } При загрузке скетча через USB, пины TXD и RXD должны быть свободны. Если ваш модуль акселерометра отличается от моего и у него контакты расположены по другому, то в скетче нужно изменить номера пинов Arduino Nano. Сборка bluetooth-акселерометраСоединения: Arduino Nano и HM-10 модуль Arduino Nano и ADXL335 модуль ADXL335 модуль Arduino Nano Цифровые выводы Модуль акселерометра ADXL335 снабжен стабилизатором напряжения. При подключении к нему напряжения больше 3.6 V, стабилизатор напряжения начинает создавать шумы видимые в результатах измерений. Чтобы уменьшить напряжение на акселерометре, он должен подключаться к 4.5 V через резистор. При подключении акселерометра к пину "3V3", в измерениях тоже видны шумы. Шумы от стабилизатора напряжения. Могут быть более значительные шумы от bluetooth-модуля. Про них читайте ниже. Подключение 4.5 V через резистор. Для тестирования, в настройках указаны такие значения, чтобы показывались величины получаемые от аналогово-цифрового преобразователя (без пересчета в вольты или ускорение). Для увеличения чувствительности аналогового входа, опорное напряжение делается в два раза меньше чем напряжение питания. Делается это делителем напряжения из двух одинаковых резисторов. Опорное напряжение подключается к пину "REF". Обратите внимание чтобы ножки резисторов ни при каких обстоятельствах не могли коснуться друг друга. Вставлять резисторы удобно с помощью плоскогубцев. Настройка приложения1: Правильность настройки частоты дискретизации нужно обязательно проверить. Для этого нужен источник вибрации с известной частотой. 2: Vref = V × R2 / (R1 + R2) На пине "AREF" имеется внутренний резистор 32 kOhm. R2 = 5K × 32K / (5K + 32K) = 4.32K Ohm Напряжение батареек в процессе работы постоянно уменьшается. Поэтому лучше измерить напряжение (под нагрузкой) мультиметром. Если напряжение (под нагрузкой) одной батарейки 1.4 V, тогда суммарное напряжение 4.2 V. Vref = 4.2 × 4.32K / (5K + 4.32K) = 1.947 V 3 и 4: Preliminary Technical Data ADXL335 Напряжение на акселерометре при подключении через резистор 5K Ohm примерно равно V × 0.7 (например 4.2 × 0.7 = 2. 94). Правильность настроек можно проверить и уточнить сделав эксперименты при отключенном режиме "Только вибрация". Значение от оси направленной строго вниз должно быть -1g, а при переворачивании акселерометра должно быть +1g. Без мультиметра сделать это сложно, из-за необходимости одновременного настраивания опорного напряжения и чувствительности акселерометра. Вначале нужно сделать так чтобы разница между максимумом и минимумом была около 2g. Потом регулируется напряжение для 0g. Настройка bluetooth-модуля HM-10 для увеличения скорости передачи данныхBluetooth-модуль можно подключить к компьютеру через адаптер USB-UART. Однако это дополнительные траты и возможные лишние действия для поиска и установки драйверов. Bluetooth-модуль можно настроить и через Arduino Nano. Однако изменять скорость передачи данных можно только до 115200 bps , потому что SoftwareSerial не поддерживает скорость 230400 bps. Тем более что при скорости 230400 bps не наблюдается реального увеличения скорости по сравнению с 115200 bps. И к сожалению SoftwareSerial не получается использовать при работе bluetooth-акселерометра (если частота дискретизации больше 500 Hz), потому что отправка данных через SoftwareSerial останавливает главную программу примерно на 2 мс. SoftwareSerial Library Скетч 2: #include <SoftwareSerial.h> //Подключаем библиотеку SoftwareSerial SoftwareSerial softSerial(11, 12); //Создаём объект softSerial указывая выводы RX, TX. В данном случае вывод TX модуля подключается к выводу 11 Arduino, а вывод RX модуля к выводу 12 Arduino. void setup() { //Инициируем работу шин UART с указанием скоростей обеих шин: //softSerial.begin(115200); softSerial.begin(9600); //Serial.begin(115200); Serial.begin(9600); //D9 => (+) pinMode(9, OUTPUT); digitalWrite(9, HIGH); //D10 => GND pinMode(10, OUTPUT); digitalWrite(10, LOW); } void loop() { //Выполняем ретрансляцию. Всё что пришло с модуля - отправляем компьютеру, а всё что пришло с компьютера - отправляем модулю. if (softSerial.available()) Serial.write(softSerial.read()); //От модуля через Arduino к компьютеру. if (Serial.available()) softSerial.write(Serial.read()); //От компьютера через Arduino к модулю. } Проверка работы монитора: AT Список всех команд: AT+HELP Получение версии прошивки и версии Bluetooth: AT+VERSION Настройка скорости передачи данных: AT+BAUD (AT+BAUD8 => 115200 bps, AT+BAUD4 => 9600 bps) Изменения в скетче 1: . . . void setup() { . . . //Serial.begin(9600); Serial.begin(115200); . . . } void loop() { . . . //delay(3); //~319 Hz. //delayMicroseconds(1000); //~880 Hz. MAX для Serial.begin(9600). delayMicroseconds(1000) = delay(1) delayMicroseconds(400); //Serial.begin(115200), ~1867 Hz. MAX } . . . Увеличение/уменьшение чувствительности Arduino NanoДля изменения чувствительности акселерометра (аналогового входа) меняется опорное напряжение на пине "REF". Если опорное напряжение будет слишком большое, то вместо синусоиды буду ступеньки. Кроме того очень маленькие изменения не будут фиксироваться. Если опорное напряжение будет слишком маленькое, то напряжение измеряемого сигнала может превысить опорное напряжение и тогда результат измерения будет соответствовать опорному напряжению. Если разница между соседними величинами будет превышать 10% (5% при дополнительном использовании лазерного датчика) от опорного напряжения, то разница между соседними измерениями не будет помещаться в байт и передача данных по bluetooth будет работать нестабильно. В этом случае можно уменьшить частоту дискретизации (увеличить паузу между измерениями). Другие варианты сборкиBluetooth-модуль в момент отправки данных потребляет больше тока. Это может привести к небольшому снижению напряжения во всем устройстве. Вследствие этого уменьшается и опорное напряжение. Это приводит к искажению результатов измерения. Чем меньше батарейки и чем хуже они подключены, тем больше будут искажения. Чтобы этого избежать, нужно подключить к bluetooth-модулю конденсатор (~220 mkF). Шумы от bluetooth-модуля. С конденсатором 220 mkF. Но при включении питания происходит быстрая зарядка конденсатора, при этом сила тока может превышать допустимые значения для пина. И чем больше емкость конденсатора тем больше вероятность что через какое то время пин сгорит. Поэтому питание к bluetooth-модулю лучше подсоединить напрямую от батареек. Но для эффективной работы конденсатора нужно между конденсатором и плюсом питания добавить резистор (~51 Ohm). При этом чем больше емкость конденсатора или сопротивление резистора, тем лучше будет фильтр. Однако при слишком большом сопротивлении резистора, bluetooth-модулю будет не хватать напряжения (особенно если источник пинания имеет напряжение 3.6 V и ниже). Также очень важно состояние контактов конденсатора с макетной платой, и иногда конденсатор нужно вытащить из макетной платы и вставить обратно. Чтобы убрать шумы иногда нужно обновить контакты подключающие батарейки, для этого нужно оба провода вытащить и вставить обратно. Лучшем вариантом избавления от шумов будет соединение деталей пайкой на специальной макетной плате. Изменения в скетче 1: . . . void setup() { . . . //A5 => Высокоимпедансное состояние //pinMode(A5, INPUT); //digitalWrite(A5, LOW); //A5 => (+) pinMode(A5, OUTPUT); digitalWrite(A5, HIGH); . . . //D4 => (+) //pinMode(4, OUTPUT); //digitalWrite(4, HIGH); //D5 => GND //pinMode(5, OUTPUT); //digitalWrite(5, LOW); . . . } . . . Если батарейка выступает из батарейного отсека, чтобы устройство стояло ровно, можно приклеить мягкий материал. Если размер устройства не имеет большого значения, то лучше использовать вместо батареек AAA батарейки AA с соответствующим батарейным отсеком. Батарейки AA будут лучше отдавать ток в моменты передачи данных, и у них будет меньше колебаться напряжение под нагрузкой. Если требуется максимально облегчить или уменьшить размер устройства, можно использовать литиевую батарейку с напряжением 3.6 V. Самая дорогая часть в этом варианте - это литиевая батарейка. Поэтому используйте этот вариант в крайнем случае. Устройство потребляет около 20 mA, а емкость батарейки (по словам продавца) около 1600 mAh, следовательно такой батарейки должно хватить примерно на трое суток непрерывной работы. Поэтому вместо батарейки размером 2/3AA можно использовать 1/2AA. Ножки батарейки конечно же можно подключить к пинам "5V" и "GND" без дополнительных проводов, но тогда будет труднее отключать питание и ножки батарейки могут быстро отломаться. Чтобы батарейка не колебалась на ножках внося помехи и результаты измерений, вставлен кусочек мягкого материала. Лазерный датчикЛазерный датчик позволяет определить смещение центра масс вращающейся детали. Максимальная частота, при которой можно примерно определить фазу метки, около 50 Hz. Только ради этой функции не нужно собирать bluetooth-акселерометр. Стробоскоп для акселерометра точнее и проще в изготовлении. Однако лазерный датчик не имеет нижней границы частоты вращения, поэтому если частота вращения меньше 15 Hz, нужно использовать лазерный датчик а не стробоскоп. Соединения: Лазерный датчик Перед использованием лазерного датчика его нужно протестировать. Для этого лазерный датчик подключается вместо ADXL335 акселерометра. Лазерный датчик и Arduino Nano Если на датчик будет светить свет от лампы подключенной к сети 220V или 110V, то могут наблюдаться колебания с частотой равной частоте сети умноженной на 2. Так можно проверять правильность настройки частоты дискретизации. Теперь можно наклеить на вентилятор полоску белой клейкой ленты и направить лазерный датчик на вращающийся вентилятор. Обратите внимание, что для стабильной передачи данных по bluetooth, нужно чтобы разница между соседними значениями была меньше 128. При работе лазерного датчика вместе с акселерометром, разница между соседними значениями не важна. После проверки лазерного датчика можно собирать следующую схему. Лазерный датчик и Arduino Nano В Arduino Nano нужно загрузить другой скетч. При загрузке скетча через USB, пины TXD и RXD должны быть свободны. Скетч 3: /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue = 0; int LastAccelValue = 0; int dValue = 0; int LaserValue = 0; int maxLaserValue = 0; int minLaserValue = 1023; int iii = 0; int Border = 0; boolean Mark = false; void setup() { //Put your setup code here, to run once: //Открывает последовательный порт, устанавливает скорость передачи данных. Serial.begin(115200); //A5 => Высокоимпедансное состояние pinMode(A5, INPUT); digitalWrite(A5, LOW); //A5 => (+) //pinMode(A5, OUTPUT); //digitalWrite(A5, HIGH); //A1 => GND pinMode(A1, OUTPUT); digitalWrite(A1, LOW); //A0 => Высокоимпедансное состояние //pinMode(A0, INPUT); //digitalWrite(A0, LOW); //Настраивает опорное напряжение, используемое для аналогового входа. analogReference(EXTERNAL); //EXTERNAL: Напряжение подаваемое на вывод AREF (только 0-5 В) используется как опорное напряжение. //D4 => (+) pinMode(4, OUTPUT); digitalWrite(4, HIGH); //D5 => GND pinMode(5, OUTPUT); digitalWrite(5, LOW); delay(500); //Пауза в миллисекундах. } void loop() { //Put your main code here, to run repeatedly: AccelValue = analogRead(A3); //Напряжение поданное на аналоговый вход (от 0В до опорного напряжения) будет преобразовано в значение от 0 до 1023. LaserValue = analogRead(A6); iii++; if (LaserValue > maxLaserValue) maxLaserValue = LaserValue; if (LaserValue < minLaserValue) minLaserValue = LaserValue; if (iii > 2000) { Border = maxLaserValue - round((maxLaserValue - minLaserValue) / 2.0); iii = 0; maxLaserValue = 0; minLaserValue = 1023; } Mark = (Border > 0 && LaserValue > Border); if (i < 3) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue); i++; ii++; ByteArr[ii] = lowByte(AccelValue); } else { dValue = AccelValue - LastAccelValue; if (abs(dValue) > 63) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue); } else { ByteArr[ii] = char(dValue); if (Mark) { if (dValue >= 0) bitWrite(ByteArr[ii], 6, 1); else bitWrite(ByteArr[ii], 6, 0); } } } LastAccelValue = AccelValue; i++; ii++; WriteFunction(); //delayMicroseconds(400); // ~1540 Hz delayMicroseconds(280); // ~1893 Hz } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 200) { i = 0; } } С загруженным в Arduino Nano скетчем для лазерного датчика, в настройках приложения обязательно должна быть включена опция "Лазерный датчик". Частота дискретизации должна быть максимальной (около 1890 Hz). Из-за наличия в конструкции модуля акселерометра RC-цепи, происходит сдвиг фазы сигнала. Для компенсации этого сдвига можно указать значение произведения значений резистора (kOhm) и конденсатора (nF). Например, 32 kOhm × 100 nF = 3200. Учитывайте что RC-цепь акселерометра уменьшает или совсем сглаживает колебания с большой частотой. Увеличение чувствительности акселерометраИспользуя операционные усилители соединенные в схему ДИФФЕРЕНЦИАЛЬНОГО усилителя, можно усилить ПОЛЕЗНУЮ часть сигнала в 100-1000 раз (и больше). На видео сигнал от акселерометра увеличен в 50 раз. При этом хорошо видны шумы акселерометра. Инструментальный усилитель AD623 - это готовая схема дифференциального усилителя составленная из трех операционных усилителей. БОльшая часть электронных компонентов на схеме ниже нужны только для уменьшения помех. 1: Чувствительность акселерометра = Исходная чувствительность 2: Для удобства настройки V2, лучше всего записать это значение равным 0. Но если есть необходимость видеть абсолютные значения, тогда нужно измерить V2 и сделать расчет: Напряжение при нулевом ускорении = (V0 - V2) × K Трехосевой Bluetooth-акселерометрИз-за передачи в три раза большего количества данных, трехосевой Bluetooth-акселерометр имеет в три раза меньшую максимальную частоту дискретизации в сравнении с одноосевым Bluetooth-акселерометром. Скетч 4 (XYZ): /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue1 = 0; int AccelValue2 = 0; int AccelValue3 = 0; int LastAccelValue1 = 0; int LastAccelValue2 = 0; int LastAccelValue3 = 0; int dValue1 = 0; int dValue2 = 0; int dValue3 = 0; void setup() { //Put your setup code here, to run once: //Opens serial port, sets data rate. Serial.begin(9600); //Serial.begin(115200); //A5 => High impedance pinMode(A5, INPUT); digitalWrite(A5, LOW); //A5 => (+) //pinMode(A5, OUTPUT); //digitalWrite(A5, HIGH); //A1 => GND pinMode(A1, OUTPUT); digitalWrite(A1, LOW); //A0 => High impedance //pinMode(A0, INPUT); //digitalWrite(A0, LOW); //Configures the reference voltage used for analog input (i.e. the value used as the top of the input range). analogReference(EXTERNAL); //EXTERNAL: the voltage applied to the AREF pin (0 to 5V only) is used as the reference. //D4 => (+) pinMode(4, OUTPUT); digitalWrite(4, HIGH); //D5 => GND pinMode(5, OUTPUT); digitalWrite(5, LOW); delay(500); //Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { //Put your main code here, to run repeatedly: AccelValue1 = analogRead(A4); //X-axis. Reads the value from the specified analog pin. This means that it will map input voltages between 0V and reference voltage into integer values between 0 and 1023. AccelValue2 = analogRead(A3); //Y-axis. AccelValue3 = analogRead(A2); //Z-axis. if (i < 7) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue1); i++; ii++; ByteArr[ii] = lowByte(AccelValue1); i++; ii++; ByteArr[ii] = highByte(AccelValue2); i++; ii++; ByteArr[ii] = lowByte(AccelValue2); i++; ii++; ByteArr[ii] = highByte(AccelValue3); i++; ii++; ByteArr[ii] = lowByte(AccelValue3); } else { dValue1 = AccelValue1 - LastAccelValue1; dValue2 = AccelValue2 - LastAccelValue2; dValue3 = AccelValue3 - LastAccelValue3; if (abs(dValue1) > 127 || abs(dValue2) > 127 || abs(dValue3) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue3); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue3); } else { ByteArr[ii] = char(dValue1); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue2); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue3); } } LastAccelValue1 = AccelValue1; LastAccelValue2 = AccelValue2; LastAccelValue3 = AccelValue3; i++; ii++; WriteFunction(); delay(3); //~293 Hz. MAX for Serial.begin(9600). //delayMicroseconds(1200); //Serial.begin(115200), ~622 Hz. MAX } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 600) { i = 0; } } Скетч 5 (XY): /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue1 = 0; int AccelValue2 = 0; int LastAccelValue1 = 0; int LastAccelValue2 = 0; int dValue1 = 0; int dValue2 = 0; void setup() { //Put your setup code here, to run once: //Opens serial port, sets data rate. Serial.begin(9600); //Serial.begin(115200); //A5 => High impedance pinMode(A5, INPUT); digitalWrite(A5, LOW); //A5 => (+) //pinMode(A5, OUTPUT); //digitalWrite(A5, HIGH); //A1 => GND pinMode(A1, OUTPUT); digitalWrite(A1, LOW); //A0 => High impedance //pinMode(A0, INPUT); //digitalWrite(A0, LOW); //Configures the reference voltage used for analog input (i.e. the value used as the top of the input range). analogReference(EXTERNAL); //EXTERNAL: the voltage applied to the AREF pin (0 to 5V only) is used as the reference. //D4 => (+) pinMode(4, OUTPUT); digitalWrite(4, HIGH); //D5 => GND pinMode(5, OUTPUT); digitalWrite(5, LOW); delay(500); //Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { //Put your main code here, to run repeatedly: AccelValue1 = analogRead(A4); //X-axis. Reads the value from the specified analog pin. This means that it will map input voltages between 0V and reference voltage into integer values between 0 and 1023. AccelValue2 = analogRead(A3); //Y-axis. if (i < 5) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue1); i++; ii++; ByteArr[ii] = lowByte(AccelValue1); i++; ii++; ByteArr[ii] = highByte(AccelValue2); i++; ii++; ByteArr[ii] = lowByte(AccelValue2); } else { dValue1 = AccelValue1 - LastAccelValue1; dValue2 = AccelValue2 - LastAccelValue2; if (abs(dValue1) > 127 || abs(dValue2) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue2); } else { ByteArr[ii] = char(dValue1); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue2); } } LastAccelValue1 = AccelValue1; LastAccelValue2 = AccelValue2; i++; ii++; WriteFunction(); delay(2); //~440 Hz. MAX для Serial.begin(9600). //delayMicroseconds(800); //Serial.begin(115200), ~934 Hz. MAX } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 400) { i = 0; } } Подключение акселерометра BMA180Можно использовать не только акселерометры с аналоговым выходом, но и с цифровым (I2C, SPI) выходом. Акселерометр BMA180 взят в качестве примера т.к. он очень чувствительный. Акселерометр BMA180 хорошо стабилизирует колебания напряжения питания. Поэтому нет необходимости в конденсаторе. Также не нужны резисторы для формирования опорного напряжения. Обратите внимание что акселерометр BMA180 питается от напряжения 3.3V. Соединения: Arduino Nano и акселерометр BMA180 Arduino Nano и HM-10 модуль 1: 1024 / 5460 = 0.188 2: 1000 3: Нижняя граница измерения. Sample code Скетч 6: /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// // BMA180 triple axis accelerometer sample code // // http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout // #include <Wire.h> #define BMA180 0x40 //Address of the accelerometer #define RESET 0x10 #define PWR 0x0D #define BW 0x20 #define RANGE 0x35 //#define DATA 0x02 #define DATA_X 0x02 #define DATA_Y 0x04 #define DATA_Z 0x06 //************************************************************ // General settings //************************************************************ #define BandWidth B0111 // Page 28 of the datasheet for the BMA180 //#define AccelRange B000 // +/- 1g (Page 28) #define AccelRange B001 // +/- 1.5g //#define AccelRange B010 // +/- 2g //#define AccelRange B011 // +/- 3g //#define AccelRange B100 // +/- 4g //#define AccelRange B101 // +/- 8g //#define AccelRange B110 // +/- 16g bool AxisX = true; bool AxisY = false; bool AxisZ = false; int offx = 0; //************************************************************ byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue = 0; int LastAccelValue = 0; int dValue = 0; void setup() { //Put your setup code here, to run once: //Opens serial port, sets data rate. //Serial.begin(9600); Serial.begin(115200); //A0 => GND pinMode(A0, OUTPUT); digitalWrite(A0, LOW); //A1 => High impedance pinMode(A1, INPUT); digitalWrite(A1, LOW); //A2 => High impedance pinMode(A2, INPUT); digitalWrite(A2, LOW); //A3 => High impedance pinMode(A3, INPUT); digitalWrite(A3, LOW); //D3 => GND pinMode(3, OUTPUT); digitalWrite(3, LOW); //D7 => GND pinMode(7, OUTPUT); digitalWrite(7, LOW); //Initializing sensors Wire.begin(); AccelerometerInit(); delay(500); //Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { //Put your main code here, to run repeatedly: AccelValue = AccelerometerRead(); if (i < 3) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue); i++; ii++; ByteArr[ii] = lowByte(AccelValue); } else { dValue = AccelValue - LastAccelValue; if (abs(dValue) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue); } else { ByteArr[ii] = char(dValue); } } LastAccelValue = AccelValue; i++; ii++; WriteFunction(); //delayMicroseconds(500); // ~820 Hz. //delayMicroseconds(400); // ~890 Hz. MAX for Serial.begin(9600) //delayMicroseconds(200); // ~1100 Hz. //delayMicroseconds(100); // ~1220 Hz. delayMicroseconds(10); // ~1370 Hz. } //************************************************************ // Functions //************************************************************ //Initializing sensors void AccelerometerInit() { byte temp[1]; byte temp1; writeTo(BMA180, RESET, 0xB6); // Wake up mode writeTo(BMA180, PWR, 0x10); // Band width, readFrom(BMA180, BW, 1, temp); temp1 = (temp[0] & 0x0F) | (BandWidth << 4); writeTo(BMA180, BW, temp1); // Acceleration range readFrom(BMA180, RANGE, 1, temp); temp1 = (temp[0] & 0xF1) | (AccelRange << 1); writeTo(BMA180, RANGE, temp1); } //Writes val to address register on ACC void writeTo(int DEVICE, byte address, byte val) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.write(val); //send value to write Wire.endTransmission(); //end transmission } //Reads num bytes starting from address register in to buff array void readFrom(int DEVICE, byte address, int num, byte buff[]) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.endTransmission(); //end transmission Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.requestFrom(DEVICE, num); //request num byte from ACC int i = 0; while(Wire.available()) //ACC may abnormal { buff[i] = Wire.read(); //receive a byte i++; } Wire.endTransmission(); //end transmission } //Read in the 1 axis data, each one is 14 bits int AccelerometerRead() { int n = 2; byte result[2]; byte AxisAddress = (AxisX) ? DATA_X : (AxisY) ? DATA_Y : (AxisZ) ? DATA_Z : DATA_X; readFrom(BMA180, AxisAddress, n, result); int x = ((result[0] | result[1] << 8) >> 2) + offx; return x + 8192; } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 200) { i = 0; } } Скетч 7 (XY): /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// // BMA180 triple axis accelerometer sample code // // http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout // #include <Wire.h> #define BMA180 0x40 //Address of the accelerometer #define RESET 0x10 #define PWR 0x0D #define BW 0x20 #define RANGE 0x35 //#define DATA 0x02 #define DATA_X 0x02 #define DATA_Y 0x04 #define DATA_Z 0x06 //************************************************************ // General settings //************************************************************ #define BandWidth B0111 // Page 28 of the datasheet for the BMA180 //#define AccelRange B000 // +/- 1g (Page 28) #define AccelRange B001 // +/- 1.5g //#define AccelRange B010 // +/- 2g //#define AccelRange B011 // +/- 3g //#define AccelRange B100 // +/- 4g //#define AccelRange B101 // +/- 8g //#define AccelRange B110 // +/- 16g bool AxisX = true; bool AxisY = true; bool AxisZ = false; int offx = 0; int offy = 0; int offz = 0; //************************************************************ byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue1 = 0; int AccelValue2 = 0; int LastAccelValue1 = 0; int LastAccelValue2 = 0; int dValue1 = 0; int dValue2 = 0; void setup() { //Put your setup code here, to run once: //Opens serial port, sets data rate. //Serial.begin(9600); Serial.begin(115200); //A0 => GND pinMode(A0, OUTPUT); digitalWrite(A0, LOW); //A1 => High impedance pinMode(A1, INPUT); digitalWrite(A1, LOW); //A2 => High impedance pinMode(A2, INPUT); digitalWrite(A2, LOW); //A3 => High impedance pinMode(A3, INPUT); digitalWrite(A3, LOW); //D3 => GND pinMode(3, OUTPUT); digitalWrite(3, LOW); //D7 => GND pinMode(7, OUTPUT); digitalWrite(7, LOW); //Initializing sensors Wire.begin(); AccelerometerInit(); delay(500); //Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { //Put your main code here, to run repeatedly: AccelerometerRead(); if (i < 5) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue1); i++; ii++; ByteArr[ii] = lowByte(AccelValue1); i++; ii++; ByteArr[ii] = highByte(AccelValue2); i++; ii++; ByteArr[ii] = lowByte(AccelValue2); } else { dValue1 = AccelValue1 - LastAccelValue1; dValue2 = AccelValue2 - LastAccelValue2; if (abs(dValue1) > 127 || abs(dValue2) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue2); } else { ByteArr[ii] = char(dValue1); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue2); } } LastAccelValue1 = AccelValue1; LastAccelValue2 = AccelValue2; i++; ii++; WriteFunction(); //delayMicroseconds(1000); //~465 Hz. MAX for Serial.begin(9600). delayMicroseconds(1); //Serial.begin(115200), ~890 Hz. MAX. } //************************************************************ // Functions //************************************************************ //Initializing sensors void AccelerometerInit() { byte temp[1]; byte temp1; writeTo(BMA180, RESET, 0xB6); // Wake up mode writeTo(BMA180, PWR, 0x10); // Band width, readFrom(BMA180, BW, 1, temp); temp1 = (temp[0] & 0x0F) | (BandWidth << 4); writeTo(BMA180, BW, temp1); // Acceleration range readFrom(BMA180, RANGE, 1, temp); temp1 = (temp[0] & 0xF1) | (AccelRange << 1); writeTo(BMA180, RANGE, temp1); } //Writes val to address register on ACC void writeTo(int DEVICE, byte address, byte val) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.write(val); //send value to write Wire.endTransmission(); //end transmission } //Reads num bytes starting from address register in to buff array void readFrom(int DEVICE, byte address, int num, byte buff[]) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.endTransmission(); //end transmission Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.requestFrom(DEVICE, num); //request num byte from ACC int i = 0; while(Wire.available()) //ACC may abnormal { buff[i] = Wire.read(); //receive a byte i++; } Wire.endTransmission(); //end transmission } //Read in the 3 axis data, each one is 14 bits void AccelerometerRead() { int n = 6; byte result[6]; readFrom(BMA180, DATA_X, n, result); int x = ((result[0] | result[1] << 8) >> 2) + offx; x = x + 8192; int y = ((result[2] | result[3] << 8) >> 2) + offy; y = y + 8192; int z = ((result[4] | result[5] << 8) >> 2) + offz; z = z + 8192; AccelValue1 = (AxisX) ? x : (AxisY && AxisZ) ? y : x; AccelValue2 = (AxisY && AxisX) ? y : (AxisZ) ? z : y; } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 400) { i = 0; } } Скетч 8 (XYZ): /////////////////////////////// // © 2017 Dmitriy Kharutskiy // /////////////////////////////// // BMA180 triple axis accelerometer sample code // // http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout // #include <Wire.h> #define BMA180 0x40 //Address of the accelerometer #define RESET 0x10 #define PWR 0x0D #define BW 0x20 #define RANGE 0x35 //#define DATA 0x02 #define DATA_X 0x02 #define DATA_Y 0x04 #define DATA_Z 0x06 //************************************************************ // General settings //************************************************************ #define BandWidth B0111 // Page 28 of the datasheet for the BMA180 //#define AccelRange B000 // +/- 1g (Page 28) #define AccelRange B001 // +/- 1.5g //#define AccelRange B010 // +/- 2g //#define AccelRange B011 // +/- 3g //#define AccelRange B100 // +/- 4g //#define AccelRange B101 // +/- 8g //#define AccelRange B110 // +/- 16g int offx = 0; int offy = 0; int offz = 0; //************************************************************ byte ByteArr[20]; int i = 0; int ii = 0; int AccelValue1 = 0; int AccelValue2 = 0; int AccelValue3 = 0; int LastAccelValue1 = 0; int LastAccelValue2 = 0; int LastAccelValue3 = 0; int dValue1 = 0; int dValue2 = 0; int dValue3 = 0; void setup() { //Put your setup code here, to run once: //Opens serial port, sets data rate. //Serial.begin(9600); Serial.begin(115200); //A0 => GND pinMode(A0, OUTPUT); digitalWrite(A0, LOW); //A1 => High impedance pinMode(A1, INPUT); digitalWrite(A1, LOW); //A2 => High impedance pinMode(A2, INPUT); digitalWrite(A2, LOW); //A3 => High impedance pinMode(A3, INPUT); digitalWrite(A3, LOW); //D3 => GND pinMode(3, OUTPUT); digitalWrite(3, LOW); //D7 => GND pinMode(7, OUTPUT); digitalWrite(7, LOW); //Initializing sensors Wire.begin(); AccelerometerInit(); delay(500); //Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { //Put your main code here, to run repeatedly: AccelerometerRead(); if (i < 7) { ByteArr[ii] = char(-128); i++; ii++; ByteArr[ii] = highByte(AccelValue1); i++; ii++; ByteArr[ii] = lowByte(AccelValue1); i++; ii++; ByteArr[ii] = highByte(AccelValue2); i++; ii++; ByteArr[ii] = lowByte(AccelValue2); i++; ii++; ByteArr[ii] = highByte(AccelValue3); i++; ii++; ByteArr[ii] = lowByte(AccelValue3); } else { dValue1 = AccelValue1 - LastAccelValue1; dValue2 = AccelValue2 - LastAccelValue2; dValue3 = AccelValue3 - LastAccelValue3; if (abs(dValue1) > 127 || abs(dValue2) > 127 || abs(dValue3) > 127) { ByteArr[ii] = char(-128); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue1); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue2); i++; ii++; WriteFunction(); ByteArr[ii] = highByte(AccelValue3); i++; ii++; WriteFunction(); ByteArr[ii] = lowByte(AccelValue3); } else { ByteArr[ii] = char(dValue1); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue2); i++; ii++; WriteFunction(); ByteArr[ii] = char(dValue3); } } LastAccelValue1 = AccelValue1; LastAccelValue2 = AccelValue2; LastAccelValue3 = AccelValue3; i++; ii++; WriteFunction(); //delay(2); //~310 Hz. MAX for Serial.begin(9600). delayMicroseconds(650); //Serial.begin(115200), ~550 Hz. MAX. } //************************************************************ // Functions //************************************************************ //Initializing sensors void AccelerometerInit() { byte temp[1]; byte temp1; writeTo(BMA180, RESET, 0xB6); // Wake up mode writeTo(BMA180, PWR, 0x10); // Band width, readFrom(BMA180, BW, 1, temp); temp1 = (temp[0] & 0x0F) | (BandWidth << 4); writeTo(BMA180, BW, temp1); // Acceleration range readFrom(BMA180, RANGE, 1, temp); temp1 = (temp[0] & 0xF1) | (AccelRange << 1); writeTo(BMA180, RANGE, temp1); } //Writes val to address register on ACC void writeTo(int DEVICE, byte address, byte val) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.write(val); //send value to write Wire.endTransmission(); //end transmission } //Reads num bytes starting from address register in to buff array void readFrom(int DEVICE, byte address, int num, byte buff[]) { Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.write(address); //send register address Wire.endTransmission(); //end transmission Wire.beginTransmission(DEVICE); //start transmission to ACC Wire.requestFrom(DEVICE, num); //request num byte from ACC int i = 0; while(Wire.available()) //ACC may abnormal { buff[i] = Wire.read(); //receive a byte i++; } Wire.endTransmission(); //end transmission } //Read in the 3 axis data, each one is 14 bits void AccelerometerRead() { int n = 6; byte result[6]; readFrom(BMA180, DATA_X, n, result); int x = ((result[0] | result[1] << 8) >> 2) + offx; AccelValue1 = x + 8192; int y = ((result[2] | result[3] << 8) >> 2) + offy; AccelValue2 = y + 8192; int z = ((result[4] | result[5] << 8) >> 2) + offz; AccelValue3 = z + 8192; } void WriteFunction() { if (ii == 20) { Serial.write(ByteArr, ii); ii = 0; } if (i >= 600) { i = 0; } } Bluetooth акселерометр на основе Arduino Nano 33 BLEArduino Nano 33 BLE Используйте ТОЛЬКО старую библиотеку ArduinoBLE (ArduinoBLE ver. 1.1.2) и старое ядро для Arduino Nano 33 BLE (Arduino Mbed OS Boards ver. 1.1.3), смотрите скриншоты ниже. При использовании новой библиотеки (ArduinoBLE ver. 1.1.3) и нового ядра (Arduino Mbed OS Boards ver. 1.1.6) получаются не верные данные (частота дискретизации постоянно меняется и обсолютно не правильная). Старые версии библиотеки и ядра можно выбрать в настройках (Installing Additional Arduino Libraries, Installing additional cores). Не устанавливайте компоненты для Arduino Nano 33 BLE автоматически предлагаемые Arduino IDE. Для проверки стабильности частоты дискретизации можно измерить частоту вибрации вращающегося внешнего жесткого диска. Пик частоты вибрации не должен менять частоту в течении нескольких минут. Tools > Manager Libraries... Tools > Board > Boards Manager... Arduino Nano 33 BLE можно купить не оплачивая международную доставку, стоимость которой превышает цену Arduino Nano 33 BLE. Смотрите здесь: https://efind.ru/offer/ABX00030. Также Arduino Nano 33 BLE бывает в Амперке (amperka.ru). Arduino Nano 33 BLE сильно отличается от Arduino Nano, например: • К пинам (в частности к пину “+5V”) нельзя подключать напряжение больше 3.3V. Есть отличия и между встроенным в Arduino Nano 33 BLE Bluetooth и модулем HM-10: • Я не нашел простого способа настройки Bluetooth встроенного в Arduino Nano 33 BLE (nRF52840). В то время как модуль HM-10 можно легко настроить через AT команды. Скетч адаптирован для смартфонов с Bluetooth 4.2 и Bluetooth 5.0. Это смартфоны начиная с iPhone 6S. Если iPhone поддерживает только Bluetooth 4.0, то в скетче нужно изменить размер передаваемого пакета на 20 (bufferSize = 20). Для смартфонов с Bluetooth 4.2 и Bluetooth 5.0 частота дискретизации (при измерении 3 осей) ограничена максимальной частотой дискретизации встроенного акселерометра (476 Hz, сделать 952 Hz не получилось). Для смартфонов с Bluetooth 4.0 максимальная частота дискретизации 119 Hz (при измерении 3 осей) и 238 Hz (при измерении 1 оси). Если Arduino Nano 33 BLE используется без корпуса, то чтобы не запачкать плату пчелиным воском (которым плата приклеивается к исследуемому механизму) к плате нужно приклеить специальную клейкую ленту НЕ ОСТАВЛЯЮЩУЮ СЛЕДОВ. Самый простой вариант - это ХОРОШАЯ малярная лента. Но к сожалению к такой ленте плохо прилипает пчелиный воск и поэтому поверхность контакта должна быть большой. Питание подключено через USB гнездо. При этом Arduino Nano 33 BLE работает при подключении напряжения от 4.1V до 5V. 5V указано в описании Arduino Nano 33 BLE, но проверялась работа при подключении 6.0V через USB в течении 7 часов и плата не сгорела. 1: Для ±2 g, 1024/16384 = 0.0625 2: 1000 3: Для ±2 g, 2 Скетч 9 (XYZ): /////////////////////////////// // © 2020 Dmitriy Kharutskiy // /////////////////////////////// // BMA180 triple axis accelerometer sample code // // http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout // #include <Wire.h> #include <ArduinoBLE.h> #define ACCELEROMETER_ADDRESS 0x6B // Address of the accelerometer #define ACCELEROMETER_STATUS_REG 0x17 // (Page 49 of the datasheet for the LSM9DS1, STATUS_REG) #define DATA_X 0x28 // (Page 56, OUT_X_L_XL) #define DATA_Y 0x2A // (Page 56, OUT_Y_L_XL) #define DATA_Z 0x2C // (Page 56, OUT_Z_L_XL) //************************************************************ // General settings //************************************************************ #define ACCELEROMETER_SETTINGS_ADDRESS 0x20 // (Page 51 of the datasheet for the LSM9DS1, CTRL_REG6_XL) //#define ACCELEROMETER_SETTINGS B10100000 // B[101]00000 - 476 Hz, B101[00]000 - 2 G (Page 51-52 of the datasheet for the LSM9DS1, CTRL_REG6_XL) //#define ACCELEROMETER_SETTINGS B10110000 // B[101]10000 - 476 Hz, B101[10]000 - 4 G //#define ACCELEROMETER_SETTINGS B10111000 // B[101]11000 - 476 Hz, B101[11]000 - 8 G #define ACCELEROMETER_SETTINGS B10101000 // B[101]01000 - 476 Hz, B101[01]000 - 16 G //#define ACCELEROMETER_SETTINGS B10011000 // B[100]11000 - 238 Hz, B100[11]000 - 8 G //#define ACCELEROMETER_SETTINGS B01111000 // B[011]11000 - 119 Hz, B011[11]000 - 8 G //#define ACCELEROMETER_SETTINGS B11011000 // B[110]11000 - 952 Hz, B110[11]000 - 8 G // DOES NOT WORK. The test shows 476 Hz instead of 952 Hz. #define ACCELEROMETER_RESET_ADDRESS 0x22 // (Page 53, CTRL_REG8) #define ACCELEROMETER_RESET B00000101 // (Page 53, CTRL_REG8) int16_t offx = 0; int16_t offy = 0; int16_t offz = 0; const int bufferSize = 244; // For Bluetooth 4.2 and Bluetooth 5.0 https://punchthrough.com/maximizing-ble-throughput-part-3-data-length-extension-dle-2/ //const int bufferSize = 20; // For Bluetooth 4.0 https://punchthrough.com/maximizing-ble-throughput-part-3-data-length-extension-dle-2/ BLEService accelerometerService("FFE0"); BLECharacteristic accelerometerDataChar("FFE1", BLERead | BLENotify, bufferSize, true); int dataLengthAfterMarker = bufferSize * 3; //************************************************************ byte ByteArr[bufferSize]; int i = 0; int ii = 0; int16_t AccelValue1 = 0; int16_t AccelValue2 = 0; int16_t AccelValue3 = 0; int16_t LastAccelValue1 = 0; int16_t LastAccelValue2 = 0; int16_t LastAccelValue3 = 0; uint16_t unsignedAccelValue = 0; int16_t dValue1 = 0; int16_t dValue2 = 0; int16_t dValue3 = 0; long previousMicros = 0; void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected Wire1.begin(); delay(50); // Initializing sensors initAccelerometer(); initBLE(); delay(500); // Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { // put your main code here, to run repeatedly: // wait for a BLE central BLEDevice central = BLE.central(); // if a central is connected to the peripheral: if (central) { // turn on the LED to indicate the connection: digitalWrite(LED_BUILTIN, HIGH); // while the central is connected: while (central.connected()) { if (newDataAvailability()) { /* // Sample rate testing long currentMicros = micros(); Serial.println(currentMicros - previousMicros); previousMicros = micros(); */ readAccelerometer(); //Serial.println(AccelValue1); if (i < 3) { ByteArr[ii] = char(-128); i++; ii++; unsignedAccelValue = AccelValue1 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; ByteArr[ii] = lowByte(unsignedAccelValue); i++; ii++; unsignedAccelValue = AccelValue2 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; ByteArr[ii] = lowByte(unsignedAccelValue); i++; ii++; unsignedAccelValue = AccelValue3 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; ByteArr[ii] = lowByte(unsignedAccelValue); } else { dValue1 = AccelValue1 - LastAccelValue1; dValue2 = AccelValue2 - LastAccelValue2; dValue3 = AccelValue3 - LastAccelValue3; if (abs(dValue1) > 127 || abs(dValue2) > 127 || abs(dValue3) > 127) { ByteArr[ii] = char(-128); i = 0; i++; ii++; sendBuffer(); unsignedAccelValue = AccelValue1 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; sendBuffer(); ByteArr[ii] = lowByte(unsignedAccelValue); i++; ii++; sendBuffer(); unsignedAccelValue = AccelValue2 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; sendBuffer(); ByteArr[ii] = lowByte(unsignedAccelValue); i++; ii++; sendBuffer(); unsignedAccelValue = AccelValue3 + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; sendBuffer(); ByteArr[ii] = lowByte(unsignedAccelValue); } else { ByteArr[ii] = char(dValue1); i++; ii++; sendBuffer(); ByteArr[ii] = char(dValue2); i++; ii++; sendBuffer(); ByteArr[ii] = char(dValue3); } } LastAccelValue1 = AccelValue1; LastAccelValue2 = AccelValue2; LastAccelValue3 = AccelValue3; i++; ii++; sendBuffer(); } } // when the central disconnects, turn off the LED: digitalWrite(LED_BUILTIN, LOW); } } //************************************************************ // Functions //************************************************************ // Initializing sensors void initAccelerometer() { byte temp[1]; byte temp1; // RESET writeTo(ACCELEROMETER_ADDRESS, ACCELEROMETER_RESET_ADDRESS, 0x05); // ACCELEROMETER SETTING: acceleration range, band width writeTo(ACCELEROMETER_ADDRESS, ACCELEROMETER_SETTINGS_ADDRESS, ACCELEROMETER_SETTINGS); delay(100); } // Initializing BLE void initBLE() { // begin initialization if (!BLE.begin()) { while (1) { Serial.println("starting BLE failed!"); delay(1000); } } BLE.setLocalName("Vibration_Analysis_App"); BLE.setAdvertisedService(accelerometerService); // add the service UUID accelerometerService.addCharacteristic(accelerometerDataChar); // add the battery level characteristic BLE.addService(accelerometerService); // Add the battery service // start advertising BLE.advertise(); } // Writes val to address register on ACC void writeTo(int DEVICE, byte address, byte val) { Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.write(address); // send register address Wire1.write(val); // send value to write Wire1.endTransmission(); // end transmission } // Reads num bytes starting from address register in to buff array void readFrom(int DEVICE, byte address, int num, byte buff[]) { Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.write(address); // send register address Wire1.endTransmission(); // end transmission Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.requestFrom(DEVICE, num); // request num byte from ACC int n = 0; while(Wire1.available()) // ACC may abnormal { buff[n] = Wire1.read(); // receive a byte n++; } Wire1.endTransmission(); // end transmission } // Read in the 3 axis data, each one is 16 bits void readAccelerometer() { int n = 6; byte result[6]; readFrom(ACCELEROMETER_ADDRESS, DATA_X, n, result); AccelValue1 = int16_t(result[1] << 8 | result[0]) + offx; AccelValue2 = int16_t(result[3] << 8 | result[2]) + offy; AccelValue3 = int16_t(result[5] << 8 | result[4]) + offz; } void sendBuffer() { if (ii == bufferSize) { long beforeMicros = micros(); accelerometerDataChar.writeValue(ByteArr, ii); long afterMicros = micros(); //Serial.println(afterMicros - beforeMicros); // Testing delay when sending data ii = 0; if (i >= dataLengthAfterMarker) i = 0; } } bool newDataAvailability() { byte temp[1]; readFrom(ACCELEROMETER_ADDRESS, ACCELEROMETER_STATUS_REG, 1, temp); if ((temp[0] & B00000001) != 0) return true; return false; } Скетч 10 (X): /////////////////////////////// // © 2020 Dmitriy Kharutskiy // /////////////////////////////// // BMA180 triple axis accelerometer sample code // // http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout // #include <Wire.h> #include <ArduinoBLE.h> #define ACCELEROMETER_ADDRESS 0x6B // Address of the accelerometer #define ACCELEROMETER_STATUS_REG 0x17 // (Page 49 of the datasheet for the LSM9DS1, STATUS_REG) #define DATA_X 0x28 // (Page 56, OUT_X_L_XL) #define DATA_Y 0x2A // (Page 56, OUT_Y_L_XL) #define DATA_Z 0x2C // (Page 56, OUT_Z_L_XL) //************************************************************ // General settings //************************************************************ #define ACCELEROMETER_SETTINGS_ADDRESS 0x20 // (Page 51 of the datasheet for the LSM9DS1, CTRL_REG6_XL) //#define ACCELEROMETER_SETTINGS B10100000 // B[101]00000 - 476 Hz, B101[00]000 - 2 G (Page 51-52 of the datasheet for the LSM9DS1, CTRL_REG6_XL) //#define ACCELEROMETER_SETTINGS B10110000 // B[101]10000 - 476 Hz, B101[10]000 - 4 G //#define ACCELEROMETER_SETTINGS B10111000 // B[101]11000 - 476 Hz, B101[11]000 - 8 G #define ACCELEROMETER_SETTINGS B10101000 // B[101]01000 - 476 Hz, B101[01]000 - 16 G //#define ACCELEROMETER_SETTINGS B10011000 // B[100]11000 - 238 Hz, B100[11]000 - 8 G //#define ACCELEROMETER_SETTINGS B01111000 // B[011]11000 - 119 Hz, B011[11]000 - 8 G //#define ACCELEROMETER_SETTINGS B11011000 // B[110]11000 - 952 Hz, B110[11]000 - 8 G // DOES NOT WORK. The test shows 476 Hz instead of 952 Hz. #define ACCELEROMETER_RESET_ADDRESS 0x22 // (Page 53, CTRL_REG8) #define ACCELEROMETER_RESET B00000101 // (Page 53, CTRL_REG8) bool AxisX = true; bool AxisY = false; bool AxisZ = false; int16_t offx = 0; const int bufferSize = 244; // For Bluetooth 4.2 and Bluetooth 5.0 https://punchthrough.com/maximizing-ble-throughput-part-3-data-length-extension-dle-2/ //const int bufferSize = 20; // For Bluetooth 4.0 https://punchthrough.com/maximizing-ble-throughput-part-3-data-length-extension-dle-2/ BLEService accelerometerService("FFE0"); BLECharacteristic accelerometerDataChar("FFE1", BLERead | BLENotify, bufferSize, true); int dataLengthAfterMarker = bufferSize * 3; //************************************************************ byte ByteArr[bufferSize]; int i = 0; int ii = 0; int16_t AccelValue = 0; int16_t LastAccelValue = 0; uint16_t unsignedAccelValue = 0; int16_t dValue = 0; long previousMicros = 0; void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected Wire1.begin(); delay(50); // Initializing sensors initAccelerometer(); initBLE(); delay(500); // Pauses the program for the amount of time (in miliseconds) specified as parameter. } void loop() { // put your main code here, to run repeatedly: // wait for a BLE central BLEDevice central = BLE.central(); // if a central is connected to the peripheral: if (central) { // turn on the LED to indicate the connection: digitalWrite(LED_BUILTIN, HIGH); // while the central is connected: while (central.connected()) { if (newDataAvailability()) { /* // Sample rate testing long currentMicros = micros(); Serial.println(currentMicros - previousMicros); previousMicros = micros(); */ AccelValue = readAccelerometer(); //Serial.println(AccelValue); if (i == 0) { ByteArr[ii] = char(-128); i++; ii++; unsignedAccelValue = AccelValue + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; ByteArr[ii] = lowByte(unsignedAccelValue); } else { dValue = AccelValue - LastAccelValue; if (abs(dValue) > 127) { ByteArr[ii] = char(-128); i = 0; i++; ii++; sendBuffer(); unsignedAccelValue = AccelValue + 32768; ByteArr[ii] = highByte(unsignedAccelValue); i++; ii++; sendBuffer(); ByteArr[ii] = lowByte(unsignedAccelValue); } else { ByteArr[ii] = char(dValue); } } LastAccelValue = AccelValue; i++; ii++; sendBuffer(); } } // when the central disconnects, turn off the LED: digitalWrite(LED_BUILTIN, LOW); } } //************************************************************ // Functions //************************************************************ // Initializing sensors void initAccelerometer() { byte temp[1]; byte temp1; // RESET writeTo(ACCELEROMETER_ADDRESS, ACCELEROMETER_RESET_ADDRESS, 0x05); // ACCELEROMETER SETTING: acceleration range, band width writeTo(ACCELEROMETER_ADDRESS, ACCELEROMETER_SETTINGS_ADDRESS, ACCELEROMETER_SETTINGS); delay(100); } // Initializing BLE void initBLE() { // begin initialization if (!BLE.begin()) { while (1) { Serial.println("starting BLE failed!"); delay(1000); } } BLE.setLocalName("Vibration_Analysis_App"); BLE.setAdvertisedService(accelerometerService); // add the service UUID accelerometerService.addCharacteristic(accelerometerDataChar); // add the battery level characteristic BLE.addService(accelerometerService); // Add the battery service // start advertising BLE.advertise(); } // Writes val to address register on ACC void writeTo(int DEVICE, byte address, byte val) { Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.write(address); // send register address Wire1.write(val); // send value to write Wire1.endTransmission(); // end transmission } // Reads num bytes starting from address register in to buff array void readFrom(int DEVICE, byte address, int num, byte buff[]) { Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.write(address); // send register address Wire1.endTransmission(); // end transmission Wire1.beginTransmission(DEVICE); // start transmission to ACC Wire1.requestFrom(DEVICE, num); // request num byte from ACC int n = 0; while(Wire1.available()) // ACC may abnormal { buff[n] = Wire1.read(); // receive a byte n++; } Wire1.endTransmission(); // end transmission } // Read in the 1 axis data, each one is 16 bits int16_t readAccelerometer() { int n = 2; byte result[2]; byte AxisAddress = (AxisX) ? DATA_X : (AxisY) ? DATA_Y : (AxisZ) ? DATA_Z : DATA_X; readFrom(ACCELEROMETER_ADDRESS, AxisAddress, n, result); int16_t x = int16_t(result[1] << 8 | result[0]) + offx; return x; } void sendBuffer() { if (ii == bufferSize) { long beforeMicros = micros(); accelerometerDataChar.writeValue(ByteArr, ii); long afterMicros = micros(); //Serial.println(afterMicros - beforeMicros); // Testing delay when sending data ii = 0; if (i >= dataLengthAfterMarker) i = 0; } } bool newDataAvailability() { byte temp[1]; readFrom(ACCELEROMETER_ADDRESS, ACCELEROMETER_STATUS_REG, 1, temp); if ((temp[0] & B00000001) != 0) return true; return false; } Шоппинг1: eBay: "bluetooth module hm-10" 2: eBay: "capacitor electrolytic 220uF" 3: AliExpress: "breadboard jumper wires 65 pcs" AliExpress: "jump wire female to female 20cm" eBay: "breadboard U shape jumper" 4: eBay: "Arduino Nano" (Для Mac eBay: "Arduino Nano FT232RL") 5: eBay: "resistor 1W kit" 6: AliExpress: "breadboard 170" 7: eBay: "battery box 3AA switch" 8: AliExpress: "ADXL335" eBay: "2.54 mm 1x40 male angle connector" 9: AliExpress: "phototransistor 3DU5C" 10: AliExpress: "laser module red" 11: eBay: "AD623AN" 12: eBay: "10K 3296W" 13: eBay: "BMA180" 14: eBay: "AA battery box USB" |