Ардуино Часовник с датчик за температура и влажност

JetMan

Администратор
Модераторски Екип
Дойде време да открием и този под-форум. Умишлено направих раздела още в началото защото имах няколко неща за които да пиша тук. От доста време събирам разни части и искам да направя нещо малко с Arduino ей така за кеф :) - Имам вече няколко неща направени и ще ви покажа първото от тях:

Ардуино Часовник с датчик за температура и влажност

Елементите които използвах са:

1. Arduino UNO R3
2. OpenSegment Shield - Red (20mm)
3. RCT module with DS1307
4. Humidity and Temperature Sensor - RHT03

Връзката на Цифровият дисплей беше сравнително лесна. Трябваше само да запоя крачетата и той си заработи нормално. След това включих към схемата RTC модула който дава точно време. Самият модул си има малка батерия която пази часа дори и след прекъсване на захранването.

За връзката използвах Аналогови пинове 4 и 5 - оказа се че не се ползват от дисплея.

Най-накрая остана да закрепя и сензора за температура и влажност RHT03 - той беше по лесен защото използва само един цифров пин, за целта избрах пин номер 5.

След като навързах всичко с поялника дойде ред на писането на кода. Тук видях че комуникацията с дисплея може да бъде направена по 3 начина (Serial/SPI/I2c)

Пробвах и трите , но избрах серийният начин защото само там намерих пример как да използвам десетичната точка на дисплея :)

Благодарение на всички добри хора които се бяха погрижили за хубавите диаграми и примерни кодове - задачата беше сравнително лесна и много приятна.

Единствено остана да помисля за някаква малка кутийка и начин на захранване. Закачих часовника към малка батерия 2s / 850mAh - но се оказа че издържа само 7-8 часа. Явно ще трябва да помисля за захранване от мрежата.


Това са страниците които намерих с много полезни примери:

https://github.com/sparkfun/Serial7SegmentDisplay/

RHT03 - от Тихомир Трифонов

RTC1307 примери от John Vaughters

Ето и няколко снимки на елементите, както и на финалния вариант.

arduino.jpg


display1.jpg


rtc.jpg


rtc-hookup.jpg


rht03.jpg


clock.JPG


А това е и кода за ардуино които написах.

Код:
/*
* Arduino Clock with RTC Module + OpenSegment Shield - Red and RHT03 Sensor
* can give time, and every 20 seconds show humidity and then temperature.
* 
* Code is just combination of examples I found for these nice modules.
*
* OpenSegment Shield Examples
* https://github.com/sparkfun/Serial7SegmentDisplay/
*
* RHT03 examples by Tihomir Trifonov
* http://playground.arduino.cc/Bulgarian/Dht22
*
* RTC1307 module examples by John Vaughters
* http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
*
* Version 1.0 , 31 July 2014 by Svetlin Simeonov
*/

#include <SoftwareSerial.h>
#include "Wire.h"

#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address
#define I2C_WRITE Wire.write 
#define I2C_READ Wire.read

#define APOSTROPHE  5
#define COLON       4
#define DECIMAL4    3
#define DECIMAL3    2
#define DECIMAL2    1
#define DECIMAL1    0

SoftwareSerial Serial7Segment(7, 8); //RX pin, TX pin

int cycles = 0;

int i;
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year,mm,hh;
byte test;
byte zero;
boolean colonOn = false;
char curtime[100];
int count=0;
int maxcount=20; // how many seconds to wayt until show humidity/temp
byte brightnessLevel = 30; // 0 to 100 %

// RTH03
byte dht_dpin = 5; // pin for RTH03 temperature sensor
byte dht_dat[5];   // temperature data array

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); }

int getMM()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(I2C_READ() & 0x7f);
  minute     = bcdToDec(I2C_READ());
  hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(I2C_READ());
  dayOfMonth = bcdToDec(I2C_READ());
  month      = bcdToDec(I2C_READ());
  year       = bcdToDec(I2C_READ());

  return minute;
}

int getHH()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(I2C_READ() & 0x7f);
  minute     = bcdToDec(I2C_READ());
  hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(I2C_READ());
  dayOfMonth = bcdToDec(I2C_READ());
  month      = bcdToDec(I2C_READ());
  year       = bcdToDec(I2C_READ());

  return hour;
}

