1 במרץ 2023

משלוח מנות CrackTheCode-Purim!

תקציר

משלוח מנות ייחודי אשר מהווה חדר בריחה קטן על בסיס המשחק המפורסם Mastermind (או בעברית "בול פגיעה")

כדי לפתוח את  משלוח המנות (או כדי להגיע ל-"אוצר" :-), ישנם שני מסלולים

א. פתרון חידת הגיון הקשורה לפורים.

ב. משחק בול פגיעה אלקטרוני.












תאור הפרוייקט

היצירה מבוססת על העיצוב של MICHAEL KLEMENTS   - קישור

השיפורים שעשיתי
  • תכנון מחודש של החלל 
  • שימוש במעבד ESP32
  • התאמת העיצוב לפורים (תמונות שנקנו בShutterStock)

מסלולי פתרון


הראשון - חידת הגיון

"בשורשם של דברים, הטוב והרע חד הם, לכאורה..."

תזכורת: הפתרון הוא מספרי.

השני - בול פגיעה 

בתחילת המשחק בוחר כל שחקן מספר בן כמה ספרות, כאשר נהוג לבחור מספר בן ארבע ספרות, אסורות חזרות על ספרות. לדוגמה, 1234 הוא מספר חוקי (גם '0' נחשב כספרה חוקית). 

המשחק מתנהל ע"י סדרה של ניחושים, לאחר הניחוש המחשב מגלה לשחקן ע"י נורות לד אדומות את מספר ה"פגיעות" ונורות לד ירוקות, את מספר ה"בול" (הלדים לא מגלים את מיקום הספרות של הבול או הפגיעה).

בול - מצב בו אחת הספרות במספר המנוחש זהה לספרה במספר המקורי, וממוקמת נכון.

פגיעה - מצב בו אחת הספרות במספר המנוחש זהה לספרה במספר המקורי, אך ממוקמת במיקום שונה.

הוראות הפעלה

  • חבר את שקע לתקע (איך אפשר בלי??) 

  • העבר את מתג ההפעלה בצד ימין כלפי מעלה.

  • לאחר הופעת מסך הפתיחה ותצוגת הלדים הזן ספרה

    • שינוי הספרה ע"י סיבוב החוגה

    • אישור הבחירה ע"י לחיצה על החוגה

    • חזור על הפעולה עד להשלמת 4 ספרות

    • המתן לחיווי בול/פגיעה

    • אם ישנו "בול" המנעול הפנימי יפתח

בניה

חיתוך לייזר
הרכבה
















רכיבים

  • לדים אדומים - 4
  • לדים ירוקים - 4
  • לחצן בחירה / Encoder
  • מעבד ESP32
  • מסך OLED SSD1306
  • מפסק - On/Off

חיווט

Number

Left Pinout

Name

Right Pinout

Name

1

EN


23

EncSW

2

VP


SCL(22)

Oled-Clock

3

VN


TXD


4

34


RXD


5

35


SDA(21)

Oled-Data

6

32

LedGreen4

19

ServoSigna

7

33

LedRed3

18

LedRed4

8

25

LedGreen3

5

EncA

9

26

LedGreen2

TX2


10

27

LedRed1

RX2


11

14

LedRed2

4

OledReset

12

12

LedGreen1

2


13

13


15

EncB

14

GND


GND

Oled/Enc-Sw/Ser

15

VIN

ServoPower

3.3

OledVin


קוד





//Code Breaker
//Source Michael Klements Arduino Uno code
//Converted to ESP32 - Asaf Matan
#include <SPI.h> //Import libraries to control the OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h> //Import library to control the servo
#include "AiEsp32RotaryEncoder.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Servo lockServo; // create servo object to control a servo
#define ROTARY_ENCODER_A_PIN 5
#define ROTARY_ENCODER_B_PIN 15
#define ROTARY_ENCODER_BUTTON_PIN 23
#define ROTARY_ENCODER_STEPS 4
byte correctNumLEDs[4] = {27,14,33,18}; //Pin numbers for correct number LEDs (Indicate a correct digit)
byte correctPlaceLEDs[4] = {12,26,25,32}; //Pin numbers for correct place LEDs (Indicate a correct digit in the correct place)
byte code[4] = {0,0,0,0}; //Create an array to store the code digits
byte codeGuess[4] = {0,0,0,0}; //Create an array to store the guessed code digits
byte guessingDigit = 0; //Tracks the current digit being guessed
byte numGuesses = 0; //Tracks how many guesses it takes to crack the code
boolean correctGuess = true; //Variable to check whether the code has been guessed correctly, true initially to generate a new code on startup
byte encoderPos = 0; //Current value of encoder position, digit being input form 0 to 9
AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, -1, ROTARY_ENCODER_STEPS);
int buttonState = 0;
void IRAM_ATTR readEncoderISR()
{
rotaryEncoder.readEncoder_ISR();
}
/* Local Functions decleration */
void startupAni ();
void updateDisplayCode();
void generateNewCode();
void inputCodeGuess();
void checkCodeGuess();
void updateLEDs (int corNum, int corPla);
void setup()
{
Serial.begin(115200); //Starts the Serial monitor for debugging
Serial.println(F("Starting..."));
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
rotaryEncoder.setBoundaries(0, 9, false); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)
rotaryEncoder.setAcceleration(250);
// Let Oled diplay power up
delay(3000);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay(); //Clear display
display.setTextColor(SSD1306_WHITE); //Set the text colour to white
lockServo.attach(19);
for(int i=0 ; i<=3 ; i++) //Define pin modes for the LEDs
{
pinMode(correctNumLEDs[i], OUTPUT);
pinMode(correctPlaceLEDs[i], OUTPUT);
digitalWrite(correctPlaceLEDs[i], LOW);
digitalWrite(correctNumLEDs[i], LOW);
}
pinMode(ROTARY_ENCODER_A_PIN, INPUT_PULLUP); //Set pinA as an input, pulled HIGH to the logic voltage
pinMode(ROTARY_ENCODER_B_PIN, INPUT_PULLUP); //Set pinB as an input, pulled HIGH to the logic voltage
delay(2000); // Pause for 2 seconds
startupAni(); //Display the startup animation
}
void loop()
{
if(correctGuess) //Code between games to reset if the guess is correct, initially true to open safe and then generate new code
{
lockServo.write(45); //Unlock the safe
delay(300);
updateLEDs (0,4); //Flashing LED sequence
delay(300);
updateLEDs (4,0);
delay(300);
updateLEDs (0,4);
delay(300);
updateLEDs (4,0);
delay(300);
updateLEDs (4,4); //Turn all LEDs on
if(numGuesses >= 1) //Check that its not the start of the game
{
display.clearDisplay(); //Clear the display
display.setTextSize(1); //Set the display text size to small
display.setCursor(35,10); //Set the display cursor position
display.print(F("In ")); //Set the display text
display.print(numGuesses); //Set the display text
display.setCursor(35,20); //Set the display cursor position
display.print(F("Attempts")); //Set the display text
display.display(); //Output the display text
delay(5000);
}
display.clearDisplay(); //Clear the display
display.setTextSize(1); //Set the display text size to small
display.setCursor(35,10); //Set the display cursor position
display.print(F("Push To")); //Set the display text
display.setCursor(35,20); //Set the display cursor position
display.print(F("Lock Safe")); //Set the display text
display.display(); //Output the display text
display.setTextSize(2); //Set the display text size back to large
boolean lock = false; //Safe is initially not locked
while(!lock) //While button is not pressed, wait for it to be pressed
{
if (rotaryEncoder.isEncoderButtonClicked())
{
Serial.println("button pressed");
lockServo.write(140); //Lock the safe
display.clearDisplay(); //Clear the display
display.setCursor(30,10); //Set the display cursor position
display.print(F("Locked")); //Set the display text
display.display(); //Output the display text
lock = true;
}
}
generateNewCode(); //Calls function to generate a new random code
updateLEDs (0,0);
correctGuess = false; //The code guess is initially set to incorrect
numGuesses = 0; //Reset the number of guesses counter
}
inputCodeGuess(); //Calls function to allow the user to input a guess
numGuesses++; //Increment the guess counter
checkCodeGuess(); //Calls function to check the input guess
guessingDigit = 0; //Reset the digit being guessed
codeGuess[0] = 0; //Reset the first digit of the code
updateDisplayCode(); //Update the displayed code
}
void updateDisplayCode() //Function to update the display with the input code
{
String temp = ""; //Temporary variable to concatenate the code string
if(!correctGuess) //If the guess is not correct then update the display
{
for (int i=0 ; i<guessingDigit ; i++) //Loops through the four digits to display them
{
temp = temp + codeGuess[i];
}
temp = temp + encoderPos;
for (int i=guessingDigit+1 ; i<=3 ; i++)
{
temp = temp + "0";
}
Serial.println(temp); //Output to Serial monitor for debugging
display.setTextSize(2); //Set the display text size
display.clearDisplay(); //Clear the display
display.setCursor(40,10); //Set the display cursor position
display.println(temp); //Set the display text
display.display(); //Update the display
}
}
void generateNewCode() //Function to generate a new random code
{
Serial.print("Code: ");
code[0]=0;
code[1]=5;
code[2]=0;
code[3]=2;
for (int i=0 ; i<= 3 ; i++) //Loops through the four digits and assigns a random number to each
{
// esp_random();
// code[i] = random(0,9); //Generate a random number for each digit
Serial.print(code[i]); //Display the code on Serial monitor for debugging
}
Serial.println();
}
void inputCodeGuess() //Function to allow the user to input a guess
{
for(int i=0 ; i<=3 ; i++) //User must guess all four digits
{
guessingDigit = i;
boolean confirmed = false; //Both used to confirm button push to assign a digit to the guess code
//rotaryEncoder.setEncoderValue(0);
updateDisplayCode();
while(!confirmed) //While the user has not confirmed the digit input
{
if (rotaryEncoder.encoderChanged())
{
Serial.println(rotaryEncoder.readEncoder());
encoderPos = rotaryEncoder.readEncoder(); //Store encoder position
codeGuess[i] = encoderPos; //If the button is pressed, accept the current digit into the guessed code
updateDisplayCode();
}
if (rotaryEncoder.isEncoderButtonClicked())
{
codeGuess[i] = encoderPos; //If the button is pressed, accept the current digit into the guessed code
updateDisplayCode();
confirmed=true; //Update the code being displayed
}
}
}
}
void checkCodeGuess() //Function to check the users guess against the generated code
{
int correctNum = 0; //Variable for the number of correct digits in the wrong place
int correctPlace = 0; //Variable for the number of correct digits in the correct place
int usedDigits[4] = {0,0,0,0}; //Mark off digits which have been already identified in the wrong place, avoids counting repeated digits twice
for (int i=0 ; i<= 3 ; i++) //Loop through the four digits in the guessed code
{
for (int j=0 ; j<=3 ; j++) //Loop through the four digits in the generated code
{
if (codeGuess[i]==code[j]) //If a number is found to match
{
if(usedDigits[j]!=1) //Check that it hasn't been previously identified
{
correctNum++; //Increment the correct digits in the wrong place counter
usedDigits[j] = 1; //Mark off the digit as been identified
break; //Stop looking once the digit is found
}
}
}
}
for (int i=0 ; i<= 3 ; i++) //Compares the guess digits to the code digits for correct digits in correct place
{
if (codeGuess[i]==code[i]) //If a correct digit in the correct place is found
correctPlace++; //Increment the correct place counter
}
Serial.print("Correct Place: ");
Serial.println(correctPlace);
updateLEDs(correctNum, correctPlace); //Calls a function to update the LEDs to reflect the guess
if(correctPlace==4) //If all 4 digits are correct then the code has been cracked
{
display.clearDisplay(); //Clear the display
display.setCursor(20,10); //Set the display cursor position
display.print(F("Cracked")); //Set the display text
display.display(); //Output the display text
correctGuess = true;
}
else
correctGuess = false;
}
void updateLEDs (int corNum, int corPla) //Function to update the LEDs to reflect the guess
{
for(int i=0 ; i<=3 ; i++) //First turn all LEDs off
{
digitalWrite(correctNumLEDs[i], LOW);
digitalWrite(correctPlaceLEDs[i], LOW);
}
for(int j=0 ; j<=corNum-1 ; j++) //Turn on the number of correct digits in wrong place LEDs
{
digitalWrite(correctNumLEDs[j], HIGH);
}
for(int k=0 ; k<=corPla-1 ; k++) //Turn on the number of correct digits in the correct place LEDs
{
Serial.print("Turn correct place led number: ");
Serial.println(correctPlaceLEDs[k]);
digitalWrite(correctPlaceLEDs[k], HIGH);
}
}
void startupAni ()
{
display.setTextSize(2); //Set the display text size
display.setCursor(35,10); //Set the display cursor position
display.println(F("Crack")); //Set the display text
display.display(); //Output the display text
delay(500);
display.clearDisplay(); //Clear the display
display.setCursor(45,10);
display.println(F("The"));
display.display();
delay(500);
display.clearDisplay();
display.setCursor(40,10);
display.println(F("Code"));
display.display();
delay(500);
display.clearDisplay();
}
סיכום

כמו בפרוייקטים הקודמים, גם כאן, מה שמנחה אותי הוא השילוב בין רוחניות וטכנולוגיה.

מי שדם דומה זורם בעורקיו, מוזמן ליצור קשר asaf.matan@gmail.com או בתגובות למטה.





20 בדצמבר 2022

תאור

בפוסט זה נסקור מערכת Media Center בתקציב של כמה מאות שקלים ש"ח (לא כולל טלבזיה) שמריצה XBMC

המצרכים הדרושים

  • מסך טלבזיה עם כניסת HDMI
  •  RaspberryPi
  • מקלדת אלחוטית - אופציונלי
  • אפליקצית XBMC לטלפון סלולרי

    תרשים מערכת



    תמונות



    שלבי התקנה

    1. התקנת התקני תוכנת XBMC על ה RaspberryPi
    2. חיבור מסך הטלבזיה בכבל HDMI ל- RaspberryPi
    3. חיבור מקלדת אלחוטית ל- RaspberryPi
    4. הגדרת XBMC והפעלתו
    מערכת מסוג זה הוטמעה בחב"ד אלקנה/הרצליה/רעננה ובמספר בתים פרטיים.

    הערה: אם רוצים להיות פחות הרפתקניים - אפשר להשתמש בWD TV. זהו מוצר מוגמר והפעלתו מיידית ולא דורשת ידע מוקדם שגם הוא לא יקר עולה כ180 ש"ח - WD TV הוטמע בבית חב"ד רעננה צפון.

    11 בפברואר 2022

    מסגרת החיוכים - Smile Frame

    פרוייקט באווירת חודש אדר על בסיס  הקטע המדהים של האדמו"ר הצמח צדק משושלת אדמורי חב"ד:

    "וגם עוד זאת, שיראה בעצמו תמיד בתנועות הגוף תנועות המשמחות, כי לפי הפעולות נמשכות הלבבות"

    מפתיע לראות את המשפט הנ"ל במשנת חב"ד אבל אמירה זאת היא אמת לאמיתה: שמחה חיצונית מעוררת את שמחת הלב.


    דבר היוצר :)




    מבט קדמי





    מבט אחורי


    מדריך מעולה של חברת Adafruit על חיבור הרסברי פי למסך והגדרתו - כאן

    קצת על התיאוריה של אלגוריתם Haar Cascade שעושים בו שימוש - כאן

    קוד האפליקציה




    import numpy as np
    import cv2
    import numpy as np
    import sys
    # https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    # https://github.com/Itseez/opencv/blob/master/data/haarcascades/haarcascade_eye.xml
    eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
    smile_cascade = cv2.CascadeClassifier('haarcascade_smile.xml')
    #cap = cv2.VideoCapture(0)
    from picamera.array import PiRGBArray
    from picamera import PiCamera
    import time
    IM_WIDTH = 640
    IM_HEIGHT = 480
    # initialize the camera and grab a reference to the raw camera capture
    camera = PiCamera()
    camera.resolution = (IM_WIDTH,IM_HEIGHT)
    camera.framerate = 10
    rawCapture = PiRGBArray(camera, size=(IM_WIDTH,IM_HEIGHT))
    rawCapture.truncate(0)
    # allow the camera to warmup
    time.sleep(1)
    # capture frames from the camera
    for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    #while 1:
    #ret, img = cap.read()
    img = frame.array
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    ###Face detection
    for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
    roi_gray = gray[y:y + h, x:x + w]
    roi_color = img[y:y + h, x:x + w]
    ###smile detection
    smile = smile_cascade.detectMultiScale(
    roi_gray,
    scaleFactor=1.7,
    minNeighbors=22,
    minSize=(25, 25),
    flags=cv2.CASCADE_SCALE_IMAGE
    )
    ##Eye Detection
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex, ey, ew, eh) in eyes:
    cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
    #print (("Found"), len(eyes), ("eyes!"))
    # Set region of interest for smiles
    for (x, y, w, h) in smile:
    print (("Found"), len(smile), ("smiles!"))
    cv2.rectangle(roi_color, (x, y), (x + w, y + h), (0, 0, 255), 1)
    image = cv2.imread('pic.png')
    cv2.namedWindow("Face1", cv2.WND_PROP_FULLSCREEN)
    cv2.setWindowProperty("Face1",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
    cv2.imshow('Face1', image)
    cv2.waitKey(3000)
    cv2.destroyWindow("Face1")
    cv2.namedWindow("Face", cv2.WND_PROP_FULLSCREEN)
    cv2.setWindowProperty("Face",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
    cv2.imshow('Face', img)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
    break
    rawCapture.truncate(0)
    #cap.release()
    cv2.destroyAllWindows()
    view raw smile_frame.py hosted with ❤ by GitHub
    קישור לקוד ומספר קישורים שעוזרים להתחיל בתהליך ההתקנה: כאן


    23 בינואר 2022

    כובע קסמים - NeoMatrix - פורים 22

     כובע קסמים - NeoMatrix - פורים 2022

    מבוא

    כבר 9 שנים ברציפות יש לנו מנהג נחמד במשפחה, להקליט סרטון קצר "פורים שמח ממשפחת מתן". לפורים תשפ"ב הכנו כובע קסמים עם מטריצת לדים גמישה של חברת Adafruit ומעבד Flora של אותה חברה.



    פרוייקט השראה - https://learn.adafruit.com/smssenger-bag של  Becky Stern

    רשימת הרכיבים

    • מטריצת לדים גמישה NeoMatrix 8x32 של חברת Adafruit - קישור
    • מעבד FLORA של Adafruit - קישור
    • חוטי חיווט בצבעי אדום, שחור, וירוק כדוגמת אלו
    • מחזיק סוללות AAAx3, עם חיבור JST - קישור
    • כובע קוסמים מלבד. שום דרישה מיוחדת, רק שיהיה מספיק גבוה - כ20ס"מ

    תכנון וביצוע

    מבט על כובע הלבד לפני חיבור המטריצה



    בדיקת המטריצה לפני החיבור





    תמונות לאחר חיבור ראשוני לפני ההידוק



    תמונת הכובע מבפנים עם מחזיק הסוללות





    חיבור החוטים למעבד FLORA


    להלן הקוד הכולל שימוש בפונטים עבריים וגלילתם מימין לשמאל

    #include <Adafruit_GFX.h>
    #include <Adafruit_NeoMatrix.h>
    #include <Adafruit_NeoPixel.h>
    #include <Fonts/hebEng5x7avia.h>
    #define PIN 12
    // MATRIX DECLARATION:
    // Parameter 1 = width of NeoPixel matrix
    // Parameter 2 = height of matrix
    // Parameter 3 = pin number (most are valid)
    // Parameter 4 = matrix layout flags, add together as needed:
    // NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
    // Position of the FIRST LED in the matrix; pick two, e.g.
    // NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
    // NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
    // rows or in vertical columns, respectively; pick one or the other.
    // NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
    // in the same order, or alternate lines reverse direction; pick one.
    // See example below for these values in action.
    // Parameter 5 = pixel type flags, add together as needed:
    // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
    // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
    // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
    // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
    // Example for NeoPixel Shield. In this application we'd like to use it
    // as a 5x8 tall matrix, with the USB port positioned at the top of the
    // Arduino. When held that way, the first pixel is at the top right, and
    // lines are arranged in columns, progressive order. The shield uses
    // 800 KHz (v2) pixels that expect GRB color data.
    Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(32, 8, PIN,
    NEO_MATRIX_BOTTOM + NEO_MATRIX_RIGHT +
    NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
    NEO_GRB + NEO_KHZ800);
    const uint16_t colors[] = {
    matrix.Color(148, 0, 211), matrix.Color(75, 0, 130), matrix.Color(0, 0, 255), matrix.Color(0, 255, 0), matrix.Color(255, 255, 0), matrix.Color(255, 127, 80) , matrix.Color(255, 0, 0)};
    // אבגדהוזחטיכךלמםנןסעפףצץקרשת//
    //char replybuffer[255]={0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9A};
    // this is a large buffer for replies
    char replybuffer[255]={0x21,0x21,0x21,0x8F,0x9A,0x8E,0x20,0x9A,0x87,0x94,0x99,0x8E,0x8E,0x20,0x87,0x8E,0x99,0x20,0x8D,0x89,0x98,0x85,0x94};
    uint8_t msgLen = 19; // Empty message
    int x = msgLen * -6;//matrix.width();
    int pass = 0; // variable we'll use to keep track of a cycling of colors
    int i;
    unsigned long prevFrameTime = 0L; // For animation timing
    #define FPS 20 // Scrolling speed
    // Pin 7 has an LED connected on FLORA.
    // give it a name:
    int led = 7;
    void setup() {
    Serial.begin(115200);
    Serial.println(F("LCD test"));
    Serial.println(F("Initializing....(May take 3 seconds)"));
    matrix.begin();
    matrix.setTextWrap(false);
    matrix.setBrightness(40);
    matrix.setTextColor(colors[0]);
    matrix.setFont(&hebEng5x7avia);
    // initialize the digital pin as an output.
    pinMode(led, OUTPUT);
    delay(1000);
    }
    void loop() {
    unsigned long t = millis(); // Current elapsed time, milliseconds.
    // millis() comparisons are used rather than delay() so that animation
    // speed is consistent regardless of message length & other factors.
    if((t - prevFrameTime) >= (1000L / FPS)) { // Handle scrolling
    matrix.fillScreen(0);
    matrix.setCursor(x, 1);
    for(i=0;i<=strlen(replybuffer);i++)
    {
    matrix.setTextColor(colors[i%7]);
    matrix.print(replybuffer[i]);
    }
    if(++x >= (msgLen * 6)) {
    x = msgLen * -6; // We must repeat!
    if(++pass >= 3) pass = 0;
    matrix.setTextColor(colors[pass]);
    }
    matrix.show();
    prevFrameTime = t;
    }
    }
    view raw magic_hat.ino hosted with ❤ by GitHub

    קישור לקוד: כאן

    לינקים שימושיים נוספים שיחסכו לכם זמן רב במידה ותרצו לממש משהו דומה

    • מדריך מפורט לשימוש במעבד Flora - כאן 
    • מדריך מפורט לילמוד שימוש NeoPixel Leds - כאן
    • פונטים עבריים לספריית Adafruit GFX - ראה כאן 
    • עורך Web לפונטים Adafruit GFX - כאן
    אשמח לקבל מכם הארות/הערות ושאלות בתגובות למטה

    28 בנובמבר 2021

    חנוכיית אולטרה - סגול


    מעט אור דוחה הרבה מן החושך (הבעל שם טוב)

    מבוא

     "באנו חושך לגרש...", הפעם, בעזרת לד אולטרה - סגול קטנטן ואבקת נאון פלורסנטית . פרוייקט  שמשלב תכנות, כימיה והדפסת תלת מימד. 


    ביצוע:

    בועז מתן: boazmatan@gmail.com

    אסף מתן: asaf.matan@gmail.com 


    פרוייקט השראה: https://learn.adafruit.com/mad-science-test-tube-rack




    רשימת הרכיבים

    • לד אולטרה סגול, 8 יחידות - קישור
    • אבקת נאון פלוריסנטית בשלל צבעים - קישור
    • מעבד D1 Mini - קישור
    • מבחנות בדיקה פלסטיות
    • עפרונות לא מחודדים - 4 יחידות
    • חוטי חשמל שחור כ-2 מ'
    • גוף החנוכייה בהדפסת תלת מימד

    מודל המנורה




    חיווט והרכבה





    חומר הנאון הפלורסנטי לפני הערבוב במבחנות



    לאחר מילוי החומר הפלורסנטי בערבוב עם מים




    לאחר חיווט הלדים בקדח 5ממ




    חיווט החוטים לבקר D1 Mini



    להלן הקוד שמדליק את הלדים בזה אחר זה - קישור

    בדיקות  של לד האולטרה - סגול ואבקת הנאון - שימו לב רק קמצוץ מספיק בכל מבחנה!!







    23 באוגוסט 2016

    גימיק שיווקי לKidsTora


    תאור

    ישנו אתר מאד שימושי שמאפשר לקנות בקלות אות בספר תורה לילדי ישראל www.kidstorah.org.

    בניתי באמצעות מעבד ESP8266 ותצוגה אלפאנומרית, מיצג שמראה אמה אותיות נשארו בספר תורה ומאפשר ע"י סריקה של ברקוד - לקנות אות בספר תורה. כמובן שתמיד אפשר לגשת לאתר באופן ישיר, אך כאמור מדובר בגימיק שיווקי.

    קהל היעד

    כל מי שרוצה לקדם את מבצעי הרבי מילובאוויטש ו/או להיות מקושר אליהם...

    המצרכים הדרושים

    • מעבד Adafruit Feather Huzzah - ESP8266 Core+USB to UART+Power manager for lithium ion
    • 2X4 Digit I2C alphanumeric display
    • MicroUSB cable
    • RIBBA picture frame from Ikea


    מאפיינים


    • חיבור חשמלי לשקע USB או מטען פלאפון.
    • מתחבר לרשת WIFI ומביא את מספר האותיות שנשארו בספר התורה ע"י ניתוח המידע מדף הבית של KidsTorah.org כל 10ד'.

    תמונות

    בשלבי הפיתוח






    המוצר המוגמר




    7 ביולי 2016

    Weather Lamp

    שלום לכולם,

    הפעם מדובר במימוש של עיצוב קיים של האחים Ruiz מ-Adafruit.

    מדובר מחשב זעיר:Feather Huzzah שיש בו התקן Wifi ומחובר לטבעת לדים NeoPixel 24

    המחשב פונה בצורה מחזורית לשירות מזג האויר של Yahoo ולפי מצב מזג האויר הוא מציג אנימציה יפה על הלדים, כך שבמבט קצר ניתן ללמוד על מזג האויר הצפוי לנו. במקום לפתוח עוד אפליקציה בטלפון, מבט חטוף באביזר הדקורטיבי הזה נותן לנו תחושה של מזג האויר.

    אני מחפש כיוונום איך לרתום התקן שכזה לכיוונים של יודאיקה., רעיונות יתקבלו בברכה...

    קישור לסרטון על ההתקן


    תמונות שצילמתי