A program
Ha minden kész akkor már csak egy valami van hátra maga a program. A NANO esetében 32Kb hely áll rendelkezésre, ez a leforgatott programra vonatkozik. Én az Aduino IDE-t használtam erre a célra. A legtöbb Linux disztribúcióban benne van. De az oldalukról le is lehet tölteni bármilyen OS-re.
Akkor jöjjön a program. A kis memória miatt csak fix változókkal dolgoztam ,azaz minden egyes paraméter változtatás után le kellet fordítani a programot és rátölteni az Arduino-ra. Minden eszköz előtte egy teszt programmal kipróbáltam, és így építkeztem lépésről lépésre.
Lássuk a programot először is a változok bevezetése, és függvénykönyvtárak beemelése:
//2015.06.28 LCD rajzolási hibák megoldása + időzítés!!!
//2015.07.03 Watchdog bekapcsolása 4s idővel, min(), max() bevezetése
//2015.07.13 DS1307 library cseréje
#include
#include
#include
#include "DHT.h"
#include
#include
#include
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
//RTC DS1307
//RTC_DS1307 rtc;
unsigned long oldSeconds = 0;
tmElements_t time; //DS1307
// SZENZOROK
#define DHTPIN 2
#define DHTTYPE DHT22
DHT DHT22_Pin(DHTPIN, DHTTYPE);
byte DS18B20_Pin = 6; //digital 6 hőmérő 4K7Ohm <-> 5V
OneWire ds(DS18B20_Pin); //MEGFELELŐ VÁLTOZONÉV!
unsigned long tempCheckTime = 0; //szenzor olvasás ideje
// KIMENETEK BEÁLLÍTÁSA
// LED PANEL
byte LED = 9; //PWM kivezetés
// RELAY 24V
byte relay = 12;
// PIR SENSOR
boolean pirStatus = false;
byte pirPin = 3;
// DÁTUM&IDŐ
byte fadeUpTime = 30; // másodpercben a led fel és le lufutásának ideje
long fadeStepTime = 1; //le-fel futás léptéke másodpercbe, mennyi időnként változtassa a led fényerejét
int fadeValue = 0; //PWM kezdő értéke 0-255 lehet
byte fadeValuePick = 255 / fadeUpTime; // a le és felfutás alatt ennyivel változik a kimenet értéke
// on time
byte onHour = 9;// bekapcsolás óra
byte onMinute = 0; // bekapcsolás perc
// off time
byte offHour = 20; // kikapcsolás óra
byte offMinute = 0; // kikapcsolás perc
//DateTime now;
// IDŐZITÉS
int backLightTime = 60 * 5; // háttérvilágítás kikapcsolási ideje másodpercben
boolean backLightStatus = false;
unsigned long backLightStop = 0; // LCD háttér világítás kikapcsolásának ideje
long ledIconTime = 0; // LEDicon villogtatás ideje ms
long pirIconTime = 0; // PIRicon villogtatás ideje ms
boolean pirLedStatus = false;
boolean ledStatus = false;
// KIÍRÓ STRINGEK
String ledTimeValue = "";
// DATA LOGGER DATAS
float maxminTemp[2] = {
0.0, 100.0};
float maxminHum[2] = {
0.0, 100.0};
unsigned long dataLoggerTime = 0; // adatLogger forgatás ideje
byte item = 2;
const char custom[][8] PROGMEM = {
{
0x00,0x06,0x06,0x14,0x0f,0x04,0x0a,0x11 }
, // pir
{
0x00,0x0e,0x15,0x19,0x11,0x1f,0x0a,0x00 }
, // LED OFF
{
0x00,0x0e,0x1b,0x17,0x1f,0x1f,0x0a,0x00 }
, // LED ON
{
0x04,0x0a,0x0a,0x0a,0x0e,0x1f,0x1f,0x0e }
, // temp
{
0x00,0x04,0x0a,0x04,0x00,0x00,0x00,0x00 }
, // degree
{
0x04,0x04,0x0e,0x0e,0x1f,0x1f,0x1f,0x0e }
, // drop
{
0x16,0x0f,0x16,0x00,0x00,0x0d,0x1e,0x0d }
, // fish
{
0x04,0x0a,0x11,0x15,0x11,0x15,0x11,0x1f } // hause
};
Jöhet az inicializálás és LCD-re ikonok kirajzolása:
void initialize(){
float t;
//SZENZOROK első lekérdezésének elvégézése...
t = DHT22_Pin.readTemperature();
delay(50);
t = DHT22_Pin.readHumidity();
delay(50);
t = getTemp();
delay(500);
//SENZOR DHT22
// haus, temp icon
lcd.setCursor(0,1);
lcd.write((uint8_t)0);
lcd.setCursor(1,1);
lcd.write((uint8_t)4);
// humidity icon
lcd.setCursor(12,1);
lcd.write((uint8_t)6);
//SENZOR DS18B20
// fish&temp icon
lcd.setCursor(0,2);
lcd.write((uint8_t)7);
lcd.write((uint8_t)4);
lcd.setCursor(0,0);
lcd.print("Init Ok");
delay(500);
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
A Setup() alaphelyzetbe állít mindent, és watchdog beállítás:
void setup(){
//Serial.begin(9600);
byte nb=0,bc=0;
byte bb[8];
//RTC DS1307
Wire.begin();
//rtc.begin();
// LCD I2C
lcd.begin(20,4);
for (nb=0; nb<8; nb++ ) { // create 8 custom characters
for (bc=0; bc<8; bc++) bb[bc]= pgm_read_byte( &custom[nb][bc] );
lcd.createChar ( nb+1, bb );
}
lcd.noBacklight();
initialize();
pinMode(relay, OUTPUT);
digitalWrite(relay, LOW);
pinMode(LED, OUTPUT);
wdt_enable (WDTO_4S);//watchdog engedélyezése 4s-re
}
És a program fő része a loop():
void loop() {
if(millis()/1000 > oldSeconds){
oldSeconds = millis()/1000;
if(RTC.read(time)){
// DATE TIME
doLCD();
// CHECK TEMPS
if(millis()/1000 > tempCheckTime ){
tempCheckTime = millis()/1000 + 5;
doTemp();
}
// DATA LOGGER
if(millis()/1000 > dataLoggerTime){
dataLoggerTime = millis()/1000 + 12;
doDataLogger();
}
}
else {
if(RTC.chipPresent()){
lcd.setCursor(0,0);
lcd.print("DS1307 is stopped!");
}
else {
lcd.setCursor(0,0);
lcd.print("DS1307 read error!");
}
}
}
doPir();
doLight();
wdt_disable(); //watchdog tiltása
}
És a függvények:
void doDataLogger(){
//now = rtc.now();
String logData;
lcd.setCursor(0,3);
switch(item){
case 0:
lcd.print(" Temp: ");
lcd.print(maxminTemp[0], 1); // MAX
lcd.print(" / ");
lcd.print(maxminTemp[1], 1); // MIN
lcd.print(" ");
break;
case 1:
lcd.print(" Hum: ");
lcd.print(maxminHum[0], 1); // MAX
lcd.print(" / ");
lcd.print(maxminHum[1], 1); // MIN
lcd.print(" ");
break;
case 2:
lcd.print(startUpTime("Run: "));
break;
case 3:
lcd.print(setCenter("RAM: " + String(freeRam()) + " / 2048"));
break;
}
item++;
if(item == 4) item=0;
}
String startUpTime(String textData){
String newData = "";
long startSeconds = millis()/1000;
int startMinutes = (startSeconds % 3600) / 60;
int startHours = (startSeconds % 86400) / 3600;
int startDays = (startSeconds % (86400 * 30)) / 86400;
newData = setCenter(textData + startDays + "d " + startHours + "h " + startMinutes + "m");
return newData;
}
String setFillLine(String text){
int length = text.length();
String space = " ";
String tmpText = "";
if(length < 20){
for(int i=length; i <= 19; i++){
tmpText += space;
}
}
return text + tmpText;
}
String setCenter( String text ){
int firstPos = (20 - text.length()) / 2;
String space = " ";
String tmpText = "";
for(int i=1; i <= firstPos; i++){
tmpText += space;
}
return setFillLine(tmpText + text);
}
void doLCD(){ //DÁTUM IDŐ KIÍRÁSA
lcd.setCursor(0,0);
lcd.print(tmYearToCalendar(time.Year));
lcd.print(".");
zero(time.Month);
lcd.print(".");
zero(time.Day);
lcd.setCursor(12,0);
zero(time.Hour);
lcd.print(":");
zero(time.Minute);
lcd.print(":");
zero(time.Second);
}
void zero(int dat){
if( dat < 10 ) lcd.print("0");
lcd.print(dat, DEC);
}
// doTemp()
// hőmérséklet, páratartalom, vízálló hőmérő adatok kiírása LCD-re
void doTemp() {
//now = rtc.now();
float h,c,temp;
//SENZOR DHT22
c = DHT22_Pin.readTemperature();
h = DHT22_Pin.readHumidity();
lcd.setCursor(3,1);
lcd.print(c, 1);
lcd.write((uint8_t)5);
lcd.print("c");
lcd.setCursor(14,1);
lcd.print(h, 1);
lcd.print("%");
// DATA LOGGER
// minMax(c, 0);//2015.07.02
// minMax(h, 1);
maxminTemp[0] = max(maxminTemp[0], c);
maxminTemp[1] = min(maxminTemp[1], c);
maxminHum[0] = max(maxminHum[0] ,h);
maxminHum[1] = min(maxminHum[1] ,h);
//SENSOR DS18B20
temp = getTemp();
lcd.setCursor(3,2);
if(temp == -1000) {
lcd.print("-none");
return;
}
lcd.print(temp, 1); // kiírás az LCD-re 1 tizedes értékkel
lcd.write((uint8_t)5);
lcd.print("c");
}
void minMax(float number, byte nr){
switch(nr){
case 0:
if(maxminTemp[0] < number ) maxminTemp[0] = number;//MAX
if(maxminTemp[1] > number ) maxminTemp[1] = number;//MIN
break;
case 1:
if(maxminHum[0] < number ) maxminHum[0] = number;//MAX
if(maxminHum[1] > number ) maxminHum[1] = number;//MIN
break;
}
}
// doLight()
// LEDPanel vezérlése
// FEL-LE-húzás, ki be kapcsolt állapotok
void doLight(){
long m = time.Minute;
long h = time.Hour;
long oM = onMinute;
long oH = onHour;
long offM = offMinute;
long offH = offHour;
unsigned long tSeconds, onSeconds, offSeconds;
String text = "";
h *= 3600;
m *= 60;
oM *= 60;
oH *= 3600;
tSeconds = h+m+time.Second;
onSeconds = oH+oM;
offM *= 60;
offH *= 3600;
offSeconds = offH+offM;
if(tSeconds >= onSeconds && offSeconds >= tSeconds){ // LIGHT ON
// ide jön amit még be kell kapcsolni
digitalWrite(relay, HIGH);
analogWrite(LED, fadeValue);
if( tSeconds >= onSeconds && tSeconds <= onSeconds + fadeUpTime ){ // LED UP
blinkLedIcon();
if(millis()/1000 >= fadeStepTime ) {
fadeStepTime = millis()/1000 + 1;
fadeValue += fadeValuePick;
if(fadeValue >= 255) fadeValue = 255;
}
}
if( tSeconds > onSeconds + fadeUpTime && tSeconds < offSeconds - fadeUpTime ){ // ON
fadeValue = 255;
analogWrite(LED, fadeValue); // max kimenet PWM
text = expandZero(offHour) + ":" + expandZero(offMinute);
if(text != ledTimeValue) {
drawTimer(1, 12,2, text);
ledTimeValue = text;
}
}
if( offSeconds - fadeUpTime <= tSeconds ){ // LED DOWN
blinkLedIcon();
if(millis()/1000 >= fadeStepTime ) {
fadeStepTime = millis()/1000 + 1;
fadeValue -= fadeValuePick;
if(fadeValue <= 0) fadeValue = 0;
}
}
}
else{ // LIGHT OFF
text = expandZero(onHour) + ":" + expandZero(onMinute);
if(text != ledTimeValue) {
drawTimer(0, 12,2, text);
ledTimeValue = text;
}
// ide jön amit még ki kell kapcsolni
//lightStatus = false;
digitalWrite(LED, LOW);
digitalWrite(relay, LOW);
}
}
// blinkLedIcon
// 500ms idönként váltogat(villogtat) 2 ikont az LCD-n
void blinkLedIcon(){
if(millis() > ledIconTime) {
ledIconTime = millis() + 350;
ledStatus = !ledStatus;
lcd.setCursor(12,2);
if(ledStatus) lcd.write((uint8_t)3);
else lcd.write((uint8_t)2);
}
}
// drawTimer()
// időzitő ikon állapt kirajzokása LCD-re
void drawTimer(boolean statusInfo, int row, int column, String data){
lcd.setCursor(row,column);
if(statusInfo) lcd.write((uint8_t)3);
else lcd.write((uint8_t)2);
lcd.print( " ");
lcd.print(data);
}
// doPir()
// pir szenzor magas jel esetén beállítja a háttér világitás kikapcsolási idejét
// JELENLEG MÁSODPERC ALAPON
void doPir(){
pirStatus = digitalRead(pirPin);
if(pirStatus){
backLightStatus = true;
backLightStop = millis()/1000 + backLightTime;
if(millis() > pirIconTime) {
pirIconTime = millis() + 350;
pirLedStatus = !pirLedStatus;
lcd.setCursor(10,1);
if(pirLedStatus) lcd.write((uint8_t)1);
else lcd.print(" ");
}
}
if(!pirStatus && pirLedStatus) {
lcd.setCursor(10,1);
lcd.print(" "); // icon törlése inaktivitáskor
pirLedStatus = !pirLedStatus;
}
if(backLightStatus && !pirStatus) {
if(millis()/1000 >= backLightStop) backLightStatus = false;
}
if(backLightStatus) lcd.backlight();
else lcd.noBacklight();
}
// expandZero()
// kibővití 0-val az elején a kapott integert
// visszatérési érték String
// expandZero(125); => "0125"
String expandZero( int nr){
if(nr < 10 ) return "0" + String( nr );
else return String(nr);
}
float minValue( float tomb[]){
float min = 100;
for(int nr=0; nr<12; nr++){
if(tomb[nr] < min){
min = tomb[nr];
}
}
return min;
}
float maxValue(float tomb[]){
float max = 0;
for(int nr=0; nr<12; nr++){
if(tomb[nr] > max){
max = tomb[nr];
}
}
return max;
}
// getTemp()
// vissza adja a szenzor által mért értéket
// DS18B20 senzor type
float getTemp(){
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
ds.reset_search();
return -1000; // nincs eszköz
}
if ( OneWire::crc8( addr, 7) != addr[7]) return -2000; // CRC hiba
if ( addr[0] != 0x10 && addr[0] != 0x28) return -3000; // eszköz nem válaszol
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two's compliment
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
A akvarium_V0_7.ino sketch letöltése
Két forrásból lehet letölteni, első helyi zip fájl, és Google Drive-rol akvarium_V0_7.ino névvel.
akvarium_V0_7.zip
akvarium_V0_7.ino
Működik, de lehetne jobb is
Az Arduino NANO megfelelő választás egy ilyen vezérléshez, kis fogyasztás elegendő programozható port, kis méret. Viszont ami nekem van az egy kínai replika, nem eredeti. Ettől függetlenül működik a vezérlés, az adatok kijelzése. 2015 első negyedéve óta használom ezt a hardver az akvárium világítás vezérlésére, még nem kellet benne semmit kicserélni. Pár alkalommal fagyott meg az egész rendszer, de mindig lekapcsolt fázisban. Így sohasem maradt felkapcsolva egész éjjel a LED panel, még nyaralások alkalmával sem.
Ami hátrány jelenleg, hogy a kis memória miatt nem megoldott a teljes külső paraméter állítás, és az adatok eltárolása, bár egy SD kártyás illesztéssel kibővítve még talán elférne a program a memóriában. És bármilyen változtatás a programban, újabb feltöltést igényel. Ennek gyorsítására én több NAN-ot használok, és egyre feltöltöm a programot áramtalanítás után csere és mehet újra az egész.
- Arduino multitaskingOlvasási idő: 3 perc Multitasking avagy párhuzamos vezérlés. Jobb kifejezés rá a párhuzamos feladat végrehajtás. Miért is van erre szükség? Nem minden esetben, de…
- Arduino Nano BMP180 tesztOlvasási idő: 4 perc BMP180 egy alap szenzor egy időjárás állomás elkészítéséhez. Megkapjuk tőle a légnyomást, hőmérsékletet, és még a tengerszint feletti magasságot is….
- Arduino pro IDE telepítése Linux-raOlvasási idő: 4 perc Arduino programozására eddig a sima Arduino IDE-t használtam. Viszont rátaláltam egy egy alfa kiadásra ami már 2019 októberében megjelent. Jelenleg…
- Arduino Nano fotodióda tesztOlvasási idő: 2 perc Fotodióda tesztelése Arduino Nano-val. Az általam használt dióda egy éjszakai fényt adó egységből való, így nem tudom a típusát, sem…
- Arduino DS1307-RTC dátum, idő beállításOlvasási idő: 3 perc Ezt az eszköz már elég régóta használom, de most volt vele csak gondom. És így megosztom, azt a pár egyszerű…
- Arduino – Akvárium világítás vezérlésOlvasási idő: 8 perc A program Ha minden kész akkor már csak egy valami van hátra maga a program. A NANO esetében 32Kb hely…
linuxStyler hozzászólásai