Авто. Температура снаружи и внутри, вывод на lcd1602, регулировка яркости подсветки при помощи фоторезистора

se7encolors
se7encolors аватар
Offline
Зарегистрирован: 26.11.2015

Здравствуйте товарищи программисты.

У меня старая машинка 97 года, которая неумеет измерять температуру. Решил что я всетаки хочу ее знать и хочу чтоб это выглядело хоть както прилично. Друг посоветовал ардуино, ну по незнанию я с ним конечно же согласился, отправился в алиэкспресс и заказал там 1х Arduino Nano, x2 Датчика DS18B20, х1 LCD 1602 дисплей в комплекте с I2C интерфейсом.

Не так давно дождался своей первой Arduino Nano ну и собственно незамедлительно приступил к изучению всего что подруку попалось на эту тему. Беспощадно тратя рабочее время вскоре я получил желаемый результат, оба датчика показывали мне свои показания на дисплее. Радостный и довольный пошел в машину тестировать свое "изобретение", датчики исправно показывали как минусовую так и плюсовую температуру. Единственным минусом стала чрезмерно высокая яркость дисплея в ночное время, аж пришлось глаза прищурить. Погуглил немного, нарвался на фоторезисторы. Благо у посоветовавшего мне ардуино друга нашлось пару штук, взял у него один, так как больше и ненужно было, вообщем теперь есть в наличии х1 Фоторезистрор порядка 50кОм при полной темноте.

Посмотрел на ардуинку утыканую припаяными проводами так что ничего не подсунуть, решил что надо немного поудобнее сделать свой первый отладочный агрегат. О бредбордах я и в помине не знал, так что попути решил изучить травление плат в дом.условиях. За часик-полтора ознакомился со Sprint Layout 5.0 ну и собствено пока ознакамливался начертил желаемую плату. Вытравил и собрал все на ней.

Немного помучался с показаниями фоторезистора выводимыми на lcd, но по своей глупости... спустя час вспомнил что lcd не удаляет символы самостоятельно и благополучно добавив пробел после вывода результата analogRead(0) получил наконец вменяемые цифры от 0 до 1013. Быстренько снял джампер отвечающий за подсветку с I2C интерфейса и подпаяв его к 10 цифровому порту, начал писать код. Написаный мной код не в какую не хотел регулировать подсветку дисплея, и даже не включал ее. На глаза попался коментарий о том кто в I2C интерфейсах заказаных с китая необходимо обязательно указывать включение подсветки lcd.backlight() после того как я ее добавил все благополучно заработало и функция analogWrite(BL,255) выставила мне желаемый результат. Дальше немного пораздумав написал топорный код для регулировки подсветки.

int PhCount = analogRead(0);
PhCount = PhCount/4;
if(PhCount > 255){
  analogWrite(BL, 255); 
} else {
  if(PhCount < 40){ //минимальный уровень подсветки 40
    analogWrite(BL, 40);
  } else {
    analogWrite(BL, PhCount);
  } 
}

Собственно говоря можно приступать к выбору места в машине под lcd, т.к. осталось собрать источник питания для ардуинки, вытравить более компактную схему, только для тех компонентов которые будут использованы. Распихать датчики по машине и все скомутировать. Пока буду заниматься всем этим, есть время подчистить код, т.к я более чем уверен что он плохо выглядит :)) На данный момент все это выглядит вот так:

Строка PhCount отображает текущее значение показаний фоторезистора деленное на 4. Собственно далее полный скетч для того чтобы меня забрасали тапками и помидорами:

//------------------------------------- Подключенные библиотеки ---------------------------

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>

//------------------------------------- Дополнительные установки --------------------------

LiquidCrystal_I2C lcd(0x27,16,2); //задаем адрес LCD экрана 0x27, 16 символов, 2 строки

int inTSensorConnectedPin = 4;
int outTSensorConnectedPin = 5;
OneWire  ds1(inTSensorConnectedPin);
OneWire  ds2(outTSensorConnectedPin);
float inTSensor;
float outTSensor;

int BL = 10;

//------------------------------------- SETUP ---------------------------------------------

