Шум на датчике далласа db18b20

Тема в разделе "Arduino & Shields", создана пользователем 64detali, 20 янв 2021.

  1. 64detali

    64detali Нерд

    Всем привет, ребят я делаю автоматический подсос на карбюратор и веду ход проекта на драйве, работает он в зависимости от температуры и оборотов двигателя, почти все проблемы решены кроме показаний датчика далласа, а они собственно периодически вылетают такие :-0.006 и 85. При чем эти цифры появляются не только на заведенной машине, но и при питании от USB компьютера. Грешу на ошибки в скетче:
    Код (C++):
    #include <OneWire.h> // Инициализация библиотеки шины OneWire.
    #include <Servo.h> // библиотека для управления серво
    Servo servo;  //объявить серво - назвать servo
    OneWire ds(4);  //подключение датчика к 4 пину
    byte addr[8]={0x28, 0xFF, 0x7C, 0x51, 0xC0, 0x17, 0x01, 0xDC}; // адрес датчика, необходимо ввести адрес своего датчика
    float Temp; // переменная значений температуры
    int s; // переменная угла поворота серво
    int zaslonka; // переменная положения воздушной заслонки
    // Переменные для тахометра
    unsigned long RPM_impuls;  // переменная считает импульсы тахометра
    int RPM = 0;                // переменная измеренных данных тахометра
    unsigned long cur_ms = 0;  // переменная для вычисления отрезков времени температуры
    unsigned long prev_ms = 0; // переменная для вычисления отрезков времени оборотов


    void setup() {
      Serial.begin(9600); // вывод в порт даных по температуре и оборотам
      pinMode(2, INPUT); // тахометр задаем пин на вход
      digitalWrite(2, HIGH); // включаем подтягивающий резистор на 2 пине
      attachInterrupt(0,RPMmetr,RISING); //задать функцию прерывания на 2 пин
      servo.attach(7);  //серво подключен к 7 порту,заслонка открыта
    }

    void loop()
    {
    getOboroti();  //функция оборотов
    getTemperature();  //функция температуры
    }
    int getTemperature()
    {
    ds.reset(); //сброс датчика
    ds.select(addr); //выбор адреса датчика
    ds.write(0x44); //команда на расчет температуры
    if (millis() - cur_ms > 1000) //считаем температуру, через каждую секунду
    {
      cur_ms = millis(); // обнуляем отрезок времени
    ds.reset(); //сброс датчика
    ds.select(addr); //выбор адреса датчика
    ds.write(0xBE); //команда чтения температуры
    Temp =  (ds.read() | (ds.read()<<8))/16.0; //формула расчета температуры
    Serial.println(Temp); // выводим температуру на экран
    Serial.print(" C");
      }
     
    return Temp; // прекращение вычислений в функции, возвращение значения температуры
      }
    int getOboroti()
    {
     
    if (millis() - prev_ms > 1000) //считаем обороты, через каждую секунду
    {
    // Считаем тахометр
        RPM=((RPM_impuls*30000)/(millis() - prev_ms)); // формула расчета оборотов
                                         
        RPM_impuls=0;                    // обнуляем счетчик прерываний
        prev_ms = millis();                // обнуляем отрезок времени
      Serial.println(RPM);  // выводим обороты на экран
      Serial.print(" Об/мин");
      //Начало блока управления воздушной заслонкой

    // 1я ступень, прогрев до 5 градусов
     
       if (Temp<=5 && RPM==0) {   // двигатель заглушен
           
        servo.write(175);  // закрываем заслонку полностью
    }
    s=servo.read();
    if (Temp<=5 && RPM>2300) {   // двигатель запущен, регулируем обороты не выше 2300
           
        s--;
        servo.write(s);  // снижаем обороты
    }
    if (Temp<=5 && RPM>100 && RPM<2000) {   // двигатель запущен, регулируем обороты не ниже 2000
       
        s++;
        servo.write(s);  // повышаем обороты
    }
    // 2я ступень, прогрев до 40 градусов
    if (Temp>5 && Temp<=40 && RPM==0) {   // двигатель заглушен и частично прогрет
     
        servo.write(90);  // прикрываем заслонку
    }
    s=servo.read();
    if (Temp>5 && Temp<=40 && RPM>1600) {   // двигатель запущен и частично прогрет, регулируем обороты не выше 1600
       
        s--;
        servo.write(s);  // снижаем обороты
    }
    if (Temp>5 && Temp<=40 && RPM>100 && RPM<1400) {   // двигатель запущен и частично прогрет, регулируем обороты не ниже 1400
       
        s++;
        servo.write(s);  // повышаем обороты
    }

    // 3я ступень, завершение прогрева
    if (Temp>40) {   // двигатель прогрет достаточно, для поддержания холостых
     
        servo.write(30);  // открываем заслонку полностью
    }
    //конец блока управления воздушной заслонкой
    s=servo.read();
    zaslonka = map(s, 175, 30, 0, 100); // перевод угла открытия сервопривода в проценты открытия
      Serial.println(s);  // выводим угол сервопривода на экран
      Serial.print("угол серво");
      Serial.println(zaslonka);  // выводим % открытия воздушной заслонки
      Serial.print(" % откр");
    }
     
      return RPM; // прекращение вычислений в функции, возвращение значения оборотов
    }
    // Запуск счетчика прерываний тахометра с нуля
    void RPMmetr()
    {
       RPM_impuls++;
    }
    Видео и ссылку на бортжурнал для более ясного понимания можно закинуть или это бан?
     
  2. b707

    b707 Гуру

    ПОЧЕМУ как только человек прочитал букварь по ардуино - его тянет что-то приколхозить к своей машине?
    на драйве больше половины подобных проектов - полная чушь.
    Код, небось. списали где-то?

    В вашем коде вы НЕПРЕРЫВНО долбите датчик командой reset. Странно. что он у вас вообще что-то показывает.
    Когда исправите это - почитайте. как читать данные датчика с контролем CRC
    Проблема с неправильными значениями в этом.
     
    parovoZZ и 64detali нравится это.
  3. 64detali

    64detali Нерд

    Я бы и не стал ардуино увлекаться, если бы не эта идея.
    Подозревал, что слишком часто опрашиваю датчик, спасибо за подсказку, попробую исправить.
     
  4. Рокки1945

    Рокки1945 Гуру

    зависит от разрешения - не буду уточнять но не чаще чем раз за 750 мс
     
    Vovka нравится это.
  5. 64detali

    64detali Нерд

    Для активного питания, если не ошибаюсь достаточно 100мс
     
  6. b707

    b707 Гуру

    время измерения зависит от разрешения и прописано в даташите. Читайте документацию чтобы не гадать.
    Для 12 бит Рокки прав - не менее 750мс
    Читать датчик чаще, чем он измеряет температуру - бессмысленно
    Но к проблеме получения неправильных значений это прямого отношения не имеет
     
  7. parovoZZ

    parovoZZ Гуру

    зачем читать 12 бит, если погрешность датчика укладывается в 8 бит?
     
  8. 64detali

    64detali Нерд

    Я своего ничего не придумываю, беру из примеров. Без задержки есть два вот таких варианта
    Код (C++):
    #include <OneWire.h>

    OneWire ds(8); // Объект OneWire

    int temperature = 0; // Глобальная переменная для хранения значение температуры с датчика DS18B20

    long lastUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика
    const int TEMP_UPDATE_TIME = 1000; // Определяем периодичность проверок

    void setup(){
      Serial.begin(9600);
    }

    void loop(){
      detectTemperature(); // Определяем температуру от датчика DS18b20
      Serial.println(temperature); // Выводим полученное значение температуры
      // Т.к. переменная temperature имеет тип int, дробная часть будет просто отбрасываться
    }

    int detectTemperature(){

      byte data[2];
      ds.reset();
      ds.write(0xCC);
      ds.write(0x44);

      if (millis() - lastUpdateTime > TEMP_UPDATE_TIME)
      {
        lastUpdateTime = millis();
        ds.reset();
        ds.write(0xCC);
        ds.write(0xBE);
        data[0] = ds.read();
        data[1] = ds.read();

        // Формируем значение
        temperature = (data[1] << 8) + data[0]; temperature = temperature >> 4;
      }
    }
    и
    Код (C++):
    #include <OneWire.h>
    OneWire  ds(2);
    byte addr[8]={0x28,0x04,0x13,0x80,0x06,0x00,0x00,0xF8};
    volatile int celsius;
    void setup(void) {
    Serial.begin(9600);
    pinMode (13,OUTPUT);
    WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты
    WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда
    // (55 страница <a href="<a href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" rel="nofollow">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a>" rel="nofollow">даташита</a>)
    // снять все ремарки если нужно поменять разрешение
    //  ds.reset(); // сброс шины
    //  ds.select(addr); //выставить адрес
    //  ds.write(0x4E); // разрешение записать конфиг
    //  ds.write(0x7F); // Th контроль температуры макс 128грд
    //  ds.write(0xFF); //Tl контроль температуры мин -128грд
    //  ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение
    }

    void loop(void) {
    Serial.print("  Temperature = ");
    Serial.println(celsius/16.0);
    }
    ISR (WDT_vect){ //вектор прерывания WD
    static boolean n=0; // флаг работы: запрос температуры или её чтение
    n=!n;
    if (n) {ds.reset();  // сброс шины
            ds.select(addr); // выбор адреса
            ds.write(0x44); // начать преобразование (без паразитного питания)
            }
    else   {ds.reset();
            ds.select(addr);  
            ds.write(0xBE); // Read Scratchpad (чтение регистров)
            celsius =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      
            }
    }
     
    оба не работали, попробую еще раз.
     
  9. b707

    b707 Гуру

    а зря. В интернете полно примеров с ошибками, например вот эти...
    Лучше все-таки "придумывать свое"
     
  10. parovoZZ

    parovoZZ Гуру

    датчик надо опрашивать не абы когда, а в искровых промежутках. 1 раз в 10 секунд более, чем достаточно. В машине ничто так быстро не греется. Проверка CRC - обязательна.
     
    Airbus нравится это.
  11. SergeiL

    SergeiL Оракул Модератор

    Уже разбирался с этим:
    upload_2021-1-20_21-55-28.png
     
  12. SergeiL

    SergeiL Оракул Модератор

    Ой ли, а масса у датчика нулевая?
    А если посчитать - может раз в минуту?
     
  13. parovoZZ

    parovoZZ Гуру

    Самое весёлое начинается, когда температура начинает гулять туда-сюда.
     
  14. parovoZZ

    parovoZZ Гуру

    В данном приложении десятки не нужны. Достаточно точности в 5 градусов.
     
  15. 64detali

    64detali Нерд

    Я пока исправлю функцию температуры, посмотрю что получится:
    Код (C++):
    int getTemperature()

    {
      if (flag == true) {
      ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0x44); //команда на расчет температуры
      flag = false;
      }
      if (millis() - cur_ms > 1000) //считаем температуру, через каждую секунду
    {
      cur_ms = millis(); // обнуляем отрезок времени
      ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0xBE); //команда чтения температуры
      Temp =  (ds.read() | (ds.read()<<8))/16.0; //формула расчета температуры
      Serial.println(Temp); // выводим температуру на экран
      Serial.print(" C");
        flag = true;
      }
    }
    Голова кипит, не доходит пока как впихнуть функцию проверки crc в скетч.
     
    Последнее редактирование: 21 янв 2021
  16. 64detali

    64detali Нерд

    Не заработал пока не поднял строку flag = false;
    Код (C++):
    int getTemperature()

    {
      if (flag == true) {
    flag = false;
      ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0x44); //команда на расчет температуры
      }
      if (millis() - cur_ms > 1000) //считаем температуру, через каждую секунду
    {
      cur_ms = millis(); // обнуляем отрезок времени
      ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0xBE); //команда чтения температуры
      Temp =  (ds.read() | (ds.read()<<8))/16.0; //формула расчета температуры
      Serial.println(Temp); // выводим температуру на экран
      Serial.print(" C");
        flag = true;
      }
    }
     
  17. 64detali

    64detali Нерд

    Ничего не изменилось, или я проверяю crc неправильно:
    Код (C++):
    #include <OneWire.h> // Инициализация библиотеки шины OneWire.
    byte addr[8]={0x28, 0xFF, 0x7C, 0x51, 0xC0, 0x17, 0x01, 0xDC}; // адрес датчика, необходимо ввести адрес своего датчика
      byte i;
      byte present = 0;
      byte type_s;
      byte data[12];
      float Temp;
    void loop()
    {
    getTemperature();  //функция температуры
    }
    int getTemperature()
    {

      if (OneWire::crc8(addr, 7) != addr[7]) {
      return;
      }
    if (flag == 1) {
      flag = 0;
      ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0x44); //команда на расчет температуры
      }
      if (millis() - cur_ms > 1000) //считаем температуру, через каждую секунду
    {
      cur_ms = millis(); // обнуляем отрезок времени
      present = ds.reset(); //сброс датчика
      ds.select(addr); //выбор адреса датчика
      ds.write(0xBE); //команда чтения температуры
      for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
          }
          int16_t raw = (data[1] << 8) | data[0];
      if (type_s) {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10) {
          // "count remain" gives full 12 bit resolution
          raw = (raw & 0xFFF0) + 12 - data[6];
        }
      } else {
        byte cfg = (data[4] & 0x60);
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
        //// default is 12 bit resolution, 750 ms conversion time
      }
      Temp = (float)raw / 16.0;
      flag = 1;
      display.setTextSize(2);
      display.setCursor(0,113);   // Устанавливаем курсор в левый верхний угол области вывода
      display.setTextColor(MAGENTA,BLACK);   // Определяем цвет вывода на дисплей
      display.print(Temp);
      }
    return Temp; // прекращение вычислений в функции, возвращение значения температуры
      }
     
    Выдает периодически два неверных значения : - 0.06 и 85 , может ввести вторую переменную "Temp2" и программно игнорировать их?
     
  18. Vovka

    Vovka Гик

    а подтягивающий резистор какого номинала?
     
  19. 64detali

    64detali Нерд

    Даташитовский на 4,7 кОм, попробовать уменьшить? до какого номинала?
    Проблемы начинаются когда вставляешь в скетч обе функции по температуре и оборотам, если с геометрически растущими оборотами я решил проблему поставив между массой и 2м пином конденсатор на 0,1 мкФ, то с температурой пока не получается.
     
    Последнее редактирование: 22 янв 2021
  20. 64detali

    64detali Нерд

    Вот примерно так работает:

     
    Последнее редактирование: 22 янв 2021