latest update
This commit is contained in:
parent
8535212aa3
commit
6969c69368
@ -1,218 +0,0 @@
|
||||
#include <FastLED.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_DotStarMatrix.h>
|
||||
#include <Adafruit_DotStar.h>
|
||||
#include <SPI.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
#undef WAIT // Prevent macro conflict with FastLED
|
||||
|
||||
// ============ PIN DEFINITIONS ============
|
||||
// PublicI2C (slave) pins
|
||||
#define PUBLIC_I2C_SDA 21
|
||||
#define PUBLIC_I2C_SCL 22
|
||||
#define PUBLIC_I2C_ADDR 0x42 // Example slave address
|
||||
|
||||
// LocalI2C (master) pins
|
||||
#define LOCAL_I2C_SDA 12
|
||||
#define LOCAL_I2C_SCL 11
|
||||
|
||||
// OLED display settings
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define OLED_RESET -1
|
||||
|
||||
// Joystick pins
|
||||
#define JOY_X_PIN 1 // ADC1_CH0
|
||||
#define JOY_Y_PIN 2 // ADC1_CH1
|
||||
#define JOY_BTN_PIN 3 // Digital input
|
||||
|
||||
// FastLED (NeoPixel) settings
|
||||
#define NUM_LEDS 16
|
||||
#define LED_DATA_PIN 5 // Example GPIO for LED data
|
||||
|
||||
// DotStar HD 8x8 Grid settings
|
||||
#define DOTSTAR_WIDTH 8
|
||||
#define DOTSTAR_HEIGHT 8
|
||||
#define DOTSTAR_DATA 6 // Example GPIO for DotStar data
|
||||
#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock
|
||||
|
||||
// ============ I2C BUS OBJECTS ============
|
||||
TwoWire PublicI2C = TwoWire(0); // I2C0 (slave)
|
||||
TwoWire LocalI2C = TwoWire(1); // I2C1 (master)
|
||||
|
||||
// ============ DEVICE OBJECTS =============
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET);
|
||||
// Use a SparkFun_APDS9960 library that supports TwoWire
|
||||
SparkFun_APDS9960 apds(&LocalI2C);
|
||||
CRGB leds[NUM_LEDS];
|
||||
Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix(
|
||||
DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK,
|
||||
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE,
|
||||
DOTSTAR_BRG
|
||||
);
|
||||
|
||||
// ============ DATA STRUCTURES ============
|
||||
struct SensorData {
|
||||
int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right
|
||||
bool joystickBtn;
|
||||
uint16_t colorR, colorG, colorB, colorC;
|
||||
};
|
||||
volatile SensorData latestData;
|
||||
|
||||
// ============ I2C SLAVE DATA HANDLERS =========
|
||||
void receiveEvent(int numBytes) {
|
||||
// Not used in this application, but required by Wire
|
||||
}
|
||||
|
||||
void requestEvent() {
|
||||
// Copy volatile to local to avoid race conditions
|
||||
SensorData copy;
|
||||
noInterrupts();
|
||||
copy = latestData;
|
||||
interrupts();
|
||||
// Send as a binary buffer
|
||||
PublicI2C.write((uint8_t*)©, sizeof(SensorData));
|
||||
}
|
||||
|
||||
// ============ JOYSTICK INTERPRETATION =========
|
||||
#define JOY_THRESHOLD_HIGH 3000
|
||||
#define JOY_THRESHOLD_LOW 1000
|
||||
|
||||
void updateJoystick(SensorData &data) {
|
||||
int joyX = analogRead(JOY_X_PIN);
|
||||
int joyY = analogRead(JOY_Y_PIN);
|
||||
bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW;
|
||||
|
||||
// Default: no direction
|
||||
data.joystickDir = -1;
|
||||
|
||||
if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up
|
||||
else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down
|
||||
else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left
|
||||
else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right
|
||||
|
||||
data.joystickBtn = joyBtn;
|
||||
}
|
||||
|
||||
// ============ COLOR SENSOR READING =========
|
||||
void updateColorSensor(SensorData &data) {
|
||||
uint16_t r=0, g=0, b=0, c=0;
|
||||
if (apds.readAmbientLight(c) &&
|
||||
apds.readRedLight(r) &&
|
||||
apds.readGreenLight(g) &&
|
||||
apds.readBlueLight(b)) {
|
||||
data.colorR = r;
|
||||
data.colorG = g;
|
||||
data.colorB = b;
|
||||
data.colorC = c;
|
||||
}
|
||||
}
|
||||
|
||||
// ============ DISPLAY LOGIC =========
|
||||
void updateDisplays(const SensorData &data) {
|
||||
// DotStar: show direction as arrow or color as background
|
||||
dotstar.fillScreen(0);
|
||||
if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up
|
||||
else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down
|
||||
else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left
|
||||
else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right
|
||||
else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color
|
||||
dotstar.show();
|
||||
|
||||
// FastLED: color bar with button brightness
|
||||
uint8_t brightness = data.joystickBtn ? 255 : 64;
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4);
|
||||
leds[i].nscale8_video(brightness);
|
||||
}
|
||||
FastLED.show();
|
||||
|
||||
// OLED: show values
|
||||
display.clearDisplay();
|
||||
display.setCursor(0,0);
|
||||
display.print("Dir: ");
|
||||
switch (data.joystickDir) {
|
||||
case 0: display.println("Up"); break;
|
||||
case 1: display.println("Down"); break;
|
||||
case 2: display.println("Left"); break;
|
||||
case 3: display.println("Right"); break;
|
||||
default: display.println("None"); break;
|
||||
}
|
||||
display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released");
|
||||
display.print("R: "); display.println(data.colorR);
|
||||
display.print("G: "); display.println(data.colorG);
|
||||
display.print("B: "); display.println(data.colorB);
|
||||
display.print("C: "); display.println(data.colorC);
|
||||
display.display();
|
||||
}
|
||||
|
||||
// ============ SETUP FUNCTION =============
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// --- Initialize PublicI2C as Slave ---
|
||||
PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000);
|
||||
PublicI2C.onReceive(receiveEvent);
|
||||
PublicI2C.onRequest(requestEvent);
|
||||
Serial.println("PublicI2C (slave) initialized.");
|
||||
|
||||
// --- Initialize LocalI2C as Master ---
|
||||
LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000);
|
||||
Serial.println("LocalI2C (master) initialized.");
|
||||
|
||||
// --- Initialize OLED Display ---
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 allocation failed");
|
||||
while (1);
|
||||
}
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0,0);
|
||||
display.println("OLED Ready!");
|
||||
display.display();
|
||||
|
||||
// --- Initialize APDS-9960 (SparkFun) ---
|
||||
if (!apds.init()) { // Uses LocalI2C if library supports it
|
||||
Serial.println("APDS-9960 initialization failed");
|
||||
display.println("No APDS-9960!");
|
||||
display.display();
|
||||
while (1);
|
||||
}
|
||||
display.println("APDS-9960 ready!");
|
||||
display.display();
|
||||
|
||||
// Enable color sensing
|
||||
apds.enableLightSensor(false);
|
||||
|
||||
// --- Initialize Joystick Pins ---
|
||||
pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW
|
||||
|
||||
// --- Initialize FastLED (NeoPixel) ---
|
||||
FastLED.addLeds<NEOPIXEL, LED_DATA_PIN>(leds, NUM_LEDS);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
|
||||
// --- Initialize DotStar Matrix ---
|
||||
dotstar.begin();
|
||||
dotstar.setBrightness(32); // Adjust as needed
|
||||
dotstar.fillScreen(0);
|
||||
dotstar.show();
|
||||
}
|
||||
|
||||
// ============ MAIN LOOP ==================
|
||||
void loop() {
|
||||
SensorData tempData;
|
||||
updateJoystick(tempData);
|
||||
updateColorSensor(tempData);
|
||||
|
||||
// Copy to shared struct for I2C
|
||||
noInterrupts();
|
||||
latestData = tempData;
|
||||
interrupts();
|
||||
|
||||
updateDisplays(tempData);
|
||||
|
||||
delay(50); // Adjust as needed
|
||||
}
|
117
src/game/code/code.ino/code.ino.ino
Normal file
117
src/game/code/code.ino/code.ino.ino
Normal file
@ -0,0 +1,117 @@
|
||||
#include "dice.h" // Dice Function
|
||||
#include "header.h" // Player Data Types
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
#define LED_PIN 8 // Digital pin connected to the LED strip
|
||||
#define NUM_LEDS 64 // 8x8 = 64 LEDs
|
||||
#define BRIGHTNESS 100 // Default max brightness
|
||||
|
||||
#define sspacer Serial.println("--------------------------------------------")
|
||||
#define dspacer Serial.println("============================================")
|
||||
|
||||
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Convert (row, col) to strip index
|
||||
uint16_t getIndex(uint8_t row, uint8_t col) {
|
||||
// Adjust depending on how your strip is wired
|
||||
if (row % 2 == 0) {
|
||||
return row * 8 + col; // Left to right
|
||||
} else {
|
||||
return row * 8 + (7 - col); // Right to left (zigzag)
|
||||
}
|
||||
}
|
||||
|
||||
// Set individual LED with row, col, color and brightness
|
||||
void setPixelColorRC(uint8_t row, uint8_t col, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) {
|
||||
if(row >= 8 || col >= 8) return; // Bounds check
|
||||
strip.setBrightness(brightness);
|
||||
uint16_t index = getIndex(row, col);
|
||||
strip.setPixelColor(index, strip.Color(r, g, b));
|
||||
strip.show();
|
||||
}
|
||||
|
||||
// Optional: set LED by index directly
|
||||
void setPixelColorIndex(uint16_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) {
|
||||
if (index >= NUM_LEDS) return;
|
||||
|
||||
strip.setBrightness(brightness);
|
||||
strip.setPixelColor(index, strip.Color(r, g, b));
|
||||
strip.show();
|
||||
}
|
||||
|
||||
//================================================================
|
||||
// SETUP
|
||||
//================================================================
|
||||
|
||||
void setup() {
|
||||
|
||||
// I2C Communications
|
||||
Wire.begin(); // For Master
|
||||
|
||||
// Start Serial And Message
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
dspacer;
|
||||
|
||||
// Starting LED Strip
|
||||
strip.begin();
|
||||
strip.setBrightness(BRIGHTNESS); // Initial brightness
|
||||
strip.show(); // Initialize all pixels to 'off'
|
||||
|
||||
// Red Player
|
||||
player[0].i2ca = 0x10;
|
||||
player[0].position.x = 0;
|
||||
player[0].position.y = 0;
|
||||
player[0].color.r = 255;
|
||||
player[0].color.i = 60;
|
||||
|
||||
// Paint The Strip Position For Red Player
|
||||
setPixelColorRC(
|
||||
player[0].position.x,
|
||||
player[0].position.y,
|
||||
player[0].color.r,
|
||||
player[0].color.g,
|
||||
player[0].color.b,
|
||||
player[0].color.i
|
||||
);
|
||||
|
||||
// Blue Player
|
||||
player[1].i2ca = 0x20;
|
||||
player[1].position.x = 7;
|
||||
player[1].position.y = 7;
|
||||
player[1].color.b = 255;
|
||||
player[1].color.i = 60;
|
||||
|
||||
// Paint The Strip Position For Blue Player
|
||||
setPixelColorRC(
|
||||
player[1].position.x,
|
||||
player[1].position.y,
|
||||
player[1].color.r,
|
||||
player[1].color.g,
|
||||
player[1].color.b,
|
||||
player[1].color.i
|
||||
);
|
||||
|
||||
// Make Dicision
|
||||
diceRoll();
|
||||
|
||||
// Make Spacer
|
||||
dspacer;
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
// LOOP
|
||||
//================================================================
|
||||
|
||||
void loop() {
|
||||
|
||||
for(int i=0; i<2; i++) {
|
||||
movePlayers(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
6
src/game/code/code.ino/dice.h
Normal file
6
src/game/code/code.ino/dice.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <esp_system.h> // For esp_random()
|
||||
|
||||
int roll_dice() {
|
||||
uint32_t random_value = esp_random();
|
||||
return (random_value % 6) + 1;
|
||||
}
|
127
src/game/code/code.ino/functions.ino
Normal file
127
src/game/code/code.ino/functions.ino
Normal file
@ -0,0 +1,127 @@
|
||||
void diceRoll() {
|
||||
|
||||
dspacer;
|
||||
Serial.println(" Dice Roll");
|
||||
dspacer;
|
||||
|
||||
while(1) {
|
||||
|
||||
// Player turn decision
|
||||
int redplayerdice = roll_dice();
|
||||
int blueplayerdice = roll_dice();
|
||||
|
||||
// Display The Dice Values
|
||||
Serial.println("Red Dice : " + String(redplayerdice));
|
||||
Serial.println("Blue Dice : " + String(blueplayerdice));
|
||||
|
||||
// Swaping The Players
|
||||
if(redplayerdice > blueplayerdice) {
|
||||
Serial.println("Red Player Starts");
|
||||
break;
|
||||
} else if(redplayerdice < blueplayerdice) {
|
||||
Serial.println("Blue Player Starts");
|
||||
temp = player[0];
|
||||
player[0] = player[1];
|
||||
player[1] = temp;
|
||||
break;
|
||||
} else if(redplayerdice == blueplayerdice) {
|
||||
Serial.println(" -X- Its A Draw, Do It Again");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
||||
|
||||
String Question(Stream &serial, String Message) {
|
||||
|
||||
// Print On Serial
|
||||
serial.print(Message + " : ");
|
||||
|
||||
// Wait Until User Input A Thing
|
||||
while(!serial.available());
|
||||
|
||||
// Read User Input
|
||||
String x = serial.readStringUntil('\n');
|
||||
|
||||
// Cleaning The Buffer
|
||||
while(serial.available()) { serial.read(); }
|
||||
|
||||
// Remove Spaces
|
||||
x.trim();
|
||||
|
||||
// Print Answer
|
||||
serial.println(x);
|
||||
|
||||
// Return The Value Of x
|
||||
return x;
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
||||
|
||||
void movePlayers(uint8_t num) {
|
||||
|
||||
// New Position Variables
|
||||
uint8_t posX, posY;
|
||||
|
||||
// Select Player
|
||||
if(player[num].color.r == 255) {
|
||||
Serial.println("Red Player Turn > > >");
|
||||
} else if(player[num].color.b == 255) {
|
||||
Serial.println("Blue Player Turn > > >");
|
||||
}
|
||||
|
||||
// Take User Input
|
||||
while(1) {
|
||||
|
||||
// User Input
|
||||
posX = Question(Serial, "Select X Position ").toInt();
|
||||
posY = Question(Serial, "Select Y Position ").toInt();
|
||||
|
||||
// Boundries Check
|
||||
if((posX >= 0 && posX <= 7) && (posY >= 0 && posY <= 7)) {
|
||||
break;
|
||||
} else {
|
||||
Serial.println(" -> Wrong Input, Exceeding Boundries, Try Again");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Seperator
|
||||
Serial.println("--------------------------------------------");
|
||||
|
||||
// Clear Current Position
|
||||
setPixelColorRC(
|
||||
player[num].position.x,
|
||||
player[num].position.y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
60
|
||||
);
|
||||
|
||||
// Update Positions Values
|
||||
player[num].position.x = posX;
|
||||
player[num].position.y = posY;
|
||||
|
||||
// Paint New Position
|
||||
setPixelColorRC(
|
||||
player[num].position.x,
|
||||
player[num].position.y,
|
||||
player[num].color.r,
|
||||
player[num].color.g,
|
||||
player[num].color.b,
|
||||
player[num].color.i
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
25
src/game/code/code.ino/header.h
Normal file
25
src/game/code/code.ino/header.h
Normal file
@ -0,0 +1,25 @@
|
||||
// Player Position Data Type
|
||||
struct _position {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
};
|
||||
|
||||
// Color Of Any Thing
|
||||
struct _color {
|
||||
uint8_t r; // Red Color
|
||||
uint8_t g; // Green Color
|
||||
uint8_t b; // Blue Color
|
||||
uint8_t i; // Intensity
|
||||
};
|
||||
|
||||
// Player Data Type
|
||||
struct _player {
|
||||
_position position; // the current position of the player
|
||||
_color color; // the color of the player light indicator
|
||||
uint8_t health; // the health level of the player 0 - 7 => 8
|
||||
uint8_t i2ca; // the i2c address of the joystic of the player
|
||||
};
|
||||
|
||||
// Two Players Instences
|
||||
_player player[2]; // The Two Contenders
|
||||
_player temp; // For Swaping Purpose
|
86
src/game/code/code.ino/i2c_functions.ino
Normal file
86
src/game/code/code.ino/i2c_functions.ino
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
int I2C_DiceCommand(uint8_t address) {
|
||||
|
||||
// Memory
|
||||
int dice = 0;
|
||||
|
||||
// Call Slave Addrees
|
||||
Wire.beginTransmission(address); // or 0x20
|
||||
|
||||
// Send Command 1 -> Roll A Dice
|
||||
Wire.write(0x01);
|
||||
|
||||
// Stop Transmition
|
||||
Wire.endTransmission();
|
||||
|
||||
// Request 1 byte from slave -> Contains A Number 1 to 6
|
||||
Wire.requestFrom(0x10, 1);
|
||||
|
||||
// If Data Received
|
||||
if(Wire.available()) {
|
||||
|
||||
// Read The Data
|
||||
dice = Wire.read();
|
||||
|
||||
}
|
||||
|
||||
// Return The Value To Master
|
||||
return dice
|
||||
|
||||
}
|
||||
|
||||
void I2C_PushData(uint8_t address, _player &pl1, _player &pl2) {
|
||||
|
||||
// Slave Address
|
||||
Wire.beginTransmission(address);
|
||||
|
||||
// Command Number - Push Data
|
||||
Wire.write(0x02);
|
||||
|
||||
// Player One Data
|
||||
Wire.write(pl1.position.x);
|
||||
Wire.write(pl1.position.y);
|
||||
Wire.write(pl1.color.r);
|
||||
Wire.write(pl1.color.g);
|
||||
Wire.write(pl1.color.b);
|
||||
Wire.write(pl1.color.i);
|
||||
Wire.write(pl1.health);
|
||||
|
||||
// Player Two Data
|
||||
Wire.write(pl1.position.x);
|
||||
Wire.write(pl1.position.y);
|
||||
Wire.write(pl1.color.r);
|
||||
Wire.write(pl1.color.g);
|
||||
Wire.write(pl1.color.b);
|
||||
Wire.write(pl1.color.i);
|
||||
Wire.write(pl1.health);
|
||||
|
||||
// Stop Transmition
|
||||
Wire.endTransmission();
|
||||
|
||||
}
|
||||
|
||||
void I2C_Permission(uint8_t address) {
|
||||
|
||||
// Card Color
|
||||
_color color;
|
||||
|
||||
// Direction
|
||||
uint8_t Direction;
|
||||
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(0x03); // permission to play command
|
||||
Wire.endTransmission();
|
||||
|
||||
// Master waits for slave to send data
|
||||
Wire.requestFrom(0x10, 4); // expecting 2 bytes: card color (R, G, B), direction (one byte)
|
||||
|
||||
// Receive Bytes
|
||||
if(Wire.available()) {
|
||||
color.r = Wire.read();
|
||||
color.g = Wire.read();
|
||||
color.b = Wire.read();
|
||||
Direction = Wire.read();
|
||||
}
|
||||
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
#include <FastLED.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_DotStarMatrix.h>
|
||||
#include <Adafruit_DotStar.h>
|
||||
#include <SPI.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
#undef WAIT // Prevent macro conflict with FastLED
|
||||
|
||||
// ============ PIN DEFINITIONS ============
|
||||
// PublicI2C (slave) pins
|
||||
#define PUBLIC_I2C_SDA 21
|
||||
#define PUBLIC_I2C_SCL 22
|
||||
#define PUBLIC_I2C_ADDR 0x42 // Example slave address
|
||||
|
||||
// LocalI2C (master) pins
|
||||
#define LOCAL_I2C_SDA 12
|
||||
#define LOCAL_I2C_SCL 11
|
||||
|
||||
// OLED display settings
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define OLED_RESET -1
|
||||
|
||||
// Joystick pins
|
||||
#define JOY_X_PIN 1 // ADC1_CH0
|
||||
#define JOY_Y_PIN 2 // ADC1_CH1
|
||||
#define JOY_BTN_PIN 3 // Digital input
|
||||
|
||||
// FastLED (NeoPixel) settings
|
||||
#define NUM_LEDS 16
|
||||
#define LED_DATA_PIN 5 // Example GPIO for LED data
|
||||
|
||||
// DotStar HD 8x8 Grid settings
|
||||
#define DOTSTAR_WIDTH 8
|
||||
#define DOTSTAR_HEIGHT 8
|
||||
#define DOTSTAR_DATA 6 // Example GPIO for DotStar data
|
||||
#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock
|
||||
|
||||
// ============ I2C BUS OBJECTS ============
|
||||
TwoWire PublicI2C = TwoWire(0); // I2C0 (slave)
|
||||
TwoWire LocalI2C = TwoWire(1); // I2C1 (master)
|
||||
|
||||
// ============ DEVICE OBJECTS =============
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET);
|
||||
// Use a SparkFun_APDS9960 library that supports TwoWire
|
||||
SparkFun_APDS9960 apds(&LocalI2C);
|
||||
CRGB leds[NUM_LEDS];
|
||||
Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix(
|
||||
DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK,
|
||||
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE,
|
||||
DOTSTAR_BRG
|
||||
);
|
||||
|
||||
// ============ DATA STRUCTURES ============
|
||||
struct SensorData {
|
||||
int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right
|
||||
bool joystickBtn;
|
||||
uint16_t colorR, colorG, colorB, colorC;
|
||||
};
|
||||
volatile SensorData latestData;
|
||||
|
||||
// ============ I2C SLAVE DATA HANDLERS =========
|
||||
void receiveEvent(int numBytes) {
|
||||
// Not used in this application, but required by Wire
|
||||
}
|
||||
|
||||
void requestEvent() {
|
||||
// Copy volatile to local to avoid race conditions
|
||||
SensorData copy;
|
||||
noInterrupts();
|
||||
copy = latestData;
|
||||
interrupts();
|
||||
// Send as a binary buffer
|
||||
PublicI2C.write((uint8_t*)©, sizeof(SensorData));
|
||||
}
|
||||
|
||||
// ============ JOYSTICK INTERPRETATION =========
|
||||
#define JOY_THRESHOLD_HIGH 3000
|
||||
#define JOY_THRESHOLD_LOW 1000
|
||||
|
||||
void updateJoystick(SensorData &data) {
|
||||
int joyX = analogRead(JOY_X_PIN);
|
||||
int joyY = analogRead(JOY_Y_PIN);
|
||||
bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW;
|
||||
|
||||
// Default: no direction
|
||||
data.joystickDir = -1;
|
||||
|
||||
if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up
|
||||
else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down
|
||||
else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left
|
||||
else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right
|
||||
|
||||
data.joystickBtn = joyBtn;
|
||||
}
|
||||
|
||||
// ============ COLOR SENSOR READING =========
|
||||
void updateColorSensor(SensorData &data) {
|
||||
uint16_t r=0, g=0, b=0, c=0;
|
||||
if (apds.readAmbientLight(c) &&
|
||||
apds.readRedLight(r) &&
|
||||
apds.readGreenLight(g) &&
|
||||
apds.readBlueLight(b)) {
|
||||
data.colorR = r;
|
||||
data.colorG = g;
|
||||
data.colorB = b;
|
||||
data.colorC = c;
|
||||
}
|
||||
}
|
||||
|
||||
// ============ DISPLAY LOGIC =========
|
||||
void updateDisplays(const SensorData &data) {
|
||||
// DotStar: show direction as arrow or color as background
|
||||
dotstar.fillScreen(0);
|
||||
if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up
|
||||
else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down
|
||||
else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left
|
||||
else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right
|
||||
else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color
|
||||
dotstar.show();
|
||||
|
||||
// FastLED: color bar with button brightness
|
||||
uint8_t brightness = data.joystickBtn ? 255 : 64;
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4);
|
||||
leds[i].nscale8_video(brightness);
|
||||
}
|
||||
FastLED.show();
|
||||
|
||||
// OLED: show values
|
||||
display.clearDisplay();
|
||||
display.setCursor(0,0);
|
||||
display.print("Dir: ");
|
||||
switch (data.joystickDir) {
|
||||
case 0: display.println("Up"); break;
|
||||
case 1: display.println("Down"); break;
|
||||
case 2: display.println("Left"); break;
|
||||
case 3: display.println("Right"); break;
|
||||
default: display.println("None"); break;
|
||||
}
|
||||
display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released");
|
||||
display.print("R: "); display.println(data.colorR);
|
||||
display.print("G: "); display.println(data.colorG);
|
||||
display.print("B: "); display.println(data.colorB);
|
||||
display.print("C: "); display.println(data.colorC);
|
||||
display.display();
|
||||
}
|
||||
|
||||
// ============ SETUP FUNCTION =============
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// --- Initialize PublicI2C as Slave ---
|
||||
PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000);
|
||||
PublicI2C.onReceive(receiveEvent);
|
||||
PublicI2C.onRequest(requestEvent);
|
||||
Serial.println("PublicI2C (slave) initialized.");
|
||||
|
||||
// --- Initialize LocalI2C as Master ---
|
||||
LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000);
|
||||
Serial.println("LocalI2C (master) initialized.");
|
||||
|
||||
// --- Initialize OLED Display ---
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 allocation failed");
|
||||
while (1);
|
||||
}
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0,0);
|
||||
display.println("OLED Ready!");
|
||||
display.display();
|
||||
|
||||
// --- Initialize APDS-9960 (SparkFun) ---
|
||||
if (!apds.init()) { // Uses LocalI2C if library supports it
|
||||
Serial.println("APDS-9960 initialization failed");
|
||||
display.println("No APDS-9960!");
|
||||
display.display();
|
||||
while (1);
|
||||
}
|
||||
display.println("APDS-9960 ready!");
|
||||
display.display();
|
||||
|
||||
// Enable color sensing
|
||||
apds.enableLightSensor(false);
|
||||
|
||||
// --- Initialize Joystick Pins ---
|
||||
pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW
|
||||
|
||||
// --- Initialize FastLED (NeoPixel) ---
|
||||
FastLED.addLeds<NEOPIXEL, LED_DATA_PIN>(leds, NUM_LEDS);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
|
||||
// --- Initialize DotStar Matrix ---
|
||||
dotstar.begin();
|
||||
dotstar.setBrightness(32); // Adjust as needed
|
||||
dotstar.fillScreen(0);
|
||||
dotstar.show();
|
||||
}
|
||||
|
||||
// ============ MAIN LOOP ==================
|
||||
void loop() {
|
||||
SensorData tempData;
|
||||
updateJoystick(tempData);
|
||||
updateColorSensor(tempData);
|
||||
|
||||
// Copy to shared struct for I2C
|
||||
noInterrupts();
|
||||
latestData = tempData;
|
||||
interrupts();
|
||||
|
||||
updateDisplays(tempData);
|
||||
|
||||
delay(50); // Adjust as needed
|
||||
}
|
103
src/joystic/code/code.ino/code.ino.ino
Normal file
103
src/joystic/code/code.ino/code.ino.ino
Normal file
@ -0,0 +1,103 @@
|
||||
#include "pins.h"
|
||||
#include <Wire.h>
|
||||
#include "healthbar.h"
|
||||
#include "map.h"
|
||||
|
||||
#define X_PIN 1
|
||||
#define Y_PIN 2
|
||||
#define BUTTON_PIN 3
|
||||
#define DEAD_ZONE 50 // Adjust this value for your joystick sensitivity
|
||||
|
||||
struct _location {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
};
|
||||
|
||||
_location playerLocation;
|
||||
|
||||
void setup() {
|
||||
|
||||
playerLocation.x = 0;
|
||||
playerLocation.y = 7;
|
||||
|
||||
Serial.begin(9600);
|
||||
while (!Serial); // Wait for serial monitor on boards like Leonardo
|
||||
|
||||
map_begin();
|
||||
|
||||
// Display Helth
|
||||
fastled_begin();
|
||||
red_health(4, 5);
|
||||
blue_health(2, 5);
|
||||
fastled_show();
|
||||
|
||||
// map display - map_setDot(int x, int y, byte r, byte g, byte b)
|
||||
map_setDot(0, 7, 255, 0, 0, 5);
|
||||
map_setDot(7, 0, 0, 0, 255, 5);
|
||||
map_show();
|
||||
|
||||
// // Initialize I2C buses (example for ESP32)
|
||||
// Wire.begin(6, 7); // Public I2C (SDA 6, SCL 7)
|
||||
// Wire1.begin(12, 11); // Local I2C (SDA 12, SCL 11) - remove if not available
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Serial.println(String(analogRead(X_PIN)) + " " + String(analogRead(Y_PIN)));
|
||||
// delay(250);
|
||||
|
||||
String joymem = readJoystick();
|
||||
Serial.println(joymem);
|
||||
|
||||
if(joymem == "up") {
|
||||
if(playerLocation.y < 7) {
|
||||
// Clear Previous playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0);
|
||||
// New Value
|
||||
playerLocation.y += 1;
|
||||
// Draw On New playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50);
|
||||
// Display On Map
|
||||
map_show();
|
||||
delay(500);
|
||||
}
|
||||
} else if(joymem == "down") {
|
||||
if(playerLocation.y > 0) {
|
||||
// Clear Previous playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0);
|
||||
// New Value
|
||||
playerLocation.y -= 1;
|
||||
// Draw On New playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50);
|
||||
// Display On Map
|
||||
map_show();
|
||||
delay(500);
|
||||
}
|
||||
} else if(joymem == "left") {
|
||||
if(playerLocation.x > 0) {
|
||||
// Clear Previous playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0);
|
||||
// New Value
|
||||
playerLocation.x -= 1;
|
||||
// Draw On New playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50);
|
||||
// Display On Map
|
||||
map_show();
|
||||
delay(500);
|
||||
}
|
||||
} else if(joymem == "right") {
|
||||
if(playerLocation.x < 7) {
|
||||
// Clear Previous playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 0, 0, 0, 0);
|
||||
// New Value
|
||||
playerLocation.x += 1;
|
||||
// Draw On New playerLocation
|
||||
map_setDot(playerLocation.x, playerLocation.y, 255, 0, 0, 50);
|
||||
// Display On Map
|
||||
map_show();
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
97
src/joystic/code/code.ino/functions.ino
Normal file
97
src/joystic/code/code.ino/functions.ino
Normal file
@ -0,0 +1,97 @@
|
||||
|
||||
// I2C scanner function
|
||||
void scanI2CBus(TwoWire &wire, const char* busName) {
|
||||
|
||||
byte error, address;
|
||||
int nDevices = 0;
|
||||
Serial.print("Scanning I2C bus: ");
|
||||
Serial.println(busName);
|
||||
for(address = 1; address < 127; address++) {
|
||||
wire.beginTransmission(address);
|
||||
error = wire.endTransmission();
|
||||
if (error == 0) {
|
||||
Serial.print("I2C device found at address 0x");
|
||||
if (address < 16) Serial.print("0");
|
||||
Serial.print(address, HEX);
|
||||
Serial.println(" !");
|
||||
nDevices++;
|
||||
} else if (error == 4) {
|
||||
Serial.print("Unknown error at address 0x");
|
||||
if (address < 16) Serial.print("0");
|
||||
Serial.println(address, HEX);
|
||||
}
|
||||
}
|
||||
if (nDevices == 0)
|
||||
Serial.println("No I2C devices found\n");
|
||||
else
|
||||
Serial.println("done\n");
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
||||
|
||||
String readJoystick() {
|
||||
|
||||
// const int X_PIN = A0;
|
||||
// const int Y_PIN = A1;
|
||||
int xVal = analogRead(X_PIN);
|
||||
int yVal = analogRead(Y_PIN);
|
||||
|
||||
// Deadzone centers and ranges (after increasing by 50)
|
||||
const int X_DEADZONE_MIN = 1975;
|
||||
const int X_DEADZONE_MAX = 2065;
|
||||
const int Y_DEADZONE_MIN = 1875;
|
||||
const int Y_DEADZONE_MAX = 1965;
|
||||
|
||||
// Deadzone centers (can be calculated as (min+max)/2)
|
||||
const int X_CENTER = (X_DEADZONE_MIN + X_DEADZONE_MAX) / 2; // 2020
|
||||
const int Y_CENTER = (Y_DEADZONE_MIN + Y_DEADZONE_MAX) / 2; // 1920
|
||||
|
||||
bool xInDeadzone = (xVal >= X_DEADZONE_MIN && xVal <= X_DEADZONE_MAX);
|
||||
bool yInDeadzone = (yVal >= Y_DEADZONE_MIN && yVal <= Y_DEADZONE_MAX);
|
||||
|
||||
if (xInDeadzone && yInDeadzone) return "center";
|
||||
|
||||
// Calculate how far each axis is from its deadzone center
|
||||
int xDist = abs(xVal - X_CENTER);
|
||||
int yDist = abs(yVal - Y_CENTER);
|
||||
|
||||
// If both axes are outside their deadzones, choose the one with the greater movement
|
||||
if (!xInDeadzone && !yInDeadzone) {
|
||||
if (xDist > yDist) {
|
||||
if (xVal < X_CENTER) return "left";
|
||||
else return "right";
|
||||
} else {
|
||||
if (yVal < Y_CENTER) return "up";
|
||||
else return "down";
|
||||
}
|
||||
}
|
||||
// If only one axis is outside, return its direction
|
||||
else if (!yInDeadzone) {
|
||||
if (yVal < Y_CENTER) return "up";
|
||||
else return "down";
|
||||
}
|
||||
else if (!xInDeadzone) {
|
||||
if (xVal < X_CENTER) return "left";
|
||||
else return "right";
|
||||
}
|
||||
|
||||
return "center";
|
||||
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//
|
||||
//================================================================
|
||||
|
||||
int analogReadAVG(uint8_t pin, uint8_t times) {
|
||||
|
||||
int value;
|
||||
|
||||
for(int i=0; i<times; i++) {
|
||||
|
||||
}
|
||||
|
||||
}
|
53
src/joystic/code/code.ino/healthbar.h
Normal file
53
src/joystic/code/code.ino/healthbar.h
Normal file
@ -0,0 +1,53 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_LEDS 16
|
||||
#define DATA_PIN 8 // Change to your actual data pin
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void fastled_color(int start, int end, byte r, byte g, byte b, byte brightness) {
|
||||
if (start < 0) start = 0;
|
||||
if (end >= NUM_LEDS) end = NUM_LEDS - 1;
|
||||
|
||||
CHSV hsv = rgb2hsv_approximate(CRGB(r, g, b));
|
||||
hsv.value = brightness;
|
||||
|
||||
for (int i = start; i <= end; i++) {
|
||||
leds[i] = hsv;
|
||||
}
|
||||
}
|
||||
|
||||
void fastled_begin() {
|
||||
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
void fastled_show() {
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
// Example health bar functions
|
||||
void red_health(uint8_t value, uint8_t brightness) {
|
||||
fastled_color(0, value-1, 255, 0, 0, brightness);
|
||||
}
|
||||
|
||||
void blue_health(uint8_t value, uint8_t brightness) {
|
||||
fastled_color(8, 8+value-1, 0, 0, 255, brightness); // Adjust if you want a different range
|
||||
}
|
||||
|
||||
void crossfade_red() {
|
||||
|
||||
for(int i=10; i<=60; i++){
|
||||
red_health(4, i);
|
||||
fastled_show();
|
||||
delay(20);
|
||||
}
|
||||
|
||||
for(int i=60; i>=10; i--) {
|
||||
red_health(4, i);
|
||||
fastled_show();
|
||||
delay(20);
|
||||
}
|
||||
|
||||
}
|
31
src/joystic/code/code.ino/map.h
Normal file
31
src/joystic/code/code.ino/map.h
Normal file
@ -0,0 +1,31 @@
|
||||
#include <Adafruit_DotStar.h>
|
||||
|
||||
#define DATAPIN 10 // Change to your data pin
|
||||
#define CLOCKPIN 9 // Change to your clock pin
|
||||
#define NUMPIXELS 64 // 8x8 matrix
|
||||
|
||||
Adafruit_DotStar matrix(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BGR);
|
||||
|
||||
// Function to set a single dot (x, y) to a color (r, g, b)
|
||||
void map_setDot(int x, int y, byte r, byte g, byte b, byte brightness) {
|
||||
if (x < 0 || x > 7 || y < 0 || y > 7) return; // Out of bounds
|
||||
int index = x + y * 8; // Convert (x,y) to strip index
|
||||
|
||||
// Scale the color by brightness (0–255)
|
||||
uint32_t color = matrix.Color(
|
||||
(uint8_t)(r * brightness / 255),
|
||||
(uint8_t)(g * brightness / 255),
|
||||
(uint8_t)(b * brightness / 255)
|
||||
);
|
||||
matrix.setPixelColor(index, color);
|
||||
}
|
||||
|
||||
void map_begin() {
|
||||
matrix.begin();
|
||||
matrix.clear();
|
||||
matrix.show();
|
||||
}
|
||||
|
||||
void map_show() {
|
||||
matrix.show();
|
||||
}
|
0
src/joystic/code/code.ino/pins.h
Normal file
0
src/joystic/code/code.ino/pins.h
Normal file
@ -1,218 +1,177 @@
|
||||
#include <FastLED.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_DotStarMatrix.h>
|
||||
#include <Adafruit_DotStar.h>
|
||||
#include <SPI.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
#undef WAIT // Prevent macro conflict with FastLED
|
||||
#include <Wire.h>
|
||||
#include <FastLED.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_DotStarMatrix.h>
|
||||
#include <Adafruit_DotStar.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// ============ PIN DEFINITIONS ============
|
||||
// PublicI2C (slave) pins
|
||||
#define PUBLIC_I2C_SDA 21
|
||||
#define PUBLIC_I2C_SCL 22
|
||||
#define PUBLIC_I2C_ADDR 0x42 // Example slave address
|
||||
// ============ PIN DEFINITIONS (ESP32-S3 Super Mini) ============
|
||||
|
||||
// LocalI2C (master) pins
|
||||
#define LOCAL_I2C_SDA 12
|
||||
#define LOCAL_I2C_SCL 11
|
||||
#define JOY_X_PIN A1 // Example: GP2, adjust to your wiring
|
||||
#define JOY_Y_PIN A2 // Example: GP3, adjust to your wiring
|
||||
#define JOY_BTN_PIN 3 // Example: GP8, adjust to your wiring
|
||||
|
||||
// OLED display settings
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define OLED_RESET -1
|
||||
#define LOCAL_I2C_SDA 12 // Example: GP9, SDA for OLED/APDS
|
||||
#define LOCAL_I2C_SCL 11 // Example: GP10, SCL for OLED/APDS
|
||||
|
||||
// Joystick pins
|
||||
#define JOY_X_PIN 1 // ADC1_CH0
|
||||
#define JOY_Y_PIN 2 // ADC1_CH1
|
||||
#define JOY_BTN_PIN 3 // Digital input
|
||||
#define NUM_LEDS 16
|
||||
#define LED_DATA_PIN 8 // Example: GP11, adjust to your wiring
|
||||
|
||||
// FastLED (NeoPixel) settings
|
||||
#define NUM_LEDS 16
|
||||
#define LED_DATA_PIN 5 // Example GPIO for LED data
|
||||
#define DOTSTAR_WIDTH 8
|
||||
#define DOTSTAR_HEIGHT 8
|
||||
#define DOTSTAR_DATA 10 // Example: GP12, adjust to your wiring
|
||||
#define DOTSTAR_CLK 9 // Example: GP13, adjust to your wiring
|
||||
|
||||
// DotStar HD 8x8 Grid settings
|
||||
#define DOTSTAR_WIDTH 8
|
||||
#define DOTSTAR_HEIGHT 8
|
||||
#define DOTSTAR_DATA 6 // Example GPIO for DotStar data
|
||||
#define DOTSTAR_CLK 7 // Example GPIO for DotStar clock
|
||||
|
||||
// ============ I2C BUS OBJECTS ============
|
||||
TwoWire PublicI2C = TwoWire(0); // I2C0 (slave)
|
||||
TwoWire LocalI2C = TwoWire(1); // I2C1 (master)
|
||||
#define ONBOARD_RGB_LED 48 // Onboard WS2812 RGB LED on GP48
|
||||
|
||||
// ============ DEVICE OBJECTS =============
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &LocalI2C, OLED_RESET);
|
||||
// Use a SparkFun_APDS9960 library that supports TwoWire
|
||||
SparkFun_APDS9960 apds(&LocalI2C);
|
||||
CRGB leds[NUM_LEDS];
|
||||
Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix(
|
||||
DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK,
|
||||
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE,
|
||||
DOTSTAR_BRG
|
||||
);
|
||||
|
||||
// ============ DATA STRUCTURES ============
|
||||
struct SensorData {
|
||||
int8_t joystickDir; // -1=none, 0=up, 1=down, 2=left, 3=right
|
||||
bool joystickBtn;
|
||||
uint16_t colorR, colorG, colorB, colorC;
|
||||
};
|
||||
volatile SensorData latestData;
|
||||
Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
// ============ I2C SLAVE DATA HANDLERS =========
|
||||
void receiveEvent(int numBytes) {
|
||||
// Not used in this application, but required by Wire
|
||||
}
|
||||
Adafruit_DotStarMatrix dotstar = Adafruit_DotStarMatrix(
|
||||
DOTSTAR_WIDTH, DOTSTAR_HEIGHT, DOTSTAR_DATA, DOTSTAR_CLK,
|
||||
DS_MATRIX_TOP + DS_MATRIX_LEFT + DS_MATRIX_ROWS + DS_MATRIX_PROGRESSIVE,
|
||||
DOTSTAR_BRG
|
||||
);
|
||||
|
||||
void requestEvent() {
|
||||
// Copy volatile to local to avoid race conditions
|
||||
SensorData copy;
|
||||
noInterrupts();
|
||||
copy = latestData;
|
||||
interrupts();
|
||||
// Send as a binary buffer
|
||||
PublicI2C.write((uint8_t*)©, sizeof(SensorData));
|
||||
}
|
||||
// ============ I2C SCAN FUNCTION =========
|
||||
|
||||
// ============ JOYSTICK INTERPRETATION =========
|
||||
#define JOY_THRESHOLD_HIGH 3000
|
||||
#define JOY_THRESHOLD_LOW 1000
|
||||
|
||||
void updateJoystick(SensorData &data) {
|
||||
int joyX = analogRead(JOY_X_PIN);
|
||||
int joyY = analogRead(JOY_Y_PIN);
|
||||
bool joyBtn = digitalRead(JOY_BTN_PIN) == LOW;
|
||||
|
||||
// Default: no direction
|
||||
data.joystickDir = -1;
|
||||
|
||||
if (joyY > JOY_THRESHOLD_HIGH) data.joystickDir = 0; // Up
|
||||
else if (joyY < JOY_THRESHOLD_LOW) data.joystickDir = 1; // Down
|
||||
else if (joyX < JOY_THRESHOLD_LOW) data.joystickDir = 2; // Left
|
||||
else if (joyX > JOY_THRESHOLD_HIGH) data.joystickDir = 3; // Right
|
||||
|
||||
data.joystickBtn = joyBtn;
|
||||
}
|
||||
|
||||
// ============ COLOR SENSOR READING =========
|
||||
void updateColorSensor(SensorData &data) {
|
||||
uint16_t r=0, g=0, b=0, c=0;
|
||||
if (apds.readAmbientLight(c) &&
|
||||
apds.readRedLight(r) &&
|
||||
apds.readGreenLight(g) &&
|
||||
apds.readBlueLight(b)) {
|
||||
data.colorR = r;
|
||||
data.colorG = g;
|
||||
data.colorB = b;
|
||||
data.colorC = c;
|
||||
void scanI2CDevices(TwoWire &bus) {
|
||||
byte error, address;
|
||||
int nDevices = 0;
|
||||
Serial.println("Scanning...");
|
||||
for (address = 1; address < 127; address++) {
|
||||
bus.beginTransmission(address);
|
||||
error = bus.endTransmission();
|
||||
if (error == 0) {
|
||||
Serial.print("I2C device found at address 0x");
|
||||
if (address < 16) Serial.print("0");
|
||||
Serial.println(address, HEX);
|
||||
nDevices++;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
if (nDevices > 0) {
|
||||
Serial.println("done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============ DISPLAY LOGIC =========
|
||||
void updateDisplays(const SensorData &data) {
|
||||
// DotStar: show direction as arrow or color as background
|
||||
dotstar.fillScreen(0);
|
||||
if (data.joystickDir == 0) dotstar.drawPixel(3, 0, dotstar.Color(0,0,255)); // Up
|
||||
else if (data.joystickDir == 1) dotstar.drawPixel(3, 7, dotstar.Color(0,0,255)); // Down
|
||||
else if (data.joystickDir == 2) dotstar.drawPixel(0, 3, dotstar.Color(0,0,255)); // Left
|
||||
else if (data.joystickDir == 3) dotstar.drawPixel(7, 3, dotstar.Color(0,0,255)); // Right
|
||||
else dotstar.fillScreen(dotstar.Color(data.colorR>>2, data.colorG>>2, data.colorB>>2)); // Show color
|
||||
dotstar.show();
|
||||
// ============ ONBOARD RGB LED TEST =========
|
||||
|
||||
// FastLED: color bar with button brightness
|
||||
uint8_t brightness = data.joystickBtn ? 255 : 64;
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = CRGB(data.colorR>>4, data.colorG>>4, data.colorB>>4);
|
||||
leds[i].nscale8_video(brightness);
|
||||
void testOnboardRGB() {
|
||||
// Note: Onboard RGB LED is a WS2812 on GP48
|
||||
FastLED.addLeds<NEOPIXEL, ONBOARD_RGB_LED>(leds, 1); // Use just 1 LED
|
||||
leds[0] = CRGB::Red;
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
leds[0] = CRGB::Blue;
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
leds[0] = CRGB::Green;
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
FastLED.clear(true); // Clear LED data and reset FastLED for main NeoPixel strip
|
||||
}
|
||||
FastLED.show();
|
||||
|
||||
// OLED: show values
|
||||
display.clearDisplay();
|
||||
display.setCursor(0,0);
|
||||
display.print("Dir: ");
|
||||
switch (data.joystickDir) {
|
||||
case 0: display.println("Up"); break;
|
||||
case 1: display.println("Down"); break;
|
||||
case 2: display.println("Left"); break;
|
||||
case 3: display.println("Right"); break;
|
||||
default: display.println("None"); break;
|
||||
}
|
||||
display.print("Btn: "); display.println(data.joystickBtn ? "Pressed" : "Released");
|
||||
display.print("R: "); display.println(data.colorR);
|
||||
display.print("G: "); display.println(data.colorG);
|
||||
display.print("B: "); display.println(data.colorB);
|
||||
display.print("C: "); display.println(data.colorC);
|
||||
display.display();
|
||||
}
|
||||
// ============ SYSTEM TEST =========
|
||||
|
||||
// ============ SETUP FUNCTION =============
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
void runSystemTest() {
|
||||
|
||||
// --- Initialize PublicI2C as Slave ---
|
||||
PublicI2C.begin(PUBLIC_I2C_ADDR, PUBLIC_I2C_SDA, PUBLIC_I2C_SCL, 100000);
|
||||
PublicI2C.onReceive(receiveEvent);
|
||||
PublicI2C.onRequest(requestEvent);
|
||||
Serial.println("PublicI2C (slave) initialized.");
|
||||
Serial.println("\n===== SYSTEM TEST =====\n");
|
||||
|
||||
// --- Initialize LocalI2C as Master ---
|
||||
LocalI2C.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000);
|
||||
Serial.println("LocalI2C (master) initialized.");
|
||||
// --- Onboard RGB LED Test ---
|
||||
|
||||
// --- Initialize OLED Display ---
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 allocation failed");
|
||||
while (1);
|
||||
}
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0,0);
|
||||
display.println("OLED Ready!");
|
||||
display.display();
|
||||
Serial.println("Testing onboard RGB LED...");
|
||||
testOnboardRGB();
|
||||
Serial.println("Onboard RGB LED: OK");
|
||||
|
||||
// --- Initialize APDS-9960 (SparkFun) ---
|
||||
if (!apds.init()) { // Uses LocalI2C if library supports it
|
||||
Serial.println("APDS-9960 initialization failed");
|
||||
display.println("No APDS-9960!");
|
||||
// --- Joystick Test ---
|
||||
|
||||
int joyX = analogRead(JOY_X_PIN);
|
||||
int joyY = analogRead(JOY_Y_PIN);
|
||||
int joyBtn = digitalRead(JOY_BTN_PIN);
|
||||
Serial.print("Joystick X: "); Serial.println(joyX);
|
||||
Serial.print("Joystick Y: "); Serial.println(joyY);
|
||||
Serial.print("Button: "); Serial.println(joyBtn ? "Released" : "Pressed");
|
||||
Serial.println("Joystick: OK");
|
||||
|
||||
// --- I2C Device Scan ---
|
||||
|
||||
Serial.println("Scanning I2C devices...");
|
||||
scanI2CDevices(Wire);
|
||||
|
||||
// --- OLED Test ---
|
||||
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("OLED: FAIL");
|
||||
while(1);
|
||||
}
|
||||
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0,0);
|
||||
display.println("SYSTEM TEST");
|
||||
display.println("Joystick OK");
|
||||
display.println("I2C OK");
|
||||
display.println("FastLED OK");
|
||||
display.println("DotStar OK");
|
||||
display.display();
|
||||
while (1);
|
||||
Serial.println("OLED: OK");
|
||||
|
||||
// --- FastLED (NeoPixel) Test ---
|
||||
|
||||
FastLED.addLeds<NEOPIXEL, LED_DATA_PIN>(leds, NUM_LEDS);
|
||||
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = CRGB(0, 255, 0); // Green
|
||||
}
|
||||
FastLED.show();
|
||||
delay(1000);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
Serial.println("FastLED: OK");
|
||||
|
||||
// --- DotStar (APA102) Test ---
|
||||
|
||||
dotstar.begin();
|
||||
dotstar.setBrightness(32);
|
||||
dotstar.fillScreen(dotstar.Color(255, 0, 0)); // Red
|
||||
dotstar.show();
|
||||
delay(1000);
|
||||
dotstar.fillScreen(0);
|
||||
dotstar.show();
|
||||
Serial.println("DotStar: OK");
|
||||
|
||||
Serial.println("===== SYSTEM TEST COMPLETE =====");
|
||||
}
|
||||
display.println("APDS-9960 ready!");
|
||||
display.display();
|
||||
|
||||
// Enable color sensing
|
||||
apds.enableLightSensor(false);
|
||||
// ============ SETUP =============
|
||||
|
||||
// --- Initialize Joystick Pins ---
|
||||
pinMode(JOY_BTN_PIN, INPUT_PULLUP); // Button is active LOW
|
||||
void setup() {
|
||||
|
||||
// --- Initialize FastLED (NeoPixel) ---
|
||||
FastLED.addLeds<NEOPIXEL, LED_DATA_PIN>(leds, NUM_LEDS);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
Serial.begin(115200);
|
||||
|
||||
// --- Initialize DotStar Matrix ---
|
||||
dotstar.begin();
|
||||
dotstar.setBrightness(32); // Adjust as needed
|
||||
dotstar.fillScreen(0);
|
||||
dotstar.show();
|
||||
}
|
||||
while(!Serial) { delay(10); }
|
||||
|
||||
// ============ MAIN LOOP ==================
|
||||
void loop() {
|
||||
SensorData tempData;
|
||||
updateJoystick(tempData);
|
||||
updateColorSensor(tempData);
|
||||
// Initialize I2C
|
||||
Wire.begin(LOCAL_I2C_SDA, LOCAL_I2C_SCL, 100000);
|
||||
|
||||
// Copy to shared struct for I2C
|
||||
noInterrupts();
|
||||
latestData = tempData;
|
||||
interrupts();
|
||||
// Initialize joystick button
|
||||
pinMode(JOY_BTN_PIN, INPUT_PULLUP);
|
||||
|
||||
updateDisplays(tempData);
|
||||
// Run system test
|
||||
runSystemTest();
|
||||
|
||||
delay(50); // Adjust as needed
|
||||
}
|
||||
// Keep the loop empty as recommended for ESP32-S3 Super Mini
|
||||
while(true) {}
|
||||
}
|
||||
|
||||
// ============ LOOP =============
|
||||
|
||||
void loop() {
|
||||
// Leave empty to avoid crashes on ESP32-S3 Super Mini
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user