Michaela Lobato
Published

Mix-a-roo 2000

You get to the party and there's no shaker. How will you get that nice even mix in your drink? The Mix-a-roo 2000 is here to save the day!

IntermediateShowcase (no instructions)10 hours545
Mix-a-roo 2000

Things used in this project

Story

Read more

Schematics

Mix-a-roo PCB

Code

Mix-a-roo 2000 Code

C/C++
#include "msp430g2553.h"
#include "UART.h"

void print_every(int rate);

char newprint = 0;
int lightclk = 0;
int dutycycle = 0;
char input = 0;

//initialize variables
int statevar = 0;
int timecount = 0;
int value = 0;
int milivolts = 0;
int flag = 1;
int timer = 0;
unsigned int avg = 0;
unsigned int average = 0;
int i=0;
int volts[10] = {0,0,0,0,0,0,0,0,0,0}; // initialize array
int voltsum = 0;

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; //setting up the register so that the sample and hold time is 8 x ADC10CLKs, the ADC10 gets turned on and the interrupt is enabled. All other settings are default
    ADC10CTL1 = INCH_3; //sets up the channel so that pin A3 is set as an input
    ADC10AE0 |= 0x08; // enables A3 as the ADC channel

    // Initialize Port 1
    P1SEL &= ~0xFF;  // Clears pins so they are GPIO
    P1SEL2 &= ~0xFF; // Clears pins so they are GPIO
    P1REN = 0xFF;  // enables the resistors
    P1DIR |= 0xF1; // Sets all pins as outputs
    P1OUT &= ~0xF1;  // Sets all pins intially to low

    //Initialize Port 2
    P2DIR |= 0x12; // Pins 2.1 and 2.4 are set up as timers
    P2SEL |= 0x12; // Pins 2.1 and 2.4 are set up as timers
    P2SEL2 &= ~0x12; // Clear the bits for P2SEL2 to set up the timer

    //Setting up the timer
    TA1CCR0 = 40000; // Sets the carrier frequency to 50 Hz
    TA1CCR1 = 4900; //  initialize duty cycle so that robot arm is holding spoon out of the cup
    TA1CCR2 = 0; // initialize duty cycle
    TA1CCTL1 = OUTMOD_7;// set/reset mode
    TA1CCTL2 = OUTMOD_7;// set/reset mode
    TA1CCTL0 = 0;
    TA1CTL = TASSEL_2 + MC_1 + ID_3; // source SMCLK, up mode ,divider 8

    // Timer A Config
    TACCTL0 = CCIE;             // Enable Periodic interrupt
    TACCR0 = 16000;                // period = 1ms
    TACTL = 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("Milivolts :%d \n\r", milivolts); //prints milivolts to tera term

            newprint = 0;
        }

    }
}

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    ADC10CTL0 |= ENC + ADC10SC; // the conversion is started and enabled

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

    value = ADC10MEM; //sets a variable that records the ADC10 readings
    milivolts = (value*3300L)/1023; //converts the ADC reading to milivolts

    timecount++; // Keep track of time for main loop
    timer++; //seperate timer that also keeps track of main loop
   print_every(250);  // units determined by the rate Timer_A ISR is called, print every "rate" calls to this function
    volts[0] = milivolts; //sets the first value of the array to the milivolts value
    voltsum=0; //intialize voltsum to zero
    for (i=0; i<10; i++){
        voltsum +=volts[i]; // adds up all of the past 10 milivolts readings
    }

    average = voltsum/10; //divides that sum by 10 to find the average
    for (i=9; i>0; i--){
        volts[i] = volts[i-1]; //goes backwards from the last array value and shifts each value so that it is equal to the previous value. Happens continually so that 10 values are being read
    }

    if ((flag == 1) && (average > 305) && (timecount >= 4000)){ //if loops that determines if the average voltage is met (water is poured into the cup) and waits 4 seconds to drop the spoon into the cup after the cup has been filled
        statevar = 1; // sends the program into case 1
        timecount = 0; //resets the timecount
        flag = 0; //sets the flag to 0 so that the program doesn't stay only in case 1

    }

    switch(statevar){
    case 1: //drops the spoon into the cup
        TA1CCR1 = 4400 ; // takes the robot arm from it's upright position to the down position using servo1
        if (timecount >= 2000){ //waits for 2 seconds before moving on
            timecount = 0; //resets the timecount timer
            statevar = 2; // switch to state 2 to start the spoon movements
    timer = 0; // resets the timer to keep track of spinning
        }
        break;

    case 2:// spins the spoon one way
        TA1CCR2 = 1900; //causes the spoon to spin in one direction using servo2
        if(timecount >= 400){ // waits for 400ms before moving to the case that spin it the other way
            timecount = 0; // resets the timecount
            statevar = 3; //sends the program to state 3 to move the spoon the other way
        }
        break;
    case 3: //spins spoon the other way
        TA1CCR2 = 4500; //causes spoon to spin in opposite direction using servo2
        if (timer >= 4000){ // if timer has reached 4 seconds (the spoon has spun back and forth 5 times)
            timer = 0; //reset the timer value
            statevar = 4; //continue to state 4 to end the program
        }

        else if(timecount >= 400){ //if the timer hasn't reached 4 secs, check timecount to see if it has reached 400ms
            timecount = 0; //resets timecount
            statevar = 2; // switch back to state 2 and turn other way
        }
        break;
    case 4: //lifts spoon out of the cup using servo1
        TA1CCR1 = 4900; // puts robot are back into it's upright position
        if (timecount > 10000){// waits for 10 seconds before re-enabling the flag to give enough time to remove the cup
            flag = 1; //re-enables flag
        }

        break;


    }
}


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

Michaela Lobato
1 project • 1 follower

Comments