Växtviskaren EITF11DigitalaprojektVT15,I12 NathalieLiljebrunn,EbbaRiismark,AnnaNorelius LundsTekniskaHögskola Institutionenförelektro ochinformationsteknik Handledare:BertilLindvall,AndreasJohansson 2015 05 12
Sammanfattning I kursen digitala projekt har vi valt att konstruera en prototyp som kan tala med växter vi kallar den Växtviskaren. Prototypen ska genom en display kunna visa temperatur, fuktighet och solljus för en planta. Växtviskaren är alltså ett medel för en planta att kommunicera med människan. Genom ett enkelt knapptryck kan människan förstå vad växten har att säga om temperaturen, fuktigheten och solljuset. De komponenter som använts till prototypen är en processor (ATmega16), en alfanumerisk display (SHARP Dot Matrix), en av vardera ljus, fukt och temperatursentor, ett utvecklingsverktyg för att köra programkoden och överföra mjukvara till hårdvara (Atmel JTAG ICE) samt diverse småkomponenter. 1
Innehållsförteckning 1. Inledning 3 2. Kravspecifikation 3 3. Hårdvara 3 3.1. Processor 3 3.2. Fuktsensor 3 3.3. Temperatursensor 4 3.4. Solljussensor 4 3.5. Knapp 4 3.6. Display 4 3.7. LED lampa 4 3.8. Atmel ATG ICE 4 4. Mjukvara 4 5. Utförande 5 6. Resultat 5 7. Slutsats 6 8. Referenser 7 9. Bilagor 8 9.1 Bilaga 1 8 9.2 Bilaga 2 9 2
1.Inledning I kursen Digitala Projekt Digitala(EITF11)harvivaltattkonstrueraochbygga enprototypaven växtviskare. Växtviskaren ska genom en display kunna visatemperatur,fuktighetochsolljusför en planta. Växtviskaren är alltså ett medel för en planta att kommunicera med människan. Genom ett enkelt knapptryck kanmänniskan förstå vad växten har att säga om temperaturen, fuktighetenochsolljuset. Detta projekt harvarit både utmanandeoch tålamodskrävandemenextremtlärorikt.irapporten som följer har vi först beskrivit prototypens kravspecifikation för att läsarenska fåenöversiktlig förståelse av prototypen. Därefter följer en beskrivning avdenhårdvaravianväntochsedanen kort sammanfattning av mjukvaran. Slutligen följer en beskrivning av utförande, resultat och slutsats.ibilagorfinnsävenkällkodochkopplingsschema. 2.Kravspecifikation Prototypenskauppfyllaföljandekrav: Kunnamätatemperatureniplantjordenmedbestämttidsintervall Kunnamätafuktigheteniplantjordenmedbestämttidsintervall Kunnamätasolljusetplantanexponerasförmedbestämttidsintervall Haendisplaysomvisarmeddelandenom: Vilkentemperaturdetärirummet Hurfuktigplantjordenär Hurmycketsolljusplantanfår Haenknappsomskiftarvisningsbildpådisplayen:temperatur,fuktighet,solljus Haenlampasomlysernärplantanbehövervattnas 3.Hårdvara 3.1Processor: AVRATmega16, High performanceavr8 bitmicrocontroller Insignaler till processorn är analoga signaler från temperaturmätare, fuktighetsmätare och fototransistor. Den analoga outputen från sensorerna skickas till processorns A/D konverterare. Processorn får också digitala insignaler från knappen. Utsignaler skickastillled lampansamtlcd displayen. 3.2Fuktsensor : Grove,MoistureSensorv1.3 Fuktsensorn består av två metallpiggar som detkopplasenspänningöver,därsignalen Bild1: DenfärdigbyggdaVäxtviskaren 3
mäts i form av resistansen mellan piggarna. Det som mäts är alltså resistansen i plantjorden, som ökar när fuktigheten minskar. Fuktsensorn kopplas till ben 38 på processorn, som är en A/D konverterare som gör om sensorns analoga signaler till digitala. 3.3 Temperatursensor : LM335, Kelvin temperature sensor LM335 är en temperatursensor som ger utslag i Kelvin, vilket gör att eventuella temperaturer under 0 grader Celsius lättare kan redovisas. Sensorn ger utslag i volt, med 10 mv per Kelvin, det vill säga 0 Kelvin motsvarar 0 volt och 2,73 volt motsvarar 273 Kelvin (0 grader Celsius). Temperatursensorn kopplas till ben 39 på processorn, av samma anledning som fuktsensorn. För att visa temperaturen i Celsius på displayen och inte Kelvin görs detta om i källkoden. 3.4 Solljussensor : Fototransistor Transistorn är avsedd att känna av det totala ljuset och ändrar resistans med ljuset. Den spänning som skickas in till processorn beror av förhållandet mellan de två resistorerna vid sensorn. Här gäller att om resistansen från den ena resistorn ökar, vilket är vad vi mäter, så ökar spänningen och tvärtom för den andra resistorn. Detta innebär att spänningen ökar med ljusinsläppet. Ljussensorn är kopplad till ben 37 på processorn. 3.5 Knapp : Enkel, digital Den digitala knappen är av enkel typ och genererar ett avbrott vid nedtryckning. Minussidan är kopplad till en spänning på 0V och vidare till processorns ben 17, via en resistor på 10 kohm. Ben 17 är ett externt avbrott, INT1, och när knappen trycks ned genereras avbrottet i systemet om det känner av motståndet på 10 kohm. Under detta avbrott gås systemloopen ur och den som istället behandlar bytet mellan information från sensorerna kommer köras. 3.6 Display: SHARP Dot Matrix, LCD Units Alfanumerisk teckendisplay Displayen är av typen SHARP Dot Matrix och är en LCD Alfanumerisk teckendisplay med plats för 2x16 synliga tecken. Varje tecken byggs upp av en kombination av punkter enligt information från de 8 bitarna från processorn. 3.7 LED lampa Lampan programmeras att lysa när fuktighetsnivån i jorden blir för låg, för att visa när plantan behöver vattnas, och sedan släckas igen när fuktighetsnivån är önskvärd igen. Genom att vid för låg fuktighet skicka en hög signal till processorns ben 20 tänds lampan, och när signalen programmeras som låg släcks lampan. 3.8 Atmel JTAG ICE Det utvecklingsverktyg som användes för att köra programkoden och överföra mjukvara till hårdvara är Atmel JTAG ICE. Med hjälp av detta programmerades processorn i språket C och överfördes via USB från en dator. 4
4.Mjukvara Programmeringsspråket C är det som använts i programmeringen av mjukvaran. Via en JTAG kopplas detta till processorn. För komplett källkod, sebilaga2. Bild2: ProgrammeringiC 5.Utförande Vi började medatt skriva upp en kravspecifikation för vårprototyp.därefterstuderadevihurett blockschema skulle se ut. En stor del av det steget var att förstå uppbyggnaden av en processor och dess funktioner. Kopplingsschemat ritades slutligen i Power Logic 5.0 och kan sesibilaga1. När kopplingschemat var klart var det dags att börja med hårdvaran. Detta steg ivårtprojekt kansessomdetlättaste,myckettackvarevårtvälgenomarbetadekopplingschema. När vi ansåg att hårdvaran var klar började vi testa den med hjälp av JTAGoch mjukvara.det visade sig uppståganska många kortslutningar med ljussensorn. Dessutomhadevigjortnågra felkopplingarsomvifickgöraom. Parallellt med testningen av hårdvaranpåbörjadeviävenkodningavvårkällkod.dettaharvarit den mest tidskrävande och frustrerande delen av vårt arbete. Mycket tid gick åt att förståhur man skriver kod för en hårdvara och hur mjukvaran kommunicerar med hårdvaran. Bit för bit testadevivårkodpåhårdvaranförattupptäckafelochkorrektabitar.tillslutfunkadeallt. 6.Resultat Resultatet blev en mycket fin växtviskare. Prototypen har en display som plantan kan kommunicera genom. Displayen har tre visningsalternativ som visar tillstånd i temperatur, fuktighet respektive solljus. Temperaturen visas i Celsius. Plantans fuktighet visas genom tre olika nivåer där plantan antingen förmedlar Jag är törstig!, Snart törstig och Fulltankad, dessutom lyser en ledlampa när plantan är törstig. För attbeskriva ljusnivånkringplantanfinns det även här trenivåer som uttrycks i meningarna Fy vad mörkt, Wowlagomljust!! samt Oj vadljust.allavärdenmätsavengångisekundenochärdärföraktuellaförstunden. 7.Slutsats 5
Vi är mycket nöjda med vårt resultat och har under tidens gång lärt oss mycket. Frånatt inte vetat vad ett ben på en processor är, har vi nu utvecklat enfulltfungerandeprototypmedbåde hård och mjukvara. Prototypen fungerar utefter de krav vi ställde upp i början avprojektetoch vårväxtviskareärenproduktviallaskulleviljahaivårahem. Bild3: EnsjälvständigVäxtviskare 6
8. Referenser Manualer/datablad för hårdvara Processor: AVR ATmega16, High performance AVR 8 bit Microcontroller http://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/processors/atmega16.pdf Temperatursensor: LM335, Kelvin Temperature Sensor http://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/sensors/lm335.pdf Display: SHARP Dot Matrix, LCD Units Alfanumerisk teckendisplay http://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/display/lcd.pdf Manualer/datablad för mjukvara Kopplingsschema: PowerLogic User's Guide Version 3.0 http://www.eit.lth.se/fileadmin/eit/courses/edi021/pdf_files/powerlogic/powerlogic.pdf AVR JTAG ICE: User Guide http://www.eit.lth.se/fileadmin/eit/courses/edi021/pdf_files/avr/jtag_ice_man.pdf 7
9. Bilagor 9.1 Bilaga 1: Kopplingsschema Figur 1 : Kopplingsschema för prototypen 8
9.2 Bilaga 2: Källkod /* * Vaxtviskaren.c * * Created: 2015 04 01 09:33:53 * Author: digpi07 */ #include <avr/io.h> #include <avr/interrupt.h> //files must be included to use interrupts. #define F_CPU 1000000UL // 1MHz int fukt; int ljus; int temp; int aktuell; //global variabel som berättar att vi öppnat aktuell port int n; void convert_sensor(); void convert_temp(); void convert_ljus(); void convert_fukt(); char digit_to_char(); char sensorread(); void led_off(); void enablebuttoninterrupt(); char temptensout; char tempsinglesout; char tempnumtensout; char tempnumsinglesout; char realtempout; char binaryout; char voltout; char ljusval; char fuktval; char tempval; // PROCESSOR // 9
void setupprocessor(){ DDRA = 0b00000000; // set PORTA for input DDRB = 0b11111111; // set PORTB for output DDRC = 0b00000000; // set PORTC for input DDRD = 0b01000111; // Port D is a mix of an input and output enablebuttoninterrupt(); // DISPLAY // void write_cmd(short int txt){ PORTB = txt; //Sätter porten till det värde vi vill ha PORTD &= ~_BV(PD0); // = R/S ska vara 0 PORTD = _BV(PD2); // E = 1 PORTD &= ~_BV(PD2); // = E ska vara 0 PORTD = _BV(PD2); // E = 1 return; void write_data(short int val){ PORTB = val; PORTD = _BV(PD0); // = R/S ska vara 1 PORTD = _BV(PD2); // E = 1 PORTD &= ~_BV(PD2); // = E ska vara 0 PORTD = _BV(PD2); // E = 1 return; void init_display() { write_cmd(0b00111100); //Set function write_cmd(0b00001111); //Display ON write_cmd(0b00000110); //Set entry mode write_cmd(0b00000010); //Return home void clear_display(void){ write_cmd(0b00000010); void draw_tempmenu(){ 10
clear_display(); write_data('h'); write_data('e'); write_data('j'); write_data('!'); write_data('m'); write_data('i'); write_data('n'); write_data('t'); write_data('e'); write_data('m'); write_data('p'); write_data(':'); write_data(temptensout); write_data(tempsinglesout); void draw_fuktmenu(){ clear_display(); if (fuktval == 1){ write_data('j'); write_data('a'); write_data('g'); write_data('a'); write_data('r'); write_data('t'); write_data('o'); 11
write_data('r'); write_data('s'); write_data('t'); write_data('i'); write_data('g'); write_data('!'); else if (fuktval == 2){ write_data('s'); write_data('n'); write_data('a'); write_data('r'); write_data('t'); write_data('t'); write_data('o'); write_data('r'); write_data('s'); write_data('t'); write_data('i'); write_data('g'); write_data('.'); write_data('.'); write_data('.'); else if (fuktval == 3){ write_data('f'); write_data('u'); write_data('l'); write_data('l'); write_data('t'); write_data('a'); write_data('n'); write_data('k'); write_data('a'); write_data('d'); write_data(':'); write_data('d'); 12
else { write_data('e'); write_data('r'); write_data('r'); write_data('o'); write_data('r'); void draw_sunmenu(){ clear_display(); if (ljusval == 1){ write_data('f'); write_data('y'); write_data(','); write_data('v'); write_data('a'); write_data('d'); write_data('m'); write_data('o'); write_data('r'); write_data('k'); write_data('t'); write_data('!'); else if (ljusval == 2){ write_data('w'); write_data('o'); write_data('w'); 13
write_data('!'); write_data('l'); write_data('a'); write_data('g'); write_data('o'); write_data('m'); write_data('l'); write_data('j'); write_data('u'); write_data('s'); write_data('t'); write_data('!'); else if (ljusval == 3){ write_data('o'); write_data('j'); write_data('v'); write_data('a'); write_data('d'); write_data('l'); write_data('j'); write_data('u'); write_data('s'); write_data('t'); write_data('!'); write_data('!'); else { write_data('e'); write_data('r'); write_data('r'); write_data('o'); 14
write_data('r'); // TIMER // void timer1_init(){ TCCR1B = 0b00000011; TCNT1 = 49915; //bestäm initialt värde för timern: TIMSK = 0b00000100; //möjliggör timer interrupts. // KNAPP // ISR(INT1_vect){ if (aktuell == temp) { //temp är öppen, initialt tillstånd aktuell = fukt; draw_tempmenu(); else if (aktuell == fukt) { draw_fuktmenu(); aktuell = ljus; else if (aktuell == ljus) { aktuell = temp; //och så loopar vi om allt igen draw_sunmenu(); void enablebuttoninterrupt(){ GICR = 0b10000000; MCUCR = 0b00001100; 15
// LED // void start_led(){ PORTD = _BV(PD6); //Skickar en signal till lampan att den ska tändas void led_off(){ PORTD &= ~_BV(PD6); // ÖPPNA SENSORPORTARNA // ISR(TIMER1_OVF_vect) { TCNT1 = 49915; if (aktuell == temp){ ADMUX = 0b01100001; //läs in från temp benet: ADCSRA = 0b11001111; //enabla omvandlaren else if (aktuell == fukt){ ADMUX = 0b01100010; //läs in från fukt benet: ADCSRA = 0b11001111; else if (aktuell == ljus){ ADMUX = 0b01100011; //läs in från ADC3: ADCSRA = 0b11001111; // LÄS AV ÖPPNADE SENSORVÄRDEN // ISR(ADC_vect){ if (aktuell == temp) { 16
convert_temp(); aktuell = fukt; n++; if (n == 1){ draw_tempmenu(); if (n == 10){ n=2; else if (aktuell == fukt) { convert_fukt(); if (fuktval == 1){ start_led(); else if(fuktval==2 fuktval ==3){ led_off(); aktuell = ljus; else if (aktuell == ljus) { convert_ljus(); aktuell = temp; // CONVERTER // char sensorread(){ return ADCH; void convert_sensor(){ binaryout = ADCH; 17
void convert_temp(){ convert_sensor(); realtempout = (binaryout*5000)/255 273 39; //1millivolt=1grad tempnumtensout = realtempout/10; tempnumsinglesout = realtempout tempnumtensout*10; temptensout = digit_to_char(tempnumtensout); tempsinglesout = digit_to_char(tempnumsinglesout); void convert_ljus(){ convert_sensor(); voltout = (binaryout*5000)/255; if (voltout < 30){ ljusval = 1; else if (voltout >= 30 && voltout < 100){ ljusval = 2; else if (voltout >= 100){ ljusval = 3; else { ljusval = 0; //om detta uppnås är det något fel på ljussensorn void convert_fukt(){ convert_sensor(); voltout = (binaryout*5000)/255; if (voltout < 70){ fuktval = 1; else if (voltout >= 70 && voltout <200){ fuktval = 2; else if (voltout >= 200){ fuktval = 3; 18
else { fuktval = 0; // convert char // char digit_to_char(int digitconvert){ if( digitconvert == 0){ return '0'; if( digitconvert == 1){ return '1'; if( digitconvert == 2){ return '2'; if( digitconvert == 3){ return '3'; if( digitconvert == 4){ return '4'; if( digitconvert == 5){ return '5'; if( digitconvert == 6){ return '6'; if( digitconvert == 7){ return '7'; if( digitconvert == 8){ return '8'; else { return '9'; 19
// MAIN // int main(void){ setupprocessor(); //Sätter upp processorn init_display(); // Startar upp display clear_display(); ADCSRA = 0b10000000; temp = 1; fukt = 2; ljus = 3; aktuell = temp; //vi vill börja att läsa in från tempsensorn n=0; timer1_init(); sei(); while(1){ 20