контроллер автоматического полива
- Войдите на сайт для отправки комментариев
Втр, 26/07/2016 - 22:32
Необходимо довести до ума контроллер автополива на Arduino Nano(ATmega328).
Есть скетч, фунционал которго меня устраивает, за исключением управления(нивигации в меню).
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <adi@clepcea.ro> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Adi Clepcea * ---------------------------------------------------------------------------- */ #include "Wire.h" #include "LiquidCrystal.h" #include "math.h" #include "EEPROM.h" #define DS1307_I2C_ADDRESS 0x68 #define PIN_STG 12 #define PIN_MENU 11 #define PIN_DR 10 #define PIN_COMMAND_A A1 //releu A #define PIN_COMMAND_B A2 //releu B #define PIN_COMMAND_C A3 //releu C #define PIN_COMMAND_D A0 //releu D #define PIN_COMMAND_E 7 //releu E #define PIN_COMMAND_F 9 //releu F #define PIN_COMMAND_G 13 //releu G #define DESCHIS LOW #define INCHIS HIGH #define NR_ALARME 6 #define MAX_MENU_POS NR_ALARME*4+3 //trebuie sa fie NR_ALARME*4+3 LiquidCrystal lcd(7, 6, 5, 4, 3, 2); byte menuPos=0; byte subMenuPos = 0; byte cursorPos = -1; char linia1[17]; char linia2[17]; char linia[17]; boolean dataDirthy = false; boolean oraDirthy = false; long lastMillis=0; boolean bAlarma = false; typedef struct alarm{ byte hour; byte minute; byte days; byte duration; byte relee; byte unitAlarma; }; typedef struct ds1307_time{ byte second; byte minute; byte hour; byte dayOfWeek; byte dayOfMonth; byte month; byte year; }; struct ds1307_time time; alarm* alarme = (alarm*) malloc(sizeof(alarm) * NR_ALARME); byte relee[]={PIN_COMMAND_G, PIN_COMMAND_F,PIN_COMMAND_E,PIN_COMMAND_D,PIN_COMMAND_C,PIN_COMMAND_B,PIN_COMMAND_A}; byte decToBcd(byte val){ return ((val/10*16)+(val%10)); } byte bcdToDec(byte val){ return ((val/16*10)+(val%16)); } void setDateDs1307(struct ds1307_time time) { Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.write(0); Wire.write(decToBcd(time.second)); Wire.write(decToBcd(time.minute)); Wire.write(decToBcd(time.hour)); Wire.write(decToBcd(time.dayOfWeek)); Wire.write(decToBcd(time.dayOfMonth)); Wire.write(decToBcd(time.month)); Wire.write(decToBcd(time.year)); Wire.endTransmission(); } void getDateDs1307(struct ds1307_time *time) { Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS,7); (*time).second = bcdToDec(Wire.read() & 0x7f); (*time).minute = bcdToDec(Wire.read()); (*time).hour = bcdToDec(Wire.read() & 0x3f); (*time).dayOfWeek = bcdToDec(Wire.read()); (*time).dayOfMonth = bcdToDec(Wire.read()); (*time).month = bcdToDec(Wire.read()); (*time).year = bcdToDec(Wire.read()); } void showMenu(){ char *zile[7]; zile[0]="L\0"; zile[1]="M\0"; zile[2]="M\0"; zile[3]="J\0"; zile[4]="V\0"; zile[5]="S\0"; zile[6]="D\0"; if(menuPos==1){ strcpy(linia1,"Data\0"); strcpy(linia2,getDate(time)); strcat(linia2," "); strcat(linia2,getZiuaSaptamaniiShort(time.dayOfWeek)); }else if(menuPos==2){ strcpy(linia1,"Ora\0"); strcpy(linia2,getTime(time)); }else if((menuPos+1)%4==0){ //incepand cu 3, din 4 in 4 avem ora alarmei strcpy(linia1,"Alarma "); linia1[7] = 48+(byte)((menuPos+1)/4)/10; linia1[8] = 48+(byte)(((menuPos+1)/4)-((menuPos+1)/4)/10*10); linia1[9]='\0'; strcat(linia1," ora\0"); strcpy(linia2,getFmt2Char((alarme[(menuPos+1)/4-1]).hour)); strcat(linia2,":"); strcat(linia2,getFmt2Char((alarme[(menuPos+1)/4-1]).minute)); strcat(linia2," "); }else if((menuPos)%4==0){ //incepand cu 4, din 4 in 4 avem zielele alarmei strcpy(linia1,"Alarma "); linia1[7] = 48+(byte)((menuPos)/4)/10; linia1[8] = 48+(byte)((menuPos)/4-(menuPos)/4/10*10); linia1[9]='\0'; strcat(linia1," zile\0"); strcpy(linia2,"L"); for(int i=6;i>=0;i--){ if((alarme[(menuPos)/4-1]).days & (byte)ceil(pow(2,i))){ strcat(linia2,"X"); }else{ strcat(linia2," "); } if(i>0)strcat(linia2,zile[7-i]); } }else if((menuPos-1)%4==0){ //incepand cu 5, din 4 in 4 avem durata alarmei strcpy(linia1,"Alarma "); linia1[7] = 48+(byte)((menuPos-1)/4)/10; linia1[8] = 48+(byte)((menuPos-1)/4-(menuPos-1)/4/10*10); linia1[9]='\0'; strcat(linia1," durata\0"); itoa(alarme[(menuPos-1)/4-1].duration,linia2,10); if(alarme[(menuPos-1)/4-1].unitAlarma){ strcat(linia2," min"); }else{ strcat(linia2," sec"); } }else if((menuPos-2)%4==0){ //incepand cu 6 din 4 in 4 avem releele activate de alarma strcpy(linia1,"Relee alarma "); linia1[13]= 48+(byte)((menuPos-2)/4)/10; linia1[14]= 48+(byte)((menuPos-2)/4-(menuPos-2)/4/10*10); linia1[15]='\0'; strcpy(linia2,""); for(int i=6;i>=0;i--){ char chBuff[2]; chBuff[0]=6-i+65; chBuff[1]='\0'; strcat(linia2,chBuff); if((alarme[(menuPos-2)/4-1]).relee & (byte)ceil(pow(2,i))){ strcat(linia2,"X"); }else{ strcat(linia2," "); } //if(i>0)strcat(linia2,zile[7-i]); } } } //punem cursorul in functie de locatia noastra in sumbeniu void showSubMenu(){ if(menuPos==1 || menuPos==2){ //data sau ora switch(subMenuPos){ case 1://zile cursorPos = 1; break; case 2://luni cursorPos = 4; break; case 3://ani cursorPos = 7; break; case 4://ziua saptamanii if(menuPos==1){//doar in cazul datei avem si ziua saptamanii cursorPos=12; break; } default: subMenuPos = 0; cursorPos = -1; break; } }else if((menuPos+1)%4==0){ //ora alarmelor switch(subMenuPos){ case 1: //ora cursorPos = 1; break; case 2: //minutul cursorPos = 4; break; default: subMenuPos = 0; cursorPos = -1; break; } }else if((menuPos)%4==0){ //zilele alarmelor if(subMenuPos>0 && subMenuPos<8){ cursorPos = subMenuPos*2-1; }else{ subMenuPos = 0; cursorPos = -1; } }else if((menuPos-1)%4==0){ //durata alarmelor if(subMenuPos==1){ cursorPos = 0; }else if(subMenuPos==2){ cursorPos=4; }else{ subMenuPos=0; cursorPos = -1; } }else if((menuPos-2)%4==0){ //releele alarmelor if(subMenuPos>0 && subMenuPos<8){ cursorPos = subMenuPos*2-1; }else{ subMenuPos = 0; cursorPos = -1; } } } void menu(){ if((millis()-lastMillis)>150){ if(digitalRead(PIN_MENU)==LOW && menuPos==0){ menuPos=(menuPos+1)%(MAX_MENU_POS); showMenu(); }else if(digitalRead(PIN_MENU)==LOW){ subMenuPos++; showSubMenu(); } } lastMillis=millis(); } void readValues(){ //citim valorile initiale din eeprom. //daca nu exista nimic scris in eeprom, consideram si orele si durata ca fiind 0 si scriem in EEPROM for(int i=0;i<NR_ALARME;i++){ byte b = EEPROM.read(i*5+1); if(b==0xFF){ b = 0; EEPROM.write(i*5+1,b); } (alarme[i]).hour = b & 31; //pozitiile 1, 6, 11 etc. (alarme[i]).unitAlarma = b >> 6; b = EEPROM.read(i*5+2); if(b==0xFF){ b = 0; EEPROM.write(i*5+2,b); } (alarme[i]).minute = b; //pozitiile 2, 7, 12 etc. b = EEPROM.read(i*5+3); if(b==0xFF){ b = 0; EEPROM.write(i*5+3,b); } (alarme[i]).days = b; //pozitiile 3, 8, 13 etc. b = EEPROM.read(i*5+4); if(b==0xFF){ b = 0; EEPROM.write(i*5+4,b); } (alarme[i]).duration = b; //pozitiile 4, 9, 14 etc. b = EEPROM.read(i*5+5); if(b==0xFF){ b = 0; EEPROM.write(i*5+5,b); } (alarme[i]).relee = b; //pozitiile 5, 10, 15 etc. } } void setup(){ pinMode(PIN_MENU,INPUT); //btn stg pinMode(PIN_DR,INPUT); //meniu pinMode(PIN_STG,INPUT); //btnDr for(int i=0;i<7;i++){ pinMode(relee[i],OUTPUT); digitalWrite(relee[i],DESCHIS); } digitalWrite(PIN_MENU,HIGH); digitalWrite(PIN_STG,HIGH); digitalWrite(PIN_DR,HIGH); attachInterrupt(0,menu,CHANGE); //alarmele readValues(); //initializam DS_1307 Wire.begin(); lcd.begin(16, 2); Serial.begin(9600); struct ds1307_time time; time.second = 15; time.minute = 55; time.hour = 11; time.dayOfWeek = 5; time.dayOfMonth = 14; time.month = 3; time.year = 14; //setDateDs1307(time); } char* getFmt2Char(byte val){ char *buf = "00\0"; buf[0] = 48+val/10; buf[1] = 48+val%10; return buf; } char* getDate(struct ds1307_time time){ char *buf=" \0"; buf[0]=48+time.dayOfMonth/10; buf[1]=48+time.dayOfMonth%10; buf[2]='.'; buf[3]=48+time.month/10; buf[4]=48+time.month%10; buf[5]='.'; buf[6]=48+time.year/10; buf[7]=48+time.year%10; return buf; } char* getTime(struct ds1307_time time){ char *buf=" \0"; buf[0]=48+time.hour/10; buf[1]=48+time.hour%10; buf[2]=':'; buf[3]=48+time.minute/10; buf[4]=48+time.minute%10; buf[5]=':'; buf[6]=48+time.second/10; buf[7]=48+time.second%10; return buf; } char* getZiuaSaptamaniiShort(byte val){ switch(val){ case 1: return "Lun\0"; //Mon break; case 2: return "Mar\0"; //Tue break; case 3: return "Mie\0"; //Wen break; case 4: return "Joi\0"; //Thu break; case 5: return "Vin\0"; //Fri break; case 6: return "Sam\0"; //Sat break; case 7: return "Dum\0"; //Sun break; default: return "?\0"; break; } } char* getZiuaSaptamanii(byte val){ switch(val){ case 1: return "Luni\0"; //replace with Monday if you want break; case 2: return "Marti\0"; //replace with Tuesday if you want break; case 3: return "Miercuri\0"; //replace with Wednesday if you want break; case 4: return "Joi\0"; //replace with Thursday if you want break; case 5: return "Vineri\0"; //replace with Friday if you want break; case 6: return "Sambata\0"; //replace with Saturday if you want break; case 7: return "Duminica\0"; //replace with Sunday if you want break; default: return "?\0"; break; } } void minusData(){ if(subMenuPos==1 && time.dayOfMonth>1){ //zilele time.dayOfMonth--; }else if(subMenuPos==2 && time.month>1){ time.month--; }else if(subMenuPos==3 && time.year>1){ time.year--; }else if(subMenuPos==4 && time.dayOfWeek>1){ time.dayOfWeek--; } dataDirthy=true; showMenu(); } void plusData(){ if(subMenuPos==1){ //zilele aici utilizatorul trebuie sa aiba grija sa nu puna mai multe zile dact are luna, eu am limitat doar la 31 time.dayOfMonth=(time.dayOfMonth+1)%32; if(time.dayOfMonth==0){ time.dayOfMonth=1; } }else if(subMenuPos==2){ time.month=(time.month+1)%13; if(time.month==0){ time.month=1; } }else if(subMenuPos==3){ time.year=(time.year+1)%99; }else if(subMenuPos==4){ time.dayOfWeek=(time.dayOfWeek+1)%8; if(time.dayOfWeek==0){ time.dayOfWeek=1; } } dataDirthy=true; showMenu(); } void minusOra(){ if(subMenuPos==1 && time.hour>0){ //zilele time.hour=time.hour-1; }else if(subMenuPos==2 && time.minute>0){ time.minute=time.minute-1; }else if(subMenuPos==3 && time.second>1){ time.second=time.second-1; } oraDirthy = true; showMenu(); } void plusOra(){ if(subMenuPos==1){ //zilele time.hour=(time.hour+1)%24; }else if(subMenuPos==2){ time.minute=(time.minute+1)%60; }else if(subMenuPos==3){ time.second=(time.second+1)%60; } oraDirthy = true; showMenu(); } void minusAlarma(int pos){ alarme[pos-1]; if(subMenuPos==1 && alarme[pos-1].hour>0){ //zilele alarme[pos-1].hour--; }else if(subMenuPos==2 && alarme[pos-1].minute>0){ alarme[pos-1].minute--; } showMenu(); } void plusAlarma(byte pos){ if(subMenuPos==1){ //zilele alarme[pos-1].hour=(alarme[pos-1].hour+1)%24; }else if(subMenuPos==2){ alarme[pos-1].minute=(alarme[pos-1].minute+1)%60; } showMenu(); } void minusZileAlarma(byte pos){ Serial.println(alarme[pos-1].days); alarme[pos-1].days =alarme[pos-1].days ^ (byte)ceil(pow(2,(7-subMenuPos))); Serial.println(alarme[pos-1].days); showMenu(); } void plusReleeAlarma(byte pos){ minusReleeAlarma(pos); } void minusReleeAlarma(byte pos){ Serial.println(alarme[pos-1].relee); alarme[pos-1].relee = alarme[pos-1].relee ^ (byte)ceil(pow(2,(7-subMenuPos))); Serial.println(alarme[pos-1].relee); showMenu(); } void plusZileAlarma(byte pos){ minusZileAlarma(pos); } void minusUnitAlarma(byte pos){ plusUnitAlarma(pos); } void plusUnitAlarma(byte pos){ if(subMenuPos==2){ alarme[pos-1].unitAlarma=(alarme[pos-1].unitAlarma+1)%2; } } void minusDurataAlarma(byte pos){ if(alarme[pos-1].duration>0 && subMenuPos==1){ alarme[pos-1].duration--; }else if(subMenuPos==2){ minusUnitAlarma(pos); } showMenu(); } void plusDurataAlarma(byte pos){ if(subMenuPos==1){ alarme[pos-1].duration=(alarme[pos-1].duration+1)%240; }else if(subMenuPos==2){ plusUnitAlarma(pos); } showMenu(); } void saveValues(){ for(int i=0;i<NR_ALARME;i++){ EEPROM.write(i*5+1,(alarme[i]).hour | (alarme[i].unitAlarma << 6)); EEPROM.write(i*5+2,(alarme[i]).minute); EEPROM.write(i*5+3,(alarme[i]).days); EEPROM.write(i*5+4,(alarme[i]).duration); EEPROM.write(i*5+5,(alarme[i]).relee); } } void applyNewDateHour(){ if(dataDirthy || oraDirthy){ if(oraDirthy){ Serial.println("Cu ora"); setDateDs1307(time); }else{ //daca ora nu s-a modificat o lasam si noi cum este Serial.println("Fara ora"); struct ds1307_time tmp; getDateDs1307(&tmp); tmp.dayOfMonth = time.dayOfMonth; tmp.dayOfWeek = time.dayOfWeek; tmp.month = time.month; tmp.year = time.year; setDateDs1307(tmp); } dataDirthy=false; oraDirthy = false; } saveValues(); } int valAlarmaMin(byte index){ return (alarme[index]).hour*3600+(alarme[index]).minute*60; } int valAlarmaMax(byte index){ byte multipl = (alarme[index]).unitAlarma?60:1; return (alarme[index]).hour*3600+(alarme[index]).minute*60+multipl*(alarme[index]).duration; } void checkAlarms(){ int valComp = time.hour*3600+time.minute*60+time.second; bAlarma=false; strcpy(linia,getTime(time)); strcat(linia,";A"); char cAl[4]; int timeToFinish=0,vAlMax=0; boolean tipTimp=0; byte statusRelee[7]; for(int i=0;i<7;i++){ statusRelee[i]=0; } for(int i=0;i<NR_ALARME;i++){ struct alarm alarma = alarme[i]; vAlMax=valAlarmaMax(i); if(valComp>=valAlarmaMin(i) && valComp<=vAlMax){ //comparam valorile minime si maxime ale fiecarei alarme cu timpul actual if((byte)ceil(pow(2,7-time.dayOfWeek)) & (alarma).days){ bAlarma=true; if((timeToFinish==0 && vAlMax-valComp>timeToFinish) || (vAlMax-valComp<timeToFinish)){//setam durata pana la sf primei alarme tipTimp = alarma.unitAlarma; if(tipTimp && vAlMax-valComp>=60){ timeToFinish=(vAlMax-valComp)/60; }else{ timeToFinish=vAlMax-valComp; tipTimp=0; } } for(int j=6;j>=0;j--){ if((alarma).relee & (byte)(ceil(pow(2,j)))){ statusRelee[j]=1; } } itoa((i+1),cAl,10); if(strlen(linia)<11){ strcat(linia,cAl); } } } for(int i=0;i<7;i++){ if(statusRelee[i]){ digitalWrite(relee[i],INCHIS); }else{ digitalWrite(relee[i],DESCHIS); } } } if(bAlarma){ itoa(timeToFinish,cAl,10); strcat(linia," "); strcat(linia,cAl); if(tipTimp){ strcat(linia,"m"); }else{ strcat(linia,"s"); } } } void loop(){ //daca avem meniul apasat aratam ceea ce ne trebuie si nu mai aratam data si ora curente if(menuPos>0){ lcd.clear(); lcd.setCursor(0,0); lcd.print(linia1); lcd.setCursor(0,1); lcd.print(linia2); if(digitalRead(PIN_STG)==LOW && menuPos){ //avem apasat minus delay(100); if(subMenuPos){ if(menuPos==1){ //data minusData(); }else if(menuPos==2){ minusOra(); }else if((menuPos+1)%4==0){ minusAlarma((menuPos+1)/4); }else if((menuPos)%4==0){ //zile alarma minusZileAlarma((menuPos)/4); }else if((menuPos-1)%4==0){ //durata alarma minusDurataAlarma((menuPos-1)/4); }else if((menuPos-2)%4==0){ //relee alarma minusReleeAlarma((menuPos-2)/4); } } else{ if(menuPos==1){ applyNewDateHour(); } menuPos--; showMenu(); } }else if(digitalRead(PIN_DR)==LOW && menuPos){ //avem apasat plus delay(200); if(subMenuPos){ if(menuPos==1){ //data plusData(); }else if(menuPos==2){ plusOra(); }else if((menuPos+1)%4==0){ //ora alarma plusAlarma((menuPos+1)/4); }else if((menuPos)%4==0){ //zile alarma plusZileAlarma((menuPos)/4); }else if((menuPos-1)%4==0){ //durata alarma plusDurataAlarma((menuPos-1)/4); }else if((menuPos-2)%4==0){ //durata alarma plusReleeAlarma((menuPos-2)/4); } } else if(menuPos<MAX_MENU_POS-1){ ++menuPos; Serial.print("Menu pos: "); Serial.print(menuPos); showMenu(); }else{ applyNewDateHour(); menuPos=0; } }else if(subMenuPos>0 && cursorPos>-1){ // Serial.println(cursorPos); lcd.cursor(); lcd.setCursor(cursorPos,1); }else{ lcd.noCursor(); } delay(100); return; } lcd.clear(); char buf[3]; getDateDs1307(&time); Serial.print(getTime(time)); Serial.print(" "); Serial.print(getDate(time)); Serial.print(":"); Serial.print("Ziua saptamanii: "); Serial.println(time.dayOfWeek, DEC); lcd.setCursor(0, 0); lcd.print(getZiuaSaptamanii(time.dayOfWeek)); lcd.setCursor(8,0); lcd.print(getDate(time)); if(bAlarma){ lcd.setCursor(0,1); lcd.print(linia); }else{ lcd.setCursor(4,1); lcd.print(getTime(time)); lcd.setCursor(12,1); lcd.print(" "); lcd.noCursor(); } checkAlarms(); delay(1000); }
Нужно сделать удобную навигацию пятью конпками(вверх, вниз, влево, вправо, меню) и еще изменить колличество релле, которыми контроллер управляет. сейчас их 7, а нужно сделать 8.
Комментарии в коде на румынском языке)
Подробности - на почту.
Ex3mGamer@mail.ru
Бюджет какой?
Сроки?
Сроки - быстро) до конца месяца нужно сделать.
Бюджет - "расскажите, почему это стоит дорого, и я вам заплачу" - пишите ваши расценки на почту.
А можно подробнее про этот контроллер? Как он выгдядит аппаратно? Какой функционал?
Просто ищу для себя :)
https://www.drive2.ru/b/1394538/