void setup()
{
  pinMode(BL, OUTPUT);
  Serial.begin(9600); //отправляем на монитор
  lcd.init(); // Инициализируем экран
  lcd.backlight(); 
  analogWrite(BL, 255);
   lcd.clear();
   lcd.setCursor(2, 0);
   lcd.print("Loading...");
   lcd.setCursor(5, 1);
   lcd.print("ver. 1.99");
   delay(1000);
    lcd.clear();
     uint8_t box[]={0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
     lcd.createChar(0,box);
     lcd.setCursor(2, 0);
     lcd.print("Loading...");
      for(int i=0; i <= 15; i++){
       lcd.setCursor(i, 1);
       lcd.write(0);
       delay(80);
      }
      delay(400);
    lcd.clear();   
}

//----------------------------------------- LOOP ------------------------------------------

void loop() {

int PhCount = analogRead(0);
PhCount = PhCount/4;
if(PhCount > 255){
  analogWrite(BL, 255); 
} else {
  if(PhCount < 40){
    analogWrite(BL, 40);
  } else {
    analogWrite(BL, PhCount);
  } 
}
uint8_t temp2[]={0x06,0x09,0x09,0x06,0x00,0x00,0x00,0x00}; //Отрисовка градусов Цельсия
lcd.createChar(1,temp2);

  float out_temp = getOutsideTemp();
  lcd.setCursor(0,0);
  lcd.print("Out:");
  lcd.setCursor(4, 0);
  lcd.print(out_temp, 0);
  lcd.write(1);
  lcd.print(" ");
  float in_temp = getInsideTemp();
  lcd.setCursor(9,0);
  lcd.print("In:");
  lcd.setCursor(12, 0);
  lcd.print(in_temp, 0);
  lcd.write(1);
  lcd.print(" ");

  lcd.setCursor(0,1);
  lcd.print("PhCount: ");
  lcd.print(PhCount);
  lcd.print("  ");
}
float getOutsideTemp() 
  {                              
    byte data[12];
    byte addr[8];
   if ( !ds2.search(addr)) {   
        lcd.setCursor(0, 0);
        lcd.print("NO more addrss!");
        ds2.reset_search();
        return -1001;
     }
    if ( OneWire::crc8( addr, 7) != addr[7]) {
          lcd.setCursor(0, 0);
          lcd.print("CRC is not valid!");
        return -1002;
    }
    if ( addr[0] != 0x10 && addr[0] != 0x28) {
          lcd.setCursor(0, 0);
          lcd.print("NOT recognizd!");
        return -1003;
    }
    ds2.reset();
    ds2.select(addr);
    ds2.write(0x44,1);
    byte present = ds2.reset();
    ds2.select(addr);
    ds2.write(0xBE);
    for (int i = 0; i < 9; i++) {
       data[i] = ds2.read();
    }
    ds2.reset_search();
    byte MSB = data[1];
    byte LSB = data[0];
    float TRead = ((MSB<<8) | LSB);
    float Temperature = TRead / 16;
  return Temperature;
}
float getInsideTemp() 
  {                              
    byte data[12];
    byte addr[8];
   if ( !ds1.search(addr)) {   
        lcd.setCursor(0, 1);
        lcd.print("NO more addrss!");
        ds1.reset_search();
        return -1001;
     }
    if ( OneWire::crc8( addr, 7) != addr[7]) {
          lcd.setCursor(0, 1);
          lcd.print("CRC is not valid!");
        return -1002;
    }
    if ( addr[0] != 0x10 && addr[0] != 0x28) {
          lcd.setCursor(0, 1);
          lcd.print("NOT recognizd!");
        return -1003;
    }
    ds1.reset();
    ds1.select(addr);
    ds1.write(0x44,1);
    byte present = ds1.reset();
    ds1.select(addr);
    ds1.write(0xBE);
    for (int i = 0; i < 9; i++) {
       data[i] = ds1.read();
    }
    ds1.reset_search();
    byte MSB = data[1];
    byte LSB = data[0];
    float TRead = ((MSB<<8) | LSB);
    float Temperature = TRead / 16;
  return Temperature;
}

P.S извиняюсь за гору текста, хотелось поделиться первым впечатлением, если необходимо впреть буду писать коротко и по делу :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

строки 64, 65 - в сетап
функции стр. 87...122 и стр. 123...158 - можно превратить в одну с параметрами - какой опрашивать и в какую строку выводить

se7encolors
se7encolors аватар
Offline
Зарегистрирован: 26.11.2015

SU-27-16 пишет:

функции стр. 87...122 и стр. 123...158 - можно превратить в одну с параметрами - какой опрашивать и в какую строку выводить

Изначально так и хотел сделать. Но не удалось разобраться как объяснить функии с каким объектом библиотеки onewire ей работать, DS1 или DS2.

На случай если возникнет такой вопрос сразу отвечу: знаю о том что данные датчики имеют свои адреса, знаю что пожно подключить их последовательно на один порт. Сделал это для практики, получилось и разобрал и подключил их к разным пинам, потому что они могут выйти из строя и придется их заменить, посчитал что лучше не привязывать показания к конкретному адресу датчика, дабы не переписывать счетч при замене датчика

SU-27-16 пишет:

строки 64, 65 - в сетап

Перенес, спасибо. Забыл совсем про них

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

1 - Изначально так и хотел сделать. Но не удалось разобраться как объяснить функии с каким объектом библиотеки onewire ей работать, DS1 или DS2.

2 - ...посчитал что лучше не привязывать показания к конкретному адресу датчика, дабы не переписывать счетч при замене датчика...

наверное , можно в функцию передать и объект DS1, DS2 или номер пина - может кто из "взрослых" подскажет :)
я - точно нет

