#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdlib.h>
#include "lcd.h"//LCD Library
#include "LinkedQueue.h"// linked queue library
#include <util/delay_basic.h>
//==============================================================GLOBAL VARIABLES======================================================
//====================================================================================================================================
volatile int scannedCount; //Keeps the count of scanned items on the belt
volatile int count;
volatile char STATE;
volatile int curState = 0; //for stepper motor
volatile unsigned int Global_min;// Used for determining material type in the reflective sensor interrupt
volatile unsigned char low;//ADC
volatile unsigned char high;//ADC
volatile unsigned int ADC_result;//ADC
volatile unsigned int ADC_result_flag;//ADC
volatile unsigned int Buffer_flag = 0; // Flag thrown when the exit sensor is triggered
volatile int Paused = 0;//0 if belt is running, 1 if belt is paused. only used for the pause interrupt to start and stop the belt
volatile int StepperPos = 0;//what bin is currently at the end of the belt
/* The four variables below are assigned values in bucket stage for looking ahead in the list
They are assigned arbitrary values to start
*/
volatile int thisDir = 12;
volatile int nextDir = 13;
volatile int nextNextDir = 14;
volatile int nextNextNextDir = 15;
/* The follwing flags are used when multiple drops during a continuous rotation happens */
volatile int dropDone_flag = 0;
volatile int bailout_flag = 0;
volatile int breakout_flag = 0;
volatile int curDir;//CW is 0, CCW is 1
/* Arrays for stepper acceleration */
int array90[] = {14976.4, 14939.6, 14850.8, 14650.6, 14240.5, 13503.4, 12375, 10931.7, 9388.31, 7981.51, 6854.06, 6032.6, 5472.33, 5106.54, 4874.31, 4729.46, 4640.08, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4640.08, 4729.46, 4874.31, 5106.54, 5472.33, 6032.6, 6854.06, 7981.51, 9388.31, 10931.7, 12375, 13503.4, 14240.5, 14650.6, 14850.8, 14939.6, 14976.4};//based on the test for what timer works, apply proper array
int array180[] = {14976.4, 14939.6, 14850.8, 14650.6, 14240.5, 13503.4, 12375, 10931.7, 9388.31, 7981.51, 6854.06, 6032.6, 5472.33, 5106.54, 4874.31, 4729.46, 4640.08, 4585.3, 4551.86, 4531.5, 4519.12, 4511.61, 4507.04, 4504.27, 4502.59, 4501.57, 4500.95, 4500.58, 4500.35, 4500.21, 4500.13, 4500.08, 4500.05, 4500.03, 4500.02, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500.02, 4500.03, 4500.05, 4500.08, 4500.13, 4500.21, 4500.35, 4500.58, 4500.95, 4501.57, 4502.59, 4504.27, 4507.04, 4511.61, 4519.12, 4531.5, 4551.86, 4585.3, 4640.08, 4729.46, 4874.31, 5106.54, 5472.33, 6032.6, 6854.06, 7981.51, 9388.31, 10931.7, 12375, 13503.4, 14240.5, 14650.6, 14850.8, 14939.6, 14976.4};
int array270[] = {14976.4, 14939.6, 14850.8, 14650.6, 14240.5, 13503.4, 12375, 10931.7, 9388.31, 7981.51, 6854.06, 6032.6, 5472.33, 5106.54, 4874.31, 4729.46, 4640.08, 4585.3, 4551.86, 4531.5, 4519.12, 4511.61, 4507.04, 4504.27, 4502.59, 4501.57, 4500.95, 4500.58, 4500.35, 4500.21, 4500.13, 4500.08, 4500.05, 4500.03, 4500.02, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500.02, 4500.03, 4500.05, 4500.08, 4500.13, 4500.21, 4500.35, 4500.58, 4500.95, 4501.57, 4502.59, 4504.27, 4507.04, 4511.61, 4519.12, 4531.5, 4551.86, 4585.3, 4640.08, 4729.46, 4874.31, 5106.54, 5472.33, 6032.6, 6854.06, 7981.51, 9388.31, 10931.7, 12375, 13503.4, 14240.5, 14650.6, 14850.8, 14939.6, 14976.4};
int array360[] = {14976.4, 14939.6, 14850.8, 14650.6, 14240.5, 13503.4, 12375, 10931.7, 9388.31, 7981.51, 6854.06, 6032.6, 5472.33, 5106.54, 4874.31, 4729.46, 4640.08, 4585.3, 4551.86, 4531.5, 4519.12, 4511.61, 4507.04, 4504.27, 4502.59, 4501.57, 4500.95, 4500.58, 4500.35, 4500.21, 4500.13, 4500.08, 4500.05, 4500.03, 4500.02, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500.02, 4500.03, 4500.05, 4500.08, 4500.13, 4500.21, 4500.35, 4500.58, 4500.95, 4501.57, 4502.59, 4504.27, 4507.04, 4511.61, 4519.12, 4531.5, 4551.86, 4585.3, 4640.08, 4729.46, 4874.31, 5106.54, 5472.33, 6032.6, 6854.06, 7981.51, 9388.31, 10931.7, 12375, 13503.4, 14240.5, 14650.6, 14850.8, 14939.6, 14976.4};
/* Arrays for stepper excitation */
int chargeArrayCW[4] = {0x2E, 0x2D, 0x35, 0x36};//from table: state 2, state 3, state 4, state 1
int chargeArrayCCW[4] = {0x35, 0x36, 0x2E, 0x2D};//from table: state 4, state 1, state 2, state 3
/* Linked list decleration */
link *head; /* The ptr to the head of the queue */
link *tail; /* The ptr to the tail of the queue */
link *newLink; /* A ptr to a link aggregate data type (struct) */
link *rtnLink; /* same as the above */
//========================================================FUNCTION INITIALIZATION====================================================
//====================================================================================================================================
void mTimer(int);
void rotateStepper();
void Home();
void PWM();
void rampTimer();
void stepperTimer();
void stepperCW_90();
void stepperCCW_90();
void motorOn();
void stepperCW_180();
void stepperCCW_270();
void stepperCW_270();
void stepperCCW_360();
void stepperCW_360();
typedef struct { //Struct which holds the values of the counts
int sortCount; // Count of items sorted into the bucket
int scanCount; // Count of items scanned
} MaterialCounts;
MaterialCounts materialCounts[4] = { {0,0}, {0,0}, {0,0}, {0,0}}; // Array of MaterialCounts for 4 material types
typedef void (*StepperAction)(); // Function pointer for stepper actions
/* Lookup table for stepper motor rotation functions of 90 and 180 degrees
Inputs are current stepper position and target location
*/
StepperAction stepperActions[4][4] = {//Stepper_pos; Exit_ID
{motorOn, stepperCW_180, stepperCCW_90, stepperCW_90}, // Currently on 0 rotate to 0,1,2,3
{stepperCW_180, motorOn, stepperCW_90, stepperCCW_90}, //Currently on 1 rotate to 0,1,2,3
{stepperCW_90, stepperCCW_90, motorOn, stepperCW_180}, //Currently on 2 rotate to 0,1,2,3
{stepperCCW_90, stepperCW_90, stepperCW_180, motorOn} //Currently on 3 rotate to 0,1,2,3
};
/* Array for continuous rotation of 270 degrees */
StepperAction stepperActions2[2] = {//Stepper_pos; Exit_ID
stepperCW_270, stepperCCW_270
};
/* Array for continuous rotation of 360 degrees */
StepperAction stepperActions3[2] = {//Stepper_pos; Exit_ID
stepperCW_360, stepperCCW_360
};
/* Lookup table for determining next rotation
Returns 0 for clockwise and 1 for counter clockwise 90 degree rotations
Returns arbitrary value otherwise
Input is current position and target position
*/
int nextDirection[4][4] = { //rows are exit ID, columns are next or target
{2, 3, 1, 0}, // first value = 0
{4, 5, 0, 1}, // 1
{0, 1, 6, 7}, // 2
{1, 0, 8, 9} // 3
};
//================================================================MAIN===============================================================
//===================================================================================================================================
int main(int argc, char *argv[]){
int Exit_ID;
//mTimer stuff
CLKPR = 0x80;
CLKPR = 0x01; // sets system clock to 8MHz
TCCR4B |= _BV(CS41);
TCCR1B|= _BV(CS11);
cli(); // Disables all interrupts
DDRD = 0xF0; // Going to set up INT2 & INT3 on PORTD
DDRC = 0xFF; //send power to LCD
DDRB = 0xFF; //send power to DC motor
DDRA = 0xFF; //send power to stepper
DDRL = 0xFF; // send power to yellow and green LEDs for trouble shooting
/* ENABLING INTERRUPTS
RISING EDGE IS WHEN GOES FROM 0 TO 5V AKA ACTiVE HIGH BUTTON
FALLING EDGE IS WHEN GOES FROM 5V TO 0V AKA ACTIVE LOW BUTTON
*/
EIMSK |= _BV(INT0) | _BV(INT1) | _BV(INT2) | _BV(INT3); //ENABLE INT0-3
EICRA |= _BV(ISC01) | _BV(ISC00); //RISING EDGE INT0
EICRA |= _BV(ISC11) | _BV(ISC10); //RISING EDGE INT1
EICRA |= _BV(ISC21) | _BV(ISC20); //RISING EDGE INT2
EICRA |= _BV(ISC31); //FALLING EDGE INT3
ADCSRA |= _BV(ADEN); // enable ADC (ADC Control and Status Reg. A) (ADEN is ADC Enable)
ADCSRA |= _BV(ADIE); // enable interrupt of ADC
ADMUX |= _BV(REFS0);
// Enable all interrupts
sei(); // Note this sets the Global Enable for all interrupts
//Initialize LCD module
InitLCD(LS_BLINK|LS_ULINE);
//Clear the screen
LCDClear();
//set up linked list
rtnLink = NULL;
newLink = NULL;
setup(&head, &tail);
PWM(); //Start the PWM
Home();//rotate to home position
PORTB=0b00000111; //Turn on the motor going CCW
goto POLLING_STAGE;
/*===========================================================POLLING STAGE===================================================
This stage is the default place in main, it is simply waiting for interupts to be fired
=========================================================================================================================== */
POLLING_STAGE:
switch(STATE){
case (0) :
goto POLLING_STAGE;
break;
case (1) :
goto BUCKET_STAGE;
break;
case (2):
goto PAUSE_STAGE;
break;
default :
goto POLLING_STAGE;
}
/* ======================================================= BUCKET STAGE ============================================================
This stage is reached when an item hits the exit sensor
=============================================================================================================================== */
BUCKET_STAGE:
Buffer_flag = 0;
int listSize = size(&head, &tail); // Checks size of the list and performs actions accordingly
switch(listSize){
case 0:
break;
case 1:
if((head->e.stage) != StepperPos){
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
stepperActions[StepperPos][Exit_ID]();
}else{
PORTB=0b00000111; // belt motor on
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
mTimer(160);
}//else
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
Paused = 0;
StepperPos = Exit_ID;
break;
case 2:
if((head->e.stage) != StepperPos){
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
thisDir = nextDirection[StepperPos][Exit_ID];
int x = head->e.stage;
nextDir = nextDirection[Exit_ID][x];
stepperActions[StepperPos][Exit_ID](); //Rotates the stepper based on the exit id and the current stepper position
if (dropDone_flag == 1){
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
dropDone_flag--;
}
}else{
PORTB=0b00000111;// belt motor on
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
mTimer(160);
}//else
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
Paused = 0;
StepperPos = Exit_ID;
break;
case 3:
if((head->e.stage) != StepperPos){
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
thisDir = nextDirection[StepperPos][Exit_ID];
int x = head->e.stage;
nextDir = nextDirection[Exit_ID][x];
int y = head->next->e.stage;
nextNextDir = nextDirection[x][y];
if( (thisDir == nextDir) && (thisDir == nextNextDir )){
stepperActions2[thisDir](); //Rotates the stepper based on the exit id and the current stepper position
}else{
stepperActions[StepperPos][Exit_ID](); //Rotates the stepper based on the exit id and the current stepper position
}
while(dropDone_flag != 0){
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
dropDone_flag--;
}
}else{
PORTB=0b00000111;// belt motor on
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
mTimer(160);
}//else
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
Paused = 0;
StepperPos = Exit_ID;
break;
default:
if((head->e.stage) != StepperPos){
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
thisDir = nextDirection[StepperPos][Exit_ID];
int x = head->e.stage;
nextDir = nextDirection[Exit_ID][x];
int y = head->next->e.stage;
nextNextDir = nextDirection[x][y];
int z = head->next->next->e.stage;
nextNextNextDir = nextDirection[y][z];
if((thisDir == nextDir) && (thisDir == nextNextDir) && (thisDir == nextNextNextDir)){
stepperActions3[thisDir](); // Calls a 360 degree continuous rotation with 4 drops
}else if ((thisDir == nextDir) && (thisDir == nextNextDir)){
stepperActions2[thisDir](); // Calls a 270 degree continuous rotation with 3 drops
}else{
stepperActions[StepperPos][Exit_ID](); //Rotates the stepper based on the exit id and the current stepper position
}
while(dropDone_flag != 0){ // Handles the queue based on how many pieces were dropped
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
dropDone_flag--;
}
}else{
PORTB = 0b00000111;// belt motor on
dequeue(&head, &tail, &rtnLink);
Exit_ID = rtnLink->e.stage;
free(rtnLink);
mTimer(160);
}//else
materialCounts[Exit_ID].sortCount++; // Increment sort count for this material
scannedCount--;
Paused = 0;
StepperPos = Exit_ID;
break;
}
if(Buffer_flag != 0){
STATE = 1;//go back to bucket stage
}else{
STATE = 0;//go to polling stage
}//else
goto POLLING_STAGE;
/* =========================================================PAUSED STAGE============================================================
This stage is reached when the pause button has been pressed
=================================================================================================================================
*/
PAUSE_STAGE:
mTimer(50);
if(Paused==1){ //button has been pressed to start the belt back up and return to previous position
LCDClear();
PORTB=0b00000111;
Paused = 0;
}else if(Paused==0){//button has been pressed to pause and display sorted and scanned pieces
PORTB=0b00001111; //break to Vcc
Paused=1;
LCDClear();
LCDWriteStringXY(0,0,"B")
LCDWriteIntXY(1,0,materialCounts[0].sortCount,2);
LCDWriteStringXY(4,0,"W");
LCDWriteIntXY(5,0,materialCounts[1].sortCount,2);
LCDWriteStringXY(8,0,"S");
LCDWriteIntXY(9, 0, materialCounts[2].sortCount,2);
LCDWriteStringXY(12, 0, "A");
LCDWriteIntXY(13, 0, materialCounts[3].sortCount,2);
LCDWriteStringXY(0,1, "SCANNED:");
LCDWriteIntXY(8, 1, scannedCount, 2);
}//if
while((PIND&0x02)==0x02); // Button debouncing
mTimer(25);
STATE = 0;
goto POLLING_STAGE;
}//main
//=====================================================ALL INTERRUPTS============================================================
//=======================================================BELOW HERE==============================================================
//======================================================= INTERRUPT 0 ===========================================================
//==================================================== RAMP DOWN BUTTON =========================================================
//active low button, goes from 1 to 0 when pressed
ISR(INT0_vect){//right button Ramp down
mTimer(20);//debounce
LCDClear();
LCDWriteStringXY(0,0,"Ramp Down");
while((PIND&0x00)==0x01); //ramp button is back to high
rampTimer();
}//INT0
//======================================================= INTERRUPT 1 ==========================================================
//====================================================== PAUSE BUTTON ==========================================================
//goes from 0 to 1 when pressed
ISR(INT1_vect){//left button Pause
STATE=2;//go to paused state
}//INT1
//======================================================= INTERRUPT 2 ===========================================================
//====================================================== OPTICAL SENSOR =========================================================
/* Gives 1 when object is in front, 0 when nothing is in front */
ISR(INT2_vect){ //OR sensor (rising edge) Middle conveyor sensor
Global_min=1023;
ADCSRA |= _BV(ADSC);
}//INT2
//======================================================= INTERRUPT 3 ===========================================================
//======================================================= EXIT SENSOR ===========================================================
/* gives 1 when tripped, 0 when nothing is there*/
ISR(INT3_vect){ //EX sensor (falling edge) End position sensor
PORTB=0b00001111;//brake
STATE = 1;//go to bucket stage
Buffer_flag++;
Paused =1;
}//INT3
//============================================================ ADC ================================================================
//===================================================== REFLECTIVE SENSOR =========================================================
ISR(ADC_vect){ //RL Sensor (ADC) Reflective sensor
low = ADCL;
high = ADCH;
ADC_result = low + (high << 8);
if(ADC_result < Global_min){ // Looking for the lowest value to classify material type
Global_min = ADC_result;
}
if((PIND&0x04)==0x04){
ADCSRA |= _BV(ADSC);
}else{
initLink(&newLink); // Initialize a new link in the queue
if(Global_min > 925){
scannedCount++;
newLink -> e.stage = 0; // Material is black delrin (0)
enqueue(&head, &tail, &newLink);
}
else if(Global_min > 750){
scannedCount++;
newLink -> e.stage = 1; // Material is white delrin (1)
enqueue(&head, &tail, &newLink);
}
else if(Global_min > 120){
scannedCount++;
newLink -> e.stage = 2; // Material is steel (2)
enqueue(&head, &tail, &newLink);
}
else{
scannedCount++;
newLink -> e.stage = 3; // Material is aluminum (3)
enqueue(&head, &tail, &newLink);
}
}
}
//================================================= RAMP TIMER INTERRUPT HANDLER ================================================
//================================================ WHEN THE rampTimer() is complete =============================================
ISR(TIMER3_COMPA_vect){
LCDClear();
LCDWriteStringXY(0,0,"SORT");
// ALUM
LCDWriteStringXY(5,0,"Al:");
LCDWriteIntXY(8,0,materialCounts[3].sortCount,2);
// STEEL
LCDWriteStringXY(0,1,"St:");
LCDWriteIntXY(3,1,materialCounts[2].sortCount,2);
// WHITE
LCDWriteStringXY(11,0,"Wt:");
LCDWriteIntXY(14,0,materialCounts[1].sortCount,2);
// BLACK
LCDWriteStringXY(11,1,"Bl:");
LCDWriteIntXY(14,1,materialCounts[0].sortCount,2);
PORTB=0b00001111;//brake to Vcc
mTimer(1000);
PORTB=0x00;
while(1);//requires user reset
}
//======================================================== BADISR INTERRUPT =======================================================
//===================================================== REEQUIRES USER RESET ======================================================
ISR(BADISR_vect){
PORTB=0b00001111; // Turn off belt motor
LCDClear();
LCDWriteStringXY(0,0,"BADISR_vect");
while(1);// Requires reset to leave ISR
}
//=================================================== HALL EFFECT SENSOR ==========================================================
//================================================== HOME STATE AKA BLACK =========================================================
void Home(){
while((PING&0b00000001)==0b00000001){ //when low the location is home
rotateStepper(1,1);// Rotate one step
}//exits loop when low
rotateStepper(1,8);// Makes end of belt centered on bin
StepperPos = 0;// Set stepper position to black
curDir=1; // Set current direction to clockwise
}
//====================================================== ALL TIMERS ==============================================================
//====================================================== BELOW HERE ==============================================================
//======================================================= MTIMER (TIMER 1) =======================================================
//============================================================= 1ms ==============================================================
void mTimer(int count){
int i = 0;
TCCR1B |= _BV(WGM12);//clear timer on compare match mode
TCCR1B |= _BV(CS11);//prescaler 8 = 1MHz
OCR1A= 0x03E8;//set output compare register to 1ms
TCNT1=0x0000;//set initial value of timer to 0
TIFR1 |= _BV(OCF1A);//clear the timer interrupt flag and begin new timing
while(i<count){//determine when timer has reached 0x03E8
if((TIFR1 & 0x02) == 0x02){//if OCF1A is true
TIFR1 |= _BV(OCF1A);//clear interrupt flag
i++;
}
}
return;
}
//============================================================= PWM ==============================================================
//===================================================== FOR CONVEYOR BELT SPEED ==================================================
void PWM(){
TCCR0B |= _BV(CS01) | _BV(CS00); //Prescaler of 64 AKA 488Hz
TCCR0A|=_BV(WGM01)|_BV(WGM00);// fast pwm mode 3 with top 0xFF
TCCR0A|=_BV(COM0A1);//clear OC0A on compare match, set OC0A at Bottom
OCR0A=95; //set the duty cycle here, max value is 255, currently set to 37% of max
}
//=================================================== RAMP DOWN (TIMER 3) ========================================================
//=============================================== TIMER FOR RAMP DOWN INTERRUPT ==================================================
void rampTimer(){
TCCR3B |= _BV(WGM32); // clear timer on compare top = OCR3A
TCCR3B |= _BV(CS32) | _BV(CS30); // Prescaler of 1024 AKA 7.8kHz
OCR3A = 0x8888; //sets output compare register to 35000 cycles = 4.48s of rampdown
TCNT3 = 0x0000; // sets initial value for timer compare to 0
TIMSK3 = _BV(OCIE3A); //enable the output compare interrupt enable
TIFR3 |= _BV(OCF3A); //clear the timer interrupt flag
}
//================================================= STEPPER TIMER(TIMER 4) =====================================================
//============================================== FOR ACCELERATION OF STEPPER ===================================================
void stepperTimer(int count){
TCCR4B |= _BV(WGM42); //clear timer on compare match mode
OCR4A = count; // set output compare register to the count value
TCNT4 = 0x0000;//set initial value of timer to 0
TIFR4 |= _BV(OCF4A);// clear interrupt
while((TIFR4&0x02) != 0x02);
}//accelerationTimer
//================================================= ALL STEPPER ROTATIONS ======================================================
//=======================================================BELOW HERE=============================================================
//==================================================== STEPPER CW 180 ==========================================================
void stepperCW_180() {
if(curDir == 0){ // Checks direction and continues same direction as previous rotation, easier on the stepper
for(int i =0; i < 100; i++){
PORTA = chargeArrayCW[curState]; // Excite motor
if(curState != 3){
curState++;
} else{
curState = 0;
}
stepperTimer(array180[i]);
if(i == 40){// Predrop to allow the piece to fall in the center of the bin
PORTB=0b00000111;//start belt motor
}
}
}else{ //curDir = 1
for(int i = 0; i < 100; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
stepperTimer(array180[i]);
if(i == 40){// Predrop
PORTB = 0b00000111;//start belt motor
}
}
}
}
/* ================================================== STEPPER CCW 90 ================================================================
This function handles single 90 degree rotation and double drop 180 dgree rotation if the following piece also requires a counter
clockwise 90 dgree rotation
==================================================================================================================================
*/
void stepperCCW_90() {
if (thisDir == nextDir){ //Check if this turn is the same as the next direction if so we call the 180 array
if(curDir == 1){
for(int i = 0; i < 100; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
if( bailout_flag == 1){ // If next item is not at exit sensor on time we bail out of the continuous rotation
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0; // Reset flag
PORTB = 0b00000111;
break;
}
} else{
stepperTimer(array180[i]);
}
if(i == 3){
PORTB=0b00000111;// Predrop first piece
}
if(i==32){
if(Buffer_flag == 0){ //If next piece is not at the exit sensor we begin bailout with enough steps to decelerate
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){ // Makes sure next piece is at the exit sensor
PORTB=0b00000111;
Buffer_flag--; // Reset exit sensor flag
dropDone_flag++;
}
}
}
}else{
//changing direction
for(int i =0; i < 100; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
if( bailout_flag == 1){
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
break;
}
} else{
stepperTimer(array180[i]);
}
if(i == 3){
PORTB = 0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB=0b00000111;
Buffer_flag--;
dropDone_flag++;
}
}
}
}
} else{ // Single 90
if(curDir == 1){
//same direction
for(int i =0; i < 50; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
stepperTimer(array90[i]);
if(i == 3){
PORTB = 0b00000111;
}
}
}else{//curDir is 0
//changing direciton
for(int i =0; i < 50; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
stepperTimer(array90[i]);
if(i == 3){
PORTB = 0b00000111;
}
}
}
}
curDir = 1;
}
//=================================================== STEPPER CW 90 ================================================================
void stepperCW_90() {
if (thisDir == nextDir){
if(curDir == 0){
//same direction
for(int i = 0; i < 100; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}
if( bailout_flag == 1){
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
break;
}
} else{
stepperTimer(array180[i]);
}
if(i == 3){
PORTB = 0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB = 0b00000111;
Buffer_flag--;
dropDone_flag++;
}
}
}
}else{//curDir = 1
//changing direction
for(int i =0; i < 100; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}
if( bailout_flag == 1){
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
break;
}
} else{
stepperTimer(array180[i]);
}
if(i == 3){
PORTB = 0b00000111;//start belt
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i==40){
if(bailout_flag==0){
PORTB = 0b00000111;
Buffer_flag--;
dropDone_flag++;
}
}
}
}
} else{ // straight 90
if(curDir == 0){
//same direction
for(int i =0; i < 50; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}
stepperTimer(array90[i]);
if(i == 3){
PORTB = 0b00000111;
}
}
}else{//curDir is 1
//changing direction
for(int i =0; i < 50; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}
stepperTimer(array90[i]);
if(i == 3){
PORTB = 0b00000111;
}
}
}
}
curDir = 0;
}
/* Called when the bucket is already in the correct position, just turns the belt motor on */
void motorOn() {
PORTB = 0b00000111;
}
//=================================================== STEPPERCCW_270 ================================================================
void stepperCCW_270() {
for(int i = 0; i < 150; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
/* Determines if a bailout flag has been thrown and on which piece
If a flag has been thrown, it switches to a different array to handle the deceleration of the stepper
*/
switch(bailout_flag){
case 1:
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 2:
stepperTimer(array180[i]);
if(i == 99){
bailout_flag = 0;
breakout_flag = 1;
}
break;
default:
stepperTimer(array270[i]);
break;
}
if(i ==3 ){
PORTB = 0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB=0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 83){
if(Buffer_flag == 0){
bailout_flag = 2;
}
}
if(i == 90){
if(bailout_flag == 0){
PORTB=0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(breakout_flag != 0){
PORTB = 0b00000111;
break;
}
}
curDir = 1;
}
//=================================================== STEPPERCW_270 ================================================================
void stepperCW_270() {
for(int i = 0; i < 150; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}//if
switch(bailout_flag){
case 1:
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 2:
stepperTimer(array180[i]);
if(i == 99){
bailout_flag = 0;
breakout_flag = 1;
}
break;
default:
stepperTimer(array270[i]);
break;
}
if(i == 3){
PORTB = 0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 83){
if(Buffer_flag == 0){
bailout_flag = 2;
}
}
if(i == 90){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(breakout_flag != 0){
PORTB = 0b00000111;
break;
}
}
curDir = 0;
}
//===================================================STEPPERCCW_360================================================================
void stepperCCW_360() {
for(int i = 0; i < 200; i++){
PORTA = chargeArrayCW[curState];
if(curState != 0){
curState--;
} else{
curState = 3;
}
switch(bailout_flag){
case 1:
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 2:
stepperTimer(array180[i]);
if(i == 99){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 3:
stepperTimer(array270[i]);
if(i == 149){
bailout_flag = 0;
breakout_flag = 1;
}
break;
default:
stepperTimer(array360[i]);
break;
}
if(i == 3){
PORTB = 0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 83){
if(Buffer_flag == 0){
bailout_flag = 2;
}
}
if(i == 90){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 133){
if(Buffer_flag == 0){
bailout_flag = 3;
}
}
if(i == 140){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(breakout_flag != 0){
PORTB = 0b00000111;
break;
}
}
curDir = 1;
}
//===================================================STEPPERCW_360================================================================
void stepperCW_360() {
for(int i = 0; i < 200; i++){
PORTA = chargeArrayCW[curState];
if(curState != 3){
curState++;
} else{
curState = 0;
}
switch(bailout_flag){
case 1:
stepperTimer(array90[i]);
if(i == 49){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 2:
stepperTimer(array180[i]);
if(i == 99){
bailout_flag = 0;
breakout_flag = 1;
}
break;
case 3:
stepperTimer(array270[i]);
if(i == 149){
bailout_flag = 0;
breakout_flag = 1;
}
break;
default:
stepperTimer(array360[i]);
break;
}
if(i == 3){
PORTB=0b00000111;
}
if(i == 32){
if(Buffer_flag == 0){
bailout_flag = 1;
}
}
if(i == 40){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 83){
if(Buffer_flag == 0){
bailout_flag = 2;
}
}
if(i == 90){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(i == 133){
if(Buffer_flag == 0){
bailout_flag = 3;
}
}
if(i == 140){
if(bailout_flag == 0){
PORTB = 0b00000111;
dropDone_flag++;
Buffer_flag--;
}
}
if(breakout_flag != 0){
break;
}
}
curDir = 0;
}
//===================================================ROTATE STEPPER================================================================
/* Used for the home() function
Input is direction and number of steps
*/
void rotateStepper(int dir, int numSteps){ //let 0=CW, 1=CCW
for(int i = 0; i < numSteps; i++){//loop through the numsteps, changing the state between steps
switch (curState) {
case 0:
if(dir == 0){//if CW
curState++;//increase state by 1
PORTA = 0b00000110;//output state 2
}else{ //if CCW
curState = 3; // previous state is 4 so set curState to 4
PORTA = 0b00000101;//output state 4
}//else
break;
case 1:
if(dir == 0){//if CW
curState++;//increase state by 1
PORTA = 0b00101000;//output state 3
}else{ //if CCW
curState--;//decrease state by 1
PORTA = 0b00110000;//output state 1
}//else
break;
case 2:
if(dir == 0){//if CW
curState++;//increase state by 1
PORTA = 0b00000101;//output state 4
}else{//if CCW
curState--;//decrease state by 1
PORTA = 0b00000110;//output state 2
}//else
break;
case 3:
if(dir == 0){//if CW
curState = 0;//next state is state 1 so set curState to state 1
PORTA = 0b00110000;//output state 1
}else{ //if CCW
curState--;//decrease state by 1
PORTA = 0b00101000;//output state 3
}//else
break;
}//switch
mTimer(15);//15 ms delay between states to allow electromagnet charge
} //for
} //rotateStepper
//============================================================================================================
// ===========================================LINKEDLIST STUFF BELOW HERE=====================================
//============================================================================================================
/**************************************************************************************
* DESC: initializes the linked queue to 'NULL' status
* INPUT: the head and tail pointers by reference
*/
void setup(link **h,link **t){
*h = NULL; /* Point the head to NOTHING (NULL) */
*t = NULL; /* Point the tail to NOTHING (NULL) */
return;
}/*setup*/
/**************************************************************************************
* DESC: This initializes a link and returns the pointer to the new link or NULL if error
* INPUT: the head and tail pointers by reference
*/
void initLink(link **newLink){
//link *l;
*newLink = malloc(sizeof(link));
(*newLink)->next = NULL;
return;
}/*initLink*/
/****************************************************************************************
* DESC: Accepts as input a new link by reference, and assigns the head and tail
* of the queue accordingly
* INPUT: the head and tail pointers, and a pointer to the new link that was created
*/
/* will put an item at the tail of the queue */
void enqueue(link **h, link **t, link **nL){
if (*t != NULL){
/* Not an empty queue */
(*t)->next = *nL;
*t = *nL; //(*t)->next;
}/*if*/
else{
/* It's an empty Queue */
//should be this
*h = *nL;
*t = *nL;
}/* else */
return;
}/*enqueue*/
/**************************************************************************************
* DESC : Removes the link from the head of the list and assigns it to deQueuedLink
* INPUT: The head and tail pointers, and a ptr 'deQueuedLink'
* which the removed link will be assigned to
*/
/* This will remove the link and element within the link from the head of the queue */
void dequeue(link **h, link **t, link **deQueuedLink){
*deQueuedLink = *h; // Will set to NULL if Head points to NULL
/* Ensure it is not an empty queue */
if (*h != NULL){
*h = (*h)->next; // move the head to the next link
}/*if*/
if(*h == NULL){
*t = NULL;
}//else
return;
}/*dequeue*/
/**************************************************************************************
* DESC: Peeks at the first element in the list
* INPUT: The head pointer
* RETURNS: The element contained within the queue
*/
/* This simply allows you to peek at the head element of the queue and returns a NULL pointer if empty */
element firstValue(link **h){
return((*h)->e);
}/*firstValue*/
/**************************************************************************************
* DESC: deallocates (frees) all the memory consumed by the Queue
* INPUT: the pointers to the head and the tail
*/
/* This clears the queue */
void clearQueue(link **h, link **t){
link *temp;
while (*h != NULL){
temp = *h;
*h=(*h)->next;
free(temp);
}/*while*/
/* Last but not least set the tail to NULL */
*t = NULL;
return;
}/*clearQueue*/
/**************************************************************************************
* DESC: Checks to see whether the queue is empty or not
* INPUT: The head pointer
* RETURNS: 1:if the queue is empty, and 0:if the queue is NOT empty
*/
/* Check to see if the queue is empty */
char isEmpty(link **h){
if(*h == NULL){
return 1; // Queue is empty
}else{
return 0;//Queue is not empty
}
}/*isEmpty*/
/**************************************************************************************
* DESC: Obtains the number of links in the queue
* INPUT: The head and tail pointer
* RETURNS: An integer with the number of links in the queue
*/
/* returns the size of the queue*/
int size(link **h, link **t){
link *temp; /* will store the link while traversing the queue */
int numElements;
numElements = 0;
temp = *h; /* point to the first item in the list */
while(temp != NULL){
numElements++;
temp = temp->next;
}/*while*/
return(numElements);
}/*size*/