// RTH03 functions

void InitDHT(){
  pinMode(dht_dpin,OUTPUT); 
  digitalWrite(dht_dpin,HIGH); 
}


void StartDHT22(){

  // start signal  
  pinMode(dht_dpin,OUTPUT);
  digitalWrite(dht_dpin,LOW);
  delay(1);
  digitalWrite(dht_dpin,HIGH);
  delayMicroseconds(40);

  // wait for answer  
  pinMode(dht_dpin,INPUT); // now pin goes INPUT
  while(digitalRead(dht_dpin) == LOW);
  while(digitalRead(dht_dpin) == HIGH);
}

byte readByte(){

  byte result = 0;

  for(byte i=0; i< 8; i++){ // read 8 bytes

      while(digitalRead(dht_dpin) == LOW);
      delayMicroseconds(45);
      if (digitalRead(dht_dpin) == HIGH)
     result |= (1 << (7 - i));        // counts byt for 1 and add to possition
     
      while (digitalRead(dht_dpin)==HIGH); // waits for new byte signal
    }

  return result;
}

// Main program

void setup() {
  Wire.begin();
  zero=0x00;
  Serial.begin(9600);

  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0822"); //Send the hour and minutes to the display
  Serial7Segment.write(0x7A);  // Brightness control command
  Serial7Segment.write((byte) brightnessLevel);  // 0 is dimmest, 255 is brightest
  sprintf(curtime, "b%03d", brightnessLevel); //Convert deciSecond into a string that is right adjusted
  Serial7Segment.print(curtime);
  InitDHT();
  //delay(1000);
}

void loop() 
{


    //Blink the colon every other second
    if(colonOn == true)
    {
      colonOn = false;
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write((byte) 0); // Turns off colon, apostrophoe, and all decimals
    }
    else
    {
      colonOn = true; 
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write( (1<<APOSTROPHE) | (1<<COLON) | (1<<DECIMAL2) ); // Turns on colon, apostrophoe, and far-right decimal
    }

  if((count>maxcount) && (colonOn == true)) {
     // display other
     
     StartDHT22();
     
      for (byte i=0; i<5; i++) { dht_dat[i] = readByte(); }
      byte checksum = dht_dat[0] + dht_dat[1] + dht_dat[2 ] + dht_dat[3];   
     
      if(dht_dat[4] == checksum) { // if data is correct

          //// finds whole and fract part for humidity
          int HighByte = dht_dat[0]; // first byte
          int LowByte = dht_dat[1];  // second byte
          int TReading = (HighByte << 8) + LowByte;
          int Whole = TReading / 10; // whole part
          int Fract = TReading % 10; // fract part

          // print in serial monitor
     Serial.print("humdity = ");
     Serial.print(Whole);
     Serial.print(".");
     Serial.print(Fract);
     Serial.print("%  ");

          // display fix to display temperature and humidity as 26.10 instead of 26.01
          // since sensor has 0.1 accuracy
          if(Fract<10) Fract = Fract * 10;

          sprintf(curtime, "%02d%02d", Whole, Fract);
          Serial7Segment.print(curtime);
          delay(2000);    

          // same procedure now for temperature
          HighByte = dht_dat[2];  // third byte
          LowByte = dht_dat[3];   // fourth byte
          TReading = (HighByte << 8) + LowByte;
          Whole = TReading / 10;
          Fract = TReading % 10;
         
          // display fix
          if(Fract<10) Fract = Fract * 10;

          // prints in serial monitor
          Serial.print("temperature = ");
          int SignBit = TReading & 0x8000; // check sign of temperature
          if (SignBit)           // if it's bellow zero
           Serial.print("-");  // we set dash
     Serial.print(Whole);  
     Serial.print(".");    
     Serial.print(Fract);  
     Serial.println("C  "); 

          sprintf(curtime, "%02d%02d", Whole, Fract);
          Serial7Segment.print(curtime);
          delay(2000);
     }
     
     // we zero counter again - so it waits another 
     // maxcount cycles before display this
     count=0; 

  } else {
     // display time
     hh=getHH();
     mm=getMM();

     sprintf(curtime, "Time: %02d:%02d", hh, mm);
     Serial.println(curtime);
     
     sprintf(curtime, "%02d%02d", hh, mm);
     Serial7Segment.print(curtime); //Send serial string out the soft serial port to the S7S
  }

  delay(1000);
  count++;
}
 

