Project 1 - Switches and Analogs

My post will be a little light on fritzing pictures because somethings wrong with my installation. As a summary I attached a joystick (2 analog inputs) to control the brightness of two LEDs separately. The two LEDs are above a light sensor (1 more analog input) that detects the changes in brightness and uses that to turn either a red or a green LED on. For the digital inputs I used two buttons to control which one of a 4x4 grid of LEDs was on.

Getting the analog circuit to work was mostly an exercise in sensor calibrating and value mapping. To get the Joystick to output a value from 0-255 instead of ~500 to 1023 in one direction and  0 to ~500 in the other took some creative math. I ended up taking the value of the joystick in the setup method and subtracting that then taking the absolute value and now the joystick increases the brightness no matter which direction you use it on. Getting the light sensor to detect the change from 2 LEDs was more of a pain. I had to take the value in setup to get a baseline then subtract that to see the change which resulted in some weird behavior when it got darker than the baseline. I solved that by clamping it to positive numbers and then treating 50 as the maximum value it could return, which increased dead zone but also made the input much more manageable.

The digital part took a lot more code and wiring work. First I hooked up two buttons and made sure I had a function that could be called when each one was unpressed, which didn't take long. Then I looked into the maximum number of LEDs I could wire into the circuit to achieve a grid that would display a position. I settled on the idea of Charlieplexing which allows you to power N * (N -1) LEDs on N pins. It works by connecting each LED in a matrix to eachother so with any combination if you set all pins to INPUT, one to HIGH, and one to LOW, it powers the LED with its anode on HIGH and its cathode on LOW. The wiring is a huge pain for this and if I had to do it again I would use the wires that go flat against the breadboard and a larger breadboard so its easier. I settled on using 5 pins to power 16 LEDs because I didn't have enough short jumper cables or pins on the breadboard to power more. The wiring almost worked the first try because I took the time to plan it out in a diagram and used color coded wires but one of the LEDs was defective and had to be swapped out. After getting the wiring done then it was time to program them. I chose not to use a library for this because why not. I ended up with a 2d array where the indices represented the row and column of the LED and the value at the indices stored a pin to set HIGH and a pin to set LOW. This works but it isn't the cleanest solution and is a huge pain to set up through trial and error. I also wanted to have a random LED start on each time so I got to use a 4th analog pin with an unconnected wire in it as a random seed which was kind of cool.

Overall I ended up with two buttons that move which LED is on, one moves it left the other up, and a joystick that can control several LEDs and also determine if the movement direction should be reversed. I'm pretty happy with the project but I would want more breadboard space and cleaner wiring next time. The code is included below.


int sensorX = A0;
int sensorY = A1;
int sensorLight = A2;
int sensorClick = 2; 

int buttonH = 4;
int prevH = 0;
int buttonV = 3;
int prevV = 0;

int ledRed = 13;
int ledGreen = 12;
int ledBlue1 = 11;
int ledBlue2 = 10;

int sensorXValue = 0; //base 502
int sensorXMax = 0;

int sensorYValue = 0; // base 508
int sensorYMax = 0;

int sensorLightValue = 0;
int sensorLightBaseline = 0;
int sensorLightMax = 50;

long milliDelay = 250;
long previousMillis = 0;
long currentMillis = 0;

bool mode = true;

//charlieplex variables
#define C1 9 //orange
#define C2 8 // white
#define C3 7 //green
#define C4 6 //yellow
#define C5 5 //purple
const int charliePorts[] = { C1,C2, C3, C4,C5};

typedef struct {
  int on;
  int off;
} charlie;

charlie coords[4][4] = {
  {{C1,C2},{C1,C3},{C1,C4},{C1,C5}},
  {{C2,C1},{C2,C3},{C2,C4},{C2,C5}},
  {{C3,C1},{C3,C2},{C3,C4},{C3,C5}},
  {{C4,C1},{C4,C2},{C4,C3},{C4,C5}}
};

charlie location;
charlie goal;