bwn
Offline
Зарегистрирован: 25.08.2014

Как вариант подключения на один пин: в момент запуска сверяем адреса с записанными в EEPROM, если соответствуют - переходим в штатный режим. Если не соответствуют, перезаписываем новые адреса, требуем нагреть один из датчиков, по нагреву записываем дополнительно к адресу признак местонахождения.
Бяка из разряда шизофрении, если зачем то поменяем датчики местами.

r00t_krsk
Offline
Зарегистрирован: 12.12.2015

Доброго времени суток, не могу разобраться как подключаеться фоторезистор по вашему скетчу, если есть возможность накидайте пожалуйста схему подключения, зранее спасибо! 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Один контакт к А0, другой к 5V.

se7encolors
se7encolors аватар
Offline
Зарегистрирован: 26.11.2015

В ходе горы работы которая внезапно на меня навалилась некогда было писать, но так как нужно было духовно обогащаться из отображения температуры плавно перешел на Старт двигателя с кнопки... Могу выложить свежеиспеченный релиз, НО заранее предупреждаю(!) работает он только в условиях "лаборатории" по двум простым причинам:

1. Написаный код слишком "топорный" и как полетный вариант еще не годится

2. Для работы с машиной необходимо провести ряд тестов безопасности, чтобы не еб....(ну вы поняли :) )

Пока что обладает следующими возможностями:

1. Управление только одной кнопкой

2. Возможна передача управления "замку зажигания" и наоборот(в случае если надо выйти, а машину глушить не надо, можно передать управление ардуинке не выключая двигатель, затем вытащить ключ(включив штатную блокировку руля) и выйти по своим делам)

3. Отказ в запуске в случае если АКПП не в положении "P"

4. Отказ в запуске стартера если двигатель на момент нажатия активен

 

Если кому интересно, подготовлю материал и выложу в отдельной теме. Т.к намечается неминуемое продолждение с нарастающей проблематичностью. Изначальный план развития по пунктам выглядит так:

1. Старт/Стоп двигателя с кнопки

2. Автостарт/стоп двигателя по указаным параметрам

3. Старт/Стоп двигателя и управление параметрами через приложение телефона по Bluetooth

4. [половина знаний уже есть] Старт/Стоп двигателя + контроль показателей + логирование показателей в облако

5. [думаю получится добиться результата] Удаленное управление в радиусе 2-3м от машины (иногда знаете бывают моменты когда нужно подтолкнуть самого себя, или же посмотреть что происходит под колесами но изнутри как известно не видно)

6. [надеюсь доживу и мозгов хватит :) не уверен что на arduino] Следование(при необходимости) за источником сигнала(маячек на водителе) в радиусе 2-3метров, в случае если достаточно места для движения