Tassadar

Редовен Потребител
Браво! Сега трябва клавиатурка и подпрограмка за сверяване на часовника.;)
 

JetMan

Администратор
Модераторски Екип
:) понеже ще е за лично ползване - мисля да не слагам бутони и начин за сверяване. Сверих модула с тестовата програма която беше в примерите за RTC модула :) , обмислям още дали има смисъл да добавя някаква друга екстра.
 

Tassadar

Редовен Потребител
Не очаквай от това RTC някаква желязна точност. Може да очакваш 2-3мин грешка на месец. Пълна екстра би била да взимаш времето от GPS модул. Тогава имаш атомно време.;) А, още по-голяма екстра - да сверяваш RTC модула по GPS. Тогава ще имаш точно време, дори да не "чуваш" GPS сателити в момента. Е, остава проблемът със зимно/лятното часово време, но той се решава напълно софтуерно.
 

JetMan

Администратор
Модераторски Екип
ммм - това е интересна идея за GPS модула наистина , но дали ще може да хване спътник при положение че се ползва основно на закрито - може би някаква друга On-Line връзка с която да се прави сверяване през определен интервал време.
 

Xape

Модератор
Модераторски Екип
Има и по-архаично, но пак "ядрено" решение. Нарича се DCF 77 от работи от 1959 г. Няма проблеми с лятно/зимно време.
Гледам че има и декодери за ардуино http://fiendie.net/arduino/funkuhr или тук http://thijs.elenbaas.net/2012/04/arduino-dcf77-radio-clock-receiver-hardware-2/
Всичките ми стенни часовници са такива, сигнала се хваща без проблем стига да не си в бункер.
Излъчвателя е маалко по-мощен от нашите - 50,000W :crazy: и излъчва на 77.5 kHz.
 
Последна промяна:

Tassadar

Редовен Потребител
Има и по-архаично, но пак "ядрено" решение. Нарича се DCF 77 от работи от 1959 г. Няма проблеми с лятно/зимно време.
Гледам че има и декодери за ардуино http://fiendie.net/arduino/funkuhr
Всичките ми стенни часовници са такива, сигнала се хваща без проблем стига да не си в бункер.
Излъчвателя е маалко по-мощен от нашите - 50,000W :crazy: и излъчва на 77.5 kHz.

Хм, и аз има няколко часовника които поддържат DCF77, но до сега никога не са успяли да хванат сигнал. Вероятно защото си нямат истинска антена заради малките си габарити.
 

JetMan

Администратор
Модераторски Екип
Това DCF77 изглежда доста лесно :) , мисля да го опитам. Предполагам че правилното решение е да запазя RTC модула и да го сверявам автоматично примерно на всеки час или веднъж на ден. Едва ли е разумно да разкарам RTC модула и да разчитам само на Ардуино + DCF

След няколко минути търсене намерих модула в Конрад за 13 евро


Относно начина с GPS - дали е възможно да се хване сигнал вътре в стаята с малка кутийка за часовника ?
 
Последна промяна:

Xape

Модератор
Модераторски Екип
Хм, и аз има няколко часовника които поддържат DCF77, но до сега никога не са успяли да хванат сигнал. Вероятно защото си нямат истинска антена заради малките си габарити.
Да, тук трябва да уточня, че моите часовници са относително маркови - Kienzle. Нищо особено не са, струват да кажем 40-50 лв. Тези най-евтините дето се продават в БГ по веригите не хващат сигнала въобще.
Същата работа е с метеостанциите, боклучивите не стават. Но виж, на станциите Hama нещата са решени елегантно - приемника за DCF77 e поставен в корпуса на външния температурен датчик, които приема сигнала без проблем и го мята към станцията. Работи на 100% проверено.
 

Tassadar

Редовен Потребител
.....
Относно начина с GPS - дали е възможно да се хване сигнал вътре в стаята с малка кутийка за часовника ?

Ако смартфонът ти лови сателити в стаята и GPS модула ще работи.

