Witam majsterkowiczów! Nazywam się Mateusz i chcę wam przedstawić mój projekt wykorzystujący nadajnik i odbiornik RF 433Mhz oraz cyfrowy czujnik temperatury DS18B20. Jest to mój pierwszy artykuł na Majsterkowiczach, więc proszę o wyrozumiałość :) Do tego projektu wykorzystałem Arduino nano i Raspberry Pi model B. Ten sam projekt można wykonać wykorzystując dwa Arduino, jeżeli ktoś byłby tym zainteresowany mogę zrobić o tym oddzielny artykuł.
Zdjęcia:
Co będzie nam potrzebne:
- Raspberry Pi,
- Dowolne Arduino,
- Cyfrowy czujnik temperatury DS18B20,
- Rezystor 4.7k Ohm lub 10k Ohm (Ja użyłem 4.7k Ohm),
- Ekran LCD na I2C (Ja użyłem ekranu 20×4),
- Moduł radiowy i odbiornik 433Mhz,
- Przewody połączeniowe,
- Mała płytka stykowa.
- Podłączamy wszystkie elementy wg. schematu:
- Gdy już wszystko podłączyliśmy, to zanim przystąpimy do kodu powinniśmy wgrać biblioteki do naszego Arduino
Wgrywamy bibliotekę OneWire, DallasTemperature, VirtualWire. - Uruchamiamy Arduino IDE i wpisujemy nasz kod:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950#include <OneWire.h>#include <DallasTemperature.h>#include <VirtualWire.h>const int NadajnikRF = 3; // Port do, którego podłączyliśmy nadajnik// ===Inicjalizacja czujnika temperatury===#define ONE_WIRE_BUS 2 // Zmieniamy liczbę 2 jeżeli podłączyliśmy nasz czujnik do innego portu w ArduinoOneWire oneWire(ONE_WIRE_BUS);DallasTemperature sensors(&oneWire);DeviceAddress insideThermometer;// ========================================void setup() {Serial.begin(9600); // Rozpoczynamy komunikację szeregową w celu debugowaniasensors.begin(); // Rozpoczęcie pracy czujnikaif (!sensors.getAddress(insideThermometer, 0)) Serial.println("Nie znaleziono czujnika");Serial.print("Adres czujnika temperatury: ");printAddress(insideThermometer);sensors.setResolution(insideThermometer, 9);vw_setup(4000); // Szybkość transferu danychvw_set_rx_pin(NadajnikRF); // Port ustalony wyżej}void printTemperature(DeviceAddress deviceAddress) // Funkcja, która odpowiada za odczyt temperatury i wysłanie jej do Raspberry{float tempC = sensors.getTempC(deviceAddress); // Zapisanie temperatury do zmiennej Floatint tempCx100 = (int)(tempC*100); // Zmiana floata na intaSerial.print("Temp C: "); // Wyświetlenie temperatury na serial monitorzeSerial.print(tempC); // Wyświetlenie temperatury na serial monitorzechar msg[10]; // Tworzymy tablicę typu CharString doWyslania = (String(tempCx100, DEC));doWyslania.toCharArray(msg, doWyslania.length() + 1); // Konwersja inta do tablicy Charvw_send((uint8_t *)msg, strlen(msg)); // Wysyłanie temperatury do Raspberryvw_wait_tx();}void loop() {sensors.requestTemperatures(); // Pomiar temperaturyprintTemperature(insideThermometer); // Użycie funkcji printTemperaturedelay(2000); // przerwa 2000ms = 2s}void printAddress(DeviceAddress deviceAddress) // Funkcja służąca do wyświetlenia adresu czujnika DS18B20{for (uint8_t i = 0; i < 8; i++){if (deviceAddress[i] < 16) Serial.println("0");Serial.print(deviceAddress[i], HEX);}} - Wgrywamy nasz kod na Arduino i przystępujemy do przygotowania naszego Raspberry.
- Instalujemy pakiet WiringPi
123456cd /home/pisudo apt-get install git-coregit clone git://git.drogon.net/wiringPicd wiringPigit pull originsudo ./build - Następnie pobieramy program do odbierania temperatur z naszego Arduino.
1234wget https://www.dropbox.com/s/vz3qpkdbop05eqk/RPiodbiornik.zipunzip RPiodbiornik.zipmakesudo ./RFSniffer - Powinniśmy zobaczyć temperatury wysyłane z Arduino, teraz zostało nam sprawić by program uruchamiał się automatycznie i napisać program w pythonie, który będzie dzielił nasz wynik przez 1000 i wyświetlał go na ekranie LCD.
1sudo nano /etc/rc.local
i do pliku dopisujemy
1sudo /home/pi/RFSniffer - Teraz tworzymy dwie biblioteki dla naszego ekranu:
1nano lcddriver.py
i wklejamy kod:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157import i2c_libfrom time import *# LCD AddressADDRESS = 0x3F // !!Zmieniamy ten adres na swój uzyskujemy go wpisując komendę sudo i2cdetect -y 1!!# commandsLCD_CLEARDISPLAY = 0x01LCD_RETURNHOME = 0x02LCD_ENTRYMODESET = 0x04LCD_DISPLAYCONTROL = 0x08LCD_CURSORSHIFT = 0x10LCD_FUNCTIONSET = 0x20LCD_SETCGRAMADDR = 0x40LCD_SETDDRAMADDR = 0x80# flags for display entry modeLCD_ENTRYRIGHT = 0x00LCD_ENTRYLEFT = 0x02LCD_ENTRYSHIFTINCREMENT = 0x01LCD_ENTRYSHIFTDECREMENT = 0x00# flags for display on/off controlLCD_DISPLAYON = 0x04LCD_DISPLAYOFF = 0x00LCD_CURSORON = 0x02LCD_CURSOROFF = 0x00LCD_BLINKON = 0x01LCD_BLINKOFF = 0x00# flags for display/cursor shiftLCD_DISPLAYMOVE = 0x08LCD_CURSORMOVE = 0x00LCD_MOVERIGHT = 0x04LCD_MOVELEFT = 0x00# flags for function setLCD_8BITMODE = 0x10LCD_4BITMODE = 0x00LCD_2LINE = 0x08LCD_1LINE = 0x00LCD_5x10DOTS = 0x04LCD_5x8DOTS = 0x00# flags for backlight controlLCD_BACKLIGHT = 0x08LCD_NOBACKLIGHT = 0x00En = 0b00000100 # Enable bitRw = 0b00000010 # Read/Write bitRs = 0b00000001 # Register select bitclass lcd:#initializes objects and lcddef __init__(self):self.lcd_device = i2c_lib.i2c_device(ADDRESS)self.lcd_write(0x03)self.lcd_write(0x03)self.lcd_write(0x03)self.lcd_write(0x02)self.lcd_write(0x02)self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)self.lcd_write(LCD_CLEARDISPLAY)self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)sleep(0.2)def lcd_write_char(self, charvalue, mode=1):self.lcd_write_four_bits(mode | (charvalue & 0xF0))self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))def lcd_load_custom_chars(self, fontdata):self.lcd_write(0x40);for char in fontdata:for line in char:self.lcd_write_char(line)# clocks EN to latch commanddef lcd_strobe(self, data, bl=1):self.lcd_device.write_cmd(data | En | (LCD_NOBACKLIGHT,LCD_BACKLIGHT)[bl])sleep(.0005)self.lcd_device.write_cmd(((data & ~En) | (LCD_NOBACKLIGHT,LCD_BACKLIGHT)[bl]))sleep(.0001)def lcd_write_four_bits(self, data):self.lcd_device.write_cmd(data | LCD_BACKLIGHT)self.lcd_strobe(data)# write a command to lcddef lcd_write(self, cmd, mode=0):self.lcd_write_four_bits(mode | (cmd & 0xF0))self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))# put string functiondef lcd_display_string(self, string, line):if line == 1:self.lcd_write(0x80)if line == 2:self.lcd_write(0xC0)if line == 3:self.lcd_write(0x94)if line == 4:self.lcd_write(0xD4)for char in string:self.lcd_write(ord(char), Rs)# clear lcd and set to homedef lcd_clear(self):self.lcd_write(LCD_CLEARDISPLAY)self.lcd_write(LCD_RETURNHOME)# put string in specific positiondef lcd_display_string_pos(self, string, line, pos):if line == 1:pos_new = poselif line == 2:pos_new = 0x40 + poselif line == 3:pos_new = 0x14 + posif line == 4:self.lcd_write(0xD4)for char in string:self.lcd_write(ord(char), Rs)# clear lcd and set to homedef lcd_clear(self):self.lcd_write(LCD_CLEARDISPLAY)self.lcd_write(LCD_RETURNHOME)# put string in specific positiondef lcd_display_string_pos(self, string, line, pos):if line == 1:pos_new = poselif line == 2:pos_new = 0x40 + poselif line == 3:pos_new = 0x14 + poselif line == 4:pos_new = 0x54 + posself.lcd_write(0x80 + pos_new)for char in string:self.lcd_write(ord(char), Rs)def lcd_backlight(self, state):if state == 1:self.lcd_device.write_cmd(LCD_BACKLIGHT)elif state == 0:self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
1nano i2c_lib.py
123456789101112131415161718192021222324252627282930313233343536#!/usr/bin/pythonimport smbusfrom time import *class i2c_device:def __init__(self, addr, port=1):self.addr = addrself.bus = smbus.SMBus(port)# Write a single commanddef write_cmd(self, cmd):self.bus.write_byte(self.addr, cmd)sleep(0.001)# Write a command and argumentdef write_cmd_arg(self, cmd, data):self.bus.write_byte_data(self.addr, cmd, data)sleep(0.001)# Write a block of datadef write_block_data(self, cmd, data):self.bus.write_block_data(self.addr, cmd, data)sleep(0.001)# Read a single bytedef read(self):return self.bus.read_byte(self.addr)# Readdef read_data(self, cmd):return self.bus.read_byte_data(self.addr, cmd)# Read a block of datadef read_block_data(self, cmd):return self.bus.read_block_data(self.addr, cmd) - W końcu tworzymy nasz program wyświetlający temperaturę.
1nano templcd.py
12345678910111213141516171819202122232425262728#!/usr/bin/pythonimport lcddriverimport timelcd = lcddriver.lcd()lcd.lcd_clear()custom_char = [[ 0x0, 0x6, 0x9, 0x9, 0x6, 0x0, 0x0, 0x0 ]]def readtemp():f_1 = open("/home/pi/temp.txt", 'r')f1 = f_1.read().replace('\n', '')return f1while True:temp = readtemp()temp1 = float(temp)temp1 = temp1 / 100temp2 = str(temp1)lcd.lcd_clear()lcd.lcd_display_string_pos("Temperatura:",1,4)lcd.lcd_display_string_pos(unichr(0),2,6)lcd.lcd_display_string_pos("C",2,7)lcd.lcd_display_string(temp2,2)time.sleep(10)
Udało nam się wyświetlić temperaturę na naszym ekranie z Arduino Nano :).
Jak macie jakieś pytania lub zauważyliście jakiś błąd piszcie w komentarzach postaram się na nie odpowiedzieć :). Pozdrawiam Mateusz.
Hej, też jestem Mateusz :DD
mam pytanko, w jakim celu skorzystałeś z biblioteki RCSwitch zamiast normalnego VirtualWire?
Cześć :D
Wykorzystałem bibliotekę RCSwitch, bo jest ona również dostępna na RPi i wiem, że będzie to na 100% kompatybilne ze sobą. Ale jak będę miał wolny czas to spróbuję również użyć VirtualWire jak mi się uda to gdzieś to dodam. Widziałem twój kanał na YT super filmy tworzysz, tylko mało ich jest :(. Pozdrawiam Mateusz
Chętnie bym tworzył więcej gdybym miał czas, od jakiegoś czasu staram się dodawać filmy raz na tydzień ale to też nie zawsze wychodzi. Czasami też mam problemy z tym g*em jakim jest Movie Maker…. czas się przesiąść na coś lepszego…
Polecam ci pobrać i używać Sony Vegasa, mnie jeszcze nigdy nie zawiódł. Jak będziesz miał jakiś problem to pisz do mnie np. na maila iwaniszczukmateusz@gmail.com lub na GG: 25863455 z chęcią pomogę :)
Każdy poleca ale nikt nie chce płacić xD
Polecam zakupy w sieciach sklepów torrent :).
Zmieniłem bibliotekę na VirtualWire :P
Wszystko fajnie ale taki dokładny termometr przydał by mi się na arduino. 3 miejsca po przecinku to fajna sprawa. Mam nadzieję że odzwierciedla rzeczywistość.
Na arduino to trzeba było by chyba zmodyfikować bibliotekę, żeby zwracała temperature z 3 miejscami, na raspberry z tym nie ma problemu bo jak podzieli się wynik z pliku przez 1000 to wychodzi temperatura z 3 miejscami po przecinku. Termometr jest super dokładny, często porównuje te temperatury z tymi co są dostępne na różnych stronach w internecie i się nie wiele różnią max o 1 stopień. Nie wiem jak jest w wersji wodoodpornej ale w tej z założoną izolacją z pozostałości po skrętce jest super. Pozdrawiam Mateusz :)
Temperaturę można zobaczyć jeszcze na stronie: http://89.229.136.81/
Oraz z aplikacji na androida. Może kiedyś opiszę jak zrobić taką aplikację z sterowaniem diodą rgb normalnymi diodami i temperaturą.
Dioda rgb:
Super projekt, tylko kod jakbyś bardziej wyjaśnił to było by super. Ja jak kupię jakieś arduino to spróbuje zrobić to u siebie. Za pomysł daję 5.
Do kodu na Arduino dodałem komentarze, mam nadzieję, że teraz już wiadomo co znaczy każda linijka kodu :)
Kody nie działają :( Nie wiem, dlaczego ale przy uruchomieniu RFSniffer’a nie czyta żadnych kodów z transmitera.
Ja mam dokładnie to samo, zamówiłem już drugi pakiet RF 433 i zobaczymy co z tego wyjdzie.
Witaj, co to jest za układ pomiędzy wyświetlaczem, a Raspberry Pi? Bo niby LCD można podłączyć bezpośrednio do maliny, ale sterując tym kontrolerem przez I2C mamy dobry zysk nóżek ;-)
Projekt spoko.
To jest Konwerter sygnału wyświetlacza HD44780 na 4pin z sygnału I2C TWI IIC .
http://allegro.pl/konwerter-lcd-hd44780-i2c-iic-twi-arduino-avr-arm-i5900520901.html
Super, dzięki ;-)
A nie lepiej było od razu zrobić to z biblioteką RadioHead, biblioteka Virtualwire nie jest już od kilku lat wspierana.
Masz może pomysł, jak wykorzystać jeden odbiornik, i kilka nadajników? To byłoby fajne i tanie rozwiązanie na kilka (kilkanaście_ termometrów do automatyki domowej. Jak dałoby się to jeszcze wpiąć w ethernet (nawet modół W5100) to byłoby super
Czy do raspberry też trzeba jakieś kody wprowadzić?
1.Czy do raspberry też trzeba wgrać do pythona jakieś kody?
Potrzebuje sterowac pilotem RF 433mhz urzadzenia podpiete do raspberry pi z odbiornikiem RF. Widzial ktos taki projekt?
Przydał by się projekt z użyciem Bluetooth 4.1