You are on page 1of 7

/* Lab 3c code

* weather_patterns.ino
* NAME: James Mayclin
* DATE: 5/23/18
* When run in conjunction with weather_api.py,
* obtains the current weather condition and offers
* a graphical display of said condition. pressing the push
* button toggles the display on and off
*/

/*******************************************************
* Constant Declaration and Global variables *
*******************************************************/

const byte ANODE_PINS[8] = {8, 5, 7, 2, 9, 4, 3, 6};


const byte CATHODE_PINS[8] = {A4, A2, 10, A5, A1, 12, A3, 11};
byte MAX_BRIGHTNESS = 15; //number representing maximum brightness in pattern array
const int BUTTON = A0;
const int DEBOUNCE_DELAY = 75;
const long ANIMATION_CLICK = 500; //milliseconds to wait in each tick of animation
cycle

byte pattern[4][4][4]; //3 dimensional array representing whether each LED is on


and its brightness.
byte drops[4][4]; //array the stores the location of particulate matter in each
column
int weather_state; //denotes current weather state
unsigned long time_between_frame; //time to wait before animating next tick
unsigned long prev_update; //time the animation was last updates
byte lightning_x = 0; // location of lightning striked for thunderstorm animation
byte lightning_y = 0;
bool on = true; //toggles display on or off

/*******************************************************
* Arudino SETUP/LOOP *
*******************************************************/

//Set up all necessary Variables


void setup() {
prev_update = millis();
weather_state = -1;
time_between_frame = 1000;

pinMode(BUTTON, INPUT_PULLUP);
for (byte i = 0; i < 8; i++) {
pinMode(ANODE_PINS[i], OUTPUT); //Set Pins
pinMode(CATHODE_PINS[i], OUTPUT);

digitalWrite(ANODE_PINS[i], HIGH); //Turn pins off


digitalWrite(CATHODE_PINS[i], HIGH);
}

// Initialize serial communication


Serial.begin(115200);
Serial.setTimeout(100);
}
//Main loop of program
void loop() {
gate();
serialHandling();
if (on) {
if (millis() - prev_update > time_between_frame) {
prev_update = millis();
increment(weather_state);
}
// This function gets called every loop
display(pattern);
}
}

//switch statement to call appropriate set method given weather_state


void setPattern(int weather_state) {
switch (weather_state) {
case 0: //thunderstorm
thunderstormS();
break;
case 1: //rain
rainS();
break;
case 2: //snow
snowS();
break;
case 3: //haze
hazeS();
break;
case 4: //clear
clearS();
break;
case 5: //clouds
cloudS();
break;
}
}

//switch statement to call appropriate increment method given weather_state


void increment(int weather_state) {
switch (weather_state) {
case 0:
thunderstormI();
break;
case 1:
rainI();
break;
case 2:
snowI();
break;
case 3:
hazeI();
break;
case 4:
clearI();
break;
case 5:
cloudI();
break;
default:
break;
}
}

//Mapping function from anode and cathde to location in pattern


inline byte getLEDState(byte pattern[4][4][4], byte aNum, byte cNum) {
byte x = cNum & B11;
byte y = aNum & B11;
byte z = (aNum >> 2) + (cNum >> 2) + (((aNum & ~cNum) >> 2) << 1);
return pattern[x][y][z];
}

//Multiplexing code that lights up LED at proper brightness in pattern


void display(byte pattern[4][4][4]){
for (byte aNum = 0; aNum < 8; aNum++) { // iterate through anode (+) wires
for (byte b = 0; b < MAX_BRIGHTNESS; b++) { //Controls brightness
// Set up all the cathode (-) wires first
for (byte cNum = 0; cNum < 8; cNum++) { // iterate through cathode (-) wires
byte value = getLEDState(pattern, aNum, cNum); // look up the value
if (value > b) {
digitalWrite(CATHODE_PINS[cNum], LOW);
} else {
digitalWrite(CATHODE_PINS[cNum], HIGH);
}
}
digitalWrite(ANODE_PINS[aNum], LOW);
delayMicroseconds(50);
digitalWrite(ANODE_PINS[aNum], HIGH);
}
}
}

/*****************************************
* SETTING/INCREMENT Functions *
*****************************************/

//Initialize the drop pattern


void setDropPattern(byte drops[4][4]) {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
drops[i][j] = random(3);
}
}
}

//Set the thunderstorm display


void thunderstormS() {
time_between_frame = ANIMATION_CLICK;
setDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 2, MAX_BRIGHTNESS / 2);
}

//Increment thunderstorm animation