Това DCF77 изглежда доста лесно :) , мисля да го опитам. Предполагам че правилното решение е да запазя RTC модула и да го сверявам автоматично примерно на всеки час или веднъж на ден. Едва ли е разумно да разкарам RTC модула и да разчитам само на Ардуино + DCF

.....

Да, запази RTC-то. Ардуиното е с кварцово стабилизирана тактова честота и ще работи като часовник толкова точно, колкото и RTC-то. Но, губиш екстрата да си помни времето като спре тока.:)
 

st5rov

Редовен Потребител
Но виж, на станциите Hama нещата са решени елегантно - приемника за DCF77 e поставен в корпуса на външния температурен датчик, които приема сигнала без проблем и го мята към станцията. Работи на 100% проверено.

Така е, само че сателита не винаги има видимост към България! :eek:
 

Xape

Модератор
Модераторски Екип
Така е, само че сателита не винаги има видимост към България! :eek:
Има, имаа щото не е сателит! :rolleyes:
Това немските радиовълни са сериозна работа - Така какво Българския Ват е най-мощен!
 
Последна промяна:

st5rov

Редовен Потребител
Има, имаа щото не е сателит! :rolleyes:
Това немските радиовълни са сериозна работа - Така какво Българския Ват е най-мощен!

Имам такъв НАМА от 4 години! Обикновено няма сигнал около 6 месеца.
Явно проходимостта на вълните не им пука дали са немски!!! :crazy:
 

JetMan

Администратор
Модераторски Екип
Докато мисля как да сверявам часовника - се сетих за още една полезна екстра. Установих че контраста през деня и вечерта трябва да бъде различен. През деня трябва да е силен, вечер в къщи трябва да е по слаб, а като угася лампите трябва да е минимален. Първия вариант който си помислих е да му слагам датчик за осветеност - но това би усложнило малко схемата а и май няма голям смисъл. За това просто сложих една функция да слага различен контраст според текущият час.

Ако часа е между 3:00 и 7:00 сутринта съм на минимален контраст 5% - предполага се че ще спя. Между 7:00 и 20:00 часа през деня е на почти 80% , а между 20:00 и 3:00 съм на 30%

Получи се много добре :) , между временно дойде и малка кутийка която намерих в tpetrov.com - трябва да помисля как да вмъкна платката вътре и да остане красиво.
 

SMarty

Редовен Потребител
JetMan, поздравления за темата!
Много добро настроение ми донесе със сутрешното кафенце :)
 

JetMan

Администратор
Модераторски Екип
Много съм доволен от машинката - докато още мисля за сверяване - часовника вече се сдоби с малка кутийка за 3лв - и вече изглежда така:

clock1.JPG clock2.JPG
 

vesibo

Редовен Потребител
Докато мисля как да сверявам часовника - се сетих за още една полезна екстра. Установих че контраста през деня и вечерта трябва да бъде различен. През деня трябва да е силен, вечер в къщи трябва да е по слаб, а като угася лампите трябва да е минимален. Първия вариант който си помислих е да му слагам датчик за осветеност - но това би усложнило малко схемата а и май няма голям смисъл. За това просто сложих една функция да слага различен контраст според текущият час.

Ако часа е между 3:00 и 7:00 сутринта съм на минимален контраст 5% - предполага се че ще спя.
Голяма грешка!!!:D:D:D При теб трябва да е от 3:00 до 12.00ч.Ти по-рано не се събуждаш.:D:D:D:biri:
 

JetMan

Администратор
Модераторски Екип
:) то си е така - но реших малко да бутна цифрите като за нормални хора , иначе преди 11:00 не ми трябва силен контраст хаха
 

tefo

Новодошъл
Има ли напредък със GPS или DCF сверяването, че и аз такова решение търся за точен часовник.
 

JetMan

Администратор
Модераторски Екип
Има ли напредък със GPS или DCF сверяването, че и аз такова решение търся за точен часовник.

За момента все още се ослушвам и го сверявам ръчно. Реално разлика във времето нямам освен 2 пъти в годината смяна на часа за лятно/зимно време. Иначе от гореизброените неща GPS-a изглежда най-читав!
 
Нагоре