| ||||
Цифровой барометр (датчик атмосферного давления)
| ||||
|
В данном проекте мы рассмотрим подключения датчика давления по интерфейсу I2C к контроллеру Arduino и снятие показаний. Проще говоря мы создадим электронный барометр своими руками. В качестве датчика давления мы будем использовать BMP085 от фирмы Bosch. Описание и документацию на датчик можно найти здесь. Даташит: BMP085.
Аппаратная частьК Arduino, датчик BMP085 подключается также, как и другие I2C устройства: подключите VCC к VCC, GND к GND, SCL к аналоговому выводу 5, а SDA к аналоговому выводу 4. Поставьте подтягивающие (pull-up) резисторы (от 1к до 20к, например 4.7кОм) между SDA, SCL и VCC (на моей плате они уже присутствуют). Напряжение питания датчика: 1.8-3.6 В. Также, датчик содержит выход EOC, который сигнализирует об окончании процесса измерения и обработки данных. Если EOC=1, то обработка завершена, если EOC=0, то в процессе. EOC подключен к аналоговому выводу 2 Arduino, но не использовался. Программное обеспечениеК нашей радости, код от Jeenode содержит всю необходимую функциональность, единственное, что я добавил, так это возможность использования всех режимов передискретизации (oversampling). В BMP085 есть возможность задания 4 режимов передискретизации, каждый из которых затрачивает больше времени и энергии, чем предыдущий режим, но в то же время повышает точность измерения. Итак, программа. Для начала, мы должны сделать возможность считывания всех 16-битных значений с регистров датчика: int read_int_register(unsigned char r) { unsigned char msb, lsb; Wire.beginTransmission(I2C_ADDRESS); Wire.send(r); // регистр для чтения Wire.endTransmission(); Wire.requestFrom(I2C_ADDRESS, 2); // считываем 2 байта while(!Wire.available()) { // ожидание } msb = Wire.receive(); while(!Wire.available()) { // ожидание } lsb = Wire.receive(); return (((int)msb<<8) | ((int)lsb)); } Далее, нам необходима функция, которая будет записывать значение в 8-ми битный регистр: char read_register(unsigned char r) { unsigned char v; Wire.beginTransmission(I2C_ADDRESS); Wire.send(r); // регистр для чтения Wire.endTransmission(); Wire.requestFrom(I2C_ADDRESS, 1); // считываем байт while(!Wire.available()) { // ожидание } v = Wire.receive(); return v; } Затем, нужно определить несколько глобальных переменных для чтения калибровочных данных из Eeprom датчика: //взято с даташита BMP085 int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; void bmp085_get_cal_data() { Serial.println("Reading Calibration Data"); ac1 = read_int_register(0xAA); Serial.print("AC1: "); Serial.println(ac1,DEC); ac2 = read_int_register(0xAC); Serial.print("AC2: "); Serial.println(ac2,DEC); ac3 = read_int_register(0xAE); Serial.print("AC3: "); Serial.println(ac3,DEC); ac4 = read_int_register(0xB0); Serial.print("AC4: "); Serial.println(ac4,DEC); ac5 = read_int_register(0xB2); Serial.print("AC5: "); Serial.println(ac5,DEC); ac6 = read_int_register(0xB4); Serial.print("AC6: "); Serial.println(ac6,DEC); b1 = read_int_register(0xB6); Serial.print("B1: "); Serial.println(b1,DEC); b2 = read_int_register(0xB8); Serial.print("B2: "); Serial.println(b1,DEC); mb = read_int_register(0xBA); Serial.print("MB: "); Serial.println(mb,DEC); mc = read_int_register(0xBC); Serial.print("MC: "); Serial.println(mc,DEC); md = read_int_register(0xBE); Serial.print("MD: "); Serial.println(md,DEC); } Снятие показаний всех значений с Eeprom может более эффективным, чем каждый раз записывать и считывать показания с каждого регистра. Т.о. достигается хороший выигрыш по времени. unsigned int bmp085_read_ut() { write_register(0xf4,0x2e); delay(5); //дольше чем 4.5 мс return read_int_register(0xf6); } long bmp085_read_up() { write_register(0xf4,0x34+(oversampling_setting<<6)); delay(pressure_waittime[oversampling_setting]); unsigned char msb, lsb, xlsb; Wire.beginTransmission(I2C_ADDRESS); Wire.send(0xf6); Wire.endTransmission(); Wire.requestFrom(I2C_ADDRESS, 3); while(!Wire.available()) { // ожидание } msb = Wire.receive(); while(!Wire.available()) { // ожидание } lsb |= Wire.receive(); while(!Wire.available()) { // ожидание } xlsb |= Wire.receive(); return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting); } Алгоритм преобразования температуры и давления из raw-данных датчика в реальную температуру (градусы Цельсия) и давление (Паскаль) взят из даташита (плюс некоторые дополнения от Jeenodes): void bmp085_read_temperature_and_pressure(int* temperature, long* pressure) { int ut= bmp085_read_ut(); long up = bmp085_read_up(); long x1, x2, x3, b3, b5, b6, p; unsigned long b4, b7; //расчет температуры x1 = ((long)ut - ac6) * ac5 >> 15; x2 = ((long) mc << 11) / (x1 + md); b5 = x1 + x2; *temperature = (b5 + 8) >> 4; //расчет давления b6 = b5 - 4000; x1 = (b2 * (b6 * b6 >> 12)) >> 11; x2 = ac2 * b6 >> 11; x3 = x1 + x2; b3 = (((int32_t) ac1 * 4 + x3)< Данные температуры и давления рассчитываются в одно и то же время (значения температуры используются для расчета давления). Скачать скетч для Arduino (исправленный, т.к. в оригинальном неправильно рассчитывалось давление). Оригинал статьи на английском языке (перевод Колтыков А.В.)
Добавил: Павел (Admin) Автор: Неизвестно Вас может заинтересовать:
|
|||
| ||||
|