Spencer Norwick
Published © MIT

Seat Sentry

Frustrated with the toilet seat being left up or dirty by the person before you? Moms/wives/girlfriends, this automated solution is for you!

IntermediateShowcase (no instructions)10 hours229
Seat Sentry

Things used in this project

Hardware components

DC motor (generic)
×2
A4973 H-Bridge Motor Driver
×2
IR Range Sensor
Digilent IR Range Sensor
×1
MSP-EXP430G2 MSP430 LaunchPad
Texas Instruments MSP-EXP430G2 MSP430 LaunchPad
×1

Story

Read more

Schematics

SeatSentry Schematic

This is a general schematic. Be sure to reference data sheets and documentation for finer points.

Code

SeatSentry(dot)C

C/C++
This code should be flashed to the MSP430G2553 (I used Code Composer)
// Spencer Norwick
// Seat Sentry
// 04-23-19
// Using:
/******************************************************************************
MSP430G2553 Project Creator

SE 423  - Dan Block
        Spring(2019)

        Written(by) : Steve(Keres)
College of Engineering Control Systems Lab
University of Illinois at Urbana-Champaign
*******************************************************************************/

#include "msp430g2553.h"
#include "UART.h"

void print_every(int rate);

char newprint = 0;
long NumOn = 0;
long NumOff = 0;
int statevar = 1;
int timecheck = 0;

int IRraw = 0;
int doorthresh = 500; // doorframe distance
//int count = 0;
int time_raise = 5000; // # milliseconds to raise
int time_lower = 5000; // # seconds to lower
int motorL = 400;
//int motorR = 400;


void main(void) {

	WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

	if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF) while(1);

	DCOCTL = CALDCO_16MHZ;    // Set uC to run at approximately 16 Mhz
	BCSCTL1 = CALBC1_16MHZ; 

    // Initializing ADC10
    ADC10CTL0 = ADC10SHT_1 + ADC10ON + ADC10IE; // Sample-and-hold time 8 x ADC10CLKS, ADC10ON, interrupt enabled,
    ADC10CTL1 = INCH_3;                        // input A0
    ADC10AE0 |= 0x8;                         // Analog input enabled on A3

//    // Initialize Port 1
//    P1SEL &= ~BIT3;                  // P1.0 and P1.4 GPIO
////    P1SEL2 &= ~(BIT0 + BIT4);                  // P1.0 and P1.4 GPIO
//    P1REN &= ~BIT3;                  // P1.0 and P1.4 Resistor disabled
//    P1DIR |= ~BIT3;                     // Set P1.6 to output direction
//    P1OUT &= ~BIT3;                     // Initially set P1.0 and P1.4 to 0 (LOW)

    // Initialize Port 2 for DC motors
	P2DIR |= 0x04; // P2.2,4 are OUTPUTs
	P2SEL |= 0x04; // P2.2,4 are TA1.1,2
    P2SEL2 &= ~0x04; // Pin cleared for TA1.#
    P2REN = 0x0; // No resistors enabled for Port 2
    P2OUT &= ~0x04; // Set low initially

	// Timer A Config
	TACCTL0 = CCIE;       		// Enable Periodic interrupt
	TACCR0 = 16000;                // period = 1ms   
	TACTL = TASSEL_2 + MC_1; // source SMCLK, up mode

	// Register init for A1.#
	TA1CCR0 = 800; // 20 Hz
	TA1CCTL1 = OUTMOD_7; // set/reset
	TA1CCTL2 = OUTMOD_7;
	TA1CTL = TASSEL_2 + MC_1; // source SMCLK, up mode


	Init_UART(115200,1);	// Initialize UART for 115200 baud serial communication

	_BIS_SR(GIE); 		// Enable global interrupt


    while(1) {  // Low priority Slow computation items go inside this while loop.  Very few (if anyt) items in the HWs will go inside this while loop

// for use if you want to use a method of receiving a string of chars over the UART see USCI0RX_ISR below
//      if(newmsg) {
//          newmsg = 0;
//      }

        // The newprint variable is set to 1 inside the function "print_every(rate)" at the given rate
        if ( (newprint == 1) && (senddone == 1) )  { // senddone is set to 1 after UART transmission is complete

            // only one UART_printf can be called every 15ms
            UART_printf("Dist: %d \n\r", IRraw);

            newprint = 0;
        }

    }
}


// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
//    timecheck++; // Keep track of time for main while loop.
    print_every(500);  // units determined by the rate Timer_A ISR is called, print every "rate" calls to this function

    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

}



// ADC 10 ISR - Called when a sequence of conversions (A7-A0) have completed
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void) {

    IRraw = ADC10MEM; // Reading IR distance value

        switch (statevar) {
            case 1:  // Detect bathroom entrance
                if (IRraw >= doorthresh){
                    statevar = 2;
                }
                else{

                    motorL = 400; // wait
                    statevar = 1; // set to detection case 1 (redundant)
                }
                break;
            case 2: // raise lid

                if (timecheck <= time_raise){ // raise seat for # seconds
                    timecheck++;
                    motorL = 200; // raise speed
                }
                else{
                    timecheck = 0; // reset timer
                    motorL = 400; // stop raise
                    statevar = 3; // go to bathroom exit detection state
                }
                break;
            case 3: // bathroom exit detection case
                if (IRraw > doorthresh){
                    statevar = 4; // go to seat lower case
                }
                else{
                    timecheck = 0; // reset timer
                    motorL = 400; // wait
                    statevar = 3; // set to detection case 3 (redundant)
                }
                break;
            case 4: // lower lid

                if (timecheck <= time_raise){ // lower seat for # seconds
                    timecheck++;
                    motorL = 600; // lower speed
                }
                else{
                    timecheck = 0; // reset timer
                    motorL = 400; // stop raise
                    statevar = 1; // go to bathroom entrance detection state
                }
                break;
        }

        TA1CCR1 = motorL; // Left motor control

}



// USCI Transmit ISR - Called when TXBUF is empty (ready to accept another character)
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void) {

	if(IFG2&UCA0TXIFG) {		// USCI_A0 requested TX interrupt
		if(printf_flag) {
			if (currentindex == txcount) {
				senddone = 1;
				printf_flag = 0;
				IFG2 &= ~UCA0TXIFG;
			} else {
				UCA0TXBUF = printbuff[currentindex];
				currentindex++;
			}
		} else if(UART_flag) {
			if(!donesending) {
				UCA0TXBUF = txbuff[txindex];
				if(txbuff[txindex] == 255) {
					donesending = 1;
					txindex = 0;
				}
				else txindex++;
			}
		} else {  // interrupt after sendchar call so just set senddone flag since only one char is sent
			senddone = 1;
		}

		IFG2 &= ~UCA0TXIFG;
	}

	if(IFG2&UCB0TXIFG) {	// USCI_B0 requested TX interrupt (UCB0TXBUF is empty)

		IFG2 &= ~UCB0TXIFG;   // clear IFG
	}
}


// USCI Receive ISR - Called when shift register has been transferred to RXBUF
// Indicates completion of TX/RX operation
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void) {

	if(IFG2&UCB0RXIFG) {  // USCI_B0 requested RX interrupt (UCB0RXBUF is full)

		IFG2 &= ~UCB0RXIFG;   // clear IFG
	}

	if(IFG2&UCA0RXIFG) {  // USCI_A0 requested RX interrupt (UCA0RXBUF is full)

//    Uncomment this block of code if you would like to use this COM protocol that uses 253 as STARTCHAR and 255 as STOPCHAR
/*		if(!started) {	// Haven't started a message yet
			if(UCA0RXBUF == 253) {
				started = 1;
				newmsg = 0;
			}
		}
		else {	// In process of receiving a message		
			if((UCA0RXBUF != 255) && (msgindex < (MAX_NUM_FLOATS*5))) {
				rxbuff[msgindex] = UCA0RXBUF;

				msgindex++;
			} else {	// Stop char received or too much data received
				if(UCA0RXBUF == 255) {	// Message completed
					newmsg = 1;
					rxbuff[msgindex] = 255;	// "Null"-terminate the array
				}
				started = 0;
				msgindex = 0;
			}
		}
*/

		IFG2 &= ~UCA0RXIFG;
	}

}

// This function takes care of all the timing for printing to UART
// Rate determined by how often the function is called in Timer ISR
int print_timecheck = 0;
void print_every(int rate) {
    if (rate < 15) {
        rate = 15;
    }
    if (rate > 10000) {
        rate = 10000;
    }
    print_timecheck++;
    if (print_timecheck == rate) {
        print_timecheck = 0;
        newprint = 1;
    }

}

Credits

Spencer Norwick

Spencer Norwick

1 project • 1 follower
Thanks to Dan Block.

Comments

Add projectSign up / Login