А что морозильника нет? Или просто куска льда в пакете чтобы приложить к датчику? )
Морозильника нет. Я дома электроникой не занимаюсь, у меня мастерская отдельная для этого, либо на работе, к тому же датчик уже стоит в устройстве и закрыт в корпусе.
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
Ну вроде победил проблему Поменял формат переменной BME280_S32_t t_fine с 32 на 64 и все поехало. Получается на положительные значения int32 хватало, а при отрицательных уходил в нирвану. В общем прихлебывая валерьянку, курим даташит.
_________________ Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
Использование модульных источников питания открытого типа широко распространено в современных устройствах. Присущие им компактность, гибкость в интеграции и высокая эффективность делают их отличным решением для систем промышленной автоматизации, телекоммуникационного оборудования, медицинской техники, устройств «умного дома» и прочих приложений. Рассмотрим подробнее характеристики и особенности трех самых популярных вариантов AC/DC-преобразователей MW открытого типа, подходящих для применения в промышленных устройствах - серий EPS, EPP и RPS представленных на Meanwell.market.
Заголовок сообщения: Re: BMP280, датчик давления и температуры
Добавлено: Сб дек 15, 2018 22:32:36
Вымогатель припоя
Карма: 10
Рейтинг сообщений: 127
Зарегистрирован: Пт дек 26, 2014 20:33:38 Сообщений: 593 Откуда: Самая большая деревня. (По мнению Габриэля Гарсиа Маркеса)
Рейтинг сообщения:0
Не очень понятно. t_fine вроде бы используется в конце вычислений: t_fine = var1 + var2; T = (t_fine * 5 +128) >> 8; return T; var1, var2 и T имеют тип BME_280_S32_t и они не переполняются, так как Вы их не меняли. Неужели var1 и var2 близки к максимуму и их сумма переполняется? Или может быть засада в том, что переполнение происходит во время умножения на 5 и возможно достаточно написать по-другому последнее выражение: T = (int32_t)((((int64_t)t_fine) * 5) >> 8 ) ; Ну или что-то в этом роде... Впрочем, похоже что это тоже самое, что сделали Вы, только другим способом. Жаль, что я сейчас не могу вытащить датчик на мороз, надо бы погонять в отладчике пошагово и понаблюдать за вычислениями.
_________________ О технике чего спорить-то, давайте попробуем.
Самое интересное, что с ошибкой отрицательных температур библиотеки bosh судя по поиску в инете мало кто столкнулся, люди похоже в основном используют в помещениях. Я блин аж второй датчик на Али купил и упёрся в те же грабли. Как уходит Т в минус, то на входе 400 и выше градусов. passer_by не могли бы вы выложить свой кусок кода, где приведение к 64 битам делаете.
Не очень понятно. t_fine вроде бы используется в конце вычислений: достаточно написать по-другому последнее выражение: T = (int32_t)((((int64_t)t_fine) * 5) >> 8 ) ; Ну или что-то в этом роде... Впрочем, похоже что это тоже самое, что сделали Вы, только другим способом. Жаль, что я сейчас не могу вытащить датчик на мороз, надо бы погонять в отладчике пошагово и понаблюдать за вычислениями.
Попробовал. Не взлетело.. Всё также при минусах температура за 400 выходит. Где-то на гитхабе попадалась библиотека для этого датчика полностью на 64 бита заточенная
Наконец то я нашел время и проверил работу при отрицательных температурах. У меня все нормально работает. Проблем не было. Вот прилагаю вырезку из своего кода. В функции PreesAndTemp я просто проверяю температуру больше она или меньше ноля и убираю или добавляю соответственно знак минуса и пихаю все это на дисплей. Расчет температуры и давления взят из datasheet, данные библиотеки не изменялись, они оригинальные. Спойлер
Код:
uint8_t BMP280_Status; uint32_t Pressure_pascale; // Значение давления в паскалях uint32_t Pressure_mmHg; // Значение давления в мм.рт.с int32_t Temperature_BMP280; // Значение температуры в градусах цельсия unsigned char ptd[6]; int32_t t_fine; uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3; int16_t dig_P4; int16_t dig_P5; int16_t dig_P6; int16_t dig_P7; int16_t dig_P8; int16_t dig_P9;
uint8_t BMP280_Update() // { while (BMP280_Status != NOT_BUSY) { _delay_us(10); } while (!TWI_Read(TWI_Adress, &adr_data, 1, ptd, 6, &BMP280_Status)); do { _delay_us(10); if (BMP280_Status == TWI_SLA_W_NACK || BMP280_Status == TWI_DATA_NACK || BMP280_Status == TWI_SLA_R_NACK) return 0; } while (BMP280_Status != NOT_BUSY); // обязательно сначала рассчитываем температуру, а потом давление. Temperature_BMP280 = bmp280_compensate_T(((int32_t)ptd[3]<<12) | ((int32_t)ptd[4]<<4) | ((int32_t)ptd[5]>>4)); Pressure_pascale = bmp280_compensate_P((((int32_t)ptd[0]<<12) | ((int32_t)ptd[1]<<4) | (int32_t)ptd[2]>>4)); Pressure_mmHg = Pressure_pascale/133.3224; return 1; }
void PreesAndTemp() { uint16_t t = 0; uint8_t i = 0; if (BMP280_Update()) { i = 10; i += LCD_AddSimbol(FONT1,ARIAL,(Pressure_mmHg/100)%10,4,i); i += LCD_AddSimbol(FONT1,ARIAL,(Pressure_mmHg/10)%10,4,i); i += LCD_AddSimbol(FONT1,ARIAL,Pressure_mmHg%10,4,i); i += LCD_AddString(" мм рт.ст.",FONT1,ARIAL,LEFT,4,i); i += 10; if (Temperature_BMP280 < 0) { t = -Temperature_BMP280; i += LCD_AddSimbol(FONT1, ARIAL, '-', 4, i); } else t = Temperature_BMP280; if (t >= 1000) i += LCD_AddSimbol(FONT1,ARIAL,(t/1000)%10,4,i); i += LCD_AddSimbol(FONT1,ARIAL,(t/100)%10,4,i); i += LCD_AddSimbol(FONT1,ARIAL,'.',4,i); i += LCD_AddSimbol(FONT1,ARIAL,(t/10)%10,4,i); i += LCD_AddSimbol(FONT1,ARIAL,t%10,4,i); i += LCD_AddString("°C",FONT1,ARIAL,LEFT,4,i); } else { i = 0; switch(BMP280_Status) { case TWI_SLA_W_NACK: LCD_AddString("ОШИБКА! BMP280 не отвечает", FONT1, ARIAL, CENTR, 4, i); break; case TWI_SLA_R_NACK: LCD_AddString("ОШИБКА! BMP280 не отвечает", FONT1, ARIAL, CENTR, 4, i); break; case TWI_DATA_NACK: LCD_AddString("BMP280 ошибка передачи данных", FONT1, ARIAL, CENTR, 4, i); break; } } }
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
if (temper_float >100) // если значение температуры перевалило в отрицательные значения { temper_float = 409.6-temper_float; temper_float = -temper_float; }
return temper_float; }
Обратите внимание. Переменная int64_t temper_int это BME280_S32_t t_fine по даташиту, используется и в расчете давления и влажности.
to DESIER Раз работает код как у DS18B20 это говорит о том что формат значения температуры на выходе у датчиков одинаков. К стате, как я понял Ваш код, Вы делаете ровно то же самое, только вместо двух строчек кода довольно громоздкая структура.
_________________ Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
if (temper_float >100) // если значение температуры перевалило в отрицательные значения { temper_float = 409.6-temper_float; temper_float = -temper_float; }
return temper_float; }
to DESIER Раз работает код как у DS18B20 это говорит о том что формат значения температуры на выходе у датчиков одинаков. К стате, как я понял Ваш код, Вы делаете ровно то же самое, только вместо двух строчек кода довольно громоздкая структура.
Да у меня абсолютно тоже самое. В datasheet на датчик есть 2 варианта кода, код для расчетов с применением переменных с плавающей запятой и вариант для расчетов с целочисленными переменными. Для 8-bit микроконтроллера расчеты с плавающей запятой занимают больше процессорного времени. Поэтому ваш вариант мне не подходит так как у меня простой 8-bit микроконтроллер. А вот если бы я использовал какой нибудь ARM, конечно же я использовал бы вариант как у вас.
Вот мой код для расчета температуры (из datasheet), я не вижу тут огромной структуры, наоборот, у меня даже меньше получается:
Здоровья читателю. Столкнулся с такой же проблемой с выводом отрицательных или около-нулевых температур. Вот лог:
Код:
temperature = 1.32 C raw_temperature = 0x0006F840 := 456768
temperature = 1.27 C raw_temperature = 0x0006F7A0 := 456608
temperature = 1.19 C raw_temperature = 0x0006F6A0 := 456352
temperature = 1.02 C raw_temperature = 0x0006F490 := 455824
temperature = 86 C raw_temperature = 0x0006F280 := 455296
temperature = 85 C raw_temperature = 0x0006F260 := 455264
temperature = 91 C raw_temperature = 0x0006F320 := 455456
temperature = 88 C raw_temperature = 0x0006F2D0 := 455376
temperature = 63 C raw_temperature = 0x0006EFA0 := 454560
temperature = 58 C raw_temperature = 0x0006EF20 := 454432
temperature = 65 C raw_temperature = 0x0006EFE0 := 454624
temperature = 68 C raw_temperature = 0x0006F040 := 454720
temperature = 3.64 C raw_temperature = 0x00071500 := 464128
Датчик ВМР280 под снегом в пакете. Код с даташита, проверял 100500 раз, сверял с выкладками в этой теме, пробовал шаман-бубен здешний с удваиванием типа t_fine - ничего не помогает... Вот по "raw_temperature" в логе (это 20-битный компот значений соответствующих регистров ВМР280), не понятно, когда температура становится отрицательной/нулевой? Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.
Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.
Покажите ваш код, тогда подумаем. А так можно гадать долго. Я думаю что проблема в типах данных, возможно вы где то вместо int используете unsigned int в коде расчета.
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
DESIER, возможно "глаз замылился" и я просто не вижу ошибку.
А вот что вот это за функция? num2dec(_bmp280_temp, 2); Она выводит переменную _bmp280_temp в знаковом типе? Что то мне кажется дело в ней. Если осуществлять вывод информации в беззнаковом типе, будет вот такая байда.
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP, я так понял это ардуино?! А в нем разве нельзя просто взять и отправить число в uart без вот таких танцев с бубнами? Я с ардуино не работал и отладку я делаю через JTAG. Не могу понять для чего эта функция? Опишите в кратце что она делает.
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
DESIER Не-не, чур меня. Ни разу ардуино не доводилось видеть. Это Мега 8 + ВМР280 + USB-UART для отладки, а и + макетка.
DESIER писал(а):
Не могу понять для чего эта функция? Опишите в кратце что она делает.
Задумывалась для преобразования любого числа (до 32 бит) в читабельный вид, с фиксированной точкой и отправки его в UART. Если есть какие-то стандартные вещи в си, для этого, не сильно отжирающие ресурсы и память, подскажите пожалуйста.
Ну вот например если отправлять побайтно. допустим переменная t несет значение температуры в виде -567 на пример, это будет температура -5,67 гр.С и какая либо функция uart(char) принимающая в качестве аргумента байт, записывая его на шину.
Код:
uint16_t t = temperatureBMP280; if (t < 0) { t = -t; uart('-'); } if (t >= 1000) uart(((t/1000)%10)+48); uart(((t/100)%10)+48); uart('.'); uart(((t/10)%10)+48); uart((t%10)+48); uart('°'); uart('C');
Может я что то и нагородил, но я вывожу на LCD дисплей по шине I2C именно таким методом. У меня вместо uart другая рисующая символ на дисплее функция выводит изображение в соответствии с кодировкой ASCII. Или вот так:
/*bcd @arg - знаковое число @fractionDigits - количество "дробных, десятичных разрядов", если = 0, точку не рисуем */ void num2dec(long arg, int fractionDigits){ unsigned long dec = 1;//десятичный делитель: 1,10, 100... int i = 0, index = 0, max = 0; char arr[16];//выходной массив с символами цифр и точки memset(arr, 0, 16); //выясним максимально возможный делитель для исходного числа - arg и заодно посчитаем разряды(количество цифр) - max while(dec < arg){ dec *= 10; max ++; } //если arg!=0, уменьшим dec в 10 раз(подготовим вычитаемое, для старшего десятичного разряда arg) if(max) dec /= 10; //если нужна точка(fractionDigits!=0) и количество цифр позволяет ее поставить, переделаем max в указатель места точки в массиве if(fractionDigits && max > fractionDigits) max -= fractionDigits; //начинаем посимвольный вывод числа в массив while(dec){//пока делитель ненулевой i = 0;//сброс счетчика цифры //если индекс ячейки массива == месту точки, сунем в эту ячейку точку, а индекс пусть кажет на седующую ячейку if(index == max && fractionDigits) arr[index ++ ] = 0x2E; // Symbol - "." //По сути это i = arg / dec, но вроде поменьше места занимает while(dec <= arg){ arg -= dec; i++; }
arr[index++] = i + 48; //кладем в массив код символа найденой цифры dec /= 10; //следующая цифра } uart_puts(arr);//вывод результата }
По сути, вся верхняя возня придумана, чтоб не выводить левые нули при любой десятичной разрядности аргумента. Иначе говоря у вас код выведет температуру нормально, а давление в паскалях уже - проблема. По вашему коду есть вопросы. 1). "if (t < 0) { t = -t; uart('-'); }". Как это условие у вас срабатывает, если t - без знаковая(uint16_t)? 2) Покажите, ради хвоста, паяльника и прочих мимоз, как у вас выглядит эта самая "-567" в 16-ричном виде! Очень прошу. И главное куда этот долбаный минус засунулся в 32-битном результате даташитовских манипуляций? У вас все просто "if (n < 0)" = кайф! У меня, почему-то, эта самая "n" всегда больше нуля.
Заголовок сообщения: Re: BMP280, датчик давления и температуры
Добавлено: Ср мар 06, 2019 17:23:04
Собутыльник Кота
Карма: 38
Рейтинг сообщений: 292
Зарегистрирован: Пт сен 07, 2018 20:20:02 Сообщений: 2594 Откуда: деревня в Тульской губернии
Рейтинг сообщения:0 Медали: 1
Не проще ли было воспользоваться если не sprintf(), то хотя бы itoa() или utoa()? А если уж очень захотелось конвертировать из двоичку в десятичку самостоятельно, то лучше воспользоваться более быстрым алгоритмом, без деления. Например, тем же Double dabble.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения