This code accomplishes the same thing the first generation of code had done, except more efficiently. Efficiently in that less wires go to the Arduino. Here, I added a servo controller along with an Input/Output expander made of Multiplexers (4051's). There is smaller versions of these codes as well as wiring documents on the previous page that better explains each. The end accomplishment though is that 18 servos and 18 sensors can be run off of 2 pins (five address pins, one transmit pin, and two outputs) of the Arduino, excluding power and ground.
/*reader pin */ #include <SoftwareSerial.h> SoftwareSerial Servos(10, 11); // RX is digital pin 10 (connect to TX of other device) * TX is digital pin 11 (connect to RX of other device)--we only need to connect pin 11 int n;//first random number int m;//second random number int threshold=30;//of ambient light int targets=6; int score=0;//initialized to 0 int time=1000;//time to hit target once it pops up int TIME=60000;//total time for game==1 minute--and yes 60000 fits into an int int TIME_Played=0;//initialize time played int anodePin=4;//all led's use this pin for their long leg int Apin=14;//A0 int Bpin=15;//A1 int Cpin=16;//A2 int Dpin=17;//A3 int Epin=18;//A4 int cathodePin0=19;//A5 int A; int B; int C; int D; int E; int delays[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //starts all delays at 0 int tworandom(int i,int j);//random funcition generator for second number int reads(int led);//read led int readsavg(int n, int led);//takes average of n readings for led int reset(int servonum);//initialize current servo, reset delay of current servo, assign a new serov to n or m int scores(int servonum);//score when you shoot (shooting aliens==++) int scored(int servonum);//score when you don't shoot (don't shoot humans==++) void talk(int command, int servo, int data1, int data2); void rotate(int servo,int angle); void initialize(void);//sets initial servo positons int convert(int i); void setup() { //deactivates pullup resistors _SFR_IO8(0x35) |= 4; _SFR_IO8(0x35) |= (1<<4); randomSeed(analogRead(0));//select start point of random number chain before setting pin A0 to output--reading analog should allow for random start in chain--wiring led to there may get rid of random start--will just cause every game to be the same--will change for final design, but for this week it would not be a problem n=random(targets); //choose first random number m=tworandom(n,m); //choose second random number based off of the first pinMode(anodePin, OUTPUT); //set pins associated with led light sensors to outputs pinMode(Apin, OUTPUT); pinMode(Bpin, OUTPUT); pinMode(Cpin, OUTPUT); pinMode(Dpin, OUTPUT); pinMode(Epin, OUTPUT); pinMode(cathodePin0, OUTPUT); digitalWrite(anodePin, HIGH); digitalWrite(cathodePin0,LOW); digitalWrite(Apin,LOW); digitalWrite(Bpin,LOW); digitalWrite(Cpin,LOW); digitalWrite(Dpin,LOW); digitalWrite(Epin,LOW); initialize(); Serial.begin(9600);//set up serial communication to monitor Servos.begin(9600); } void loop(){ rotate(m,0);//pop up the first two servos rotate(n,0); Serial.print("n and m are"); Serial.print(n); Serial.println(m); int number=3;//number of times led is read //all delays initialized at 0 or reset to 0 in "reset" delays[m]=delays[m]+(2*number*50);//each read delays 50 so n times 50 is full delay delays[n]=delays[n]+(2*number*50); //read sensors int i = readsavg(number, n);//servo will be 0 to 5 but led is 14 to 19 int j = readsavg(number, m); if((i<threshold)&&(i>0)){ //you hit target n Serial.println("You hit n"); scores(n); n=reset(n,m); /*delaysn=0; initialize(n); n=tworandom(m);//*/ } if((j<threshold)&&(j>0)){ Serial.println("You hit m"); //you hit target m scores(m); /*delaysm=0; initialize(m); m=tworandom(n);*/ m=reset(m,n); } if((delays[n]>time)&&(delays[m]>time)){ Serial.println("ran out of time 0"); /*delaysn=0; delaysm=0; initialize(m); initialize(n); n=random(targets); //choose first random number m=tworandom(n); //choose second random number based off of the first*/ n=reset(n,m); m=reset(m,n); } if(delays[n]>time){ Serial.println("ran out of time 1"); //you ran out of time for target n scored(n); /*delaysn=0; initialize(n); n=tworandom(m);//*/ n=reset(n,m); } if(delays[m]>time){ Serial.println("ran out of time 2"); //you ran out of time for target m scored(m); /*delaysm=0; initialize(m); m=tworandom(n);*/ m=reset(m,n); } TIME_Played=TIME_Played+(2*number*50); if(TIME_Played<TIME){ Serial.print("Game over. Your score is"); Serial.print(score); while(1){ } } } ////////////////////// ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// /////////////////////////////////////////////////////// int tworandom(int i,int j){ //i is the number staying the same j is the one you are changing //chooses second random number that is not the same as the fist or equal to that of its pair int k=0; k=random(targets);//not redundant--if i is not in the first position setting m to 0 at first would cause it to be 0 almost always while(((k%(targets/2))==(i%(targets/2)))||(k==j)){ /*((k-3)==i)||(k==i)||((k+3)==i)||(k==j)*/ k=random(targets); } return k; } int reads(int led){ int val = 0; int vcc=anodePin; convert(led);//get address of led //set multiplexer's to read that address digitalWrite(Apin, A); digitalWrite(Bpin, B); digitalWrite(Cpin, C); digitalWrite(Dpin, D); digitalWrite(Epin, E); digitalWrite(vcc, HIGH); digitalWrite(cathodePin0, LOW); /*Serial.print(A); Serial.print(B); Serial.print(C); Serial.print(D); Serial.println(E);*/ //already emitting light delay(50); //switch potentials -- charge LED to -5V digitalWrite(vcc, LOW); digitalWrite(cathodePin0, HIGH); //measure time for potential to equalize (for cathode to be LOW) //switch pinmode pinMode(cathodePin0, INPUT); //measure time it takes for cathodePin to go to zero //this value probably depends on the chip clock or something while((digitalRead(cathodePin0) != 0)&&(val<100)){ delay(1); val++; } pinMode(cathodePin0, OUTPUT); digitalWrite(vcc, HIGH); digitalWrite(cathodePin0, LOW); //Serial.println(val, DEC); return val; } int readsavg(int n, int led){ int val=0; for(int i=0; i<n; i++){ val=val+reads(led);//read n times and sum } val=val/n;//divide by n for average return val; } int reset(int servonum1, int servonum2){ rotate(servonum1,90);//reset to position delays[servonum1]=0;//reset delays int j=tworandom(servonum2,servonum1);//change 1 based on 2 } int scores(int servonum){ //scores==score when shot if(servonum<=(targets/2)){ //servos 0, 1, 2 are humans score--;//don't shoot humans } if(servonum>((targets/2))){ //servos 3, 4, 5 are aliens score++;//do shoot aliens } } int scored(int servonum){ //scored==scored when did not shoot if(servonum<=(targets/2)){ //servos 0, 1, 2 are humans score++;//good you did not shoot the humans } if(servonum>((targets/2))){ //servos 3, 4, 5 are aliens score--;//baka, you forgot to shoot the aliens--have you seen Independence Day? } } ////////////////////// //////////////////// //Servo Controller void talk(int command, int servo, int data1, int data2){ /* This uses the pololu portocol for controlling the servos--the shorting block must be removed for these commands to work--I say this twice, because it is important. The data 1 is lsb and data 2 is msb, it ignores the first bit, and the units in 1/4 micro seconds. For example, the code uses 0x70, 0x2E->in binary 00111000, 00101110 to indicate 6000 1/4 micro seconds, which is lsb: 0111000, msb: 0101110, but together in proper oder reads as 0x1770. This is further 1500 microseconds which is the 90 degree position--The conversion from degrees to microseconds is covered below. */ Servos.write(0xAA); //start byte Servos.write(0x0C); //device id which is 12 in decimal for the 24 serial servo controller Servos.write(command); //command number Servos.write((byte)servo); //servo number (0-23) Servos.write((byte)data1); //data 1--lsb--lowest 7 bits Servos.write((byte)data2); //data 2--msb--highest 7 bits delay(75); } /* I made this cheat sheet of postions and inputs until a proper conversion was found, it discusses how to convert from degrees to microseconds and then to proper bits need to be sent: Microseconds are found by multiplying by 11 and then adding 500 to degrees--remember that the controller takes ins quarter of a microsecond (four times this number) though and discrads the first bit of data of each data byte (i.e. send the lowest 7 bits with a leading 0 and then the highest 7 bits with a leading 0) The afore said covnversion is found by noting that the signals to the servo controller vary from 500 (0) to 2500 (180). Thus to get zero subtract 500. To get everything else divide 2000 by 180. The result is not exactly 11, but the error is very slight. (microseconds--least significant bit, most significant bit) 500--0X50,0X0F->about 0 degrees 700--0X0F,0X15->18 750--0X38,0X17->22 800--0X00,0X19->27 1000--0X20,0X1F->45 1200--0X40,0X25->63 1500--0X70,0X2E->about 90 degrees 1800--0X20,0X38->118 2500--0X10,0X4E->about 180 degrees */ ///////////////////////////////////////////////////// void rotate(int servo,int angle){ //Uses talk() to send servo to some angle int converted=(angle*11+500)*4;//in quarter microseconds int data2=converted>>7;//most significant bit int data1=converted&0x7F;//least significant bit talk(0x04, servo, data1, data2);//sends data } void initialize(void){ //set all servos to an inital 90 degrees. Allows for rotation in either direction of 90 degrees for(int i=0; i<targets; i++){ rotate(i,90); } delay(250); } int convert(int i){ //converts a decimal number from 0 to 17, inclusively, to binary A=i/16; if(A==1){ i=i-16; B=0; C=0; D=0; E=i; } if(A==0){ B=i/8; if(B==1){ i=i-8; C=i/4; if(C==1){ i=i-4; D=i/2; if(D==1){ i=i-2; E=i; } if(D==0){ E=i; } } if(C==0){ D=i/2; if(D==1){ i=i-2; E=i; } if(D==0){ E=i; } } } if(B==0){ C=i/4; if(C==1){ i=i-4; D=i/2; if(D==1){ i=i-2; E=i; } if(D==0){ E=i; } } if(C==0){ D=i/2; if(D==1){ i=i-2; E=i; } if(D==0){ E=i; } } } } }