Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // A video demonstration of this project can be found here: https://bit.ly/2Wfsdqs
- /*
- PARTS USED:
- [1] PIC18F4520
- [5] LEDs (1 clear, 1 blue, 1 yellow, 1 red, 1 green)
- [2] SG90 Servo Motors
- [1] TCS34725 Color Sensor
- [1] 9v Battery
- [1] 5v 1A Power supply
- [1] Elegoo 9v power supply module
- [5] 220 resistors
- [2] 10k resistors
- [40+] jumper wires
- [1] Plastic Funnel
- Lots of cardboard
- Lots of hot glue
- */
- #include <xc.h>
- #include <pic18f4520.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include "SkittleSorterConfigBits.h"
- void __interrupt() HIGH_ISR(void);
- int interruptCounter = 0;
- void bitSetupOscillator(void);
- void bitSetupLED(void);
- void bitSetupI2C(void);
- void bitSetupPWM(void);
- void bitSetupInterrupt(void);
- void PWM_Set(uint16_t duty, char specifiedServo);
- void i2cIdleCheck(void);
- void i2cStart(void);
- void i2cStop(void);
- void i2cRepStart(void);
- void i2cWrite(uint8_t data);
- uint8_t i2cRead(uint8_t ack);
- void enableColorSensor(void);
- void setColorSensorInterrupt(bool i);
- void getRawData(uint16_t *redHigh, uint16_t *greenHigh, uint16_t *blueHigh,
- uint16_t *clearHigh);
- void moveSpecificServo(uint16_t servoBaseVal, char specifiedServo);
- void handleLEDs(char red, char orange, char yellow, char green, char purple);
- void main(void)
- {
- uint16_t servoSlideVal;
- uint16_t red;
- uint16_t green;
- uint16_t blue;
- uint16_t clear;
- uint16_t *pRed = &red;
- uint16_t *pGreen = &green;
- uint16_t *pBlue = &blue;
- uint16_t *pClear = &clear;
- bitSetupOscillator();
- bitSetupLED();
- bitSetupI2C();
- bitSetupPWM();
- bitSetupInterrupt();
- enableColorSensor();
- while(1)
- {
- if(interruptCounter == 2)
- {
- setColorSensorInterrupt(false);
- getRawData(pRed, pGreen, pBlue, pClear);
- setColorSensorInterrupt(true);
- }
- else
- {
- red = green = blue = 0;
- }
- if(clear == 0)
- {
- red = green = blue = 0;
- }
- else
- {
- red = (float)red / clear * 255.0;
- green = (float)green / clear * 255.0;
- blue = (float)blue / clear * 255.0;
- }
- if(red > 100 && blue >= 47) //red
- {
- servoSlideVal = 25;
- handleLEDs(1,0,0,0,0);
- moveSpecificServo(servoSlideVal, SERVO_SLIDE);
- }
- else if(red > 100 && blue < 47 && green < 70) //orange
- {
- servoSlideVal = 33;
- handleLEDs(0,1,0,0,0);
- moveSpecificServo(servoSlideVal, SERVO_SLIDE);
- }
- else if(red >= 80 && green > 80 && blue < 45) //yellow
- {
- servoSlideVal = 40;
- handleLEDs(0,0,1,0,0);
- moveSpecificServo(servoSlideVal, SERVO_SLIDE);
- }
- else if(green > 110 && red < 80) //green
- {
- servoSlideVal = 47;
- handleLEDs(0,0,0,1,0);
- moveSpecificServo(servoSlideVal, SERVO_SLIDE);
- }
- else if(green > 80 && blue > 63 && red > 79) //purple
- {
- servoSlideVal = 56;
- handleLEDs(0,0,0,0,1);
- moveSpecificServo(servoSlideVal, SERVO_SLIDE);
- }
- else
- {
- handleLEDs(0,0,0,0,0);
- }
- }
- return;
- }
- void __interrupt() HIGH_ISR()
- {
- INTCONbits.GIEH = 0;
- if(INTCONbits.TMR0IF)
- {
- interruptCounter ++;
- if(interruptCounter == 1)
- {
- moveSpecificServo(44, SERVO_BASE);
- }
- if(interruptCounter == 3)
- {
- moveSpecificServo(25, SERVO_BASE);
- }
- if(interruptCounter == 4)
- {
- moveSpecificServo(73, SERVO_BASE);
- interruptCounter = 0;
- }
- INTCONbits.TMR0IF = 0;
- }
- INTCONbits.GIEH = 1;
- }
- void bitSetupInterrupt()
- {
- RCONbits.IPEN = 1;
- INTCONbits.TMR0IE = 1;
- INTCON2bits.TMR0IP = 1;
- T0CONbits.TMR0ON = 0; //turn timer off
- T0CONbits.T08BIT = 1; //configure timer to an 8 bit timer
- T0CONbits.T0CS = 0; //sets the clock source to the internal oscillator
- T0CONbits.PSA = 0; //assign prescaler
- T0CONbits.T0PS = 0b111; //sets prescaler value 1:2
- T0CONbits.TMR0ON = 1;
- INTCONbits.GIEH = 1;
- }
- void bitSetupOscillator()
- {
- OSCCONbits.IRCF = 0b011; //500kHz
- OSCCONbits.SCS = 0b10;
- while(!OSCCONbits.IOFS);
- }
- void bitSetupLED()
- {
- TRISE = 0;
- TRISDbits.RD0 = 0;
- TRISDbits.RD1 = 0;
- LATE = 0;
- LATDbits.LD0 = 0;
- LATDbits.LD1 = 0;
- }
- void bitSetupI2C()
- {
- TRISCbits.RC3 = 1; //SCL
- TRISCbits.RC4 = 1; //SDA
- SSPSTATbits.SMP = 1; //disables slew rate
- SSPSTATbits.CKE = 0; //disables SMBus
- SSPCON1bits.SSPM = 0b1000; //I2C Master mode clock = FOSC/(4 * (SSPADD + 1))
- SSPADD = 11; //100kHz
- SSPCON1bits.SSPEN = 1; //enables serial port and SDA/SCL pins
- }
- void bitSetupPWM()
- {
- TRISCbits.RC1 = 0;
- TRISCbits.RC2 = 0;
- T2CONbits.T2OUTPS = 0x00; //Postscale = 0
- T2CONbits.T2CKPS = 0b10; //Prescaler = 16
- PR2 = 156; //appropriate PR2 value to get a 50Hz pwm frequency
- CCP2CONbits.DC2B = 0; //clears the last 2 bits of the pwm duty cycle
- CCP2CONbits.CCP2M = 0b1100; //puts the CCP into pwm mode
- CCPR2L = 0; //clears the first 8 bits of the pwm duty cycle
- CCP1CONbits.DC1B = 0;
- CCP1CONbits.CCP1M = 0b1100;
- CCPR1L = 0;
- T2CONbits.TMR2ON = 1;
- }
- void PWM_Set(uint16_t duty, char specifiedServo)
- {
- if(specifiedServo == 1)
- {
- CCP2CONbits.DC2B = (uint8_t)(duty & 0x0003); //parses the last 2 bits of the pwm cycle
- CCPR2L = (uint8_t)(duty >> 2);
- }
- else
- {
- CCP1CONbits.DC1B = (uint8_t)(duty & 0x0003);
- CCPR1L = (uint8_t)(duty >> 2);
- }
- }
- void i2cIdleCheck()
- {
- while((SSPCON2 & 0x1F) || (SSPSTAT & 0x04)); // waits until
- // the i2c bus is in
- // an idle state.
- }
- void i2cStart()
- {
- i2cIdleCheck();
- SSPCON2bits.SEN = 1; //initiates a start command
- }
- void i2cStop()
- {
- i2cIdleCheck();
- SSPCON2bits.PEN = 1; //initiates a stop command
- }
- void i2cRepStart()
- {
- i2cIdleCheck();
- SSPCON2bits.RSEN = 1; //initiates a repeat start command
- }
- void i2cWrite(uint8_t data)
- {
- i2cIdleCheck();
- SSPBUF = data; //loads data into buffer
- while(SSPSTATbits.BF != 0); //makes sure that the data leaves the buffer
- while(SSPCON2bits.ACKSTAT != 0); //makes sure that the master receives an ACK from slave
- }
- uint8_t i2cRead(uint8_t ack)
- {
- uint8_t receive = 0;
- i2cIdleCheck();
- SSPCON2bits.RCEN = 1; //puts master into receive mode
- while(SSPSTATbits.BF != 1); //waits until buffer is full
- receive = SSPBUF; //loads data from buffer into variable
- SSPCON2bits.ACKEN = ack;
- return receive;
- }
- void enableColorSensor()
- {
- __delay_ms(500);
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_ATIME);
- i2cWrite(0xEB); //sets the wait time to 50ms
- i2cStop();
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_CONTROL);
- i2cWrite(0x01); //sets the gain to 4x
- i2cStop();
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_ENABLE);
- i2cWrite(TCS34725_ENABLE_PON); //powers on the colorSensor
- i2cStop();
- __delay_ms(3);
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_ENABLE);
- i2cWrite(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); //enables the color
- //sensors interrupts
- i2cStop();
- __delay_ms(500);
- }
- void getRawData(uint16_t *redHigh, uint16_t *greenHigh, uint16_t *blueHigh,
- uint16_t *clearHigh)
- {
- uint8_t redLow;
- uint8_t greenLow;
- uint8_t blueLow;
- uint8_t clearLow;
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_BDATAL);
- i2cRepStart();
- i2cWrite(TCS34725_READ_ADDRESS);
- blueLow = i2cRead(1); //reads the first 8 bits of the 16 bit BDATA register
- *blueHigh = i2cRead(0);//reads the last 8 bits of the 16 bit BDATA register
- i2cStop();
- *blueHigh <<= 8;
- *blueHigh |= blueLow;
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_GDATAL);
- i2cRepStart();
- i2cWrite(TCS34725_READ_ADDRESS);
- greenLow = i2cRead(1);
- *greenHigh = i2cRead(0);
- i2cStop();
- *greenHigh <<= 8;
- *greenHigh |= greenLow;
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_RDATAL);
- i2cRepStart();
- i2cWrite(TCS34725_READ_ADDRESS);
- redLow = i2cRead(1);
- *redHigh = i2cRead(0);
- i2cStop();
- *redHigh <<= 8;
- *redHigh |= redLow;
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_CDATAL);
- i2cRepStart();
- i2cWrite(TCS34725_READ_ADDRESS);
- clearLow = i2cRead(1);
- *clearHigh = i2cRead(0);
- i2cStop();
- *clearHigh <<= 8;
- *clearHigh |= clearLow;
- __delay_ms(50);
- }
- void setColorSensorInterrupt(bool i)
- {
- uint8_t r;
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_ENABLE);
- i2cRepStart();
- i2cWrite(TCS34725_READ_ADDRESS);
- r = i2cRead(0); //reads current interrupt state
- i2cStop();
- if(i)
- {
- r |= TCS34725_ENABLE_AIEN; //this line ensures that r will = 1
- }
- else
- {
- r &= ~TCS34725_ENABLE_AIEN; //this line ensures that r will = 0
- }
- i2cStart();
- i2cWrite(TCS34725_WRITE_ADDRESS);
- i2cWrite(TCS34725_COMMAND_BIT | TCS34725_ENABLE);
- i2cWrite(r);
- i2cStop();
- }
- void moveSpecificServo(uint16_t servoBaseVal, char specifiedServo)
- {
- PWM_Set(servoBaseVal, specifiedServo);
- }
- void handleLEDs(char red, char orange, char yellow, char green, char purple)
- {
- LATEbits.LE1 = red;
- LATEbits.LE2 = orange;
- LATEbits.LE0 = yellow;
- LATDbits.LD0 = green;
- LATDbits.LD1 = purple;
- }
Add Comment
Please, Sign In to add comment