ПростоНуб, про sprintf(), itoa(), utoa() гугл тоже подсказывал, но там непонятное форматирование в аргументах и говорят память отъедают хорошо. Ну и доступного хелпа по ним не удалось отыскать. За упоминание о Double dabble - спасибо! Поищу, что за зверь.
По сути, вся верхняя возня придумана, чтоб не выводить левые нули при любой десятичной разрядности аргумента. Иначе говоря у вас код выведет температуру нормально, а давление в паскалях уже - проблема. По вашему коду есть вопросы. 1). "if (t < 0) { t = -t; uart('-'); }". Как это условие у вас срабатывает, если t - без знаковая(uint16_t)? 2) Покажите, ради хвоста, паяльника и прочих мимоз, как у вас выглядит эта самая "-567" в 16-ричном виде! Очень прошу. И главное куда этот долбаный минус засунулся в 32-битном результате даташитовских манипуляций? У вас все просто "if (n < 0)" = кайф! У меня, почему-то, эта самая "n" всегда больше нуля.
Знаковая или без знаковая важно при работе в десятичном формате, а в бинарном виде все останется тем же -567 = 0b1111110111001001 = 0xFDC9, а с другим знаком 567 = 0b0000001000110111 = 0x0237; То есть при температуре -5,67 гр.С переменная _bmp280_temp должна быть равна 0x0xFDC9. Если это же число представить в десятичном беззнаковом виде, получится 64969 вместо нужных -567, несмотря на то что в hex виде данные числа останутся одинаковыми. А в каком компиляторе вы пишите?
_________________ Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
Так, а если она беззнаковая (всегда положительная), то компилятор ее всегда будет считать больше нуля и, при отрицательной температуре, условие не сработает же... Спасибо! С битовой разностью + и - вы меня успокоили. Переписал я уже "num2dec" - видит она теперь и отрицательные числа корректно - проверил именно на таком варианте. Причем потестировал именно _bmp280_temp, вот этак вот...
Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.
Здоровья читателю. Столкнулся с такой же проблемой с выводом отрицательных или около-нулевых температур ... не понятно, когда температура становится отрицательной/нулевой? Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.
В даташите на BME280 мельком упоминается, что данные в регистрах пишутся в дополнительном коде. И этот код просто переводит отрицательное значение в дополнительном коде в прямой с установленным знаком (-), понятый для того же sprintf(). К примеру: +25.0625 | 0000 0001 1001 0001 | 0191h -25.0625 | 1111 1110 0110 1111 | FE6Fh
Код:
if (temper_float >100) // если значение температуры перевалило в отрицательные значения { temper_float = 409.6-temper_float; temper_float = -temper_float; }
Почему это не оговорено в примере из даташита, хрен знает. Может они дали свободу выбора по преобразованию дополнительный/прямой код, можно по разному преобразовывать. И ни каких танцев с бубном
_________________ Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
passer_by, дык она, забака такая, никогда у меня не была в доп.коде. Вот положил на датчик кусок льда и смотрите, что получаю: рав данные тоже там есть Спойлер
Код:
temperature = 1.32 C pressure = 97999 Pa, 735.05 mmHg RAW data raw_pressure = 0x0004DCE0 := 318688 raw_temperature = 0x0006F840 := 456768 o temperature = 1.27 C pressure = 97997 Pa, 735.03 mmHg RAW data raw_pressure = 0x0004DCB0 := 318640 raw_temperature = 0x0006F7A0 := 456608 o temperature = 1.19 C pressure = 97994 Pa, 735.01 mmHg RAW data raw_pressure = 0x0004DC60 := 318560 raw_temperature = 0x0006F6A0 := 456352 o temperature = 1.02 C pressure = 98000 Pa, 735.06 mmHg RAW data raw_pressure = 0x0004DBA0 := 318368 raw_temperature = 0x0006F490 := 455824
/* И ВНЕЗАПНО!! */ o temperature = 86 C pressure = 97993 Pa, 735.00 mmHg RAW data raw_pressure = 0x0004DB10 := 318224 raw_temperature = 0x0006F280 := 455296 o temperature = 85 C pressure = 97995 Pa, 735.02 mmHg RAW data raw_pressure = 0x0004DB00 := 318208 raw_temperature = 0x0006F260 := 455264
Еще, в кодах на гитхабе от BoschSensortec есть допустимые пределы калибровочных констант. Я их процитирую, для BMP280: Спойлер
И простой тест нашел ошибки аж в 4!! константах. Спойлер
Код:
Calibration coefficients T1 28286 T2 26445 T3 50 X P1 38173 P2 -11029 P3 3024 P4 6663 P5 -33 X P6 -7 X P7 15500 P8 -14600 X P9 6000 WARNING! 4 ERROR[s] in calibration constants found.
Если с "Т3" я соглашусь, то с давлением непонятно, они-то вроде как в диапазон вписываются... Калибровка у меня читается разово, при подаче питания. Ну забил я Т3 = -2000. Ошибка пропала, но поведение датчика не изменилось. Точно также, при около-нулевой температуре, прыгает в Сахару.
passer_by, дык она, забака такая, никогда у меня не была в доп.коде. В
А Вы тут ни причем. BME280 сама пишет в регистры в дополнительном коде. Все данные там так пишутся. Математику видишь ли им удобнее в этом формате вычислять Формат регистра таблица соответствия
Цитата:
При положительном значении ( S=0 ) код перевести в десятичный и умножить на 0,0625 °C. При отрицательном значении ( S=1 ) сначала необходимо перевести дополнительный код в прямой. Для этого надо инвертировать каждый разряд двоичного кода и прибавить 1. А затем перевести в десятичный и умножить на 0,0625 °C.
Ну или как у меня. Иначе ни как. Что косается ошибок в чтении калибровочных данных, скорее всего у Вас ошибки в написании чтения калибровочных регистров BME280. Я, к примеру вот такую хрень городил для чтения 24 бит
Взялся я за этот датчик и... товарищи форумчане, кто-нибудь сталкивался с тем, что датчик зависает при чтении области калибровочных констант? У меня датчик позволяет считать адреса 0x88~0x9D (Calib_T1~Calib_P8), но при попытке чтения адресов дальше, датчик не возвращает нишу в Z-состояние. Скриншот из логического анализатора:
Видно, что идёт запись регистра 0xF4 = 0x6F, установка указателя на 0x9E и попытка чтения его. И всё. Шина зависает в состоянии нуля. Пришлось вбить в код костыль, который после чтения именно байта 9E несколько раз дёргает SCK до тех пор, пока SDA не будет отпущен.
Взялся я за этот датчик и... товарищи форумчане, кто-нибудь сталкивался с тем, что датчик зависает при чтении области калибровочных констант? У меня датчик позволяет считать адреса 0x88~0x9D (Calib_T1~Calib_P8), но при попытке чтения адресов дальше, датчик не возвращает нишу в Z-состояние. Скриншот из логического анализатора:
У меня не BMP280, а BME280. Подозреваю, что это одно и то же (I2C-адрес тот же). Какой-то у Вас странный способ работы.... В-первых: зачем читать по-байтно? Калибровочные данные там лежат 2-мя сплошными блоками: 0x88...0xA1 и 0xE1...0xF0. И соответственно - считываются двумя многобайтными транзакциями: первая = длиной 26 байт, вторая == 7 байт. Во-вторых: судя по приложенным осциллограммам - переключение на чтение делаете "стоп-стартом", я же для переключения на чтение использую "повторный старт". Хотя возможно, что будет работать и так и так. Но можно проверить.
В-первых: зачем читать по-байтно? Калибровочные данные там лежат 2-мя сплошными блоками: 0x88...0xA1 и 0xE1...0xF0.
Оно тупо зависает насмерть и не отпускает шину, из-за этого машина состояний в блоке I2C бесконечно ждёт. В моём случае - BMP280, только с одним блоком 0x88~0xA1 (хотя 0xA0-0xA1 помечены как `reserved` в даташите). А чтение стабильно запинается на 0x9E. Следующий читает корректно. Ну и это как раз кусок отладочного кода отрабатывал. Я искал, какой именно байт ломает всё.
Во-вторых: судя по приложенным осциллограммам - переключение на чтение делаете "стоп-стартом", я же для переключения на чтение использую "повторный старт". Хотя возможно, что будет работать и так и так. Но можно проверить.
Взял готовые функции из другого проекта на этом же кристалле. Там были другие сигнатуры и проще всего оказалось записать массив из одного элемента, а потом прочитать байт. Сути это не меняет, чип стабильно вешается. Помог только "ногодрыг". Хорошо виден во втором скриншоте логического анализатора. Вообще не понимаю. Вроди бы и руки не из *опы, а вот такую штуку получил. И ведь стабильно. Тосовал транзакции, вставлял задержки, убирал, читал массивом - вообще пофигистично. Такое ощущение, что сам датчик битый В магазине последний взял. Видимо, моя "удача".
А с чего вообще решили, что "чип вешается"? По выложенной осциллограмме видно только, что I2C-мастер (МК) почему-то остановил тактирование SCLK на ACK-бите. Даже не дотактировав его. Зависла ваша программа похоже.
А с чего вообще решили, что "чип вешается"? По выложенной осциллограмме видно только, что I2C-мастер (МК) почему-то остановил тактирование SCLK на ACK-бите. Даже не дотактировав его. Зависла ваша программа похоже.
К сожалению, не так. Код выглядит так: Там вбит костыль, который после зависания шины дёргает её до тех пор, пока та не освободится. И именно на байте 0x9E.
uint8_t I2C_Read8(uint8_t DevAddr, uint8_t RegAddr) { uint8_t value; (void) (I2C2->ISR); I2C2->TXDR = RegAddr; I2C2->ICR = I2C_ICR_STOPCF; I2C2->CR2 = (I2C_CR2_AUTOEND | ((DevAddr << 1) & 0xFE) | (1<<16) | I2C_CR2_START); while (!(I2C2->ISR & (I2C_ISR_TXE | I2C_ISR_NACKF))) {}; if (I2C2->ISR & I2C_ISR_NACKF) { I2C2->ICR = I2C_ICR_STOPCF | I2C_ICR_NACKCF; delay_ms(1); return -1; }; I2C2->ICR = 0x3F38; // В очередной раз сбрасываем флаги // Настраиваем модуль на чтение одного (1) байта, сразу готовимся ответить NACK, и запускаем (START) передачу. I2C2->CR2 = (I2C_CR2_AUTOEND | I2C_CR2_NACK | ((DevAddr << 1) & 0xFE) | I2C_CR2_RD_WRN | (1<<16) | I2C_CR2_START); while (!(I2C2->ISR & I2C_ISR_RXNE)) {}; // Успешно читаем результат value = (I2C2->RXDR); // Возвращаем значение. STOP должен сгенерироваться самостоятельно (AUTOEND). return value; }
Самое смешное, что код зависает на следующем обращении к шине. Вызывается i2c_write8 () и код зависает на ожидании TXE, но так как шина в состоянии активности (датчик не отпустил её), то... всё.
На шине сейчас висят два датчика - AHT10 и BMP280. Если отключить последний - работает сутками. Проверено - за три выходных данные читались. Если отключить первый - вешается на цикле опроса BMP'шки в рандомный момент времени Вообще не понимаю причину. То есть, код работает, а потом вдруг зависает.
Снял с шины AHT10, оставив подключенным только BMP280. Работает уже пол часа. Чёрт знает что. Но не тайминги же...
Что именно "не так"? Вы свою же осциллограмму смотрели?? Похоже что нет. Видно, что ACK недотактирован. Не завершаете корректно I2C-транзакцию.
И зачем втюхивать какой-то "код", даже не указав к какому МК он относится?? Изучите получше I2C своего МК. Судя по осциллограмме: скорее всего не завершаете корректно I2C-транзакцию и начинаете новую. Без хрустального шара никто не сможет угадать какой МК ковыряете и что именно делаете.
PS: И хорошим тоном является не только: a) указывать название МК; b) подписывать - какая осциллограмма к какому действию относится; c) подписывать названия сигналов на осциллограмме.
Что именно "не так"? Вы свою же осциллограмму смотрели?? Похоже что нет. Видно, что ACK недотактирован. Не завершаете корректно I2C-транзакцию.
И зачем втюхивать какой-то "код", даже не указав к какому МК он относится?? Изучите получше I2C своего МК. Судя по осциллограмме: скорее всего не завершаете корректно I2C-транзакцию и начинаете новую. Без хрустального шара никто не сможет угадать какой МК ковыряете и что именно делаете.
PS: И хорошим тоном является не только: a) указывать название МК; b) подписывать - какая осциллограмма к какому действию относится; c) подписывать названия сигналов на осциллограмме.
[Zanuda Mode ON] 1. То есть, вас не смутило, что датчик ЯВНО I2C и висит на этой шине? 2. На "осциллограмме" (хотя это скриншот логического анализатора, но не суть) видно и начало транзакции и такая же транзакция с другим адресом, которая проходит корректно (и даже виден импульс, появляющийся в момент передачи шины slave->master) прямо под всеми ACK кроме адреса 0x9E.
a - STM32F767ZGT6 (аналогично ведёт себя и STM32L152) при наличии двух датчиков на шине. b - Обе относятся к моменту сбоя ответа. И теперь непонятно, к сбою какого из датчиков - AHT10 / BME280. c - 0 - SCK, 1 - SDA. Два следующих - болтаются в воздухе. Над ними - встроенный в интерфейс декодер сигналов I2C. [Zanuda Mode OFF] ----------
По результатам теста стало понятно, что ничего не понятно. ATH10 (Single) -> OK. Работает без нареканий все выходные (прошлые) BME280 (Single) -> OK. Работает без нареканий все выходные (текущие) AHT10 + BME280 -> Stuck. Зависает в случайные моменты времени от 30 секунд (~5 циклов запросов данных) до 10 минут. Всё питается от 3.6V. И у меня такое ощущение, что AHT10 в какой-то момент считает, что обращаются к нему. И имеются некоторые подозрения на корректность работы схемы сдвига уровня на его плате:
Убрал с платы стабилизатор и обошёл парой перемычек "схему сдвига уровней". Наблюдаем-с...
Обошёл схему сдвига уровней на AHT10. Не помогло. Поменял адрес оного с 0x38 на 0x39. Не помогло. Уменьшил агрессивность таймингов шины I2C: I2C2->TIMINGR = 0x40541010; (SDA_DELAY) Теперь SDA меняется на четыре такта позже, чем SCK, а не на один, как работало с любыми другими чипами, к которым у меня был доступ. Вроди бы заработало. Самое странное, что работает с одним датчиком на шине без сбоев!.
UPD 2: Не помогло. Но на этот раз видно, что дело где-то на стороне одного из ведомых - это видно по фазе сигнала. STM32 делает переход уровня на SDA со сдвигом на указанное выше количество тактов (4) (хотя для наглядности выставил , общая длительность одного бита - 0x10 + 0x10 = 32 условных такта.
В то время как ведомый тянет линию вниз по спаду уровня на SCK. У меня создаётся подозрение, что AHT10 наблюдает за линией и "находит" START там, где его нет, а за ним из байта 0x72 читает "свой" адрес и отвечает не в попад, потому как стабильно передача обрывается, когда BMP280 выдает ответ: 0x6F 0x82 0xC0 0x7E 0x72 0xC0.
:/ Теперь виню второй датчик. Снял новый дамп обмена на шине. Дополнительно подключил канал (2) непосредственно рядом с самим AHT10 ("SDA-AHT" на скниншотах). Но ничего понятнее не стало. Момент запуска: (Прошу обратить внимание на время на шкале ~0.9с - время от момента начала захвата).
Вложение:
Комментарий к файлу: Момент перезапуска шины после зависания Scr_2.png [12.49 KiB]
Скачиваний: 100
Собственно, чтение области калибровочных констант (на скниншоте не очень хорошо видно, но всё читается), затем - проверка статуса AHT10. Удачная. (39-E1-08-00).
До момента T+137c всё идёт корректно, посылки идут пачкой: AHT10->Trigger() +0.1c AHT10->GetData() -> Status? -> Not ready +0.1c AHT10->GetData() -> Status? -> Not ready +0.1c AHT10->GetData() -> Status? -> Conversion Done BMP280->Read (0xF7..0xFC) Скриншот не прикладываю - тут всё похоже на вертикальные полоски и паузу в пару секунд.
И по какой-то причине когда датчик давления выдаёт 0x72 в предпоследнем байте - всё виснет. Проверил по битам, да, там можно угадать х111001 - 0x39 Общий вид транзакции:
И разница между фазами сигналов, когда шину ведёт STM32 и BMP280. Первый оставляет задержку в 2.9мкс между переходом SCK 1->0 и изменением уровня SDA, второй - 0,2мкс (плюс-минус, потому что захват происходил на 10MSa/s, ибо шина изначально медленная).
ACK дотактирован. А причину я уже описал чуть выше. Всего-то слишком агрессивная работа с шиной со стороны датчика BMP280 и слишком медленная работа с шиной у датчика AHT10. В итоге - конфликт, когда первый вроди бы ведёт шину, но отпускает её, чтобы мастер мог вернуть NACK, а второй считает, что обратились к нему и продавливает 9-й бит в ноль, таким образом мастер отвечает датчику NACK, соседний датчик на шине отвечает ACK (чёрт его знает, почему он решил, что обращение идёт к нему), и в итоге на шине ACK, но периферийный блок STM32 в гробу видал читать лишние данные (его об этом никто не просил в коде), потому шина зависает в некорректном состоянии.
Всё. Финита ля комедия. Проблема именно во взаимодействии двух датчиков, а не в коде. Предлагаю посмотреть скриншоты в предыдущем сообщении Особенно "Scr_4" и его метку времени.
В описании BMP280 есть фрагмент программы расчета с поправками. Хочу узнать- это формула или алгоритм? Если формула, то какая? Я не программист, поэтому заинтересован лишь этим вопросом, и только. Буду благодарен за понятный ответ или совет.
Это формула пересчета измеренных "сырых" данных температуры во вменяемое значение. Ну и алгоритм в ней "зашит", естественно. t_fine используется в дальнейших "формулах" пересчета давления и влажности, для температурной коррекции.
Спасибо за пояснение. Прошу прощения за кривую терминологию. А t_fine в дальнейшем используется для сглаживания, в фильтре Калмана (IIR filter)? Это, ведь, считает сам BMP?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения