Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Re: BMP280, датчик давления и температуры

Ср мар 06, 2019 17:42:26

ПростоНуб, про sprintf(), itoa(), utoa() гугл тоже подсказывал, но там непонятное форматирование в аргументах и говорят память отъедают хорошо. Ну и доступного хелпа по ним не удалось отыскать. За упоминание о Double dabble - спасибо! Поищу, что за зверь.

Re: BMP280, датчик давления и температуры

Ср мар 06, 2019 17:48:53

За упоминание о Double dabble - спасибо! Поищу, что за зверь.

А чего его искать? В английской вики даже пример есть для него на C: https://en.wikipedia.org/wiki/Double_dabble

Re: BMP280, датчик давления и температуры

Ср мар 06, 2019 22:25:47

По сути, вся верхняя возня придумана, чтоб не выводить левые нули при любой десятичной разрядности аргумента. Иначе говоря у вас код выведет температуру нормально, а давление в паскалях уже - проблема. По вашему коду есть вопросы.
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 виде данные числа останутся одинаковыми.
А в каком компиляторе вы пишите?

Re: BMP280, датчик давления и температуры

Чт мар 07, 2019 00:23:09

Так, а если она беззнаковая (всегда положительная), то компилятор ее всегда будет считать больше нуля и, при отрицательной температуре, условие не сработает же...
Спасибо! С битовой разностью + и - вы меня успокоили. Переписал я уже "num2dec" - видит она теперь и отрицательные числа корректно - проверил именно на таком варианте. Причем потестировал именно _bmp280_temp, вот этак вот...
Код:
num2dec1(_bmp280_temp,2);
   uart_puts("\r");
   _bmp280_temp--;
   _bmp280_temp^=0xFFFFFFFF;
   num2dec1(_bmp280_temp,2);
   uart_puts("\r");
// вывод в терминале
23.22
-23.22

Вопрос остался, почему даташитовская функция компенсации не переворачивает отрицательную температуру в дополнительный код?
DESIER писал(а):А в каком компиляторе вы пишите?
:oops: Прошу прощения за мое невежество, но - не знаю. Пишу в 7 AtmelStudio, на уровне чайника с боольшим носиком. :)

Re: BMP280, датчик давления и температуры

Вт мар 19, 2019 15:41:14

Здоровья читателю.
Столкнулся с такой же проблемой с выводом отрицательных или около-нулевых температур
...
не понятно, когда температура становится отрицательной/нулевой?
Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.

Я писал о том как я решил эту проблему:

В даташите на 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;
  }   

Почему это не оговорено в примере из даташита, хрен знает. Может они дали свободу выбора по преобразованию дополнительный/прямой код, можно по разному преобразовывать.
И ни каких танцев с бубном 8)

Re: BMP280, датчик давления и температуры

Вт мар 19, 2019 16:35:34

passer_by, дык она, забака такая, никогда у меня не была в доп.коде. Вот положил на датчик кусок льда и смотрите, что получаю: рав данные тоже там есть

Еще, в кодах на гитхабе от BoschSensortec есть допустимые пределы калибровочных констант. Я их процитирую, для BMP280:
И простой тест нашел ошибки аж в 4!! константах.
Если с "Т3" я соглашусь, то с давлением непонятно, они-то вроде как в диапазон вписываются...
Калибровка у меня читается разово, при подаче питания. Ну забил я Т3 = -2000. Ошибка пропала, но поведение датчика не изменилось. Точно также, при около-нулевой температуре, прыгает в Сахару.

Re: BMP280, датчик давления и температуры

Ср мар 20, 2019 10:45:28

passer_by, дык она, забака такая, никогда у меня не была в доп.коде. В

А Вы тут ни причем. BME280 сама пишет в регистры в дополнительном коде. Все данные там так пишутся. Математику видишь ли им удобнее в этом формате вычислять :))
Формат регистра
Изображение
таблица соответствия
Изображение
При положительном значении ( S=0 ) код перевести в десятичный и умножить на 0,0625 °C.
При отрицательном значении ( S=1 ) сначала необходимо перевести дополнительный код в прямой. Для этого надо инвертировать каждый разряд двоичного кода и прибавить 1. А затем перевести в десятичный и умножить на 0,0625 °C.

Ну или как у меня. Иначе ни как.
Что косается ошибок в чтении калибровочных данных, скорее всего у Вас ошибки в написании чтения калибровочных регистров BME280.
Я, к примеру вот такую хрень городил для чтения 24 бит :facepalm:
Код:
uint32_t I2C1_ReadDataU24(uint8_t addr, uint8_t Reg)
{
  uint8_t data[3];
  uint32_t rezult =0;
  data[0] = I2C1_MemoryRead(addr, Reg);
  data[1] = I2C1_MemoryRead(addr, Reg + 1);
  data[2] = I2C1_MemoryRead(addr, Reg + 2);
  rezult = data[0];
  rezult = rezult<<8;
  rezult |= data[1];
  rezult = rezult<<8;
  rezult |= data[2];
  return rezult;
}

Re: BMP280, датчик давления и температуры

Вт мар 26, 2019 16:16:28

passer_by, спасибо! Попробую так, вдруг чего получится? :))

Re: BMP280, датчик давления и температуры

Ср июн 15, 2022 06:40:39

Взялся я за этот датчик и... товарищи форумчане, кто-нибудь сталкивался с тем, что датчик зависает при чтении области калибровочных констант?
У меня датчик позволяет считать адреса 0x88~0x9D (Calib_T1~Calib_P8), но при попытке чтения адресов дальше, датчик не возвращает нишу в Z-состояние.
Скриншот из логического анализатора:
Screenshot_20220615_092323.png
(18.51 KiB) Скачиваний: 92

Видно, что идёт запись регистра 0xF4 = 0x6F, установка указателя на 0x9E и попытка чтения его. И всё. Шина зависает в состоянии нуля.
Пришлось вбить в код костыль, который после чтения именно байта 9E несколько раз дёргает SCK до тех пор, пока SDA не будет отпущен.
Screenshot_20220615_093941.png
(20.03 KiB) Скачиваний: 85

Кто-нибудь сталкивался с таким поведением?

Re: BMP280, датчик давления и температуры

Ср июн 15, 2022 12:42:25

Взялся я за этот датчик и... товарищи форумчане, кто-нибудь сталкивался с тем, что датчик зависает при чтении области калибровочных констант?
У меня датчик позволяет считать адреса 0x88~0x9D (Calib_T1~Calib_P8), но при попытке чтения адресов дальше, датчик не возвращает нишу в Z-состояние.
Скриншот из логического анализатора:
У меня не BMP280, а BME280. Подозреваю, что это одно и то же (I2C-адрес тот же).
Какой-то у Вас странный способ работы.... :dont_know: В-первых: зачем читать по-байтно? Калибровочные данные там лежат 2-мя сплошными блоками: 0x88...0xA1 и 0xE1...0xF0. И соответственно - считываются двумя многобайтными транзакциями: первая = длиной 26 байт, вторая == 7 байт.
Во-вторых: судя по приложенным осциллограммам - переключение на чтение делаете "стоп-стартом", я же для переключения на чтение использую "повторный старт". Хотя возможно, что будет работать и так и так. Но можно проверить.

Re: BMP280, датчик давления и температуры

Ср июн 15, 2022 17:11:00

В-первых: зачем читать по-байтно? Калибровочные данные там лежат 2-мя сплошными блоками: 0x88...0xA1 и 0xE1...0xF0.

Оно тупо зависает насмерть и не отпускает шину, из-за этого машина состояний в блоке I2C бесконечно ждёт. :( В моём случае - BMP280, только с одним блоком 0x88~0xA1 (хотя 0xA0-0xA1 помечены как `reserved` в даташите). А чтение стабильно запинается на 0x9E. Следующий читает корректно.
Ну и это как раз кусок отладочного кода отрабатывал. Я искал, какой именно байт ломает всё.

Во-вторых: судя по приложенным осциллограммам - переключение на чтение делаете "стоп-стартом", я же для переключения на чтение использую "повторный старт". Хотя возможно, что будет работать и так и так. Но можно проверить.
Взял готовые функции из другого проекта на этом же кристалле. Там были другие сигнатуры и проще всего оказалось записать массив из одного элемента, а потом прочитать байт. Сути это не меняет, чип стабильно вешается.
Помог только "ногодрыг". Хорошо виден во втором скриншоте логического анализатора. Вообще не понимаю. Вроди бы и руки не из *опы, а вот такую штуку получил. И ведь стабильно.
Тосовал транзакции, вставлял задержки, убирал, читал массивом - вообще пофигистично. Такое ощущение, что сам датчик битый :( В магазине последний взял. Видимо, моя "удача".

Re: BMP280, датчик давления и температуры

Чт июн 16, 2022 17:14:39

Тосовал транзакции, вставлял задержки, убирал, читал массивом - вообще пофигистично..
Я бы попробовал всё-таки многобайтные транзакции и изменить тип переключения на "повторный старт". Как уже писал выше.

Сути это не меняет, чип стабильно вешается.
А с чего вообще решили, что "чип вешается"? По выложенной осциллограмме видно только, что I2C-мастер (МК) почему-то остановил тактирование SCLK на ACK-бите. Даже не дотактировав его. Зависла ваша программа похоже. :dont_know:

Re: BMP280, датчик давления и температуры

Пт июн 17, 2022 07:55:21

А с чего вообще решили, что "чип вешается"? По выложенной осциллограмме видно только, что I2C-мастер (МК) почему-то остановил тактирование SCLK на ACK-бите. Даже не дотактировав его. Зависла ваша программа похоже. :dont_know:

К сожалению, не так. Код выглядит так:
Там вбит костыль, который после зависания шины дёргает её до тех пор, пока та не освободится. И именно на байте 0x9E.
Код:
      BMPE_Cal.dig_P9 = I2C_Read8(BMPE_Address, 0x9E);
      // Костыль. Датчик вешает шину, не позволяя дать NACK.
      if ((GPIOF->IDR & GPIO_IDR_IDR_0) == 0) {
         GPIOF->BSRR = GPIO_BSRR_BS_1;
         GPIOF->MODER &= 0xFFFFFFF3;
         GPIOF->MODER |= 0x00000004;
         while ((GPIOF->IDR & GPIO_IDR_IDR_0) == 0) {
            delay_us(5);
            GPIOF->BSRR = GPIO_BSRR_BR_1;
            delay_us(5);
            GPIOF->BSRR = GPIO_BSRR_BS_1;
         };
         GPIOF->MODER &= 0xFFFFFFF3;
         GPIOF->MODER |= 0x00000008;
      };
      InitI2C2();

Сама функция I2C_Read8 выглядит так:
Код:
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, но так как шина в состоянии активности (датчик не отпустил её), то... всё.
Код:
void I2C_Write8(uint8_t DevAddr, uint8_t RegAddr, uint8_t RegValue) {
   I2C2->TXDR = RegAddr;
   I2C2->ICR = 0x3F38;
   I2C2->CR2 = (((DevAddr << 1) & 0xFE) | (2<<16) | I2C_CR2_START);
   while (!(I2C2->ISR & I2C_ISR_TXE)) {}; // <--------- Вот тут виснем, ибо SCK = 1, SDA = 0. WTF?
   I2C2->TXDR = RegValue;
   while (!(I2C2->ISR & I2C_ISR_TXE)) {};
   I2C2->CR2 = I2C_CR2_STOP;
}


На шине сейчас висят два датчика - AHT10 и BMP280. Если отключить последний - работает сутками. Проверено - за три выходных данные читались.
Если отключить первый - вешается на цикле опроса BMP'шки в рандомный момент времени :( Вообще не понимаю причину. То есть, код работает, а потом вдруг зависает.

Снял с шины AHT10, оставив подключенным только BMP280. Работает уже пол часа. Чёрт знает что. Но не тайминги же...

Re: BMP280, датчик давления и температуры

Пт июн 17, 2022 17:01:15

К сожалению, не так. Код выглядит так:
Что именно "не так"? Вы свою же осциллограмму смотрели?? Похоже что нет.
Изображение
Видно, что ACK недотактирован. Не завершаете корректно I2C-транзакцию.

И зачем втюхивать какой-то "код", даже не указав к какому МК он относится??
Изучите получше I2C своего МК. Судя по осциллограмме: скорее всего не завершаете корректно I2C-транзакцию и начинаете новую. Без хрустального шара никто не сможет угадать какой МК ковыряете и что именно делаете.

PS: И хорошим тоном является не только:
a) указывать название МК;
b) подписывать - какая осциллограмма к какому действию относится;
c) подписывать названия сигналов на осциллограмме.

Re: BMP280, датчик давления и температуры

Пн июн 20, 2022 06:22:17

