Reid Farchmin
Published

Automated Toilet Paper Dispenser

This project automatically unrolls toilet paper to allow the user a much more relaxing and care free time on the throne.

IntermediateShowcase (no instructions)1,043
Automated Toilet Paper Dispenser

Things used in this project

Story

Read more

Custom parts and enclosures

TP Video

Code

TP dispenser Code

C/C++
/******************************************************************************
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;

//Reid's Variables
int ADC_ranged_value = 0; //This variable takes the range that the light sensor can sense and expands it to utilize the full 1023 range of values
int ADC_A0_A3_value = 0; //The variable used to store the ADC A0 or A3 value
int milivolts = 0; //The variable used to store the milivolt value of the ADC
int timecnt = 0; //Used to keep track of time passed

void main(void) {

    WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

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

    //I slowed down the counter so that we could have the carrier frequency be 50Hz = 20ms
    //Even at 8MHz the carrier frequency would have been 160,000 which is still greater than the
    //65,535 max of a long int
    DCOCTL = CALDCO_16MHZ;//CALDCO_16MHZ;    // Set uC to run at approximately 1 Mhz
    BCSCTL1 = CALBC1_16MHZ;//CALBC1_16MHZ;

    // Initialize Port 1
    P1SEL |= 0x01;  //Initialized P1.0 to be TA0 (1)
    P1SEL2 = 0x0; //
    P1REN = 0x0;  //
    P1DIR |= 0x01; //Initialized P1.0 to be TA0 (1)
    P1OUT = 0x0;  //

    //Initializes P2.1 to be TA1 and P2.4 to be TA2
    P2SEL |= 0x04;   //For P2.2 to be TA1 and their SEL bits need to be set to 1
    P2SEL2 = 0x0; //
    P2REN = 0x0; //
    P2DIR |= 0x04; //For P2.1 to be TA1 and their DIR bits need to be set to 1
    P2OUT = 0x0; // Initially set all P2 pins to 0

    //Main initialization of the ADC10
    ADC10CTL0 = SREF_0 + ADC10SHT_1 + ADC10ON + ADC10IE;
    //Initialization of the ADC10 A3 channel
    ADC10CTL1 = INCH_0 + SHS_0 + ADC10DIV_0 + ADC10SSEL_0 + CONSEQ_0; //samples and sets up channel 0
    ADC10AE0 = 0x01;//allows channel A0 to be sampled

    // Timer A0 Config
    TA0CCTL0 = CCIE;            // Enable Periodic interrupt
    TA0CCR0 = 16000;                // period = 1ms/cycle @ 1MHz --> (1/1,000,000)s/cycle * x = 0.001s/cycle --> x = 1000
    TA0CTL = TASSEL_2 + MC_1; // source SMCLK, up mode

    //Timer A1 Config
    TA1CCR0 = 800;                             // period --> 1MHz(rate) = 1/1,000,000 s/cycle --> 50Hz = 50 cycle/s = 0.02 s --> 20 ms/cycle --> (1/1,000,000)x = 0.02 --> x = 20,000
    TA1CCTL1 = OUTMOD_7;                         // PWM output mode: 7 - PWM reset/set
    TA1CCR1 = 400;    // TA1CCR1 PWM duty cycle, initially set to 0 torque which is 400
    TA1CTL = TASSEL_2 + MC_1;                  // SMCLK, up mode

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

    _BIS_SR(GIE);       // Enable global interrupt
    //__bis_SR_register(GIE);       // Enable global interrupts

    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("St%d On %ld Off %ld\n\r",statevar,NumOn,NumOff);

            newprint = 0;
        }

    }
}


// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    //ADC10 Enable Conversion & Starts Conversion
    ADC10CTL0 |= ENC + ADC10SC;
}


// ADC 10 ISR - Called when a sequence of conversions (A7-A0) have completed
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    ADC_A0_A3_value = ADC10MEM;     //Takes the ADC10MEM value and puts it in the variable ADC_A0_A3_value
    milivolts = (ADC_A0_A3_value*3300L)/1023;       //converts the ADC10 value (0-1023) to milivolts

    //if the IR sensor reads greater than 100 then it stops the motor.The ADC values normally are around 70 or so.
    if(ADC_A0_A3_value > 400)
    {
        TA1CCR1 = 400;    // TA1CCR1 PWM duty cycle, %0 duty cycle. TA1CCR1 ranges from 0-800 with 400 being the middle which signifies neither forward nor backward movement
    }
    else
    {
        TA1CCR1 = 400 + (400 * 0.75);    // TA1CCR1 PWM duty cycle, %75 duty cycle. TA1CCR1 ranges from 0-800 with 400 being the middle which signifies neither forward nor backward movement
    }
}



// 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

Reid Farchmin
2 projects • 1 follower

Comments