// final project // smartBlinds #include #include // sprintf #include // delay_ms #include #define LCDwidth 16 //characters #define t1 30 #define t2 200 #define t3 50 #define t4 1000 #define maxkeys 12 #asm .equ __lcd_port=0x15 #endasm #include // LCD driver routines unsigned int time1, time2, time3, time4; //timeout counters char lcd_buffer[17]; // LCD display buffer char Ain; //raw A to D number char led, rot, prevdir, mode, maybe, keycount,init_time, alarm_trigger; char hall_state, key_state, motor_state; float light[3]; float light_avg, hall; unsigned char key, butnum, hour, minute, alarm_hour, alarm_minute; unsigned char keystring[4]; enum{NOPUSH, MAYBEPUSH, PUSH, MAYBENOTPUSH}; enum{FWD, BKW, STP}; enum{TIMESET, OPTIMIZE, PRIVACY, ALARM, UPDOWN, MODESET}; enum {RELEASE, DEBOUNCE, ENDCHAR, STILLPRESSED, DONE, DEBOUNCERELEASE}; //key pad scan table flash unsigned char keytbl[12]={0xed, 0xeb, 0xe7, 0xdd, 0xdb, 0xd7, 0xbd,0xbb, 0xb7, 0x7d, 0x7b, 0x77}; void task1(void); void task2(void); void task3(void); void task4(void); //This function rotates the blinds to positoin pos. It must be called repeatedly //until the desired position is obtained. Once you arrive at your destination, //the motor turns off. void gotopos (char pos) { lcd_gotoxy(4,3); sprintf(lcd_buffer,"w=%d",pos); lcd_puts(lcd_buffer); if (rot < pos) { if(prevdir == BKW) { rot = rot - 2; } PORTD = 0x02; prevdir = FWD; } else if (rot > pos) { if(prevdir == FWD) { rot = rot + 2; } PORTD = 0x01; prevdir = BKW; } else PORTD = 0x00; } //This funtion prints the time into the lcd_buffer void printtime(char hour, char minute) { if ((hour < 10) && (minute >= 10)) sprintf(lcd_buffer,"0%d:%d",hour,minute); else if ((hour >= 10) && (minute < 10)) sprintf(lcd_buffer,"%d:0%d",hour,minute); else if ((hour < 10) && (minute < 10)) sprintf(lcd_buffer,"0%d:0%d",hour,minute); else sprintf(lcd_buffer,"%d:%d",hour,minute); } //This function does the necessary operations to read a keypad keypress from the keypad. void keypressed(void) { //get upper nibble DDRB = 0x0f; PORTB = 0xf0; delay_us(5); key = PINB; //get lower nibble DDRB = 0xf0; PORTB = 0x0f; delay_us(5); key = key | PINB; //find matching keycode in keytbl if(key != 0xff) { for (butnum=0; butnum .1 && light_avg <.996) { if (light[0] >= light[1] && light[1] >= light[2]) { //light brighter on one side, move that way lcd_gotoxy(0,2); sprintf(lcd_buffer,"fwd"); lcd_puts(lcd_buffer); gotopos(6); } else if (light[0] <= light[1] && light[1] <= light[2]) { //light brighter on one side, move that way lcd_gotoxy(0,2); sprintf(lcd_buffer,"bkd"); lcd_puts(lcd_buffer); gotopos(2); } else { //just stay where you are! lcd_gotoxy(0,2); sprintf(lcd_buffer,"stp"); lcd_puts(lcd_buffer); gotopos(4); } } else { //very small or large value, don't move the motor lcd_gotoxy(0,2); sprintf(lcd_buffer,"nan"); lcd_puts(lcd_buffer); PORTD = 0x00; } } //set led for next time switch(led) { case 0: led = 1; break; case 1: led = 2; break; case 2: led = 0; break; } break; case PRIVACY: //close blinds gotopos(8); break; case ALARM: if ((alarm_trigger == 1) || (alarm_trigger = alarm_hour == hour && alarm_minute == minute)) { //if the alarm went off in the past or is going off now, print message and open blinds to half way alarm_trigger = 1; lcd_gotoxy(0,2); sprintf(lcd_buffer,"It's Time!!!!"); lcd_puts(lcd_buffer); gotopos(4); } else gotopos(8); break; case MODESET: //don't move the blinds in this case gotopos(rot); break; case UPDOWN: keypressed(); if(butnum==6) { //up gotopos(8); } else if(butnum == 9) { //down gotopos(0); } else gotopos(rot); //stop break; } } // hall effect task void task3 (void) { time3 = t3; //channel 3 of ADC ADMUX = 0b01100011; //delay necessary to ensure we're reading the right channel delay_us(500); //0 to 1 scale hall = ADCH/256.0; //simple debouncer for the Hall effect sensor switch(hall_state) { case NOPUSH: if (hall < 0.1) { hall_state = MAYBEPUSH; } break; case MAYBEPUSH: if (hall < 0.1) { hall_state = PUSH; if (PORTD == 0x02) { //if we're going forward, increment rot rot++; } } else { hall_state = NOPUSH; } break; case PUSH: if (hall >= 0.1) { hall_state = MAYBENOTPUSH; } break; case MAYBENOTPUSH: if (hall >= 0.1) { hall_state = NOPUSH; if (PORTD == 0x01) { //if we're going backwards, decrement rot rot--; } } else { hall_state = PUSH; } break; } } //This is the time task void task4 (void) { lcd_gotoxy(0,3); sprintf(lcd_buffer,"r=%d",rot); lcd_puts(lcd_buffer); time4 = t4; minute++; if (minute == 60) { minute = 0; hour++; if (hour == 24) hour = 0; } lcd_gotoxy(11,0); printtime(hour,minute); lcd_puts(lcd_buffer); } void main(void) { //init port a to input for ADC DDRA = 0x00; //input to ADC DDRD = 0xff; // output to motor (first 2 bits) // input from Hall Effect sensor (3rd bit) MCUCR = 0b10010000; //sleep enable, ADC noise reduction ADMUX = 0b01100000; //Avcc, ADLAR, channel 0 ADCSR = 0b11100110; // initialize the LCD for 16 char wide lcd_init(LCDwidth); //initialize the display lcd_clear(); //clear the display rot = 0; led = 0; prevdir = FWD; motor_state = STP; key_state = RELEASE; // initial state is optimize set_modeset(); init_time = 1; //set up timer 0 TIMSK=2; //turn on timer 0 cmp match ISR OCR0 = 250; //set the compare re to 250 time ticks //prescalar to 64 and turn on clear-on-match TCCR0=0b00001011; //init the task timers time1=t1; time2=t2; time3=t3; #asm sei #endasm // measure and display loop while (1) { if (time1==0) task1(); if (time2==0) task2(); if (time3==0) task3(); if (time4==0) task4(); } } //timer 0 compare ISR interrupt [TIM0_COMP] void timer0_compare(void) { //Decrement the three times if they are not already zero if (time1>0) --time1; if (time2>0) --time2; if (time3>0) --time3; if (time4>0) --time4; }