void thunderstormI() {
zeroLightningStrike(pattern, lightning_x, lightning_y);
zeroDropPattern(drops, pattern);
incrementDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 2, MAX_BRIGHTNESS / 2);
if (random(3) == 0) { // 1/3 chance for a lightning strike
lightning_x = random(4);
lightning_y = random(4);
lightningStrike(pattern, lightning_x, lightning_y);
}
}

//Set rain pattern


void rainS() {
time_between_frame = ANIMATION_CLICK;
setDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 2, MAX_BRIGHTNESS / 2);
}

//increment rain pattern


void rainI() {
zeroDropPattern(drops, pattern);
incrementDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 2, MAX_BRIGHTNESS / 2);
}

//set snow pattern


void snowS() {
time_between_frame = ANIMATION_CLICK * 3;
setDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 2, MAX_BRIGHTNESS / 2);
}

//increment snow pattern


void snowI() {
zeroDropPattern(drops, pattern);
incrementDropPattern(drops);
drawCloudsDrop(drops, pattern, MAX_BRIGHTNESS / 3, MAX_BRIGHTNESS / 2);
}

//set haze pattern


void hazeS() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
pattern[i][j][k] = random(1, MAX_BRIGHTNESS / 2);
}
}
}
}

//increment haze pattern


void hazeI() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
pattern[i][j][k] = random(1, MAX_BRIGHTNESS / 2);
}
}
}
}

//set 'clear' pattern


void clearS() {
for (int i = 2; i < 4; i++) {
for (int j = 2; j < 4; j++) {
for (int k = 2; k < 4; k++) {
pattern[i][j][k] = MAX_BRIGHTNESS;
}
}
}
}

//increment 'clear' pattern


//Function just returns because there is no animation.
void clearI() {
return;
}

//Set cloud pattern


void cloudS() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 2; k < 4; k++) {
pattern[i][j][k] = MAX_BRIGHTNESS/2;
}
}
}
}

//increment cloud pattern


void cloudI() {
return;
}

/*******************************************************
* Weather Helper Functions *
*******************************************************/

//Draw clouds and drop pattern (used by multiple methods). Avoids having to loop
over all 64 elements.
void drawCloudsDrop(byte drops[4][4], byte pattern[4][4][4], byte drop_brightness,
byte cloud_brightness) {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
pattern[i][j][3] = cloud_brightness;
pattern[i][j][drops[i][j]] = drop_brightness;
}
}
}
//Zero out the drops in the LED pattern
void zeroDropPattern(byte drops[4][4], byte pattern[4][4][4]) {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
pattern[i][j][drops[i][j]] = 0;
}
}
}

//Increment the drop pattern to the next frame


void incrementDropPattern(byte drops[4][4]) {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
drops[i][j] = (drops[i][j] - 1 + 3) % 3;
}
}
}
//Lightning strike.
void lightningStrike(byte pattern[4][4][4], byte x, byte y) {
for (int i = 0; i < 4; i++) {
pattern[x][y][i] = MAX_BRIGHTNESS;
}
}

//Zeros out lightning strike.


void zeroLightningStrike(byte pattern[4][4][4], byte x, byte y) {
for (int i = 0; i < 4; i++) {
pattern[x][y][i] = 0;
}
}

//zeros out a pattern


void zeroPattern(byte pattern[4][4][4]) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
pattern[i][j][k] = 0;
}
}
}
}

/*******************************************************
* IO Function *
*******************************************************/

//Handles serial input


void serialHandling() {
if (Serial.available()) {
zeroPattern(pattern);

// Parse the values from the serial


weather_state = Serial.parseInt();

// Check for input validity


if (Serial.read() != '\n') {
Serial.println("invalid input - check that line ending is set to \"Newline\";
input must be three numbers");
return;
}

if (weather_state < 0 || weather_state > 10) {


Serial.println("Not recognized code");
return;
}

setPattern(weather_state);
}
}

//Toggles on state and debounces button


void gate() {
static int counter = 0; // count (debounced) button presses
static byte button_state = HIGH;
static byte last_reading = HIGH;
static long last_reading_change = 0;
static char message[50]; // buffer for sprintfs

byte reading = digitalRead(BUTTON);


unsigned long now = millis();

if (now - last_reading_change > DEBOUNCE_DELAY) {


if (reading == LOW && button_state == HIGH) { // button pressed down (HIGH to
LOW)
on = !on;
}
button_state = reading;
}

// Prepare for next loop


if (reading != last_reading) last_reading_change = now;
last_reading = reading;
}

You might also like