Hae Woo Chung
Published

Pigeon Repellent

An automated pigeon repellent using Texas Instruments MSP-EXP430G2 MSP430 LaunchPad, 2 IR sensors, 2 RC servos, and a pepper spray.

BeginnerShowcase (no instructions)693
Pigeon Repellent

Things used in this project

Story

Read more

Schematics

videocapture_20190417-101956_HiedrS26Lj.jpg

Code

user_Individual_Project.c

C/C++
/******************************************************************************
MSP430G2553 Project Creator

GE 423  - Dan Block
        Spring(2012)

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

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

char newprint = 0;
unsigned long timecnt = 0;

unsigned int ADC[4]={0,0,0,0};  // Array to hold ADC values (A0 A1 A2 A3)
int A0value = 0;
int A3value = 0;
char newADC = 0;
int statevar = 2;
int timecount = 0;
int spraycount = 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;

    // Initialize Port 1 IR Readings as ADC MEM Input
    P1SEL &= ~0x09;  // See page 42 and 43 of the G2553's datasheet, It shows that when both P1SEL and P1SEL2 bits are zero
    P1SEL2 &= ~0x09; // the corresponding pin is set as a I/O pin.  Datasheet: http://coecsl.ece.illinois.edu/ge423/datasheets/MSP430Ref_Guides/msp430g2553datasheet.pdf
    P1REN = 0x0;  // No resistors enabled for Port 1
    P1DIR &= ~0x9; // Set P1.0 P1.3 to intput to Read IR Sensor data on LaunchPad board.  Make sure shunt jumper is in place at LaunchPad's Red LED

    // Initialize Pordt 2 to be PWM set p2.1 and p2.4 as PWM
    P2SEL |= BIT1+BIT4;
    P2SEL2 &= ~(BIT1+BIT4);
    P2DIR |= BIT1+BIT4;


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

    TA1CCR0 = 40000; // set carrier frequency to 50Hz period = 20 ms
    TA1CCTL1 = OUTMOD_7;                         // TA1CCR1 reset/set
    TA1CCTL2 = OUTMOD_7;                        // TA1CCR2 reset/set
    TA1CCTL0 = 0;
    TA1CTL = TASSEL_2 + ID_3 + MC_1;                  // SMCLK, up mode, divider 8 so 20000 = 1 ms

    ADC10CTL1 = INCH_3 + ADC10SSEL_3 + CONSEQ_1; //INCH_3: Enable A3 first, Use SMCLK, Sequence of Channels
    ADC10CTL0 = ADC10ON + MSC + ADC10IE;  // Turn on ADC,  Put in Multiple Sample and Conversion mode,  Enable Interrupt

    ADC10AE0 |= 0x09;                   // Enable A0 and A3 which are P1.0,P1.3

    ADC10DTC1 = 4;                 // Four conversions. Only A3 and A0 are being used.
    ADC10SA = (short)&ADC[0];           // ADC10 data transfer starting address.


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

    _BIS_SR(GIE);       // Enable global interrupt


    while(1) {

        if(newmsg) {
            newmsg = 0;
        }

        if (newprint)  {

            newprint = 0;
        }
        if (newADC == 1) {

            UART_printf("0:%d 3:%d time: %d spraycount = %d\n\r",A0value,A3value,timecount,spraycount);  // Print to UART

            newADC = 0;

        }
    }
}


// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    timecnt++; // Keep track of time for main while loop.

    if ((timecnt%500) == 0) {
        ADC10CTL0 |= ENC + ADC10SC;         // Enable Sampling and start conversion.
    }

    if ((timecnt%500) == 0) {
    newprint = 1;  // flag main while loop that .5 seconds have gone by.
    }

}



//ADC10 interrupt Service Routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void) {

    A0value = 4095 - ADC[3]*4095L/1023;  // We read in the value of IR sensor in A0 port and store it in A0value
    A3value = 4095 - ADC[0]*4095L/1023;  // We read in the value of IR sensor in A3 port and store it in A3value

    ADC10CTL0 &= ~ADC10IFG;  // clear interrupt flag

    ADC10SA = (short)&ADC[0]; // ADC10 data transfer starting address.

    newADC = 1;

    switch (statevar){
    case 1:
        TA1CCR2 = 4000; // move IR sensor to right
        timecount++; //increment time

        if (timecount > 5) { //If pigeon is still right of the fixture for 4 seconds, press the nozzle by moving the top servo
            TA1CCR1 = 5000; // Move top servo
            spraycount++; // increment timer that counts how much time elapsed till pressed.
            timecount = 0;
        }
        if (spraycount > 1) { //If nozzle has been pressed release the nozzle by moving the servo back.
            TA1CCR1 = 3000; // reset top servo
            spraycount = 0; //reset the spray count
        }

        if (A0value > 2200) { //if no object sensed in right servo go back to initial state (2)
            timecount = 0;
            statevar = 2;
        }
        break;
    case 2: //Initialized as 2. When no pigeon as been detected.
        TA1CCR1 = 3000;
        TA1CCR2 = 3000;
        timecount = 0;
        if ((A3value > 2200) && (A0value < 2200)){ // if IR sensor in A0 is low
            statevar = 1; //change state to move pepper spray to right
        }
        if ((A3value < 2200) && (A0value > 2200)){ // if IR sensor in A3 is low
            statevar = 3; //change state to move pepper spray to left
        }
        break;
    case 3:
        TA1CCR2 = 2000;// move IR sensor to left
        timecount++;//increment time

        if (timecount > 5) {//If pigeon is still right of the fixture for 4 seconds, press the nozzle by moving the top servo
            TA1CCR1 = 5000;// Move top servo
            spraycount++;// increment timer that counts how much time elapsed till pressed.
            timecount = 0;
        }
        if (spraycount > 1) { //If nozzle has been pressed release the nozzle by moving the servo back
            TA1CCR1 = 3000; // reset top servo
            spraycount = 0; //reset the spray count
        }
        if (A3value > 2200) {//if no object sensed in right servo go back to initial state (2)
            timecount = 0;
            statevar = 2;
        }
        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;
    }

}

Credits

Hae Woo Chung

Hae Woo Chung

1 project • 0 followers

Comments