К сожалению, не так. Код выглядит так:
Что именно "не так"? Вы свою же осциллограмму смотрели?? Похоже что нет.
Изображение
Видно, что 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) (хотя для наглядности выставил 8), общая длительность одного бита - 0x10 + 0x10 = 32 условных такта.
Код:
SCK ````|____|````|____|````|____|````|____|````|____
SDA ``|__(s)___(0)__|````(1)```|___(0)__|``````````|_

В то время как ведомый тянет линию вниз по спаду уровня на SCK.
У меня создаётся подозрение, что AHT10 наблюдает за линией и "находит" START там, где его нет, а за ним из байта 0x72 читает "свой" адрес и отвечает не в попад, потому как стабильно передача обрывается, когда BMP280 выдает ответ: 0x6F 0x82 0xC0 0x7E 0x72 0xC0.

:/
Теперь виню второй датчик. Снял новый дамп обмена на шине. Дополнительно подключил канал (2) непосредственно рядом с самим AHT10 ("SDA-AHT" на скниншотах). Но ничего понятнее не стало.
Момент запуска: (Прошу обратить внимание на время на шкале ~0.9с - время от момента начала захвата).
Scr_2.png
Момент перезапуска шины после зависания
(12.49 KiB) Скачиваний: 98

Собственно, чтение области калибровочных констант (на скниншоте не очень хорошо видно, но всё читается), затем - проверка статуса AHT10. Удачная. (39-E1-08-00).
Scr_3.png
(9.67 KiB) Скачиваний: 88

До момента 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
Общий вид транзакции:
Scr_4.png
(19.79 KiB) Скачиваний: 102

И сами биты:
Scr_5.png
(17.51 KiB) Скачиваний: 84


И разница между фазами сигналов, когда шину ведёт STM32 и BMP280.
Первый оставляет задержку в 2.9мкс между переходом SCK 1->0 и изменением уровня SDA, второй - 0,2мкс (плюс-минус, потому что захват происходил на 10MSa/s, ибо шина изначально медленная).
Scr_6.png
(25.37 KiB) Скачиваний: 89


Вот и вопрос: И как это победить? У меня пока банальный вариант - разнести датчики на физически разные шины. Но это же костыль!

Re: BMP280, датчик давления и температуры

Вт июн 21, 2022 18:44:45

Вот и вопрос: И как это победить?
Для танкистов ещё раз:
Разобраться почему недотактирован ACK на осциллограмме:
Изображение
Найти баг в своём коде - почему недоктактируется ACK?

Гуглить на тему "что такое I2C и как оно работает?"
В инете целая куча диаграмм. Например сравните своё с: https://developer.electricimp.com/resources/i2cerrors

Re: BMP280, датчик давления и температуры

Ср июн 22, 2022 06:29:35

ACK дотактирован. А причину я уже описал чуть выше. Всего-то слишком агрессивная работа с шиной со стороны датчика BMP280 и слишком медленная работа с шиной у датчика AHT10. В итоге - конфликт, когда первый вроди бы ведёт шину, но отпускает её, чтобы мастер мог вернуть NACK, а второй считает, что обратились к нему и продавливает 9-й бит в ноль, таким образом мастер отвечает датчику NACK, соседний датчик на шине отвечает ACK (чёрт его знает, почему он решил, что обращение идёт к нему), и в итоге на шине ACK, но периферийный блок STM32 в гробу видал читать лишние данные (его об этом никто не просил в коде), потому шина зависает в некорректном состоянии.

Всё. Финита ля комедия. Проблема именно во взаимодействии двух датчиков, а не в коде.
Предлагаю посмотреть скриншоты в предыдущем сообщении Особенно "Scr_4" и его метку времени.

Re: BMP280, датчик давления и температуры

Вт янв 31, 2023 18:53:13

В описании BMP280 есть фрагмент программы расчета с поправками. Хочу узнать- это формула или алгоритм? Если формула, то какая? Я не программист, поэтому заинтересован лишь этим вопросом, и только. Буду благодарен за понятный ответ или совет.
Вложения
Формула.jpg
(84.54 KiB) Скачиваний: 60

Re: BMP280, датчик давления и температуры

Вт янв 31, 2023 19:09:54

Это формула пересчета измеренных "сырых" данных температуры во вменяемое значение. Ну и алгоритм в ней "зашит", естественно. :)
t_fine используется в дальнейших "формулах" пересчета давления и влажности, для температурной коррекции.

Re: BMP280, датчик давления и температуры

Сб фев 04, 2023 14:03:25

Спасибо за пояснение. Прошу прощения за кривую терминологию. А t_fine в дальнейшем используется для сглаживания, в фильтре Калмана (IIR filter)? Это, ведь, считает сам BMP?
Ответить