Разбираюсь с библиотекой Wire прошу помощи.
- Войдите на сайт для отправки комментариев
Приветствую товарищи.
В общем задался целью освоить библиотеку Wire, пробую общаться с датчиком Bmp180 по I2C шине. Ардуиной увлекся с месяц назад, знаний накопил пока не много так что сильно не ругайте.
Суть проблемы в том что я никак не могу корректно записать в датчик значение байта=0x2E в регистр=0xF4, это нужно сделать для инициализации измерения температуры. Согласно даташиту на датчик после данной записи он должен начать измерение, подготовить их для чтения и переустановить значение байта на 0xE регистра 0xF4. Так вот после выполнения записи в этот регистр я пытаюсь его прочитать и передаю на компьютер прочитанное значение. При чтении получаю 0xA или 0b1010. Подскажите что не так, бьюсь уже целый день... :(
#include <Wire.h> #define bmp180address 0x77 char mAC1 = 0; char lAC1 = 0; int AC1 = 0; char mAC2 = 0; char lAC2 = 0; int AC2 = 0; char mAC3 = 0; char lAC3 = 0; int AC3 = 0; unsigned char mAC4 = 0; unsigned char lAC4 = 0; unsigned int AC4 = 0; unsigned char mAC5 = 0; unsigned char lAC5 = 0; unsigned int AC5 = 0; unsigned char mAC6 = 0; unsigned char lAC6 = 0; unsigned int AC6 = 0; char mB1 = 0; char lB1 = 0; int BB1 = 0; char mB2 = 0; char lB2 = 0; int BB2 = 0; char mMB = 0; char lMB = 0; int MB = 0; char mMC = 0; char lMC = 0; int MC = 0; char mMD = 0; char lMD = 0; int MD = 0; char chipID = 0; char CSO = 0; char MSB = 0, LSB = 0, xLSB = 0; int UT = 0, UP = 0, PP1 = 0, PP4 = 0, Temper = 0, Press = 0; unsigned int PP2 = 0, PP3 = 0; void setup() { Wire.begin(); Serial.begin(9600); } void loop() { Wire.beginTransmission(bmp180address); Wire.write(0xAA); Wire.endTransmission(false); Wire.requestFrom(bmp180address, 23, true); mAC1 = Wire.read(); lAC1 = Wire.read(); mAC2 = Wire.read(); lAC2 = Wire.read(); mAC3 = Wire.read(); lAC3 = Wire.read(); mAC4 = Wire.read(); lAC4 = Wire.read(); mAC5 = Wire.read(); lAC5 = Wire.read(); mAC6 = Wire.read(); lAC6 = Wire.read(); mB1 = Wire.read(); lB1 = Wire.read(); mB2 = Wire.read(); lB2 = Wire.read(); mMB = Wire.read(); lMB = Wire.read(); mMC = Wire.read(); lMC = Wire.read(); mMD = Wire.read(); lMD = Wire.read(); chipID = Wire.read(); AC1 = (mAC1 << 8); AC1 = (AC1 | lAC1); AC2 = (mAC2 << 8); AC2 = (AC2 | lAC2); AC3 = (mAC3 << 8); AC3 = (AC3 | lAC3); AC4 = (mAC4 << 8); AC4 = (AC4 | lAC4); AC5 = (mAC5 << 8); AC5 = (AC5 | lAC5); AC6 = (mAC6 << 8); AC6 = (AC6 | lAC6); BB1 = (mB1 << 8); BB1 = (BB1 | lB1); BB2 = (mB2 << 8); BB2 = (BB2 | lB2); MB = (mMB << 8); MB = (MB | lMB); MC = (mMC << 8); MC = (MC | lMC); MD = (mMD << 8); MD = (MD | lMD); Wire.beginTransmission(bmp180address); Wire.write(0xF4); Wire.write(0x2E); Wire.endTransmission(true); delay(50); Wire.beginTransmission(bmp180address); Wire.write(0xF4); Wire.endTransmission(false); Wire.requestFrom(bmp180address, 1, true); CSO = Wire.read(); Wire.beginTransmission(bmp180address); Wire.write(0xF6); Wire.endTransmission(false); Wire.requestFrom(bmp180address, 2, true); MSB = Wire.read(); LSB = Wire.read(); UT = (MSB << 8); UT = (UT | LSB); PP1 = ((UT-AC6)*AC5/32768)+(MC*2048/(((UT-AC6)*AC5/32768))+MD); Temper = (char(PP1)+8)/16; Serial.println(CSO,BIN); Serial.println(MSB); Serial.println(LSB); Serial.println(UT); Serial.println(PP1); Serial.println(Temper); Serial.println(chipID,BIN); Serial.println(AC1); Serial.println(AC2); Serial.println(AC3); Serial.println(AC4); Serial.println(AC5); Serial.println(AC6); Serial.println(BB1); Serial.println(BB2); Serial.println(MB); Serial.println(MC); Serial.println(MD); delay(1000); }
Фрагмент в районе строки 117-122 должен делать следующее:
Читать SCO bit с регистра 0xF4h, затем принимать решение о продолжении процесса, ориентируясь на следующее: "Sco (register F4h <5>): Start of conversion. The value of this bit stays “1” during conversion and is reset to “0” after conversion is complete (data registers are filled)."
Обратите внимание, что проверять нужно только пятый бит, т.е. данные готовы, когда (0x00 == 0xF4h_value & 0x20)
Вы же просто один раз читаете регистр 0xF4h. Для чего?
Я читаю его для того чтобы убедиться, что с пятого бита (CSO) еденичка сменилась на ноль (визуально так сказать). И тем самым в регистрах 0xF6, 0xF7 подготовились данные для чтения.
Ну... считали вы регистр, а где проверяете, что единичка сменилась на ноль?
Понимаете, о чем я вам пишу? Нужно читать этот регистр до тех пор, пока в том бите не появляется ноль и только затем уже считывать температуру. У вас же регистр считывается и вне зависимости от его значения сразу читается температура. В этом нет никакого смысла.
Я вас понимаю. Необходимо сделать цикл записи значения 0x2E в регистр 0xF4 до тех пор пока условие не выполниться, что 5 бит данных в этом регистре не сменится с 1 на 0. Только как реализовать это условие я не знаю.
Нет, не понимаете.
Вот на примере вареного яйца:
В первом случае вы кидаете яйцо в воду, затем сразу вытаскиваете, начинаете чистить, а только потом смотрите на секундомер.
Во втором случае вы постоянно кидаете яйцо в воду.
Но вам, как нормальному человеку, надо:
1) Бросить яйцо один раз: 0x2E -> 0xF4
2) Ждать, пока оно не сварится: while (0x01 == (read(0xF4) & 0x20) )
3) Вытащить яйцо и чистить: read(0xF6)
Хоршо попробую сделать как вы мне написал, спасибо за наводящие примеры. У меня еще один вопрос, я записываю данные по средством Wire.endTransmission(), согласно справочной информации ведомый отправляет ACK/NACK ведущему как мне это вывести для понимания что запись прошла успешно?
https://www.arduino.cc/en/Reference/WireEndTransmission
Это я читал, а где он этот возвращаемый байт храниться, у него есть название или как его вывести на монитор порта?
А где Wire.read() хранит байт?
Действуйте с endTransmission() точно так же как и с read().
А вообще: http://www.c-cpp.ru/books/vozvrashchaemye-znacheniya
Вот это чудеса:) Присвоил имя endTransmission() получил нолик (0:success)! Пошел читать справочник по С/С++.
Разобрался с задержкой плюс "причесал" код, теперь чтение данных выполняется корректно. Столкнулся с другой бедой, при расчете температуры значение выдает не правильное при Т_атм=25 выдает 406, на нагрев датчик реагирует увеличением значения. Есть подозрение что связанно с не правильным типом данных, хотя делал согласно даташиту: https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf еще сравнивал с этим: http://iarduino.ru/lib/datasheet%20bmp180.pdf типы данных в этих документах разные, проверял оба варианта значение температуры в обоих случаях не корректное.
Боюсь, что вы еще недокрутили. Потому что requestFrom() находится вне цикла ожидания, т.е. делается, в сущности, только один запрос. Просто вам везет и сенсор успевает завершить конверсию. К тому же я могу вам порекомендовать, проверяет, что возвращает requestFrom(). Если это значение не равно кол-ву запрашиваемых байт, то нет оснований доверять Wire.read().
Ну, а после while(){} лучше делать endTransmission(), полагаю. Это будет полезным навыком впоследствии.
В формуле копаться не буду, у меня вот такая:
Разобрался! Проблемма заключалась в побитовых сдвигах, которые я применил вместо *2^n = <<n и /2^n = >>n соответственно, хотя где то читал, что такая запись более целесообразна, плюс добавил преобразование типов, без них так же не корректно температура расчитывается. С расчетом давления далее я надеюсь проблем не возникнет, все аналогично.
Насколько я помню свои мучения, то побитовые сдвиги там непричем, а вся соль была в приведении типов. Я с даташита срисовывал расчет.
Поправочные коэффициенты можно один раз считывать в setup(), они не меняются. Вы же не будете на ходу менять сенсоры?
Выяснл - побитовые сдвиги работают с переменными типа byt, int, long. Проблема в моем случае в томчто я не взял в скобки ((long)MC<<11), кажется приоритет умножения и деления выше чем байтовый сдвиг.
Последовал вашему совту перенес попраочне коэффициенты в setup().
Огромное сасибо за советы sadman41 без них я б так и плюхался!