Hi everyone!
I'm new to the forum and excited to be here. I've been working on an ambitious project to create a multi-functional computer using Arduino. It's been quite a journey, and the project is still a work in progress.
I've recently decided to transition the project to use an ESP32 because of its Bluetooth capabilities, which opens up a lot of possibilities for control and connectivity.
Below is my old program code. It's not perfect, but I gave it my all. Since it's quite long, remember that it's designed for a multi-functional computer. I would love to hear your thoughts on it and any advice you might have!
/*
* Project: Arduino Computer
* Author: Logan.W. (LoganTheEngineer)
* Description: This code is part of an Arduino-based computer system using the ATmega2560 microcontroller.
* It includes functionalities for environmental sensing, motion detection, distance measurement,
* remote control handling, display management, and more.
*
* computer: "LoganMultiFunctionComputer"
*
* version: 0.0.1.
*
* processor: ATMEGA2560/ATMEGA1280. it doesn't matter, as long as they have lots of pins and storage.
*
* development board: Arduino MEGA2560/Arduino MEGA. it doesn't matter, as long as they have lots of pins and storage.
*
* UART_processor: MEGA16U2.
*
* clockSpeed: 16MHz.
*
* MAX_overClockSpeed: 24MHz.
*
* COM_address: 4.
*
* cores: 4.
*
* pins: 70. (no shift regiaters are included in this calculation, this calculation includes ALL Arduino pins.)
*
* max pin current draw: 40mA.
*
* max voltage: 12V though power adapter, this is not recommended. 5V though vin/USB, however is recommended.
*
* max current: 500mA though power adapter, which can cause significant heat, this is not recommended. 1.5A though vin/USB, however is recommended.
*
* CPU board max current to CPU: 200mA.
*
* Disclaimer: This code, part of the "LoganMultiFunctionComputer" project, is created by Logan W. (LoganTheEngineer)
* for educational and personal use only. It is not affiliated with any commercial company or official entity.
* Any resemblance to actual company names, logos, or trademarks is purely coincidental and unintentional.
* Components and parts used in this system may be derived from various official manufacturers; however,
* their inclusion does not imply any endorsement or association with LoganTheEngineer. LoganTheEngineer
* assumes no responsibility for any misuse of logos or other intellectual property.
*/
#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
// Code specific to the Arduino MEGA2560/MEGA
#pragma message("Correct microcontroller. Arduino MEGA/MEGA2560 is reqiured for direct port manipulation, storage, and computing speeds.")
#warning The computer code is currently under development, if any issues happen to occur, please contact Logan.
#warning WARNING: All of this new stuff is all experimental so it might have some issues.
#warning Please adjust the interrupt and ISR if it does not work, the interrupt and ISR may vary from microcontroller to microcontroller.
// now run rest of code since there's no error.
#else
#error "This code is intended for the Arduino MEGA2560/MEGA with ATmega2560/ATmega1280 microcontroller. Please select the correct board in your IDE."
#endif
#include <EEPROM.h> // the required libries.
#include <Wire.h>
#include <dht_nonblocking.h>
#include <IRremote.hpp>
#include "MPU6050.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OUTPUT_PULLHIGH 0x3
enum ColorFadeConstants{FADE, CYCLE};
enum SSD1306_constants{SCREEN_WIDTH = 128, SCREEN_HEIGHT = 64, OLED_RESET = -1, SCREEN_ADDRESS = 0x3C};
enum pedometer_distanceTypes{MILES_PER_HOUR, METERS_PER_SECOND, KILOMETERS_PER_HOUR, FEET_PER_SECOND};
enum pedometer_energyTypes{CALORIES, KILOCALORIES, JOULES, KILOJOULES};
enum ColorList{COLOR_BY_BLACK, COLOR_BY_LIGHT_RED, COLOR_BY_RED, COLOR_BY_DARK_RED, COLOR_BY_LIGHT_GREEN,COLOR_BY_GREEN, COLOR_BY_DARK_GREEN,
COLOR_BY_LIGHT_BLUE, COLOR_BY_BLUE, COLOR_BY_DARK_BLUE, COLOR_BY_YELLOW, COLOR_BY_CYAN, COLOR_BY_MAGENTA, COLOR_BY_ORANGE, COLOR_BY_DARK_ORANGE,
COLOR_BY_GOLD, COLOR_BY_LIME, COLOR_BY_PURPLE, COLOR_BY_PINK, COLOR_BY_DEEP_PINK, COLOR_BY_INDIGO, COLOR_BY_VIOLET, COLOR_BY_DARK_VIOLET,
COLOR_BY_WHITE};
enum UsbSlowCharger{USB_SLOW_CHARGER_PIN = 4};
enum recorder{RECORD, PLAY, MAX_REC_ADDRESS = 2008, USED_LOWER_NUMBER_ADDRESSES = 8};
enum MPU6050_compass{NORTH, NORTH_WEST, WEST, SOUTH_WEST, SOUTH, SOUTH_EAST, EAST, NORTH_EAST};
enum rebootPin{resetTrigPin = 5};
enum months{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
enum tempTypes{CELSIUS, FAHRENHEIT, KELVIN};
enum clockTypes{AM, PM};
enum DHT_info{DHT_PIN = A0, DHT_TYPE = DHT_TYPE_11};
enum ultrasonicDistanceSensorPins{ECHO_PIN = 8, TRIG_PIN = 2};
enum distanceTypes{MM, CM, IN, FT, YD, M};
enum mainShiftRegisterInPins{MAIN_DATA_PIN = 10, MAIN_CLOCK_PIN = 12, MAIN_LATCH_PIN = 11};
enum DisableByResetingValueBackToZero{DISABLE};
//daisy-chain shift registers together to get a higher-bit shift register.
enum mainShiftRegisterBits{MAIN_SHIFT_REGISTER_8_BIT = 8, MAIN_SHIFT_REGISTER_16_BIT = 16, MAIN_SHIFT_REGISTER_24_BIT = 24,
MAIN_SHIFT_REGISTER_32_BIT = 32, MAIN_SHIFT_REGISTER_40_BIT = 40, MAIN_SHIFT_REGISTER_48_BIT = 48, MAIN_SHIFT_REGISTER_56_BIT = 56,
MAIN_SHIFT_REGISTER_64_BIT = 64, MAIN_SHIFT_REGISTER_72_BIT = 72, MAIN_SHIFT_REGISTER_80_BIT = 80, MAIN_SHIFT_REGISTER_88_BIT = 88};
enum IR_remoteButtonMap{POWER = 0xBA45FF00, FUNC_OR_STOP = 0xB847FF00, INCREMENT_VOL = 0xB946FF00, FAST_BACK = 0xBB44FF00,
PAUSE_OR_PLAY = 0xBF40FF00, FAST_FORWARD = 0xBC43FF00, DOWN = 0xF807FF00, DECREMENT_VOL = 0xEA15FF00, UP = 0xF609FF00,
EQ = 0xE619FF00, ST_OR_REPT = 0xF20DFF00, ZERO = 0xE916FF00, ONE = 0xF30CFF00, TWO = 0xE718FF00, THREE = 0xA15EFF00,
FOUR = 0xF708FF00, FIVE = 0xE31CFF00, SIX = 0xA55AFF00, SEVEN = 0xBD42FF00, EIGHT = 0xAD52FF00, NINE = 0xB54AFF00};
enum currentMainShiftRegisterSize{MAIN_SHIFT_REGISTER_SIZE = MAIN_SHIFT_REGISTER_8_BIT};//i'm using an 8-bit shift register. how about you?
enum calculatorSettings{MULTIPLICATION, DIVISION, ADDITION, SUBTRACTION, SQUARED, CUBED, ABSOLUTE_VALUE, TO_THE_POWER_OF, REMAINDER, LOG, SIN, COS,
PERCENT, PERCENTAGE_VALUE, NUM_TO_BOOL, PERCENTAGE_TO_FBOOL};
enum IR_receiver{receiverPin = 9};
uint8_t ShiftPWMArray[8];
uint16_t ShiftToneArray[8];
MPU6050 mpu;
DHT_nonblocking DHT(DHT_PIN, DHT_TYPE);
IRrecv IR_Receiver(receiverPin);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const uint8_t degree_bitmap[] PROGMEM = {
0b00111100,
0b01000010,
0b01000010,
0b00111100,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
const uint8_t cloud_bitmap[] PROGMEM = {
0b00011110,
0b01111110,
0b11111111,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
const uint8_t rainy_bitmap[] PROGMEM = {
0b00011110,
0b01111110,
0b11111111,
0b00000000,
0b10001000,
0b10001000,
0b00100010,
0b00100010
};
const uint8_t snowy_bitmap[] PROGMEM = {
0b00011110,
0b01111110,
0b11111111,
0b01000000,
0b11100100,
0b01001110,
0b00000100,
0b00000000
};
const uint8_t lightning_cloud_bitmap[] PROGMEM = {
0b00111000,
0b01111100,
0b11111111,
0b11111111,
0b00010000,
0b00111100,
0b00001000,
0b00010000
};
const uint8_t sunny_bitmap[] PROGMEM = {
0b00000000,
0b10011001,
0b01011010,
0b00111100,
0b00111100,
0b01011010,
0b10011001,
0b00000000
};
const uint8_t lightbulb_bitmap[] PROGMEM = {
0b00111100,
0b11111111,
0b11111111,
0b11111111,
0b01111110,
0b00111100,
0b00111100,
0b00011000
};
const uint8_t halfBright_lightbulb_bitmap[] PROGMEM = {
0b00111100,
0b11101011,
0b10101011,
0b11010101,
0b01010110,
0b00111100,
0b00111100,
0b00011000
};
const uint8_t dark_lightbulb_bitmap[] PROGMEM = {
0b00111100,
0b11000011,
0b10000001,
0b10000001,
0b01000010,
0b00111100,
0b00111100,
0b00011000
};
const uint8_t LoganComputerBootupSymbol_bitmap[] PROGMEM = {
0b00000000,
0b10000000,
0b10011100,
0b10100000,
0b10100000,
0b10011100,
0b10000000,
0b11111000
};
const uint8_t up_arrow_bitmap[] PROGMEM = {
0b00011000,
0b00111100,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000
};
const uint8_t down_arrow_bitmap[] PROGMEM = {
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00111100,
0b00011000
};
const uint8_t left_arrow_bitmap[] PROGMEM = {
0b00000000,
0b00000000,
0b01000000,
0b11111111,
0b11111111,
0b01000000,
0b00000000,
0b00000000
};
const uint8_t right_arrow_bitmap[] PROGMEM = {
0b00000000,
0b00000000,
0b00000010,
0b11111111,
0b11111111,
0b00000010,
0b00000000,
0b00000000
};
const uint8_t top_left_arrow_bitmap[] PROGMEM = {
0b11100000,
0b11000000,
0b10100000,
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000001
};
const uint8_t top_right_arrow_bitmap[] PROGMEM = {
0b00000111,
0b00000011,
0b00000101,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000
};
const uint8_t bottom_left_arrow_bitmap[] PROGMEM = {
0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b10100000,
0b11000000,
0b11100000
};
const uint8_t bottom_right_arrow_bitmap[] PROGMEM = {
0b10000000,
0b01000000,
0b00100000,
0b00010000,
0b00001000,
0b00000101,
0b00000011,
0b00000111,
};
const uint8_t white_square_bitmap[] PROGMEM = {
0b00000000,
0b01111110,
0b01111110,
0b01111110,
0b01111110,
0b01111110,
0b01111110,
0b00000000
};
const uint8_t black_square_bitmap[] PROGMEM = {
0b11111111,
0b10000001,
0b10000001,
0b10000001,
0b10000001,
0b10000001,
0b10000001,
0b11111111
};
const uint8_t waterdrop_bitmap[] PROGMEM = {
0b00000000,
0b00001000,
0b00001000,
0b00011100,
0b00011100,
0b00111110,
0b00111110,
0b00011100
};
const uint8_t snowflake_bitmap[] PROGMEM = {
0b00000000,
0b01001001,
0b00101010,
0b00011100,
0b01110111,
0b00011100,
0b00101010,
0b01001001
};
const uint8_t flame_bitmap[] PROGMEM = {
0b00000000,
0b00000000,
0b00000000,
0b00001000,
0b00011100,
0b00111110,
0b00111110,
0b00011100
};
const uint8_t warning_bitmap[] PROGMEM = {
0b00000000,
0b00001000,
0b00010100,
0b00101010,
0b00101010,
0b01000001,
0b01001001,
0b01111111
};
const uint8_t hot_surface_bitmap[] PROGMEM = {
0b01010001,
0b10001010,
0b01010001,
0b10001010,
0b01010001,
0b10001010,
0b00000000,
0b11111111
};
const uint8_t crossed_square_bitmap[] PROGMEM = {
0b11111111,
0b11000011,
0b10100101,
0b10011001,
0b10011001,
0b10100101,
0b11000011,
0b11111111
};
const uint8_t circled_square_bitmap[] PROGMEM = {
0b11111111,
0b10000001,
0b10111101,
0b10100101,
0b10100101,
0b10111101,
0b10000001,
0b11111111
};
const uint8_t hourglass_bitmap[] PROGMEM = {
0b11111111,
0b10000001,
0b10000001,
0b01111110,
0b00111100,
0b01011010,
0b10111101,
0b11111111,
};
void setup() {
setupRebootPin(resetTrigPin);
fastPinSetup(MAIN_DATA_PIN, OUTPUT);
fastPinSetup(MAIN_CLOCK_PIN, OUTPUT);
fastPinSetup(MAIN_LATCH_PIN, OUTPUT);
// Set up Timer1
TCCR1A = _BV(WGM11); // Configure for Fast PWM mode using ICR1 as top
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // Set mode, fast PWM, and no prescaling
ICR1 = 100; // Set the top value for Timer1 (defines PWM frequency)
OCR1A = 0; // Set the compare match value for OCR1A
// Enable Timer1 compare interrupt
TIMSK1 = _BV(OCIE1A); // Enable interrupt on compare match with OCR1A
}
ISR(TIMER1_COMPA_vect) {
volatile uint8_t *MAIN_dataPinPort = portOutputRegister(digitalPinToPort(MAIN_DATA_PIN));
volatile uint8_t *MAIN_clockPinPort = portOutputRegister(digitalPinToPort(MAIN_CLOCK_PIN));
volatile uint8_t *MAIN_latchPinPort = portOutputRegister(digitalPinToPort(MAIN_LATCH_PIN));
volatile uint8_t *READ_MAIN_latchPinPort = portInputRegister(digitalPinToPort(MAIN_LATCH_PIN));
uint8_t MAIN_dataPinBit = digitalPinToBitMask(MAIN_DATA_PIN);
uint8_t MAIN_clockPinBit = digitalPinToBitMask(MAIN_CLOCK_PIN);
uint8_t MAIN_latchPinBit = digitalPinToBitMask(MAIN_LATCH_PIN);
static bool ToneprevState[MAIN_SHIFT_REGISTER_SIZE];
static bool PWM_prevState[MAIN_SHIFT_REGISTER_SIZE];
static uint8_t pwmTimer = 0;
static uint16_t toneTimer = 0;
bool pwmToggle = 0;
uint16_t period = 0;
bool toneToggle = 0;
if((*READ_MAIN_latchPinPort & MAIN_latchPinBit) != 0){
toneTimer = (toneTimer < period) ? toneTimer+1:0;
pwmTimer = (pwmTimer < 255)?pwmTimer+5:0;
*MAIN_latchPinPort &= ~MAIN_latchPinBit;
for (int i = 0; i < MAIN_SHIFT_REGISTER_SIZE; i++) {
period = (ShiftToneArray[i] == 0)?0:30000/ShiftToneArray[i];
toneToggle = (toneTimer < period / 2);
if (toneToggle != ToneprevState[i]) {
(toneToggle)?*MAIN_dataPinPort |= MAIN_dataPinBit:*MAIN_dataPinPort &= ~MAIN_dataPinBit;
*MAIN_clockPinPort |= MAIN_clockPinBit;
*MAIN_clockPinPort &= ~MAIN_clockPinBit;
ToneprevState[i] = toneToggle; // Update the previous state
}
}
*MAIN_latchPinPort |= MAIN_latchPinBit;
*MAIN_latchPinPort &= ~MAIN_latchPinBit;
for (int i = 0; i < MAIN_SHIFT_REGISTER_SIZE; i++) {
if(ShiftPWMArray[i] > 0 && ShiftPWMArray[i] < 255){
pwmToggle = (pwmTimer < ShiftPWMArray[i]);
}else{
pwmToggle = true;
}
if (pwmToggle != PWM_prevState[i]) {
(pwmToggle)?*MAIN_dataPinPort |= MAIN_dataPinBit:*MAIN_dataPinPort &= ~MAIN_dataPinBit;
*MAIN_clockPinPort |= MAIN_clockPinBit;
*MAIN_clockPinPort &= ~MAIN_clockPinBit;
PWM_prevState[i] = pwmToggle; // Update the previous state
}
}
*MAIN_latchPinPort |= MAIN_latchPinBit;
}
}
void loop() {
//do nothing for now.
}
//currently set to 8 bits.
void MainShiftRegisterWrite(uint8_t portToWrite, bool val){
volatile uint8_t *MAIN_dataPinPort = portOutputRegister(digitalPinToPort(MAIN_DATA_PIN));
volatile uint8_t *MAIN_clockPinPort = portOutputRegister(digitalPinToPort(MAIN_CLOCK_PIN));
volatile uint8_t *MAIN_latchPinPort = portOutputRegister(digitalPinToPort(MAIN_LATCH_PIN));
uint8_t MAIN_dataPinBit = digitalPinToBitMask(MAIN_DATA_PIN);
uint8_t MAIN_clockPinBit = digitalPinToBitMask(MAIN_CLOCK_PIN);
uint8_t MAIN_latchPinBit = digitalPinToBitMask(MAIN_LATCH_PIN);
static bool state[MAIN_SHIFT_REGISTER_SIZE]; //Adjust the size of the state array based on the bit of the register or number of registers.
static bool prevState[MAIN_SHIFT_REGISTER_SIZE];
state[portToWrite] = val;
*MAIN_latchPinPort &= ~MAIN_latchPinBit;
for (int i = 0; i < MAIN_SHIFT_REGISTER_SIZE; i++) {
if (state[i] != prevState[i]) {
(state[i])?*MAIN_dataPinPort |= MAIN_dataPinBit:*MAIN_dataPinPort &= ~MAIN_dataPinBit;
*MAIN_clockPinPort |= MAIN_clockPinBit;
*MAIN_clockPinPort &= ~MAIN_clockPinBit;
prevState[i] = state[i]; // Update the previous state
}
}
*MAIN_latchPinPort |= MAIN_latchPinBit;
}
bool PIR_Read(uint8_t pin, uint32_t delay) {
// delay is how long to keep alarm triggered once triggered.
static bool motionDetected = false;
static uint32_t lastMotionTime = 0;
bool currentState = digitalRead(pin);
if (currentState && !motionDetected) {
lastMotionTime = millis();
motionDetected = true;
}
if (millis() - lastMotionTime > delay) {
motionDetected = false;
}
return motionDetected;
}
void DHT_Read(float *temperature, float *humidity, uint8_t tempType)
{
static uint32_t timeStart;
float temp;
float humid;
timeStart = millis();
if(millis()-timeStart > 250){
if(DHT.measure(&temp, &humid)){
switch(tempType){
case CELSIUS:
*temperature = temp;
break;
case FAHRENHEIT:
*temperature = (temp*1.8)+32;
break;
case KELVIN:
*temperature = temp+273.15;
break;
default:
*temperature = temp;
}
*humidity = humid;
}
}
}
double ReadDistance(uint8_t OutputPin, uint8_t InputPin, bool state, uint8_t convertTo, uint32_t pulse_us){
volatile uint8_t *pulseOutPort = portOutputRegister(digitalPinToPort(OutputPin));
volatile uint8_t *pulseInPort = portInputRegister(digitalPinToPort(InputPin));
uint8_t PulseInBit = digitalPinToBitMask(InputPin);
uint8_t PulseOutBit = digitalPinToBitMask(OutputPin);
uint32_t timeout = 40000;
uint32_t pulseStart = micros();
uint32_t startMicros = micros();
uint32_t pulseStartMicros;
uint32_t pulseEndMicros;
uint32_t pulsePeriod;
const double speedOfSoundCmPerSec = 34350.0; // Speed of sound in cm/s
const double CF = speedOfSoundCmPerSec / 1000000.0 / 2.0;
double distance;
while(micros()-pulseStart < pulse_us){
*pulseOutPort |= PulseOutBit;
*pulseOutPort &= ~PulseOutBit;
}
while (((*pulseInPort & PulseInBit) != 0) != state && micros() - startMicros <= timeout);
pulseStartMicros = micros();
while (((*pulseInPort & PulseInBit) != 0) == state && micros() - pulseStartMicros <= timeout);
pulseEndMicros = micros();
if(pulseEndMicros - pulseStartMicros <= timeout){
pulsePeriod = pulseEndMicros - pulseStartMicros;
distance = pulsePeriod*CF; // Calculate distance in cm
switch(convertTo){
case MM:
distance *= 10.0; // Convert cm to mm
break;
case IN:
distance /= 2.54; // Convert cm to inches
break;
case FT:
distance /= 30.48; // Convert cm to feet
break;
case YD:
distance /= 91.44; // Convert cm to yards
break;
case M:
distance /= 100.0; // Convert cm to meters
break;
}
return distance;
}else{
return(NAN);
}
}
uint8_t ReadLight(uint8_t pin){
uint8_t output;
output = 100*(analogRead(pin)/1023.0);
return(output);
}
uint8_t ReadNCVNS(uint8_t pin){ //Non-Contact Volage / Noise sensor, thus the name NCVNS.
static uint8_t output;
uint16_t input;
input = analogRead(pin);
output = 0.01*input+(1.0-0.01)*output;
return(100*(output/1023));
}
void IR_Remote(bool *powerButtonIsPressed, bool *funcOrStopButtonIsPressed, bool *incrementVolButtonIsPressed, bool *fastBackButtonIsPressed,
bool *pauseOrPlayButtonIsPressed, bool *fastForwardButtonIsPressed, bool *downButtonIsPressed, bool *decrementVolButtonIsPressed,
bool *upButtonIsPressed, bool *EQ_buttonIspressed, bool *stOrReptButtonIspressed, bool *zeroButtonIspressed, bool *oneButtonIspressed,
bool *twoButtonIspressed, bool *threeButtonIspressed, bool *fourButtonIspressed, bool *fiveButtonIspressed, bool *sixButtonIspressed,
bool *sevenButtonIspressed, bool *eightButtonIspressed, bool *nineButtonIspressed){
//assign all variables to zero before we begin.
*powerButtonIsPressed = 0;
*funcOrStopButtonIsPressed = 0;
*incrementVolButtonIsPressed = 0;
*fastBackButtonIsPressed = 0;
*pauseOrPlayButtonIsPressed = 0;
*fastForwardButtonIsPressed = 0;
*downButtonIsPressed = 0;
*decrementVolButtonIsPressed = 0;
*upButtonIsPressed = 0;
*EQ_buttonIspressed = 0;
*stOrReptButtonIspressed = 0;
*zeroButtonIspressed = 0;
*oneButtonIspressed = 0;
*twoButtonIspressed = 0;
*threeButtonIspressed = 0;
*fourButtonIspressed = 0;
*fiveButtonIspressed = 0;
*sixButtonIspressed = 0;
*sevenButtonIspressed = 0;
*eightButtonIspressed = 0;
*nineButtonIspressed = 0;
if(IR_Receiver.available()){
switch (IR_Receiver.decodedIRData.decodedRawData){
case POWER: *powerButtonIsPressed = 1; break;
case FUNC_OR_STOP:*funcOrStopButtonIsPressed = 1; break;
case INCREMENT_VOL: *incrementVolButtonIsPressed = 1; break;
case FAST_BACK: *fastBackButtonIsPressed = 1; break;
case PAUSE_OR_PLAY: *pauseOrPlayButtonIsPressed = 1; break;
case FAST_FORWARD: *fastForwardButtonIsPressed = 1; break;
case DOWN: *downButtonIsPressed = 1; break;
case DECREMENT_VOL: *decrementVolButtonIsPressed = 1; break;
case UP: *upButtonIsPressed = 1; break;
case EQ: *EQ_buttonIspressed = 1; break;
case ST_OR_REPT: *stOrReptButtonIspressed = 1; break;
case ZERO: *zeroButtonIspressed = 1; break;
case ONE: *oneButtonIspressed = 1; break;
case TWO: *twoButtonIspressed = 1; break;
case THREE: *threeButtonIspressed = 1; break;
case FOUR: *fourButtonIspressed = 1; break;
case FIVE: *fiveButtonIspressed = 1; break;
case SIX: *sixButtonIspressed = 1; break;
case SEVEN: *sevenButtonIspressed = 1; break;
case EIGHT: *eightButtonIspressed = 1; break;
case NINE: *nineButtonIspressed = 1; break;
default:
return; //we can't use an error. can we? break is not required in this default case as return ends the function.
}
}
IR_Receiver.resume();
}
void MainShiftRegisterAnalogWrite(uint8_t pin, uint8_t val){
ShiftPWMArray[pin] = val;
}
void MainShiftRegisterTone(uint8_t pin, uint16_t frequency){
ShiftToneArray[pin] = frequency;
}
void NoMainShiftRegisterAnalogWrite(uint8_t pin, uint8_t val){
ShiftPWMArray[pin] = DISABLE;
}
void NoMainShiftRegisterTone(uint8_t pin, uint16_t frequency){
ShiftToneArray[pin] = DISABLE;
}
bool isLeapYear(uint16_t year) {
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
void CLOCK(uint8_t setTimeSeconds, uint8_t setTimeMinutes, uint8_t setTimeHours, uint8_t setDay, uint8_t setMonth, uint16_t setYear,
uint8_t CLOCK_TYPE, uint8_t *GetSeconds, uint8_t *GetMinutes,uint8_t *GetHours, uint8_t *GetDay, uint8_t *GetMonth, uint16_t *GetYear,
uint8_t *return_type){
static uint32_t timeStart;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;
static uint8_t day;
static uint8_t month;
static uint16_t year;
static bool DST;
static bool runClock;
static uint8_t clock_type;
uint8_t daysInMonth[] = {31, uint8_t((isLeapYear(year))?29:28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(hour > 0 && day > 0 && year > 0 && runClock){
if(millis()-timeStart >= 1000){
timeStart = millis();
if(sec < 60){
sec++;
}else{
min++;
sec = 0;
}
if(min == 60){
hour++;
min = 0;
}
if(hour > 12){
clock_type = !clock_type;
hour = 1;
}
*GetSeconds = sec;
*GetMinutes = min;
*GetHours = hour;
*return_type = clock_type;
}
if(hour == 12 && clock_type == 0){
day++;
}
if(day < daysInMonth[month]){
month++;
day = 1;
}
if(month == 3 && !DST && day == 10){
hour++;
DST = !DST;
}else if(month == 10 && DST && day == 3){
hour--;
DST = !DST;
}
if(month > Dec){
month = Jan;
year++;
}
}
if(setTimeHours > 0 && setTimeHours <= 12 && setTimeMinutes < 60 && setTimeSeconds < 60 && CLOCK_TYPE < 2 && setDay > 0 && setMonth >= Jan
&& setMonth <= Dec && setYear > 0){
if(setDay <= daysInMonth[setMonth]){
day = setDay;
}else{
return;
}
month = setMonth;
year = setYear;
sec = setTimeSeconds;
min = setTimeMinutes;
hour = setTimeHours;
clock_type = CLOCK_TYPE;
if(!runClock){
timeStart = millis();
runClock = true;
}
}
}
void LCD_Refresh(uint16_t refreshRateHz, bool *timeToWriteOLED, bool holdPreviousImage){
static uint32_t timeStamp = micros();
*timeToWriteOLED = 0;
if(refreshRateHz > 0){
uint32_t delay = 1000000/refreshRateHz;
if(micros()-timeStamp >= delay){
if(!holdPreviousImage){
display.fillScreen(BLACK);
display.display();
}
timeStamp = micros();
*timeToWriteOLED = true;
}
}else{
*timeToWriteOLED = false; /* If you set refreshRateHz to 0, your screen will freeze up, so uh, don't do that. However, I can't stop you.
If you freeze your screen, a reboot/reset is necessary. There is a built-in RST button, press that,
since you can't software-wise with a frozen screen. */
}
}
float calculator(float X, float Y, int mode){ //i know, i'm working on this and everything else.
float result;
switch(mode){
case MULTIPLICATION:
result = X*Y;
break;
case DIVISION:
result = (Y >= 0.01 || Y <= -0.01)?X/Y:NAN;
break;
case ADDITION:
result = X+Y;
break;
case SUBTRACTION:
result = X-Y;
break;
case SQUARED:
result = pow(X, 2.0);
break;
case CUBED:
result = pow(X, 3.0);
break;
case ABSOLUTE_VALUE:
result = (X < 0)?-X:X;
break;
case TO_THE_POWER_OF:
result = pow(X, Y);
break;
case REMAINDER:
result = (Y >= 0.01 || Y <= -0.01)?fmod(X, Y):NAN;
break;
case LOG:
result = log(X);
break;
case SIN:
result = sin(X);
break;
case COS:
result = cos(X);
break;
case PERCENT:
result = X*0.01;
break;
case PERCENTAGE_VALUE:
result = X*100.0;
break;
case NUM_TO_BOOL:
result = (X < 0.5)?0:1;
break;
case PERCENTAGE_TO_FBOOL:
result = (X >= 0 && X <= 100)?X*0.01:NAN;
break;
default:
return(NAN);
}
return(result);
}
void fastPinSetup(uint8_t pin, uint8_t mode){
uint8_t pinBit = digitalPinToBitMask(pin);
volatile uint8_t *setMode = portModeRegister(digitalPinToPort(pin));
volatile uint8_t *pinState = portOutputRegister(digitalPinToPort(pin));
switch(mode){
case INPUT:
*setMode &= ~pinBit;
*pinState &= ~pinBit;
break;
case OUTPUT:
*setMode |= pinBit;
*pinState &= ~pinBit;
break;
case INPUT_PULLUP:
*setMode &= ~pinBit;
*pinState |= pinBit;
break;
case OUTPUT_PULLHIGH: //#define OUTPUT_PULLHIGH 0x3
*setMode |= pinBit;
*pinState |= pinBit;
break;
default:
// "INPUT".
*setMode &= ~pinBit;
*pinState &= ~pinBit;
}
}
bool isNAN(float val){
return(val != val);
}
bool isPOS_INFINITY(float val){
return(val == INFINITY);
}
bool isNEG_INFINITY(float val){
return(val == -INFINITY);
}
bool isOVF(float val, float limit){
return(val > limit); //float doesn't have an OVF (overflow) value, so this is for displays & stuff.
}
bool isUNF(float val, float limit){
return(val < limit); //float doesn't have an UNF (underflow) value, so this is for displays & stuff.
}
void setupRebootPin(uint8_t pin){
uint8_t pinBit = digitalPinToBitMask(pin);
volatile uint8_t *setMode = portModeRegister(digitalPinToPort(pin));
volatile uint8_t *pinState = portOutputRegister(digitalPinToPort(pin));
*pinState |= pinBit;
*setMode |= pinBit;
}
//just handling fatal errors, or just fresh restarts.
void rebootAVR_Microcontroller(uint8_t pin){
volatile uint8_t *PinPort = portOutputRegister(digitalPinToPort(pin));
uint8_t PinBit = digitalPinToBitMask(pin);
*PinPort &= ~PinBit;
}
void digital_MPU6050_compass(uint8_t *direction, uint16_t *degrees, uint8_t offset, bool changeOffset){
const uint8_t defaultFactor = 211;
const float scalingFactor = 0.0008;
static float totalYaw;
float yawChange;
int16_t gx, gy, gz;
if(changeOffset){
switch(offset){
case NORTH:
totalYaw = 22.5;
break;
case NORTH_WEST:
totalYaw = 67.5;
break;
case WEST:
totalYaw = 112.5;
break;
case SOUTH_WEST:
totalYaw = 157.5;
break;
case SOUTH:
totalYaw = 202.5;
break;
case SOUTH_EAST:
totalYaw = 247.5;
break;
case EAST:
totalYaw = 292.5;
break;
case NORTH_EAST:
totalYaw = 337.5;
break;
default: //NORTH.
totalYaw = 22.5;
}
}
mpu.getRotation(&gx, &gy, &gz);
// Calculate change in yaw angle (angular velocity) around Z-axis
yawChange = (gz+defaultFactor)*scalingFactor;
// Update total yaw angle
totalYaw += yawChange;
// Keep yaw angle within [0, 360] range
if(totalYaw < 0){
totalYaw += 360;
}else if(totalYaw >= 360) {
totalYaw -= 360;
}
*degrees = totalYaw;
// Determine compass direction (approximate)
if(totalYaw > 0 && totalYaw < 45){
*direction = NORTH;
}else if(totalYaw > 45 && totalYaw < 90){
*direction = NORTH_WEST;
}else if(totalYaw > 90 && totalYaw < 135) {
*direction = WEST;
}else if(totalYaw > 135 && totalYaw < 180) {
*direction = SOUTH_WEST;
}else if(totalYaw > 180 && totalYaw < 225) {
*direction = SOUTH;
}else if(totalYaw > 225 && totalYaw < 270) {
*direction = SOUTH_EAST;
}else if(totalYaw > 270 && totalYaw < 315) {
*direction = EAST;
}else{
*direction = NORTH_EAST;
}
}
void digital_MPU6050_speedometer(float *speedX, float *speedY, float *speedZ, bool include_gravity){
const float G_To_M_PER_SECOND_Factor = 9.806;
const float AxisTo_G_Factor = 0.00006103515625;
const int RemoveGravityFactor = 17950;
int ax, ay, az;
mpu.getAcceleration(&ax, &ay, &az);
switch(include_gravity){
case true:
*speedY = (az*AxisTo_G_Factor)*G_To_M_PER_SECOND_Factor;
break;
case false:
*speedY = ((az-RemoveGravityFactor)*AxisTo_G_Factor)*G_To_M_PER_SECOND_Factor;
break;
}
*speedZ = ((ax-1100)*AxisTo_G_Factor)*G_To_M_PER_SECOND_Factor;
*speedX = ((ay-90)*AxisTo_G_Factor)*G_To_M_PER_SECOND_Factor;
}
void digital_MPU6050_force_meter(float *forceX, float *forceY, float *forceZ, bool include_gravity){
const float AxisTo_G_Factor = 0.00006103515625;
const int RemoveGravityFactor = 17950;
int ax, ay, az;
mpu.getAcceleration(&ax, &ay, &az);
switch(include_gravity){
case true:
*forceY = az*AxisTo_G_Factor;
break;
case false:
*forceY = (az-RemoveGravityFactor)*AxisTo_G_Factor;
break;
}
*forceZ = ((ax*-1)-1000)*AxisTo_G_Factor;
*forceX = ((ay*-1)-150)*AxisTo_G_Factor;
}
void setAlarm1(uint8_t hour, uint8_t min, uint8_t sec, bool clockMode){
if(hour > 0){
EEPROM.write(0, hour);
delay(10); //writing EEPROM takes time, so be patient. GREG!
EEPROM.write(1, min);
delay(10);
EEPROM.write(2, sec);
delay(10);
EEPROM.write(3, clockMode); //0 = AM, 1 = PM.
delay(10);
}else{ //erase EEPROM
EEPROM.write(0, 0x00);
delay(10); //writing EEPROM takes time, so be patient. GREG!
EEPROM.write(1, 0x00);
delay(10);
EEPROM.write(2, 0x00);
delay(10);
EEPROM.write(3, 0x00);
delay(10);
}
}
void setAlarm2(uint8_t hour, uint8_t min, uint8_t sec, bool clockMode){
if(hour > 0){
EEPROM.write(4, hour);
delay(10); //writing EEPROM takes time, so be patient. GREG!
EEPROM.write(5, min);
delay(10);
EEPROM.write(6, sec);
delay(10);
EEPROM.write(7, clockMode); //0 = AM, 1 = PM.
delay(10);
}else{ //erase EEPROM
EEPROM.write(4, 0x00);
delay(10); //writing EEPROM takes time, so be patient. GREG!
EEPROM.write(5, 0x00);
delay(10);
EEPROM.write(6, 0x00);
delay(10);
EEPROM.write(7, 0x00);
delay(10);
}
}
bool alarmIsTriggered(){ // no need to tell me what alarm, I check both.
uint8_t hours = 0;
uint8_t minutes = 0;
uint8_t seconds = 0;
uint8_t clockMode = 0;
uint8_t setHours1 = EEPROM.read(0);
uint8_t setMinutes1 = EEPROM.read(1);
uint8_t setSeconds1 = EEPROM.read(2);
bool setClockMode1 = EEPROM.read(3);
uint8_t setHours2 = EEPROM.read(4);
uint8_t setMinutes2 = EEPROM.read(5);
uint8_t setSeconds2 = EEPROM.read(6);
bool setClockMode2 = EEPROM.read(7);
static uint32_t millisStart = 0;
static bool alarmTriggered = 0;
CLOCK(0, 0, 0, 0, 0, 0, 0, &seconds, &minutes, &hours, NULL, NULL, NULL, &clockMode);
if((setHours1 == hours && setMinutes1 == minutes && setSeconds1 == seconds && setClockMode1 == clockMode)
|| (setHours2 == hours && setMinutes2 == minutes && setSeconds2 == seconds && setClockMode2 == clockMode)){
alarmTriggered = 1;
millisStart = millis();
}
if(millis()-millisStart > 600000 && alarmTriggered == 1){
alarmTriggered = 0;
}
return(alarmTriggered);
}
void manageSound(uint8_t shiftPin, uint8_t micPin, uint8_t mode, uint8_t RecAddress){
volatile uint8_t *micPort = portInputRegister(digitalPinToPort(micPin));
uint8_t micBit = digitalPinToBitMask(micPin);
uint8_t soundData[MAX_REC_ADDRESS] = {0};
if(mode == PLAY){
for(int address = USED_LOWER_NUMBER_ADDRESSES; address < MAX_REC_ADDRESS; address++){
soundData[address] = EEPROM.read(address); // write soundData[] before replaying to provent bugs and stressing the micro-controller.
}
for(int VarAddress = USED_LOWER_NUMBER_ADDRESSES; VarAddress < MAX_REC_ADDRESS; VarAddress++){
for(int bitPos = 0; bitPos < 8; bitPos++) {
bool sampleBit = (soundData[VarAddress] >> bitPos) & 1;
MainShiftRegisterWrite(shiftPin, sampleBit);
delayMicroseconds(50);
}
}
}else if(mode == RECORD){
for(int VarAddress = USED_LOWER_NUMBER_ADDRESSES; VarAddress < MAX_REC_ADDRESS; VarAddress++){
for(int bitPos = 0; bitPos < 8; bitPos++) {
bool sampleBit = (*micPort & micBit) != 0;
soundData[VarAddress] |= (sampleBit << bitPos);
delayMicroseconds(50);
}
}
for(int address = USED_LOWER_NUMBER_ADDRESSES; address < MAX_REC_ADDRESS; address++){
EEPROM.write(address, soundData[address]);
delay(25); //writing an EEPROM takes time as it takes time for it to register data. so be patient, Greg!!
}
}
}
void detectSoilMoisture(uint8_t pin, uint8_t *val, bool *isDry, bool *isWet){ //use a soil moisture sensor.
uint8_t moisturePercentage = analogRead(pin) / 10.23;
*isWet = (moisturePercentage > 75);
*isDry = (moisturePercentage < 25);
*val = moisturePercentage;
}
void detectSensorWetness(uint8_t pin, uint8_t *val){ /*use a "raindrop" sensor, though i'll use it for other things becuase leaving a computer
in the rain is illogical.*/
uint8_t sensorWetness = analogRead(pin) / 10.23;
*val = sensorWetness;
}
void extractFloatBits(float val, bool *sign, uint8_t *exponent, uint32_t *mantissa){
uint32_t Bits = 0;
memcpy(&Bits, &val, sizeof(val));
*sign = (Bits >> 31) & 0x1;
*exponent = (Bits >> 23) & 0xFF;
*mantissa = Bits & 0x7FFFFF;
}
void createFloatBits(bool sign, uint8_t exponent, uint32_t mantissa, float *val) {
uint32_t Bits = (uint32_t(sign) << 31) | (uint32_t(exponent) << 23) | (mantissa & 0x7FFFFF);
memcpy(val, &Bits, sizeof(Bits));
}
void enableUsbSlowCharger(uint8_t UsbSlowChargerPowerTransistorPin, bool enableSlowCharging){
volatile uint8_t *UsbSlowChargerPort = portOutputRegister(digitalPinToPort(UsbSlowChargerPowerTransistorPin));
uint8_t UsbSlowChargerBit = digitalPinToBitMask(UsbSlowChargerPowerTransistorPin);
if(enableSlowCharging){
*UsbSlowChargerPort |= UsbSlowChargerBit;
}else{
*UsbSlowChargerPort &= ~UsbSlowChargerBit;
}
}
void timer(uint8_t hours, uint8_t minutes, uint8_t seconds, bool reset,
uint8_t *hoursLeft, uint8_t *minutesLeft, uint8_t *secondsLeft, bool *timerDoneAlarm) {
static uint32_t timeStamp = 0;
static uint8_t Hours = 0;
static uint8_t Minutes = 0;
static uint8_t Seconds = 0;
static bool timerBegan = false;
if(reset){
Hours = hours;
Minutes = minutes;
Seconds = seconds;
timeStamp = millis();
timerBegan = true;
*timerDoneAlarm = false;
}
if (timerBegan){
if (millis() - timeStamp >= 1000) {
timeStamp += 1000;
if(Seconds > 0){
Seconds--;
}else{
if(Minutes > 0){
Minutes--;
Seconds = 59;
}else if(Hours > 0){
Hours--;
Minutes = 59;
Seconds = 59;
}
}
}
*hoursLeft = Hours;
*minutesLeft = Minutes;
*secondsLeft = Seconds;
if(Hours == 0 && Minutes == 0 && Seconds == 0){
timerBegan = false;
*timerDoneAlarm = true;
}else{
*timerDoneAlarm = false;
}
}
}
uint16_t systemRandomizer(uint16_t min_val, uint16_t max_val){
static uint16_t lfsr = 1;
uint16_t bit;
uint16_t result;
bit = ((lfsr >> 0)^(lfsr >> 2)^(lfsr >> 3)^(lfsr >> 5)+1); //taps at 0, 2, 3, and 5.
lfsr = (lfsr >> 1)|(bit << 15);
result = min_val + (lfsr % (max_val - min_val + 1)); //calculate a result in between min_val and max_val.
return(result); //give the result.
}
void colorBy(uint8_t R_pin, uint8_t G_pin, uint8_t B_pin, uint8_t colorMapNum, uint8_t Brightness, uint8_t Saturation){
uint8_t R = 0;
uint8_t G = 0;
uint8_t B = 0;
switch(colorMapNum){
case COLOR_BY_BLACK:
R = 0;
G = 0;
B = 0;
break;
case COLOR_BY_LIGHT_RED:
R = 255;
G = 51;
B = 51;
break;
case COLOR_BY_RED:
R = 255;
G = 0;
B = 0;
break;
case COLOR_BY_DARK_RED:
R = 255;
G = 0;
B = 0;
break;
case COLOR_BY_LIGHT_GREEN:
R = 0;
G = 204;
B = 0;
break;
case COLOR_BY_GREEN:
R = 0;
G = 153;
B = 0;
break;
case COLOR_BY_DARK_GREEN:
R = 0;
G = 102;
B = 0;
break;
case COLOR_BY_LIGHT_BLUE:
R = 51;
G = 51;
B = 255;
break;
case COLOR_BY_BLUE:
R = 0;
G = 0;
B = 255;
break;
case COLOR_BY_DARK_BLUE:
R = 0;
G = 0;
B = 139;
break;
case COLOR_BY_YELLOW:
R = 255;
G = 255;
B = 0;
break;
case COLOR_BY_CYAN:
R = 0;
G = 255;
B = 255;
break;
case COLOR_BY_MAGENTA:
R = 255;
G = 0;
B = 255;
break;
case COLOR_BY_ORANGE:
R = 255;
G = 165;
B = 0;
break;
case COLOR_BY_DARK_ORANGE:
R = 255;
G = 140;
B = 0;
break;
case COLOR_BY_GOLD:
R = 255;
G = 215;
B = 0;
break;
case COLOR_BY_LIME:
R = 0;
G = 255;
B = 0;
break;
case COLOR_BY_PURPLE:
R = 128;
G = 0;
B = 128;
break;
case COLOR_BY_PINK:
R = 255;
G = 64;
B = 64;
break;
case COLOR_BY_DEEP_PINK:
R = 255;
G = 16;
B = 16;
break;
case COLOR_BY_INDIGO:
R = 75;
G = 0;
B = 130;
break;
case COLOR_BY_VIOLET:
R = 127;
G = 32;
B = 255;
break;
case COLOR_BY_DARK_VIOLET:
R = 127;
G = 0;
B = 255;
break;
case COLOR_BY_WHITE:
R = 255;
G = 255;
B = 255;
break;
default:
R = 0;
G = 0;
B = 0;
break;
}
color(R_pin, G_pin, B_pin, R, G, B, Brightness, Saturation);
}
void RGB_CCT_ColorLighting(uint8_t R_pin, uint8_t G_pin, uint8_t B_pin, uint32_t CCT, uint8_t Brightness, uint8_t Saturation) {
uint8_t R = 0;
uint8_t G = 0;
uint8_t B = 0;
uint32_t val = CCT / 100;
if (val <= 66) {
R = 255;
G = (99.4708025861 * log(val)) - 161.1195681661;
G = constrain(G, 0, 255);
if (val <= 20) {
B = 0;
}else{
B = (138.5177312231 * log(val - 10)) - 305.0447927307;
B = constrain(B, 0, 255);
}
}else{
R = 329.698727466 * pow(val - 60, -0.1332047592);
R = constrain(R, 0, 255);
G = 288.1221695283 * pow(val - 60, -0.0755148492);
G = constrain(G, 0, 255);
B = 255;
}
color(R_pin, G_pin, B_pin, R, G, B, Brightness, Saturation);
}
void ColorFade(uint8_t R_pin, uint8_t G_pin, uint8_t B_pin, uint8_t fadeSpeed, uint8_t Brightness, uint8_t Saturation, uint8_t mode, bool reset){
static uint32_t RGB_Timestamp = 0;
static uint8_t ColorFadeRegister = 0;
static uint8_t ColorCycleRegister = 0;
static uint8_t Red = 255;
static uint8_t Green = 0;
static uint8_t Blue = 0;
if(reset){
ColorFadeRegister = 0;
ColorCycleRegister = 0;
Red = 255;
Green = 0;
Blue = 0;
}
if(millis()-RGB_Timestamp >= fadeSpeed){ //millis timer.
RGB_Timestamp = millis();
switch(mode){
case FADE:
if(ColorFadeRegister == 0 && Red < 255){
Red++; //brighten red.
}else if(ColorFadeRegister == 0 && Red == 255){
ColorFadeRegister = 1; //next stage.
}if(ColorFadeRegister == 1 && Blue > 0){
Blue--; //dim blue.
}else if(ColorFadeRegister == 1 && Blue == 0){
ColorFadeRegister = 2; //next stage.
}if(ColorFadeRegister == 2 && Green < 255){
Green++; //brighten green.
}else if(ColorFadeRegister == 2 && Green == 255){
ColorFadeRegister = 3; //next stage.
}if(ColorFadeRegister == 3 && Red > 0){
Red--; //dim red.
}else if(ColorFadeRegister == 3 && Red == 0){
ColorFadeRegister = 4; //next stage.
}if(ColorFadeRegister == 4 && Blue < 255){
Blue++; //brighten blue.
}else if(ColorFadeRegister == 4 && Blue == 255){
ColorFadeRegister = 5; //next stage.
}if(ColorFadeRegister == 5 && Green > 0){
Green--; //dim green.
}else if(ColorFadeRegister == 5 && Green == 0){
ColorFadeRegister = 0; //back to first stage.
}
break;
case CYCLE:
if(ColorCycleRegister == 0 && Red < 255){
Red++; //brighten red.
}else if(ColorCycleRegister == 0 && Red == 255){
ColorCycleRegister = 1; //next stage.
}if(ColorCycleRegister == 1 && Red > 0){
Red--; //dim red.
}else if(ColorCycleRegister == 1 && Red == 0){
ColorCycleRegister = 2; //next stage.
}if(ColorCycleRegister == 2 && Green < 255){
Green++; //brighten green.
}else if(ColorCycleRegister == 2 && Green == 255){
ColorCycleRegister = 3; //next stage.
}if(ColorCycleRegister == 3 && Green > 0){
Green--; //dim green.
}else if(ColorCycleRegister == 3 && Green == 0){
ColorCycleRegister = 4; //next stage.
}if(ColorCycleRegister == 4 && Blue < 255){
Blue++; //brighten blue.
}else if(ColorCycleRegister == 4 && Blue == 255){
ColorCycleRegister = 5; //next stage.
}if(ColorCycleRegister == 5 && Blue > 0){
Blue--; //dim blue.
}else if(ColorCycleRegister == 5 && Blue == 0){
ColorCycleRegister = 6; //next stage.
}if(ColorCycleRegister == 6 && Red < 255 && Green < 255){
Red++; //brighten red.
Green++; //brighten green.
}else if(ColorCycleRegister == 6 && Red == 255 && Green == 255){
ColorCycleRegister = 7; //next stage.
}if(ColorCycleRegister == 7 && Red > 0 && Green > 0){
Red--; //dim red.
Green--; //dim green.
}else if(ColorCycleRegister == 7 && Red == 0 && Green == 0){
ColorCycleRegister = 8; //next stage.
}if(ColorCycleRegister == 8 && Red < 255 && Blue < 255){
Red++; //brighten red.
Blue++; //brighten blue.
}else if(ColorCycleRegister == 8 && Red == 255 && Blue == 255){
ColorCycleRegister = 9; //next stage.
}if(ColorCycleRegister == 9 && Red > 0 && Blue > 0){
Red--; //dim red.
Blue--; //dim blue.
}else if(ColorCycleRegister == 9 && Red == 0 && Blue == 0){
ColorCycleRegister = 10; //next stage.
}if(ColorCycleRegister == 10 && Green < 255 && Blue < 255){
Green++; //brighten green.
Blue++; //brighten blue.
}else if(ColorCycleRegister == 10 && Green == 255 && Blue == 255){
ColorCycleRegister = 11; //next stage.
}if(ColorCycleRegister == 11 && Green > 0 && Blue > 0){
Green--; //dim green.
Blue--; //dim blue.
}else if(ColorCycleRegister == 11 && Green == 0 && Blue == 0){
ColorCycleRegister = 0; //back to first stage.
}
break;
}
color(R_pin, G_pin, B_pin, Red, Green, Blue, Brightness, Saturation);
}
}
void color(uint8_t R_pin, uint8_t G_pin, uint8_t B_pin, uint8_t R, uint8_t G, uint8_t B, uint8_t Brightness, uint8_t Saturation){
//set up color function, for an easy and more professional way to change led colors.
uint8_t outputRedValue, outputGreenValue, outputBlueValue;
uint8_t saturator = (R+G+B)/3;
outputRedValue = ((R*Saturation)/255)+(saturator*(255-Saturation)/255);
outputGreenValue = ((G*Saturation)/255)+(saturator*(255-Saturation)/255);
outputBlueValue = ((B*Saturation)/255)+(saturator*(255-Saturation)/255);
outputRedValue = outputRedValue/(256-Brightness);
outputGreenValue = outputGreenValue/(256-Brightness);
outputBlueValue = outputBlueValue/(256-Brightness);
ShiftPWMArray[R_pin] = outputRedValue;
ShiftPWMArray[G_pin] = outputGreenValue;
ShiftPWMArray[B_pin] = outputBlueValue;
}
bool isDark(uint8_t photoResistorPin){
uint8_t output = 100*(analogRead(photoResistorPin)/1023.0);
return(output < 30);
}
bool isBright(uint8_t photoResistorPin){
uint8_t output = 100*(analogRead(photoResistorPin)/1023.0);
return(output > 60);
}
void pedometer(float *distance, float *energyUsed, uint8_t distanceType, uint8_t energyType, float weightIn, bool reset){
const float G_To_MILES_PER_HOUR_Factor = 21.93736;
const float AxisTo_G_Factor = 0.00006103515625;
static uint32_t millisStart = 0;
static bool millisStarted = 0;
static uint32_t minsWhileWalking = 0;
static float weight = 0;
float caloriesBurnedPerMin = 0.0;
float totalCaloriesBurned = 0.0;
float energyOut = 0.0;
float speedZ = 0.0;
float speedX = 0.0;
float totalSpeed = 0.0;
float MET_calSpeed = 0.0;
float OutputSpeed = 0.0;
float METs = 0.0;
int ax, ay;
if(reset){
millisStart = 0;
millisStarted = 0;
minsWhileWalking = 0;
}
if(weightIn > 30 && weightIn < 150){
weight = weightIn;
}
if(weight < 30){
*distance = NAN;
*energyUsed = NAN;
return;
}
mpu.getAcceleration(&ax, &ay, NULL);
speedZ = ((ax-1100)*AxisTo_G_Factor)*G_To_MILES_PER_HOUR_Factor;
speedX = ((ay-90)*AxisTo_G_Factor)*G_To_MILES_PER_HOUR_Factor;
totalSpeed = abs(speedZ)+abs(speedX);
OutputSpeed = totalSpeed;
MET_calSpeed = totalSpeed/2.23693629*60;
METs = (0.1 * MET_calSpeed + 3.5)/3.5;
if(totalSpeed > 0){
if(!millisStarted){
millisStart = millis();
millisStarted = 1;
}else if(millis()-millisStart >= 60000){
minsWhileWalking++;
}
}else{
millisStarted = 0;
}
caloriesBurnedPerMin = (METs*3.5*(weight*2.20462)/200)*minsWhileWalking;
energyOut = caloriesBurnedPerMin;
switch(distanceType){
case METERS_PER_SECOND:
OutputSpeed /= 2.23693629;
break;
case KILOMETERS_PER_HOUR:
OutputSpeed *= 1.609344;
break;
case FEET_PER_SECOND:
OutputSpeed *= 1.46666667;
break;
}
switch(energyType){
case KILOCALORIES:
energyOut /= 1000.0;
break;
case JOULES:
energyOut *= 4.184;
break;
case KILOJOULES:
energyOut /= 239.005736;
break;
}
*distance = OutputSpeed;
*energyUsed = energyOut;
}
void SetFanSpeed(uint8_t pin, uint8_t speed){
ShiftPWMArray[pin] = speed;
}
void resetScreen(){
display.clearDisplay();
display.display();
}
Thank you all for your support!