void setup() {

  // declare the ledPin as an OUTPUT:
  pinMode(ledRed, OUTPUT);
  pinMode(ledGreen, OUTPUT);
  pinMode(ledBlue1, OUTPUT);
  pinMode(ledBlue2, OUTPUT);
  
  pinMode(sensorClick, INPUT_PULLUP); 
  pinMode(buttonH, INPUT_PULLUP);
  pinMode(buttonV, INPUT_PULLUP);
  
  sensorLightBaseline = analogRead(sensorLight);
  Serial.begin(9600);


  Serial.print(analogRead(A3));
  Serial.println();
  randomSeed(analogRead(A3));
  location = {random(0,4),random(0,4)};
  //goal ={random(0,4),random(0,4)};
//loops through each led
  for(int row = 0; row < 4; row = row + 1){
    for(int col = 0; col < 4; col = col + 1){
      //Serial.print(coords[row][col]);
       //CharlieTest(coords[row][col].on,coords[row][col].off);
    }
  }
  Serial.print(location.on);
  Serial.print(location.off);
}

void loop() {
  // read the value from the sensor axis, base around zero as the default value is ~500
  sensorXValue = abs(analogRead(sensorX) - sensorXMax);
  if(sensorXMax < sensorXValue){
    sensorXMax = sensorXValue;
  }
  sensorXValue = map(sensorXValue, 0, sensorXMax,0,255);
  
  sensorYValue = abs(analogRead(sensorY) - sensorYMax);
  if(sensorYMax < sensorYValue){
    sensorYMax = sensorYValue;
  }
  sensorYValue = map(sensorYValue, 0, sensorYMax,0,255);

  //check the light sensor
  sensorLightValue = map(sensorLightBaseline - analogRead(sensorLight),0,50,0,255);
  sensorLightValue = abs(sensorLightValue);
  if(sensorLightValue > sensorLightMax){
    sensorLightMax = sensorLightValue;
  }

  //joystick controlled LEDs
  analogWrite(ledBlue1,sensorXValue);
  analogWrite(ledBlue2,sensorYValue);

  //get the current time
  currentMillis = millis();
  
  //light controlled LEDs
  if(currentMillis - milliDelay > previousMillis){ //prevents flickering and both being on
    if(sensorLightValue > 100){
      digitalWrite(ledGreen, HIGH);
      digitalWrite(ledRed, LOW);
      previousMillis = millis();
      mode = true;
      //Serial.print(">");
  } else {
      digitalWrite(ledRed, HIGH);
      digitalWrite(ledGreen, LOW);
      previousMillis = millis();
      mode = false;
      //Serial.print("<");
  }
  }
  //keep track of buttons
  if(prevH > digitalRead(buttonH)){
    buttonHPress();
  }
  prevH = digitalRead(buttonH);

  if(prevV > digitalRead(buttonV)){
    buttonVPress();
  }
  prevV = digitalRead(buttonV);
  //show location
  if(location.on > 3){
    location.on = 0;
  }
  if(location.on < 0){
    location.on = 3;
  }
  if(location.off > 3){
    location.off = 0;
  }
  if(location.off < 0){
    location.off = 3;
  }
  CharlieTest(coords[location.on][location.off].on,coords[location.on][location.off].off);
  
  //Serial.print(digitalRead(buttonH));
 // Serial.print(" : ");
  //Serial.print(digitalRead(sensorClick));
  //Serial.print(digitalRead(sensorClick));
  //Serial.println();
} //end loop

void CharlieTest(int on, int off){
  for(int i : charliePorts){
     pinMode(i, INPUT);
  }
  pinMode(on, OUTPUT);
  pinMode(off, OUTPUT);
  digitalWrite(on,HIGH);
  digitalWrite(off,LOW);
}

void buttonHPress(){
    if(mode){
      location.on = location.on - 1;
    } else {
      location.on = location.on + 1;
    }
}

void buttonVPress(){
  if(mode){
      location.off = location.off - 1;
    } else {
      location.off = location.off + 1;
    }
}

Comments