├── .gitignore ├── README.md ├── alarm-clock ├── AlarmTone.cpp ├── AlarmTone.h ├── Button.cpp ├── Button.h ├── Clock.cpp ├── Clock.h ├── config.h ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── blink-without-delay-3-leds ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── blink ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── calculator ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── charlieplexing ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── dice-roller ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── eeprom ├── lesson.json ├── lesson.md └── sketch.ino ├── electronic-safe ├── SafeState.cpp ├── SafeState.h ├── icons.cpp ├── icons.h ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── fastled ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── happy-birthday ├── gift.h ├── lesson.json ├── lesson.md ├── pitches.h └── sketch.ino ├── i2c-scanner ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── keypad ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── lcd1602-i2c ├── cover.svg ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── lcd1602 ├── lesson.json ├── lesson.md └── sketch.ino ├── neopixel-matrix ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── neopixel-strip ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── potentiometer ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── rotary-dialer ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── serial ├── lesson.json ├── lesson.md ├── serial.svg ├── sketch.ino └── thumbnail.png ├── servo ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── seven-segment-clock ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── simon-game ├── lesson.json ├── lesson.md ├── pitches.h ├── sketch.ino └── thumbnail.png ├── spaceship-game ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── ssd1306 ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png ├── tamaguino ├── lesson.json ├── lesson.md └── sketch.ino ├── task-scheduler ├── lesson.json ├── lesson.md ├── sketch.ino └── task-scheduler.svg ├── traffic-light ├── lesson.json ├── lesson.md ├── sketch.ino └── thumbnail.png └── wokwi.json /.gitignore: -------------------------------------------------------------------------------- 1 | .history 2 | .idea 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation notice 2 | 3 | This repository is deprecated, as it is now possible to [create projects directly on Wokwi.com](https://wokwi.com/arduino/new). 4 | 5 | # Wokwi Playground Repository 6 | 7 | This repository hosts the code playgrounds on [wokwi.com](https://wokwi.com), e.g.: 8 | 9 | * [Blink](https://wokwi.com/playground/blink?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 10 | * [Blink (without delay)](https://wokwi.com/playground/blink-without-delay-3-leds?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 11 | * [Dice Roller](https://wokwi.com/playground/dice-roller?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 12 | * [LCD1602 I2C](https://wokwi.com/playground/lcd1602-i2c?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 13 | * [NeoPixel strip](https://wokwi.com/playground/neopixel-strip?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 14 | * [NeoPixel Matrix](https://wokwi.com/playground/neopixel-matrix?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 15 | * [Serial Playground](https://wokwi.com/playground/serial?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 16 | * [TaskScheduler](https://wokwi.com/playground/task-scheduler?utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 17 | 18 | ## Directory structure 19 | 20 | Each subdirectory is a different playground, and contains the following files: 21 | 22 | * `lesson.md` - A markdown file with text explaining about the background and HTML code that defines the hardware. A full list of supported hardware components can be found in the [Wokwi Elements Storybook page](https://elements.wokwi.com), and new components can be contributed [through github](https://github.com/wokwi/wokwi-elements). 23 | * `sketch.ino` - The arduino code for the playground 24 | * `lesson.json` - File that describes the lesson. You can add your name there, e.g.: `{"author": "Ariella Eliassaf"}`. This file must be present for the lesson to be recognized by Wokwi. 25 | 26 | ## Live editing 27 | 28 | If you wish to tinker with the markdown / hardware of any of the playgrounds, you can do so by going to 29 | the live playground on wokwi.com and adding `?beta-editor=yeah` at the end of the playground URL. For instance: 30 | 31 | [https://wokwi.com/playground/blink?beta-editor=yeah](https://wokwi.com/playground/blink?beta-editor=yeah&utm_source=github&utm_medium=social&utm_campaign=wokwi-playgrounds) 32 | 33 | This will open the [blink](blink/lesson.md) playground in live editing mode. 34 | 35 | # License 36 | 37 | The content of this repo is released under the [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) license. 38 | -------------------------------------------------------------------------------- /alarm-clock/AlarmTone.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "AlarmTone.h" 3 | 4 | #define TONE_TIME 500 /* ms */ 5 | #define TONE_SPACING 100 /* ms */ 6 | 7 | static const uint16_t TONES[] = { 8 | 500, 9 | 800, 10 | }; 11 | const uint16_t NUM_TONES = sizeof(TONES) / sizeof(TONES[0]); 12 | 13 | AlarmTone::AlarmTone() 14 | : _playing(false) 15 | , _tone_index(0) 16 | , _last_tone_time(0) { 17 | } 18 | 19 | void AlarmTone::begin(uint8_t pin) { 20 | _pin = pin; 21 | pinMode(_pin, OUTPUT); 22 | } 23 | 24 | void AlarmTone::play() { 25 | if (!_playing || _last_tone_time + TONE_TIME + TONE_SPACING < millis()) { 26 | tone(_pin, TONES[_tone_index], TONE_TIME); 27 | _tone_index = (_tone_index + 1) % NUM_TONES; 28 | _last_tone_time = millis(); 29 | } 30 | _playing = true; 31 | } 32 | 33 | void AlarmTone::stop() { 34 | noTone(_pin); 35 | _tone_index = 0; 36 | _playing = false; 37 | } 38 | -------------------------------------------------------------------------------- /alarm-clock/AlarmTone.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALARM_TONE_H__ 2 | #define __ALARM_TONE_H__ 3 | 4 | class AlarmTone { 5 | public: 6 | AlarmTone(); 7 | void begin(uint8_t pin); 8 | void play(); 9 | void stop(); 10 | 11 | private: 12 | uint8_t _pin; 13 | bool _playing; 14 | uint8_t _tone_index; 15 | unsigned long _last_tone_time; 16 | }; 17 | 18 | #endif /* __ALARM_TONE_H */ 19 | -------------------------------------------------------------------------------- /alarm-clock/Button.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Button - a small library for Arduino to handle button debouncing 3 | 4 | MIT licensed. 5 | */ 6 | 7 | #include "Button.h" 8 | #include 9 | 10 | Button::Button(uint8_t pin, uint16_t debounce_ms) 11 | : _pin(pin) 12 | , _delay(debounce_ms) 13 | , _state(HIGH) 14 | , _ignore_until(0) 15 | , _has_changed(false) 16 | , _reported_repeats(0) 17 | , _repeat_delay_ms(-1) 18 | , _repeat_ms(-1) 19 | { 20 | } 21 | 22 | void Button::begin() 23 | { 24 | pinMode(_pin, INPUT_PULLUP); 25 | } 26 | 27 | // 28 | // public methods 29 | // 30 | 31 | bool Button::read() 32 | { 33 | // ignore pin changes until after this delay time 34 | if (_ignore_until > millis()) 35 | { 36 | // ignore any changes during this period 37 | } 38 | 39 | // pin has changed 40 | else if (digitalRead(_pin) != _state) 41 | { 42 | _state = !_state; 43 | 44 | if (_state == RELEASED) 45 | { 46 | _reported_repeats = repeats_since_press(); 47 | } 48 | 49 | else 50 | { 51 | _reported_repeats = 0; 52 | } 53 | 54 | _ignore_until = millis() + _delay; 55 | _has_changed = true; 56 | } 57 | 58 | return _state; 59 | } 60 | 61 | // has the button been toggled from on -> off, or vice versa 62 | bool Button::toggled() 63 | { 64 | read(); 65 | return has_changed(); 66 | } 67 | 68 | // mostly internal, tells you if a button has changed after calling the read() function 69 | bool Button::has_changed() 70 | { 71 | if (_has_changed) 72 | { 73 | _has_changed = false; 74 | return true; 75 | } 76 | return false; 77 | } 78 | 79 | // how many repeated press events occured since the button was pressed 80 | uint16_t Button::repeat_count() 81 | { 82 | return _state == PRESSED ? repeats_since_press() : _reported_repeats; 83 | } 84 | 85 | // has the button gone from off -> on or pressed repeatedly 86 | bool Button::pressed() 87 | { 88 | if (read() == PRESSED) 89 | { 90 | uint16_t old_repeats = _reported_repeats; 91 | _reported_repeats = repeats_since_press(); 92 | return (has_changed() || old_repeats != _reported_repeats); 93 | } 94 | else 95 | { 96 | return false; 97 | } 98 | } 99 | 100 | // has the button gone from on -> off 101 | bool Button::released() 102 | { 103 | return (read() == RELEASED && has_changed()); 104 | } 105 | 106 | void Button::set_repeat(int16_t delay_ms, int16_t repeat_ms) 107 | { 108 | _repeat_delay_ms = delay_ms > _delay ? delay_ms - _delay : 0; 109 | _repeat_ms = repeat_ms; 110 | } 111 | 112 | uint16_t Button::repeats_since_press() 113 | { 114 | if (_repeat_delay_ms == -1 || millis() < _ignore_until + _repeat_delay_ms) 115 | { 116 | return 0; 117 | } 118 | 119 | if (_repeat_ms <= 0) 120 | { 121 | return 1; 122 | } 123 | 124 | uint32_t press_time = millis() - _ignore_until; 125 | return 1 + (press_time - _repeat_delay_ms) / _repeat_ms; 126 | } 127 | -------------------------------------------------------------------------------- /alarm-clock/Button.h: -------------------------------------------------------------------------------- 1 | /* 2 | Button - a small library for Arduino to handle button debouncing 3 | 4 | MIT licensed. 5 | */ 6 | 7 | #ifndef Button_h 8 | #define Button_h 9 | #include "Arduino.h" 10 | 11 | class Button 12 | { 13 | public: 14 | Button(uint8_t pin, uint16_t debounce_ms = 100); 15 | void begin(); 16 | bool read(); 17 | bool toggled(); 18 | bool pressed(); 19 | bool released(); 20 | bool has_changed(); 21 | uint16_t repeat_count(); 22 | void set_repeat(int16_t delay_ms, int16_t repeat_ms); 23 | 24 | const static bool PRESSED = LOW; 25 | const static bool RELEASED = HIGH; 26 | 27 | private: 28 | uint16_t repeats_since_press(); 29 | 30 | uint8_t _pin; 31 | uint16_t _delay; 32 | bool _state; 33 | uint32_t _ignore_until; 34 | bool _has_changed; 35 | uint16_t _reported_repeats; 36 | int16_t _repeat_delay_ms; 37 | int16_t _repeat_ms; 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /alarm-clock/Clock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Clock.h" 3 | 4 | #define MINUTE 60 * 1000L /* ms */ 5 | #define TIMESPAN_DAY TimeSpan(1, 0, 0, 0) 6 | 7 | #define NVRAM_ADDR_ALARM_ENABLED 0 8 | #define NVRAM_ADDR_ALARM_HOUR 1 9 | #define NVRAM_ADDR_ALARM_MINUTE 2 10 | 11 | 12 | Clock::Clock() 13 | : _alarm_state(ALARM_OFF) 14 | , _alarm_snooze_time(0) 15 | , _alarm_hour(DEFAULT_ALARM_HOUR) 16 | , _alarm_minute(0) { 17 | } 18 | 19 | void Clock::begin() { 20 | # if USE_RTC 21 | if (!_rtc.begin()) { 22 | Serial.println("Couldn't find RTC"); 23 | abort(); 24 | } 25 | _alarm_state = _rtc.readnvram(NVRAM_ADDR_ALARM_ENABLED) ? ALARM_OFF : ALARM_DISABLED; 26 | _alarm_hour = _rtc.readnvram(NVRAM_ADDR_ALARM_HOUR) % 24; 27 | _alarm_minute = _rtc.readnvram(NVRAM_ADDR_ALARM_MINUTE) % 60; 28 | # else /* USE_RTC */ 29 | DateTime zeroTime; 30 | _rtc.begin(zeroTime); 31 | # endif 32 | } 33 | 34 | /***** Clock management *****/ 35 | 36 | DateTime Clock::now() { 37 | return _rtc.now(); 38 | } 39 | 40 | void Clock::incrementMinute() { 41 | DateTime now = _rtc.now(); 42 | DateTime newTime = DateTime(now.year(), now.month(), now.day(), now.hour(), 43 | (now.minute() + 1) % 60); 44 | _rtc.adjust(newTime); 45 | } 46 | 47 | void Clock::incrementHour() { 48 | DateTime now = _rtc.now(); 49 | DateTime newTime = DateTime(now.year(), now.month(), now.day(), 50 | (now.hour() + 1) % 24, now.minute()); 51 | _rtc.adjust(newTime); 52 | } 53 | 54 | /***** Alarm management *****/ 55 | bool Clock::_isAlarmDueTime() { 56 | auto currentTime = now(); 57 | auto alarm = alarmTime(); 58 | return ((currentTime.hour() == alarm.hour()) 59 | && (currentTime.minute() == alarm.minute())); 60 | } 61 | 62 | bool Clock::alarmEnabled() { 63 | return _alarm_state != ALARM_DISABLED; 64 | } 65 | 66 | bool Clock::alarmActive() { 67 | switch (_alarm_state) { 68 | case ALARM_DISABLED: 69 | return false; 70 | 71 | case ALARM_OFF: 72 | if (_isAlarmDueTime()) { 73 | _alarm_state = ALARM_ACTIVE; 74 | return true; 75 | } 76 | return false; 77 | 78 | case ALARM_ACTIVE: 79 | return true; 80 | 81 | case ALARM_SNOOZED: 82 | if (millis() >= _alarm_snooze_time) { 83 | _alarm_state = ALARM_ACTIVE; 84 | return true; 85 | } 86 | return false; 87 | 88 | case ALARM_STOPPED: 89 | if (!_isAlarmDueTime()) { 90 | _alarm_state = ALARM_OFF; 91 | } 92 | return false; 93 | 94 | default: 95 | return false; 96 | } 97 | } 98 | 99 | 100 | void Clock::toggleAlarm() { 101 | bool enabled = !alarmEnabled(); 102 | _alarm_state = enabled ? ALARM_OFF : ALARM_DISABLED; 103 | _rtc.writenvram(NVRAM_ADDR_ALARM_ENABLED, enabled); 104 | } 105 | 106 | DateTime Clock::alarmTime() { 107 | DateTime now = _rtc.now(); 108 | DateTime alarm = DateTime(now.year(), now.month(), now.day(), _alarm_hour, _alarm_minute); 109 | return alarm >= now ? alarm : alarm + TIMESPAN_DAY; 110 | } 111 | 112 | void Clock::snooze() { 113 | _alarm_state = ALARM_SNOOZED; 114 | _alarm_snooze_time = millis() + SNOOZE_TIME * MINUTE; 115 | } 116 | 117 | void Clock::stopAlarm() { 118 | _alarm_state = ALARM_STOPPED; 119 | } 120 | 121 | void Clock::incrementAlarmHour() { 122 | _alarm_hour = (_alarm_hour + 1) % 24; 123 | _alarm_state = ALARM_OFF; 124 | _rtc.writenvram(NVRAM_ADDR_ALARM_HOUR, _alarm_hour); 125 | } 126 | 127 | void Clock::incrementAlarmMinute() { 128 | _alarm_minute = (_alarm_minute + 1) % 60; 129 | _alarm_state = ALARM_OFF; 130 | _rtc.writenvram(NVRAM_ADDR_ALARM_MINUTE, _alarm_minute); 131 | } 132 | -------------------------------------------------------------------------------- /alarm-clock/Clock.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLOCK_H__ 2 | #define __CLOCK_H__ 3 | 4 | #include 5 | #include "config.h" 6 | 7 | enum AlarmState { 8 | ALARM_DISABLED, 9 | ALARM_OFF, 10 | ALARM_ACTIVE, 11 | ALARM_SNOOZED, 12 | ALARM_STOPPED, 13 | }; 14 | 15 | class Clock { 16 | public: 17 | Clock(); 18 | void begin(); 19 | 20 | /* Clock management */ 21 | DateTime now(); 22 | void incrementMinute(); 23 | void incrementHour(); 24 | 25 | /* Alarm Management */ 26 | bool alarmEnabled(); 27 | DateTime alarmTime(); 28 | bool alarmActive(); 29 | void toggleAlarm(); 30 | void snooze(); 31 | void stopAlarm(); 32 | void incrementAlarmHour(); 33 | void incrementAlarmMinute(); 34 | 35 | protected: 36 | bool _isAlarmDueTime(); 37 | 38 | #if USE_RTC 39 | RTC_DS1307 _rtc; 40 | #else /* USE_RTC */ 41 | RTC_Millis _rtc; 42 | #endif /* USE_RTC */ 43 | 44 | byte _alarm_hour; 45 | byte _alarm_minute; 46 | AlarmState _alarm_state; 47 | unsigned long _alarm_snooze_time; 48 | }; 49 | 50 | #endif /* __CLOCK_H__ */ 51 | -------------------------------------------------------------------------------- /alarm-clock/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Digital Alarm Clock 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | 7 | Clock Configuration File. 8 | */ 9 | 10 | #ifndef __CONFIG_H__ 11 | #define __CONFIG_H__ 12 | 13 | /** 14 | Change to 0 for running without an external RTC (Real time clock) 15 | */ 16 | #define USE_RTC 1 17 | 18 | /** 19 | Your 7-Segment display type: COMMON_ANODE or COMMON_CATHODE 20 | */ 21 | #define DISPLAY_TYPE COMMON_ANODE 22 | 23 | /** 24 | For how long should we show the alarm status (on/off)? 25 | */ 26 | const int ALARM_STATUS_DISPLAY_TIME = 1000; /* ms */ 27 | 28 | /** 29 | For how long should we show the alarm hour? 30 | */ 31 | const int ALARM_HOUR_DISPLAY_TIME = 2500; /* ms */ 32 | 33 | /** 34 | For how long should we display the snooze screen? 35 | */ 36 | const int SNOOZE_DISPLAY_TIME = 500; /* ms */ 37 | 38 | /** 39 | How many minutes to snooze the alarm for? 40 | */ 41 | const int SNOOZE_TIME = 9; /* minutes */ 42 | 43 | /** 44 | The default Alarm hour (for non-RTC mode) 45 | */ 46 | const int DEFAULT_ALARM_HOUR = 9; 47 | 48 | #endif /* __CONFIG_H__ */ 49 | -------------------------------------------------------------------------------- /alarm-clock/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Alarm Clock", 3 | "thumbnail": "thumbnail.png", 4 | "files": [ 5 | "AlarmTone.cpp", 6 | "AlarmTone.h", 7 | "Button.cpp", 8 | "Button.h", 9 | "config.h", 10 | "Clock.cpp", 11 | "Clock.h" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /alarm-clock/lesson.md: -------------------------------------------------------------------------------- 1 | # Arduino Alarm Clock 2 | 3 | Digital Alarm Clock with RTC and Snooze function. Click on Run Code to start the simulation. 4 | 5 |
6 | 8 | 9 |
10 | 11 |
12 |
13 | 14 | Hour 15 |
16 |
17 | 18 | Minute 19 |
20 |
21 | 22 | Alarm 23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /alarm-clock/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Digital Alarm Clock 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | 7 | */ 8 | 9 | #include 10 | #include "Button.h" 11 | #include "AlarmTone.h" 12 | #include "Clock.h" 13 | #include "config.h" 14 | 15 | const int COLON_PIN = 13; 16 | const int SPEAKER_PIN = A3; 17 | 18 | Button hourButton(A0); 19 | Button minuteButton(A1); 20 | Button alarmButton(A2); 21 | 22 | AlarmTone alarmTone; 23 | Clock clock; 24 | SevSeg sevseg; 25 | 26 | enum DisplayState { 27 | DisplayClock, 28 | DisplayAlarmStatus, 29 | DisplayAlarmTime, 30 | DisplayAlarmActive, 31 | DisplaySnooze, 32 | }; 33 | 34 | DisplayState displayState = DisplayClock; 35 | long lastStateChange = 0; 36 | 37 | void changeDisplayState(DisplayState newValue) { 38 | displayState = newValue; 39 | lastStateChange = millis(); 40 | } 41 | 42 | long millisSinceStateChange() { 43 | return millis() - lastStateChange; 44 | } 45 | 46 | void setColon(bool value) { 47 | digitalWrite(COLON_PIN, value ? LOW : HIGH); 48 | } 49 | 50 | void displayTime() { 51 | DateTime now = clock.now(); 52 | bool blinkState = now.second() % 2 == 0; 53 | sevseg.setNumber(now.hour() * 100 + now.minute()); 54 | setColon(blinkState); 55 | } 56 | 57 | void clockState() { 58 | displayTime(); 59 | 60 | if (alarmButton.read() == Button::RELEASED && clock.alarmActive()) { 61 | // Read alarmButton has_changed() to clear its state 62 | alarmButton.has_changed(); 63 | changeDisplayState(DisplayAlarmActive); 64 | return; 65 | } 66 | 67 | if (hourButton.pressed()) { 68 | clock.incrementHour(); 69 | } 70 | if (minuteButton.pressed()) { 71 | clock.incrementMinute(); 72 | } 73 | if (alarmButton.pressed()) { 74 | clock.toggleAlarm(); 75 | changeDisplayState(DisplayAlarmStatus); 76 | } 77 | } 78 | 79 | void alarmStatusState() { 80 | setColon(false); 81 | sevseg.setChars(clock.alarmEnabled() ? " on" : " off"); 82 | if (millisSinceStateChange() > ALARM_STATUS_DISPLAY_TIME) { 83 | changeDisplayState(clock.alarmEnabled() ? DisplayAlarmTime : DisplayClock); 84 | return; 85 | } 86 | } 87 | 88 | void alarmTimeState() { 89 | DateTime alarm = clock.alarmTime(); 90 | sevseg.setNumber(alarm.hour() * 100 + alarm.minute(), -1); 91 | 92 | if (millisSinceStateChange() > ALARM_HOUR_DISPLAY_TIME || alarmButton.pressed()) { 93 | changeDisplayState(DisplayClock); 94 | return; 95 | } 96 | 97 | if (hourButton.pressed()) { 98 | clock.incrementAlarmHour(); 99 | lastStateChange = millis(); 100 | } 101 | if (minuteButton.pressed()) { 102 | clock.incrementAlarmMinute(); 103 | lastStateChange = millis(); 104 | } 105 | if (alarmButton.pressed()) { 106 | changeDisplayState(DisplayClock); 107 | } 108 | } 109 | 110 | void alarmState() { 111 | displayTime(); 112 | 113 | if (alarmButton.read() == Button::RELEASED) { 114 | alarmTone.play(); 115 | } 116 | if (alarmButton.pressed()) { 117 | alarmTone.stop(); 118 | } 119 | if (alarmButton.released()) { 120 | alarmTone.stop(); 121 | bool longPress = alarmButton.repeat_count() > 0; 122 | if (longPress) { 123 | clock.stopAlarm(); 124 | changeDisplayState(DisplayClock); 125 | } else { 126 | clock.snooze(); 127 | changeDisplayState(DisplaySnooze); 128 | } 129 | } 130 | } 131 | 132 | void snoozeState() { 133 | sevseg.setChars("****"); 134 | if (millisSinceStateChange() > SNOOZE_DISPLAY_TIME) { 135 | changeDisplayState(DisplayClock); 136 | return; 137 | } 138 | } 139 | 140 | void setup() { 141 | Serial.begin(115200); 142 | 143 | clock.begin(); 144 | 145 | hourButton.begin(); 146 | hourButton.set_repeat(500, 200); 147 | 148 | minuteButton.begin(); 149 | minuteButton.set_repeat(500, 200); 150 | 151 | alarmButton.begin(); 152 | alarmButton.set_repeat(1000, -1); 153 | 154 | alarmTone.begin(SPEAKER_PIN); 155 | 156 | pinMode(COLON_PIN, OUTPUT); 157 | 158 | byte digits = 4; 159 | byte digitPins[] = {2, 3, 4, 5}; 160 | byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12}; 161 | bool resistorsOnSegments = false; 162 | bool updateWithDelays = false; 163 | bool leadingZeros = true; 164 | bool disableDecPoint = true; 165 | sevseg.begin(DISPLAY_TYPE, digits, digitPins, segmentPins, resistorsOnSegments, 166 | updateWithDelays, leadingZeros, disableDecPoint); 167 | sevseg.setBrightness(90); 168 | } 169 | 170 | void loop() { 171 | sevseg.refreshDisplay(); 172 | 173 | switch (displayState) { 174 | case DisplayClock: 175 | clockState(); 176 | break; 177 | 178 | case DisplayAlarmStatus: 179 | alarmStatusState(); 180 | break; 181 | 182 | case DisplayAlarmTime: 183 | alarmTimeState(); 184 | break; 185 | 186 | case DisplayAlarmActive: 187 | alarmState(); 188 | break; 189 | 190 | case DisplaySnooze: 191 | snoozeState(); 192 | break; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /alarm-clock/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/alarm-clock/thumbnail.png -------------------------------------------------------------------------------- /blink-without-delay-3-leds/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Blink Without Delay", 3 | "thumbnail": "thumbnail.png", 4 | "coverImage": "https://developwithdan.com/wp-content/uploads/2020/02/Blink-Without-Delayt-1200x700.jpg" 5 | } 6 | -------------------------------------------------------------------------------- /blink-without-delay-3-leds/lesson.md: -------------------------------------------------------------------------------- 1 | # Understanding Blink without Delay Demo Code 2 | 3 | This is the sample code from Dan Hoover's article Understanding Blink Without Delay 4 | 5 | It shows how to use the `millis()` function to blink 3 LEDs, each with a different interval: 6 | 7 | 8 | 9 | 10 | 11 | Click on "Run Code" to see it in action. Can you achieve the same effect with 12 | less code and still without using `delay()` ? 13 | 14 | For more information, check out Dan's YouTube tutorial: 15 | 16 | 17 | -------------------------------------------------------------------------------- /blink-without-delay-3-leds/sketch.ino: -------------------------------------------------------------------------------- 1 | // Code from https://github.com/mudmin/AnotherMaker/tree/master/blink-without-delay 2 | 3 | int red = 2; 4 | int intervalRed = 1000; //how long to delay in millis 5 | unsigned long previousRed = 0; 6 | int redState = LOW; 7 | 8 | int blue = 3; 9 | int intervalBlue = 2500; //how long to delay in millis 10 | unsigned long previousBlue = 0; 11 | int blueState = LOW; 12 | 13 | int green = 4; 14 | int intervalGreen = 5000; //how long to delay in millis 15 | unsigned long previousGreen = 0; 16 | int greenState = LOW; 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | pinMode(red, OUTPUT); 21 | pinMode(blue, OUTPUT); 22 | pinMode(green, OUTPUT); 23 | } 24 | 25 | void checkRed() { 26 | unsigned long currentMillis = millis(); 27 | 28 | if (currentMillis - previousRed >= intervalRed) { 29 | //save this reading! 30 | previousRed = currentMillis; 31 | 32 | //figure out if you should turn the LED on or off 33 | if (redState == LOW) { 34 | redState = HIGH; 35 | } else { 36 | redState = LOW; 37 | } 38 | digitalWrite(red, redState); 39 | } 40 | } 41 | 42 | void checkGreen() { 43 | unsigned long currentMillis = millis(); 44 | 45 | if (currentMillis - previousGreen >= intervalGreen) { 46 | //save this reading! 47 | previousGreen = currentMillis; 48 | 49 | //figure out if you should turn the LED on or off 50 | if (greenState == LOW) { 51 | greenState = HIGH; 52 | } else { 53 | greenState = LOW; 54 | } 55 | digitalWrite(green, greenState); 56 | } 57 | } 58 | 59 | void checkBlue() { 60 | unsigned long currentMillis = millis(); 61 | 62 | if (currentMillis - previousBlue >= intervalBlue) { 63 | //save this reading! 64 | previousBlue = currentMillis; 65 | 66 | //figure out if you should turn the LED on or off 67 | if (blueState == LOW) { 68 | blueState = HIGH; 69 | } else { 70 | blueState = LOW; 71 | } 72 | digitalWrite(blue, blueState); 73 | } 74 | } 75 | 76 | 77 | void loop() { 78 | checkRed(); 79 | checkGreen(); 80 | checkBlue(); 81 | } 82 | -------------------------------------------------------------------------------- /blink-without-delay-3-leds/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/blink-without-delay-3-leds/thumbnail.png -------------------------------------------------------------------------------- /blink/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Blink", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /blink/lesson.md: -------------------------------------------------------------------------------- 1 | # Arduino Blink 2 | 3 | The "Hello World" Arduino code example: Blinking an LED. 4 | 5 | The red LED is attached to digital pin 13, represented by `LED_BUILTIN` in the code. 6 | 7 | 8 | 9 | Click on "Run Code" to see it in action. 10 | -------------------------------------------------------------------------------- /blink/sketch.ino: -------------------------------------------------------------------------------- 1 | // the setup function runs once when you press reset or power the board 2 | void setup() { 3 | // initialize digital pin LED_BUILTIN as an output. 4 | pinMode(LED_BUILTIN, OUTPUT); 5 | } 6 | 7 | // the loop function runs over and over again forever 8 | void loop() { 9 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) 10 | delay(1000); // wait for a second 11 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW 12 | delay(1000); // wait for a second 13 | } 14 | -------------------------------------------------------------------------------- /blink/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/blink/thumbnail.png -------------------------------------------------------------------------------- /calculator/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Calculator", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /calculator/lesson.md: -------------------------------------------------------------------------------- 1 | # Arduino Calculator 🧮 2 | 3 | Project from [Good Arduino Code](https://goodarduinocode.com?utm_source=wokwi&utm_medium=site&utm_campaign=calculator). For more information, check out the [Calculator Project Page](https://goodarduinocode.com/projects/calculator?utm_source=wokwi&utm_medium=site&utm_campaign=calculator). 4 | 5 | Click on Run code to see it in action! 6 | 7 |
8 | 9 | 11 |
12 | -------------------------------------------------------------------------------- /calculator/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Calculator 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* Display */ 13 | LiquidCrystal lcd(12, 11, 10, 9, 8, 7); 14 | 15 | /* Keypad setup */ 16 | const byte KEYPAD_ROWS = 4; 17 | const byte KEYPAD_COLS = 4; 18 | byte rowPins[KEYPAD_ROWS] = {5, 4, 3, 2}; 19 | byte colPins[KEYPAD_COLS] = {A3, A2, A1, A0}; 20 | char keys[KEYPAD_ROWS][KEYPAD_COLS] = { 21 | {'1', '2', '3', '+'}, 22 | {'4', '5', '6', '-'}, 23 | {'7', '8', '9', '*'}, 24 | {'.', '0', '=', '/'} 25 | }; 26 | 27 | Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS); 28 | 29 | uint64_t value = 0; 30 | 31 | void showSpalshScreen() { 32 | lcd.print("GoodArduinoCode"); 33 | lcd.setCursor(3, 1); 34 | String message = "Calculator"; 35 | for (byte i = 0; i < message.length(); i++) { 36 | lcd.print(message[i]); 37 | delay(50); 38 | } 39 | delay(500); 40 | } 41 | 42 | void updateCursor() { 43 | if (millis() / 250 % 2 == 0 ) { 44 | lcd.cursor(); 45 | } else { 46 | lcd.noCursor(); 47 | } 48 | } 49 | 50 | void setup() { 51 | Serial.begin(115200); 52 | lcd.begin(16, 2); 53 | 54 | showSpalshScreen(); 55 | lcd.clear(); 56 | lcd.cursor(); 57 | 58 | lcd.setCursor(1, 0); 59 | } 60 | 61 | char operation = 0; 62 | String memory = ""; 63 | String current = ""; 64 | uint64_t currentDecimal; 65 | bool decimalPoint = false; 66 | 67 | double calculate(char operation, double left, double right) { 68 | switch (operation) { 69 | case '+': return left + right; 70 | case '-': return left - right; 71 | case '*': return left * right; 72 | case '/': return left / right; 73 | } 74 | } 75 | 76 | void processInput(char key) { 77 | if ('-' == key && current == "") { 78 | current = "-"; 79 | lcd.print("-"); 80 | return; 81 | } 82 | 83 | switch (key) { 84 | case '+': 85 | case '-': 86 | case '*': 87 | case '/': 88 | if (!operation) { 89 | memory = current; 90 | current = ""; 91 | } 92 | operation = key; 93 | lcd.setCursor(0, 1); 94 | lcd.print(key); 95 | lcd.setCursor(current.length() + 1, 1); 96 | return; 97 | 98 | case '=': 99 | float leftNum = memory.toDouble(); 100 | float rightNum = current.toDouble(); 101 | memory = String(calculate(operation, leftNum, rightNum)); 102 | current = ""; 103 | lcd.clear(); 104 | lcd.setCursor(1, 0); 105 | lcd.print(memory); 106 | lcd.setCursor(0, 1); 107 | lcd.print(operation); 108 | return; 109 | 110 | } 111 | 112 | if ('.' == key && current.indexOf('.') >= 0) { 113 | return; 114 | } 115 | 116 | if ('.' != key && current == "0") { 117 | current = String(key); 118 | } else if (key) { 119 | current += String(key); 120 | } 121 | 122 | lcd.print(key); 123 | } 124 | 125 | void loop() { 126 | updateCursor(); 127 | 128 | char key = keypad.getKey(); 129 | if (key) { 130 | processInput(key); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /calculator/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/calculator/thumbnail.png -------------------------------------------------------------------------------- /charlieplexing/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Charlieplexing", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /charlieplexing/lesson.md: -------------------------------------------------------------------------------- 1 | # Charlieplexing Playground 2 | 3 | Charlieplexing is a technique that lets you control a large number of LEDs using just a few 4 | Arduino pins. In this example, we're only using pins 2-10 to control 72 LEDs. 5 | 6 | Each LED is connected to a different combination of pins. For instance, the top-left LED's 7 | negative end (cathode) is connected to Arduino pin 2, and it's positive end (anode) is 8 | connected to pin number 3. 9 | 10 | Click on "Run Code" to see it in action! 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 |
82 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 |
93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 |
102 | 103 | **Challenge**: Can you change the code to display a pattern that looks like the letter "H"? 104 | 105 | **Advanced challenge**: Change the code to scroll the text "HELLO!" on the LED matrix. 106 | -------------------------------------------------------------------------------- /charlieplexing/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Charlieplexed LED Matrix Scanning demo. 3 | 4 | Copyright (C) 2019, Uri Shaked. Released under the MIT license. 5 | */ 6 | 7 | #define SCAN_DELAY 50 8 | 9 | byte LEDS[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 10 | const byte LED_COUNT = sizeof(LEDS); 11 | 12 | void setup() { 13 | } 14 | 15 | void loop() { 16 | for (int i = 0; i < LED_COUNT; i++) { 17 | for (int j = 0; j < LED_COUNT; j++) { 18 | if (i != j) { 19 | pinMode(LEDS[i], OUTPUT); 20 | pinMode(LEDS[j], OUTPUT); 21 | digitalWrite(LEDS[i], LOW); 22 | digitalWrite(LEDS[j], HIGH); 23 | delay(SCAN_DELAY); 24 | pinMode(LEDS[i], INPUT); 25 | pinMode(LEDS[j], INPUT); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /charlieplexing/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/charlieplexing/thumbnail.png -------------------------------------------------------------------------------- /dice-roller/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Dice Roller", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /dice-roller/lesson.md: -------------------------------------------------------------------------------- 1 | ## Game Dice Playground 🎲 2 | 3 | Write your code in the editor on the right, and the click on "Run code" 4 | to see it in action: 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
31 | 32 | 33 | A0 34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /dice-roller/sketch.ino: -------------------------------------------------------------------------------- 1 | // Arduino Dice Roller 2 | // Copyright (C) 2020, Uri Shaked 3 | 4 | #define BUTTON_PIN A0 5 | 6 | const byte die1Pins[] = { 2, 3, 4, 5, 6, 7, 8}; 7 | const byte die2Pins[] = { 9, 10, 11, 12, A3, A4, A5}; 8 | 9 | void setup() { 10 | pinMode(A0, INPUT_PULLUP); 11 | for (byte i = 0; i < 7; i++) { 12 | pinMode(die1Pins[i], OUTPUT); 13 | pinMode(die2Pins[i], OUTPUT); 14 | } 15 | } 16 | 17 | void displayNumber(const byte pins[], byte number) { 18 | digitalWrite(pins[0], number > 1 ? HIGH : LOW); // top-left 19 | digitalWrite(pins[1], number > 3 ? HIGH : LOW); // top-right 20 | digitalWrite(pins[2], number == 6 ? HIGH : LOW); // middle-left 21 | digitalWrite(pins[3], number % 2 == 1 ? HIGH : LOW); // center 22 | digitalWrite(pins[4], number == 6 ? HIGH : LOW); // middle-right 23 | digitalWrite(pins[5], number > 3 ? HIGH : LOW); // bottom-left 24 | digitalWrite(pins[6], number > 1 ? HIGH : LOW); // bottom-right 25 | } 26 | 27 | bool randomReady = false; 28 | 29 | void loop() { 30 | bool buttonPressed = digitalRead(BUTTON_PIN) == LOW; 31 | if (!randomReady && buttonPressed) { 32 | // Use the time until the first button press 33 | // to initialize the random number generator 34 | randomSeed(micros()); 35 | randomReady = true; 36 | } 37 | 38 | if (buttonPressed) { 39 | for (byte i = 0; i < 10; i++) { 40 | int num1 = random(1, 7); 41 | int num2 = random(1, 7); 42 | displayNumber(die1Pins, num1); 43 | displayNumber(die2Pins, num2); 44 | delay(50 + i * 20); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /dice-roller/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/dice-roller/thumbnail.png -------------------------------------------------------------------------------- /eeprom/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "EEPROM Playground" 3 | } 4 | -------------------------------------------------------------------------------- /eeprom/lesson.md: -------------------------------------------------------------------------------- 1 | # EEPROM Playground 2 | 3 | Run the simulation by clicking on Run Code, then interact with the program in the virtual Serial Monitor. 4 | 5 | The program counts how many times you pressed the green button, and also the total time the button was pressed. It stores this data in the Arduino's EEPROM, so the information is kept even if you refresh this page. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /eeprom/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUTTON_PIN 9 4 | #define DEBOUNCE_TIME 50 5 | 6 | struct UserData { 7 | bool firstTime; 8 | char name[32]; 9 | long pressCounter; 10 | double buttonSeconds; 11 | }; 12 | 13 | struct UserData userData; 14 | 15 | void initUserData() { 16 | userData.firstTime = true; 17 | memset(userData.name, 0, sizeof(userData.name)); 18 | userData.pressCounter = 0; 19 | userData.buttonSeconds = 0; 20 | } 21 | 22 | void saveUserData() { 23 | EEPROM.put(0, userData); 24 | } 25 | 26 | void inputUserName() { 27 | // Remove old data from the Serial input buffer 28 | while (Serial.available()) { 29 | Serial.read(); 30 | } 31 | 32 | Serial.println("Welcome to the Arduino EEPROM Playground!"); 33 | Serial.println("Please type your name:"); 34 | 35 | int inputChar = Serial.read(); 36 | int index = 0; 37 | while (inputChar != '\n') { 38 | if (inputChar != -1 && index < sizeof(userData.name) - 1) { 39 | userData.name[index] = inputChar; 40 | index++; 41 | } 42 | inputChar = Serial.read(); 43 | } 44 | userData.name[index] = '\0'; // End of string 45 | userData.firstTime = false; 46 | 47 | saveUserData(); 48 | 49 | Serial.print("Nice to meet you, "); 50 | Serial.print(userData.name); 51 | Serial.println("!"); 52 | 53 | Serial.println("Now, press the button..."); 54 | } 55 | 56 | void greetUser() { 57 | Serial.print("Good you see you again, "); 58 | Serial.print(userData.name); 59 | Serial.println("!"); 60 | 61 | Serial.println("To delete all data, write 'E'."); 62 | } 63 | 64 | void printButtonStats() { 65 | Serial.print("You pressed the button "); 66 | Serial.print(userData.pressCounter); 67 | Serial.print(" times, for a total of "); 68 | Serial.print(userData.buttonSeconds); 69 | Serial.println(" seconds."); 70 | } 71 | 72 | void setup() { 73 | pinMode(BUTTON_PIN, INPUT_PULLUP); 74 | Serial.begin(115200); 75 | 76 | EEPROM.get(0, userData); 77 | 78 | if (userData.firstTime) { 79 | initUserData(); 80 | inputUserName(); 81 | } else { 82 | greetUser(); 83 | printButtonStats(); 84 | } 85 | } 86 | 87 | bool buttonPressed() { 88 | return digitalRead(BUTTON_PIN) == LOW; 89 | } 90 | 91 | void loop() { 92 | // Wait for button press 93 | if (buttonPressed()) { 94 | long pressStartTime = millis(); 95 | delay(DEBOUNCE_TIME); // Wait for the button to settle 96 | while (buttonPressed()); // and to be released... 97 | 98 | userData.pressCounter++; 99 | userData.buttonSeconds += (double)(millis() - pressStartTime) / 1000; 100 | saveUserData(); 101 | 102 | printButtonStats(); 103 | } 104 | 105 | if (Serial.available() && Serial.read() == 'E') { 106 | Serial.print("Erasing your data..."); 107 | initUserData(); 108 | saveUserData(); 109 | Serial.println("DONE!"); 110 | Serial.println(""); 111 | 112 | // Now start from the beginning... 113 | inputUserName(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /electronic-safe/SafeState.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Electronic Safe 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #include 9 | #include 10 | #include "SafeState.h" 11 | 12 | /* Safe state */ 13 | #define EEPROM_ADDR_LOCKED 0 14 | #define EEPROM_ADDR_CODE_LEN 1 15 | #define EEPROM_ADDR_CODE 2 16 | #define EEPROM_EMPTY 0xff 17 | 18 | #define SAFE_STATE_OPEN (char)0 19 | #define SAFE_STATE_LOCKED (char)1 20 | 21 | SafeState::SafeState() { 22 | this->_locked = EEPROM.read(EEPROM_ADDR_LOCKED) == SAFE_STATE_LOCKED; 23 | } 24 | 25 | void SafeState::lock() { 26 | this->setLock(true); 27 | } 28 | 29 | bool SafeState::locked() { 30 | return this->_locked; 31 | } 32 | 33 | bool SafeState::hasCode() { 34 | auto codeLength = EEPROM.read(EEPROM_ADDR_CODE_LEN); 35 | return codeLength != EEPROM_EMPTY; 36 | } 37 | 38 | void SafeState::setCode(String newCode) { 39 | EEPROM.write(EEPROM_ADDR_CODE_LEN, newCode.length()); 40 | for (byte i = 0; i < newCode.length(); i++) { 41 | EEPROM.write(EEPROM_ADDR_CODE + i, newCode[i]); 42 | } 43 | } 44 | 45 | bool SafeState::unlock(String code) { 46 | auto codeLength = EEPROM.read(EEPROM_ADDR_CODE_LEN); 47 | if (codeLength == EEPROM_EMPTY) { 48 | // There was no code, so unlock always succeeds 49 | this->setLock(false); 50 | return true; 51 | } 52 | if (code.length() != codeLength) { 53 | return false; 54 | } 55 | for (byte i = 0; i < code.length(); i++) { 56 | auto digit = EEPROM.read(EEPROM_ADDR_CODE + i); 57 | if (digit != code[i]) { 58 | return false; 59 | } 60 | } 61 | this->setLock(false); 62 | return true; 63 | } 64 | 65 | void SafeState::setLock(bool locked) { 66 | this->_locked = locked; 67 | EEPROM.write(EEPROM_ADDR_LOCKED, locked ? SAFE_STATE_LOCKED : SAFE_STATE_OPEN); 68 | } 69 | 70 | -------------------------------------------------------------------------------- /electronic-safe/SafeState.h: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Electronic Safe 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #ifndef SAFESTATE_H 9 | #define SAFESTATE_H 10 | 11 | class SafeState { 12 | public: 13 | SafeState(); 14 | void lock(); 15 | bool unlock(String code); 16 | bool locked(); 17 | bool hasCode(); 18 | void setCode(String newCode); 19 | 20 | private: 21 | void setLock(bool locked); 22 | bool _locked; 23 | }; 24 | 25 | #endif /* SAFESTATE_H */ 26 | -------------------------------------------------------------------------------- /electronic-safe/icons.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Electronic Safe 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #include 9 | #include "icons.h" 10 | 11 | const byte iconLocked[8] PROGMEM = { 12 | 0b01110, 13 | 0b10001, 14 | 0b10001, 15 | 0b11111, 16 | 0b11011, 17 | 0b11011, 18 | 0b11111, 19 | }; 20 | 21 | const byte iconUnlocked[8] PROGMEM = { 22 | 0b01110, 23 | 0b10000, 24 | 0b10000, 25 | 0b11111, 26 | 0b11011, 27 | 0b11011, 28 | 0b11111, 29 | }; 30 | 31 | void init_icons(LiquidCrystal &lcd) { 32 | byte icon[8]; 33 | memcpy_P(icon, iconLocked, sizeof(icon)); 34 | lcd.createChar(ICON_LOCKED_CHAR, icon); 35 | memcpy_P(icon, iconUnlocked, sizeof(icon)); 36 | lcd.createChar(ICON_UNLOCKED_CHAR, icon); 37 | } 38 | -------------------------------------------------------------------------------- /electronic-safe/icons.h: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Electronic Safe 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #ifndef ICONS_H 9 | #define ICONS_H 10 | 11 | #include 12 | 13 | // Our custom icon numbers 14 | #define ICON_LOCKED_CHAR (byte)0 15 | #define ICON_UNLOCKED_CHAR (byte)1 16 | 17 | // This is a standard icon on the LCD1602 character set 18 | #define ICON_RIGHT_ARROW (byte)126 19 | 20 | void init_icons(LiquidCrystal &lcd); 21 | 22 | #endif /* ICONS_H */ 23 | -------------------------------------------------------------------------------- /electronic-safe/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Electronic Safe", 3 | "thumbnail": "thumbnail.png", 4 | "files": ["icons.cpp", "icons.h", "SafeState.cpp", "SafeState.h"] 5 | } 6 | -------------------------------------------------------------------------------- /electronic-safe/lesson.md: -------------------------------------------------------------------------------- 1 | # Arduino Electronic Safe 2 | 3 | Project from [Good Arduino Code](https://goodarduinocode.com?utm_source=wokwi&utm_medium=site&utm_campaign=electronic_safe). For more information, check out the [Electronic Safe Project Page](https://goodarduinocode.com/projects/electronic-safe?utm_source=wokwi&utm_medium=site&utm_campaign=electronic_safe). 4 | 5 | Click on Run code to see it in action! 6 | 7 |
8 | 9 | 10 |
11 | Locked 12 | 13 | Open 14 |
15 |
16 | -------------------------------------------------------------------------------- /electronic-safe/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Arduino Electronic Safe 3 | 4 | Copyright (C) 2020, Uri Shaked. 5 | Released under the MIT License. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "SafeState.h" 12 | #include "icons.h" 13 | 14 | /* Locking mechanism definitions */ 15 | #define SERVO_PIN 6 16 | #define SERVO_LOCK_POS 20 17 | #define SERVO_UNLOCK_POS 90 18 | Servo lockServo; 19 | 20 | /* Display */ 21 | LiquidCrystal lcd(12, 11, 10, 9, 8, 7); 22 | 23 | /* Keypad setup */ 24 | const byte KEYPAD_ROWS = 4; 25 | const byte KEYPAD_COLS = 4; 26 | byte rowPins[KEYPAD_ROWS] = {5, 4, 3, 2}; 27 | byte colPins[KEYPAD_COLS] = {A3, A2, A1, A0}; 28 | char keys[KEYPAD_ROWS][KEYPAD_COLS] = { 29 | {'1', '2', '3', 'A'}, 30 | {'4', '5', '6', 'B'}, 31 | {'7', '8', '9', 'C'}, 32 | {'*', '0', '#', 'D'} 33 | }; 34 | 35 | Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS); 36 | 37 | /* SafeState stores the secret code in EEPROM */ 38 | SafeState safeState; 39 | 40 | void lock() { 41 | lockServo.write(SERVO_LOCK_POS); 42 | safeState.lock(); 43 | } 44 | 45 | void unlock() { 46 | lockServo.write(SERVO_UNLOCK_POS); 47 | } 48 | 49 | void showStartupMessage() { 50 | lcd.setCursor(4, 0); 51 | lcd.print("Welcome!"); 52 | delay(1000); 53 | 54 | lcd.setCursor(0, 2); 55 | String message = "ArduinoSafe v1.0"; 56 | for (byte i = 0; i < message.length(); i++) { 57 | lcd.print(message[i]); 58 | delay(100); 59 | } 60 | delay(500); 61 | } 62 | 63 | String inputSecretCode() { 64 | lcd.setCursor(5, 1); 65 | lcd.print("[____]"); 66 | lcd.setCursor(6, 1); 67 | String result = ""; 68 | while (result.length() < 4) { 69 | char key = keypad.getKey(); 70 | if (key >= '0' && key <= '9') { 71 | lcd.print('*'); 72 | result += key; 73 | } 74 | } 75 | return result; 76 | } 77 | 78 | void showWaitScreen(int delayMillis) { 79 | lcd.setCursor(2, 1); 80 | lcd.print("[..........]"); 81 | lcd.setCursor(3, 1); 82 | for (byte i = 0; i < 10; i++) { 83 | delay(delayMillis); 84 | lcd.print("="); 85 | } 86 | } 87 | 88 | bool setNewCode() { 89 | lcd.clear(); 90 | lcd.setCursor(0, 0); 91 | lcd.print("Enter new code:"); 92 | String newCode = inputSecretCode(); 93 | 94 | lcd.clear(); 95 | lcd.setCursor(0, 0); 96 | lcd.print("Confirm new code"); 97 | String confirmCode = inputSecretCode(); 98 | 99 | if (newCode.equals(confirmCode)) { 100 | safeState.setCode(newCode); 101 | return true; 102 | } else { 103 | lcd.clear(); 104 | lcd.setCursor(1, 0); 105 | lcd.print("Code mismatch"); 106 | lcd.setCursor(0, 1); 107 | lcd.print("Safe not locked!"); 108 | delay(2000); 109 | return false; 110 | } 111 | } 112 | 113 | void showUnlockMessage() { 114 | lcd.clear(); 115 | lcd.setCursor(0, 0); 116 | lcd.write(ICON_UNLOCKED_CHAR); 117 | lcd.setCursor(4, 0); 118 | lcd.print("Unlocked!"); 119 | lcd.setCursor(15, 0); 120 | lcd.write(ICON_UNLOCKED_CHAR); 121 | delay(1000); 122 | } 123 | 124 | void safeUnlockedLogic() { 125 | lcd.clear(); 126 | 127 | lcd.setCursor(0, 0); 128 | lcd.write(ICON_UNLOCKED_CHAR); 129 | lcd.setCursor(2, 0); 130 | lcd.print(" # to lock"); 131 | lcd.setCursor(15, 0); 132 | lcd.write(ICON_UNLOCKED_CHAR); 133 | 134 | bool newCodeNeeded = true; 135 | 136 | if (safeState.hasCode()) { 137 | lcd.setCursor(0, 1); 138 | lcd.print(" A = new code"); 139 | newCodeNeeded = false; 140 | } 141 | 142 | auto key = keypad.getKey(); 143 | while (key != 'A' && key != '#') { 144 | key = keypad.getKey(); 145 | } 146 | 147 | bool readyToLock = true; 148 | if (key == 'A' || newCodeNeeded) { 149 | readyToLock = setNewCode(); 150 | } 151 | 152 | if (readyToLock) { 153 | lcd.clear(); 154 | lcd.setCursor(5, 0); 155 | lcd.write(ICON_UNLOCKED_CHAR); 156 | lcd.print(" "); 157 | lcd.write(ICON_RIGHT_ARROW); 158 | lcd.print(" "); 159 | lcd.write(ICON_LOCKED_CHAR); 160 | 161 | safeState.lock(); 162 | lock(); 163 | showWaitScreen(100); 164 | } 165 | } 166 | 167 | void safeLockedLogic() { 168 | lcd.clear(); 169 | lcd.setCursor(0, 0); 170 | lcd.write(ICON_LOCKED_CHAR); 171 | lcd.print(" Safe Locked! "); 172 | lcd.write(ICON_LOCKED_CHAR); 173 | 174 | String userCode = inputSecretCode(); 175 | bool unlockedSuccessfully = safeState.unlock(userCode); 176 | showWaitScreen(200); 177 | 178 | if (unlockedSuccessfully) { 179 | showUnlockMessage(); 180 | unlock(); 181 | } else { 182 | lcd.clear(); 183 | lcd.setCursor(0, 0); 184 | lcd.print("Access Denied!"); 185 | showWaitScreen(1000); 186 | } 187 | } 188 | 189 | void setup() { 190 | lcd.begin(16, 2); 191 | init_icons(lcd); 192 | 193 | lockServo.attach(SERVO_PIN); 194 | 195 | /* Make sure the physical lock is sync with the EEPROM state */ 196 | Serial.begin(115200); 197 | if (safeState.locked()) { 198 | lock(); 199 | } else { 200 | unlock(); 201 | } 202 | 203 | showStartupMessage(); 204 | } 205 | 206 | void loop() { 207 | if (safeState.locked()) { 208 | safeLockedLogic(); 209 | } else { 210 | safeUnlockedLogic(); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /electronic-safe/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/electronic-safe/thumbnail.png -------------------------------------------------------------------------------- /fastled/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "FastLED ColorPalette", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /fastled/lesson.md: -------------------------------------------------------------------------------- 1 | ## FastLED Color Palette Playground 2 | 3 | The NeoPixel strip is connected to Arduino pin 5. 4 | Click the "Run Code" button on the right to see it in action: 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /fastled/sketch.ino: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/FastLED/FastLED/blob/master/examples/ColorPalette/ColorPalette.ino 2 | 3 | #include 4 | 5 | #define LED_PIN 5 6 | #define NUM_LEDS 16 7 | #define BRIGHTNESS 255 8 | #define LED_TYPE WS2812 9 | #define COLOR_ORDER GRB 10 | CRGB leds[NUM_LEDS]; 11 | 12 | #define UPDATES_PER_SECOND 100 13 | 14 | // This example shows several ways to set up and use 'palettes' of colors 15 | // with FastLED. 16 | // 17 | // These compact palettes provide an easy way to re-colorize your 18 | // animation on the fly, quickly, easily, and with low overhead. 19 | // 20 | // USING palettes is MUCH simpler in practice than in theory, so first just 21 | // run this sketch, and watch the pretty lights as you then read through 22 | // the code. Although this sketch has eight (or more) different color schemes, 23 | // the entire sketch compiles down to about 6.5K on AVR. 24 | // 25 | // FastLED provides a few pre-configured color palettes, and makes it 26 | // extremely easy to make up your own color schemes with palettes. 27 | // 28 | // Some notes on the more abstract 'theory and practice' of 29 | // FastLED compact palettes are at the bottom of this file. 30 | 31 | 32 | 33 | CRGBPalette16 currentPalette; 34 | TBlendType currentBlending; 35 | 36 | extern CRGBPalette16 myRedWhiteBluePalette; 37 | extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM; 38 | 39 | void setup() { 40 | FastLED.addLeds(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); 41 | FastLED.setBrightness( BRIGHTNESS ); 42 | 43 | currentPalette = RainbowColors_p; 44 | currentBlending = LINEARBLEND; 45 | } 46 | 47 | 48 | void loop() 49 | { 50 | ChangePalettePeriodically(); 51 | 52 | static uint8_t startIndex = 0; 53 | startIndex = startIndex + 1; /* motion speed */ 54 | 55 | FillLEDsFromPaletteColors( startIndex); 56 | 57 | FastLED.show(); 58 | FastLED.delay(1000 / UPDATES_PER_SECOND); 59 | } 60 | 61 | void FillLEDsFromPaletteColors( uint8_t colorIndex) 62 | { 63 | uint8_t brightness = 255; 64 | 65 | for ( int i = 0; i < NUM_LEDS; i++) { 66 | leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); 67 | colorIndex += 3; 68 | } 69 | } 70 | 71 | 72 | // There are several different palettes of colors demonstrated here. 73 | // 74 | // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p, 75 | // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p. 76 | // 77 | // Additionally, you can manually define your own color palettes, or you can write 78 | // code that creates color palettes on the fly. All are shown here. 79 | 80 | void ChangePalettePeriodically() 81 | { 82 | uint8_t secondHand = (millis() / 1000) % 60; 83 | static uint8_t lastSecond = 99; 84 | 85 | if ( lastSecond != secondHand) { 86 | lastSecond = secondHand; 87 | if ( secondHand == 0) { 88 | currentPalette = RainbowColors_p; 89 | currentBlending = LINEARBLEND; 90 | } 91 | if ( secondHand == 10) { 92 | currentPalette = RainbowStripeColors_p; 93 | currentBlending = NOBLEND; 94 | } 95 | if ( secondHand == 15) { 96 | currentPalette = RainbowStripeColors_p; 97 | currentBlending = LINEARBLEND; 98 | } 99 | if ( secondHand == 20) { 100 | SetupPurpleAndGreenPalette(); 101 | currentBlending = LINEARBLEND; 102 | } 103 | if ( secondHand == 25) { 104 | SetupTotallyRandomPalette(); 105 | currentBlending = LINEARBLEND; 106 | } 107 | if ( secondHand == 30) { 108 | SetupBlackAndWhiteStripedPalette(); 109 | currentBlending = NOBLEND; 110 | } 111 | if ( secondHand == 35) { 112 | SetupBlackAndWhiteStripedPalette(); 113 | currentBlending = LINEARBLEND; 114 | } 115 | if ( secondHand == 40) { 116 | currentPalette = CloudColors_p; 117 | currentBlending = LINEARBLEND; 118 | } 119 | if ( secondHand == 45) { 120 | currentPalette = PartyColors_p; 121 | currentBlending = LINEARBLEND; 122 | } 123 | if ( secondHand == 50) { 124 | currentPalette = myRedWhiteBluePalette_p; 125 | currentBlending = NOBLEND; 126 | } 127 | if ( secondHand == 55) { 128 | currentPalette = myRedWhiteBluePalette_p; 129 | currentBlending = LINEARBLEND; 130 | } 131 | } 132 | } 133 | 134 | // This function fills the palette with totally random colors. 135 | void SetupTotallyRandomPalette() 136 | { 137 | for ( int i = 0; i < 16; i++) { 138 | currentPalette[i] = CHSV( random8(), 255, random8()); 139 | } 140 | } 141 | 142 | // This function sets up a palette of black and white stripes, 143 | // using code. Since the palette is effectively an array of 144 | // sixteen CRGB colors, the various fill_* functions can be used 145 | // to set them up. 146 | void SetupBlackAndWhiteStripedPalette() 147 | { 148 | // 'black out' all 16 palette entries... 149 | fill_solid( currentPalette, 16, CRGB::Black); 150 | // and set every fourth one to white. 151 | currentPalette[0] = CRGB::White; 152 | currentPalette[4] = CRGB::White; 153 | currentPalette[8] = CRGB::White; 154 | currentPalette[12] = CRGB::White; 155 | 156 | } 157 | 158 | // This function sets up a palette of purple and green stripes. 159 | void SetupPurpleAndGreenPalette() 160 | { 161 | CRGB purple = CHSV( HUE_PURPLE, 255, 255); 162 | CRGB green = CHSV( HUE_GREEN, 255, 255); 163 | CRGB black = CRGB::Black; 164 | 165 | currentPalette = CRGBPalette16( 166 | green, green, black, black, 167 | purple, purple, black, black, 168 | green, green, black, black, 169 | purple, purple, black, black ); 170 | } 171 | 172 | 173 | // This example shows how to set up a static color palette 174 | // which is stored in PROGMEM (flash), which is almost always more 175 | // plentiful than RAM. A static PROGMEM palette like this 176 | // takes up 64 bytes of flash. 177 | const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM = 178 | { 179 | CRGB::Red, 180 | CRGB::Gray, // 'white' is too bright compared to red and blue 181 | CRGB::Blue, 182 | CRGB::Black, 183 | 184 | CRGB::Red, 185 | CRGB::Gray, 186 | CRGB::Blue, 187 | CRGB::Black, 188 | 189 | CRGB::Red, 190 | CRGB::Red, 191 | CRGB::Gray, 192 | CRGB::Gray, 193 | CRGB::Blue, 194 | CRGB::Blue, 195 | CRGB::Black, 196 | CRGB::Black 197 | }; 198 | 199 | 200 | 201 | // Additional notes on FastLED compact palettes: 202 | // 203 | // Normally, in computer graphics, the palette (or "color lookup table") 204 | // has 256 entries, each containing a specific 24-bit RGB color. You can then 205 | // index into the color palette using a simple 8-bit (one byte) value. 206 | // A 256-entry color palette takes up 768 bytes of RAM, which on Arduino 207 | // is quite possibly "too many" bytes. 208 | // 209 | // FastLED does offer traditional 256-element palettes, for setups that 210 | // can afford the 768-byte cost in RAM. 211 | // 212 | // However, FastLED also offers a compact alternative. FastLED offers 213 | // palettes that store 16 distinct entries, but can be accessed AS IF 214 | // they actually have 256 entries; this is accomplished by interpolating 215 | // between the 16 explicit entries to create fifteen intermediate palette 216 | // entries between each pair. 217 | // 218 | // So for example, if you set the first two explicit entries of a compact 219 | // palette to Green (0,255,0) and Blue (0,0,255), and then retrieved 220 | // the first sixteen entries from the virtual palette (of 256), you'd get 221 | // Green, followed by a smooth gradient from green-to-blue, and then Blue. 222 | -------------------------------------------------------------------------------- /fastled/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/fastled/thumbnail.png -------------------------------------------------------------------------------- /happy-birthday/gift.h: -------------------------------------------------------------------------------- 1 | // OLED Animation: gift heart 2 | // Code auto-generated by https://wokwi.com/animator, graphics by icons8.com 3 | 4 | #ifndef __GIFT_H__ 5 | #define __GIFT_H__ 6 | 7 | #define GIFT_FRAME_DELAY (42) 8 | #define GIFT_FRAME_WIDTH (48) 9 | #define GIFT_FRAME_HEIGHT (48) 10 | #define GIFT_FRAME_COUNT (sizeof(gift_frames) / sizeof(gift_frames[0])) 11 | const byte PROGMEM gift_frames[][288] = { 12 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 13 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 14 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 15 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 16 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,62,0,1,255,0,0,255,128,1,131,128,1,193,128,3,1,192,3,128,192,3,0,224,7,0,192,3,128,112,14,1,192,1,128,48,12,1,128,1,192,24,24,3,128,0,240,12,48,15,0,0,127,255,255,254,0,255,255,255,255,255,255,255,255,255,255,255,255,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,255,255,255,255,255,255,255,255,255,255,255,255,127,255,255,255,255,254,24,0,48,12,0,24,56,0,48,12,0,24,56,0,48,12,0,28,48,0,48,12,0,28,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,56,0,48,12,0,28,56,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 17 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,0,0,127,0,1,255,0,0,255,128,3,131,192,3,193,192,3,0,192,3,0,192,3,0,96,6,0,192,3,0,56,28,0,192,3,128,28,56,1,192,1,254,31,248,127,128,255,255,255,255,255,255,255,255,255,255,255,255,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,255,255,255,255,255,255,255,255,255,255,255,255,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,63,255,255,255,255,252,31,255,255,255,255,248,0,0,0,0,0,0}, 18 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,126,0,0,126,0,1,255,128,1,255,128,3,131,192,3,193,192,3,0,224,7,0,192,3,0,112,14,0,192,3,128,28,56,1,192,1,255,255,255,255,128,127,255,255,255,255,254,127,255,255,255,255,254,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,56,28,0,6,127,255,255,255,255,254,127,255,255,255,255,254,0,0,0,0,0,0,15,255,255,255,255,240,15,255,255,255,255,240,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,15,255,255,255,255,240,15,255,255,255,255,240,0,0,0,0,0,0}, 19 | {0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,1,129,192,3,129,192,3,0,112,14,0,64,3,0,24,24,0,192,1,255,255,255,255,128,63,255,255,255,255,252,48,0,63,252,0,12,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,48,0,24,24,0,12,63,255,255,255,255,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,255,255,255,255,224,7,255,255,255,255,224,4,0,16,8,0,32,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,6,0,16,8,0,96,6,0,63,252,0,96,7,255,255,255,255,224,0,0,0,0,0,0}, 20 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,254,127,0,0,0,3,207,243,192,0,0,7,3,192,224,0,0,6,1,128,96,0,0,6,1,128,96,0,0,14,0,0,96,0,0,6,0,0,96,0,0,6,0,0,96,0,0,7,0,0,224,0,0,3,0,0,192,0,0,1,128,1,128,0,0,0,192,3,0,0,0,0,96,6,0,0,0,0,48,28,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,3,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 21 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,224,7,224,0,0,31,248,31,248,0,0,124,30,120,62,0,0,224,7,224,7,0,1,192,3,192,3,128,1,128,1,128,1,128,3,0,1,128,0,192,3,0,0,0,0,192,3,0,0,0,0,192,6,0,0,0,0,96,6,0,0,0,0,96,6,0,0,0,0,96,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,3,0,0,0,0,192,3,128,0,0,1,192,1,128,0,0,1,128,0,192,0,0,3,0,0,224,0,0,7,0,0,112,0,0,14,0,0,56,0,0,28,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,128,1,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,60,60,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,3,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 22 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,192,3,252,0,0,255,240,15,255,0,3,192,60,60,3,192,7,0,14,112,0,224,14,0,7,224,0,112,28,0,3,192,0,56,56,0,1,128,0,28,48,0,0,0,0,12,48,0,0,0,0,12,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,112,0,0,0,0,14,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,28,24,0,0,0,0,24,28,0,0,0,0,56,14,0,0,0,0,112,6,0,0,0,0,96,7,0,0,0,0,192,3,128,0,0,1,192,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,60,0,0,60,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,120,30,0,0,0,0,60,60,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 23 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 24 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 25 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 26 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 27 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 28 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 29 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,224,7,252,0,0,255,248,31,255,0,1,192,28,56,3,128,7,128,14,112,1,224,6,0,3,192,0,96,12,0,3,192,0,48,28,0,1,128,0,56,24,0,0,0,0,24,56,0,0,0,0,28,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0,24,28,0,0,0,0,56,12,0,0,0,0,48,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,1,128,0,0,1,128,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 30 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,192,3,252,0,0,255,240,15,255,0,3,192,60,60,3,192,7,0,14,112,0,224,14,0,7,224,0,112,28,0,3,192,0,56,56,0,1,128,0,28,48,0,0,0,0,12,48,0,0,0,0,12,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,96,0,0,0,0,6,112,0,0,0,0,14,48,0,0,0,0,12,48,0,0,0,0,12,56,0,0,0,0,28,24,0,0,0,0,24,28,0,0,0,0,56,14,0,0,0,0,112,6,0,0,0,0,96,7,0,0,0,0,192,3,128,0,0,1,192,1,192,0,0,3,128,0,224,0,0,7,0,0,112,0,0,14,0,0,60,0,0,60,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,192,3,192,0,0,0,224,7,0,0,0,0,120,30,0,0,0,0,60,60,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 31 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,224,7,224,0,0,31,248,31,248,0,0,124,30,120,62,0,0,224,7,224,7,0,1,192,3,192,3,128,1,128,1,128,1,128,3,0,1,128,0,192,3,0,0,0,0,192,3,0,0,0,0,192,6,0,0,0,0,96,6,0,0,0,0,96,6,0,0,0,0,96,6,0,0,0,0,96,7,0,0,0,0,224,3,0,0,0,0,192,3,0,0,0,0,192,3,128,0,0,1,192,1,128,0,0,1,128,0,192,0,0,3,0,0,224,0,0,7,0,0,112,0,0,14,0,0,56,0,0,28,0,0,28,0,0,56,0,0,14,0,0,112,0,0,7,0,0,224,0,0,3,128,1,192,0,0,0,224,7,0,0,0,0,112,14,0,0,0,0,60,60,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,3,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 32 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,254,127,0,0,0,3,207,243,192,0,0,7,3,192,224,0,0,6,1,128,96,0,0,6,1,128,96,0,0,14,0,0,96,0,0,6,0,0,96,0,0,6,0,0,96,0,0,7,0,0,224,0,0,3,0,0,192,0,0,1,128,1,128,0,0,0,192,3,0,0,0,0,96,6,0,0,0,0,48,28,0,0,0,0,28,56,0,0,0,0,14,112,0,0,0,0,7,224,0,0,0,0,3,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 33 | {0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,1,129,192,3,129,192,3,0,112,14,0,64,3,0,24,24,0,192,1,255,255,255,255,128,63,255,255,255,255,252,48,0,63,252,0,12,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,32,0,16,8,0,4,48,0,24,24,0,12,63,255,255,255,255,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,255,255,255,255,224,7,255,255,255,255,224,4,0,16,8,0,32,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,2,0,16,8,0,64,6,0,16,8,0,96,6,0,63,252,0,96,7,255,255,255,255,224,0,0,0,0,0,0}, 34 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,0,0,127,0,1,255,128,1,255,128,3,129,192,3,129,192,3,0,224,7,0,192,3,0,120,30,0,192,3,128,28,56,1,192,1,255,255,255,255,128,127,255,255,255,255,254,127,255,255,255,255,254,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,56,28,0,6,127,255,255,255,255,254,127,255,255,255,255,254,0,0,0,0,0,0,15,255,255,255,255,240,15,255,255,255,255,240,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,12,0,48,15,255,255,255,255,240,15,255,255,255,255,240,0,0,0,0,0,0}, 35 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,0,0,127,0,1,255,0,0,255,128,3,131,192,3,193,192,3,0,192,3,0,192,3,0,96,6,0,192,3,0,56,28,0,192,3,128,28,56,1,192,1,254,31,248,127,128,255,255,255,255,255,255,255,255,255,255,255,255,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,255,255,255,255,255,255,255,255,255,255,255,255,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,63,255,255,255,255,252,31,255,255,255,255,248,0,0,0,0,0,0}, 36 | {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,62,0,1,255,0,0,255,128,1,131,128,1,193,128,3,129,192,3,129,192,3,0,224,7,0,192,3,0,96,6,0,192,1,128,48,12,1,128,1,192,56,28,3,128,0,240,28,56,15,0,0,127,255,255,254,0,255,255,255,255,255,255,255,255,255,255,255,255,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,192,0,48,12,0,3,255,255,255,255,255,255,255,255,255,255,255,255,127,255,255,255,255,254,24,0,48,12,0,24,56,0,48,12,0,24,56,0,48,12,0,28,48,0,48,12,0,28,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,48,0,48,12,0,12,56,0,48,12,0,28,56,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 37 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 38 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0}, 39 | {0,0,0,0,0,0,0,124,0,0,62,0,0,255,0,0,255,0,1,195,128,1,195,128,1,129,192,3,129,128,1,128,192,3,1,128,1,128,96,6,1,128,1,128,112,14,1,128,1,192,48,12,3,128,0,224,24,24,7,0,0,112,28,56,14,0,0,63,15,240,252,0,127,255,255,255,255,254,127,255,255,255,255,254,96,0,63,252,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,96,0,48,12,0,6,127,255,255,255,255,254,127,255,255,255,255,254,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,24,0,48,12,0,24,31,255,255,255,255,248,31,255,255,255,255,248,0,0,0,0,0,0} 40 | }; 41 | 42 | #endif /* __GIFT_H__ */ 43 | -------------------------------------------------------------------------------- /happy-birthday/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Happy Birthday", 3 | "files": ["gift.h", "pitches.h"] 4 | } 5 | -------------------------------------------------------------------------------- /happy-birthday/lesson.md: -------------------------------------------------------------------------------- 1 | # Happy Birthday, Karin! 2 | 3 | 🎉🎉🎉 4 | 5 |
6 |
7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /happy-birthday/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * Public Constants 3 | *************************************************/ 4 | 5 | #define NOTE_B0 31 6 | #define NOTE_C1 33 7 | #define NOTE_CS1 35 8 | #define NOTE_D1 37 9 | #define NOTE_DS1 39 10 | #define NOTE_E1 41 11 | #define NOTE_F1 44 12 | #define NOTE_FS1 46 13 | #define NOTE_G1 49 14 | #define NOTE_GS1 52 15 | #define NOTE_A1 55 16 | #define NOTE_AS1 58 17 | #define NOTE_B1 62 18 | #define NOTE_C2 65 19 | #define NOTE_CS2 69 20 | #define NOTE_D2 73 21 | #define NOTE_DS2 78 22 | #define NOTE_E2 82 23 | #define NOTE_F2 87 24 | #define NOTE_FS2 93 25 | #define NOTE_G2 98 26 | #define NOTE_GS2 104 27 | #define NOTE_A2 110 28 | #define NOTE_AS2 117 29 | #define NOTE_B2 123 30 | #define NOTE_C3 131 31 | #define NOTE_CS3 139 32 | #define NOTE_D3 147 33 | #define NOTE_DS3 156 34 | #define NOTE_E3 165 35 | #define NOTE_F3 175 36 | #define NOTE_FS3 185 37 | #define NOTE_G3 196 38 | #define NOTE_GS3 208 39 | #define NOTE_A3 220 40 | #define NOTE_AS3 233 41 | #define NOTE_B3 247 42 | #define NOTE_C4 262 43 | #define NOTE_CS4 277 44 | #define NOTE_D4 294 45 | #define NOTE_DS4 311 46 | #define NOTE_E4 330 47 | #define NOTE_F4 349 48 | #define NOTE_FS4 370 49 | #define NOTE_G4 392 50 | #define NOTE_GS4 415 51 | #define NOTE_A4 440 52 | #define NOTE_AS4 466 53 | #define NOTE_B4 494 54 | #define NOTE_C5 523 55 | #define NOTE_CS5 554 56 | #define NOTE_D5 587 57 | #define NOTE_DS5 622 58 | #define NOTE_E5 659 59 | #define NOTE_F5 698 60 | #define NOTE_FS5 740 61 | #define NOTE_G5 784 62 | #define NOTE_GS5 831 63 | #define NOTE_A5 880 64 | #define NOTE_AS5 932 65 | #define NOTE_B5 988 66 | #define NOTE_C6 1047 67 | #define NOTE_CS6 1109 68 | #define NOTE_D6 1175 69 | #define NOTE_DS6 1245 70 | #define NOTE_E6 1319 71 | #define NOTE_F6 1397 72 | #define NOTE_FS6 1480 73 | #define NOTE_G6 1568 74 | #define NOTE_GS6 1661 75 | #define NOTE_A6 1760 76 | #define NOTE_AS6 1865 77 | #define NOTE_B6 1976 78 | #define NOTE_C7 2093 79 | #define NOTE_CS7 2217 80 | #define NOTE_D7 2349 81 | #define NOTE_DS7 2489 82 | #define NOTE_E7 2637 83 | #define NOTE_F7 2794 84 | #define NOTE_FS7 2960 85 | #define NOTE_G7 3136 86 | #define NOTE_GS7 3322 87 | #define NOTE_A7 3520 88 | #define NOTE_AS7 3729 89 | #define NOTE_B7 3951 90 | #define NOTE_C8 4186 91 | #define NOTE_CS8 4435 92 | #define NOTE_D8 4699 93 | #define NOTE_DS8 4978 94 | -------------------------------------------------------------------------------- /happy-birthday/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gift.h" 4 | #include "pitches.h" 5 | 6 | #define SCREEN_I2C_ADDR 0x3D // or 0x3C 7 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 8 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 9 | #define OLED_RST_PIN -1 // Reset pin (-1 if not available) 10 | 11 | Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST_PIN); 12 | 13 | //notes in the melody 14 | int melody[] = { 15 | NOTE_C4, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_F4, NOTE_E4, NOTE_C4, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_G4, NOTE_F4, NOTE_C4, NOTE_C4, NOTE_C5, NOTE_A4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_AS4, NOTE_AS4, NOTE_A4, NOTE_F4, NOTE_G4, NOTE_F4 16 | }; 17 | 18 | //note durations: 4 = quarter note, 8 = eight note, etc. 19 | int noteDurations[] = { 20 | 8, 8, 4, 4, 4, 2, 8, 8, 4, 4, 4, 2, 8, 8, 4, 4, 4, 4, 4, 8, 8, 4, 4, 4, 2, 21 | }; 22 | 23 | int frame = 0; 24 | String message = "Happy Birthday, Karin"; 25 | int messageIndex = 0; 26 | 27 | void drawFrame() { 28 | display.clearDisplay(); 29 | display.drawBitmap(40, 0, gift_frames[frame], GIFT_FRAME_WIDTH, GIFT_FRAME_HEIGHT, 1); 30 | display.setCursor(0, 52); 31 | display.print(message.substring(0, messageIndex)); 32 | display.display(); 33 | frame = (frame + 1) % GIFT_FRAME_COUNT; 34 | if (frame % 3 == 0) { 35 | messageIndex = (messageIndex + 1) % 40; 36 | } 37 | } 38 | 39 | void setup() { 40 | display.begin(SSD1306_SWITCHCAPVCC, SCREEN_I2C_ADDR); 41 | display.setTextColor(SSD1306_WHITE); 42 | 43 | pinMode (9, OUTPUT); 44 | pinMode (10, OUTPUT); 45 | pinMode (11, OUTPUT); 46 | 47 | for (int thisNote = 0 ; thisNote < 25 ; thisNote++) { 48 | int randomLight1 = random(9, 12); 49 | int randomLight2 = random(9, 12); 50 | int randomLight3 = random(9, 12); 51 | 52 | digitalWrite (randomLight1, HIGH); 53 | digitalWrite (randomLight2, HIGH); 54 | digitalWrite (randomLight3, LOW); 55 | 56 | int noteDuration = 1130 / noteDurations[thisNote]; 57 | tone (6, melody[thisNote], noteDuration); 58 | int pause = noteDuration * 1.275; 59 | delay (pause); 60 | noTone(6); 61 | 62 | drawFrame(); 63 | } 64 | 65 | delay(3000); 66 | digitalWrite(9, LOW); 67 | digitalWrite(10, LOW); 68 | digitalWrite(11, LOW); 69 | } 70 | 71 | void loop() { 72 | drawFrame(); 73 | delay(GIFT_FRAME_DELAY); 74 | } 75 | -------------------------------------------------------------------------------- /i2c-scanner/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "I²C Scanner", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /i2c-scanner/lesson.md: -------------------------------------------------------------------------------- 1 | # I2C Scanner Playground 2 | 3 | This code sample shows how to scan the I2C bus 4 | and detect the devices attached to it. In this 5 | case we have one I2C LCD screen. 6 | 7 | Click on **"Run code"** to find out which I2C address the screen is attached to! 8 | 9 |
10 | 11 | 12 | 13 |
14 | -------------------------------------------------------------------------------- /i2c-scanner/sketch.ino: -------------------------------------------------------------------------------- 1 | // -------------------------------------- 2 | // i2c-scanner 3 | // 4 | // This sketch tests the standard 7-bit addresses 5 | // Devices with higher bit address might not be seen properly. 6 | // See full version history here: https://gist.github.com/urish/917414da3477e528c8782ee05cd6f557 7 | 8 | #include 9 | 10 | void setup() { 11 | Wire.begin(); 12 | 13 | Serial.begin(9600); 14 | Serial.println("\nI2C Scanner"); 15 | } 16 | 17 | void loop() { 18 | byte error, address; 19 | int nDevices; 20 | 21 | Serial.println("Scanning..."); 22 | 23 | nDevices = 0; 24 | for(address = 1; address < 127; address++) { 25 | // The i2c-scanner uses the return value of 26 | // the Write.endTransmisstion to see if 27 | // a device did acknowledge to the address. 28 | Wire.beginTransmission(address); 29 | error = Wire.endTransmission(); 30 | 31 | if (error == 0) 32 | { 33 | Serial.print("I2C device found at address 0x"); 34 | if (address<16) { 35 | Serial.print("0"); 36 | } 37 | Serial.print(address,HEX); 38 | Serial.println(" !"); 39 | 40 | nDevices++; 41 | } 42 | else if (error==4) { 43 | Serial.print("Unknown error at address 0x"); 44 | if (address<16) { 45 | Serial.print("0"); 46 | } 47 | Serial.println(address,HEX); 48 | } 49 | } 50 | if (nDevices == 0) { 51 | Serial.println("No I2C devices found\n"); 52 | } else { 53 | Serial.println("done\n"); 54 | } 55 | 56 | delay(5000); // wait 5 seconds for next scan 57 | } 58 | -------------------------------------------------------------------------------- /i2c-scanner/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/i2c-scanner/thumbnail.png -------------------------------------------------------------------------------- /keypad/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Keypad", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /keypad/lesson.md: -------------------------------------------------------------------------------- 1 | ## Arduino Keypad Playground 2 | 3 | The rows of the keypad are connected to arduino pins 2, 3, 4, and 5, and 4 | the columns to pins 6, 7, 8, 9. See below for a full connection table. 5 | 6 | Click "Run code" to see the demo program in action. 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | Pin connection list: 15 | 16 | | Keypad pin | Arduino Pin | 17 | |------------|-------------| 18 | | R0 | 2 | 19 | | R1 | 3 | 20 | | R2 | 4 | 21 | | R3 | 5 | 22 | | C0 | 6 | 23 | | C1 | 7 | 24 | | C2 | 8 | 25 | | C3 | 9 | 26 | 27 | -------------------------------------------------------------------------------- /keypad/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const byte ROWS = 4; 4 | const byte COLS = 4; 5 | char keys[ROWS][COLS] = { 6 | {'1', '2', '3', 'A'}, 7 | {'4', '5', '6', 'B'}, 8 | {'7', '8', '9', 'C'}, 9 | {'*', '0', '#', 'D'} 10 | }; 11 | 12 | byte rowPins[ROWS] = {2, 3, 4, 5}; // Connect to the row pinouts of the keypad 13 | byte colPins[COLS] = {6, 7, 8, 9}; // Connect to the column pinouts of the keypad 14 | 15 | Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | } 20 | 21 | void loop() { 22 | char key = keypad.getKey(); 23 | 24 | if (key != NO_KEY) { 25 | Serial.println(key); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /keypad/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/keypad/thumbnail.png -------------------------------------------------------------------------------- /lcd1602-i2c/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "LCD1602 Playground", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /lcd1602-i2c/lesson.md: -------------------------------------------------------------------------------- 1 | ## LCD-1602 Arduino Simulation 2 | 3 | The LCD1602 is connected at I²C address `0x27`. 4 | 5 | Click the "Run Code" button on the right to see it in action: 6 | 7 | 8 | 9 | Can you change the code to print your name? 10 | -------------------------------------------------------------------------------- /lcd1602-i2c/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | LiquidCrystal_I2C lcd(0x27, 16, 2); 4 | 5 | byte heart[8] = { 6 | 0b00000, 7 | 0b01010, 8 | 0b11111, 9 | 0b11111, 10 | 0b11111, 11 | 0b01110, 12 | 0b00100, 13 | 0b00000, 14 | }; 15 | 16 | void setup() { 17 | lcd.init(); 18 | lcd.backlight(); 19 | lcd.createChar(3, heart); 20 | lcd.setCursor(2, 0); 21 | lcd.print("I \x03 Arduino \xaf"); 22 | lcd.blink(); 23 | } 24 | 25 | int i = 0; 26 | char *msg = "Hello, World!"; 27 | void loop() { 28 | if (i < strlen(msg)) { 29 | lcd.setCursor(i + 2, 1); 30 | lcd.print(msg[i]); 31 | i++; 32 | } 33 | delay(200); 34 | } 35 | -------------------------------------------------------------------------------- /lcd1602-i2c/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/lcd1602-i2c/thumbnail.png -------------------------------------------------------------------------------- /lcd1602/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "LCD1602 Playground", 3 | "thumbnail": "../lcd1602-i2c/thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /lcd1602/lesson.md: -------------------------------------------------------------------------------- 1 | ## LiquidCrystal LCD-1602 Simulation 2 | 3 | The LCD1602 display is connected to pins 12, 11, 2, 3, 4, and 5 4 | of the Arduino. 5 | 6 | Click the "Run Code" button on the right to see it in action: 7 | 8 | 9 | 10 | Can you change the code to print your name? 11 | 12 | Pin connection list: 13 | 14 | | LCD1602 Pin | Arduino Pin | 15 | |-------------|-------------| 16 | | RS | 12 | 17 | | ENABLE | 11 | 18 | | D7 | 2 | 19 | | D6 | 3 | 20 | | D5 | 4 | 21 | | D4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /lcd1602/sketch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | LiquidCrystal Library - Hello World 3 | 4 | Demonstrates the use a 16x2 LCD display. The LiquidCrystal 5 | library works with all LCD displays that are compatible with the 6 | Hitachi HD44780 driver. There are many of them out there, and you 7 | can usually tell them by the 16-pin interface. 8 | */ 9 | 10 | // include the library code: 11 | #include 12 | 13 | // initialize the library with the numbers of the interface pins 14 | LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 15 | 16 | void setup() { 17 | // set up the LCD's number of columns and rows: 18 | lcd.begin(16, 2); 19 | // Print a message to the LCD. 20 | lcd.print("hello, world!"); 21 | } 22 | 23 | void loop() { 24 | // set the cursor to column 0, line 1 25 | // (note: line 1 is the second row, since counting begins with 0): 26 | lcd.setCursor(0, 1); 27 | // print the number of seconds since reset: 28 | lcd.print(millis() / 1000); 29 | } 30 | -------------------------------------------------------------------------------- /neopixel-matrix/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "NeoPixel Matrix", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /neopixel-matrix/lesson.md: -------------------------------------------------------------------------------- 1 | ## NeoPixel Matrix 2 | 3 | This 16x16 NeoPixel matrix is connected to Arduino's digital pin number 3. 4 | It has total of 256 LEDs. 5 | 6 | Click the "Run Code" button on the right to see it in action: 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 | Curious to know how the simulation works? 15 | We've got you covered! 16 | 17 |

18 | -------------------------------------------------------------------------------- /neopixel-matrix/sketch.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED.h" 2 | 3 | // Matrix size 4 | #define NUM_ROWS 16 5 | #define NUM_COLS 16 6 | 7 | // LEDs pin 8 | #define DATA_PIN 3 9 | 10 | // LED brightness 11 | #define BRIGHTNESS 180 12 | 13 | #define NUM_LEDS NUM_ROWS * NUM_COLS 14 | 15 | // Define the array of leds 16 | CRGB leds[NUM_LEDS]; 17 | 18 | void setup() { 19 | FastLED.addLeds(leds, NUM_LEDS); 20 | FastLED.setBrightness(BRIGHTNESS); 21 | } 22 | 23 | int counter = 0; 24 | void loop() { 25 | for (byte row = 0; row < NUM_ROWS; row++) { 26 | for (byte col = 0; col < NUM_COLS; col++) { 27 | int delta = abs(NUM_ROWS - row * 2) + abs(NUM_COLS - col * 2); 28 | leds[row * NUM_COLS + col] = CHSV(delta * 4 + counter, 255, 255); 29 | } 30 | } 31 | FastLED.show(); 32 | delay(5); 33 | counter++; 34 | } 35 | -------------------------------------------------------------------------------- /neopixel-matrix/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/neopixel-matrix/thumbnail.png -------------------------------------------------------------------------------- /neopixel-strip/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "NeoPixel Strip", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /neopixel-strip/lesson.md: -------------------------------------------------------------------------------- 1 | ## NeoPixel Strip 2 | 3 | The NeoPixel strip is connected to Arduino pin 6. 4 | Click the "Run Code" button on the right to see it in action: 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /neopixel-strip/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PIN 6 4 | #define NUMPIXELS 8 5 | 6 | Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); 7 | 8 | void setup() { 9 | pixels.begin(); 10 | } 11 | 12 | int r = 150; 13 | int g = 0; 14 | int b = 0; 15 | 16 | void loop() { 17 | pixels.clear(); 18 | 19 | for(int i=0; i 8 | 9 | 10 | Can you make the potentiometer control the brightness of the LED instead? 11 | -------------------------------------------------------------------------------- /potentiometer/sketch.ino: -------------------------------------------------------------------------------- 1 | /* Potentiometer controlled LED Blink */ 2 | 3 | void setup() { 4 | pinMode(A0, INPUT); 5 | pinMode(11, OUTPUT); 6 | } 7 | 8 | void loop() { 9 | digitalWrite(11, HIGH); 10 | delayPotentiometer(); 11 | digitalWrite(11, LOW); 12 | delayPotentiometer(); 13 | } 14 | 15 | int delayValue() { 16 | int value = analogRead(A0); 17 | return map(value, 0, 1023, 100, 1000); 18 | } 19 | 20 | void delayPotentiometer() { 21 | for (int i = 0; i < delayValue(); i++) { 22 | delay(1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /potentiometer/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/potentiometer/thumbnail.png -------------------------------------------------------------------------------- /rotary-dialer/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Rotary Dialer", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /rotary-dialer/lesson.md: -------------------------------------------------------------------------------- 1 | # Vintage Dial Phone for Arduino 2 | 3 | Click on "Run code" to start the simulation. 4 | 5 |
6 | 7 | 8 | Rotary dialer by Liron Hazan, code by talofer99. 9 | -------------------------------------------------------------------------------- /rotary-dialer/sketch.ino: -------------------------------------------------------------------------------- 1 | // Include the library code: 2 | #include 3 | 4 | // Initialize the library with the numbers of the interface pins 5 | LiquidCrystal lcd(12, 11, 10, 9, 8, 7); 6 | #define INDIALPIN 3 7 | #define PULSEPIN 2 8 | boolean inDialPinLastState; 9 | boolean pulsPinLastState; 10 | byte counter = 0; 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | Serial.println("System started"); 15 | // set up the LCD's number of columns and rows: 16 | lcd.begin(16, 2); 17 | // set the fixed text 18 | lcd.setCursor(0, 0); 19 | pinMode(INDIALPIN, INPUT_PULLUP); 20 | pinMode(PULSEPIN, INPUT_PULLUP); 21 | inDialPinLastState = digitalRead(INDIALPIN); 22 | pulsPinLastState = digitalRead(PULSEPIN); 23 | } 24 | 25 | void loop() { 26 | boolean inDialPinState = digitalRead(INDIALPIN); 27 | boolean pulsPinState = digitalRead(PULSEPIN); 28 | if (inDialPinState != inDialPinLastState) { 29 | if (!inDialPinState) { 30 | Serial.println("Start of dial"); 31 | counter = 0; 32 | } else { 33 | Serial.println("End of dial"); 34 | Serial.print("Dialed Digit - "); 35 | Serial.println(counter); 36 | if (counter) { 37 | counter = counter % 10; 38 | lcd.print(counter); 39 | } 40 | } //end if 41 | inDialPinLastState = inDialPinState; 42 | } //end if 43 | if (pulsPinLastState != pulsPinState) { 44 | if (!pulsPinLastState) { 45 | counter++; 46 | } // end if 47 | Serial.println("pulsPinState - " + String(pulsPinState)); 48 | pulsPinLastState = pulsPinState; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rotary-dialer/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/rotary-dialer/thumbnail.png -------------------------------------------------------------------------------- /serial/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Serial Monitor", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /serial/lesson.md: -------------------------------------------------------------------------------- 1 | ## Arduino Serial Monitor Playground 2 | 3 | This is the perfect place to paste some Arduino code, run it and see the output. 4 | 5 | Click Run Code to compile, and you will see the "Serial Monitor" with 6 | all the prints from the code. 7 | 8 | 9 | 10 | Built with for the Arduino community. 11 | -------------------------------------------------------------------------------- /serial/serial.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 55 | 62 | 69 | 73 | 77 | 82 | 87 | 92 | 97 | 98 | 101 | 106 | 111 | 116 | 117 | 122 | 127 | 128 | Serial MonitorSandbox 144 | 149 | LearnArduinoProgramming 175 | Serial.begin(115200);Serial.println( "Hello, World!"); 218 | 223 | 224 | -------------------------------------------------------------------------------- /serial/sketch.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | Serial.begin(115200); 3 | Serial.println("Welcome to the Serial Playground!"); 4 | Serial.println("---------------------------------"); 5 | } 6 | 7 | byte value = 0; 8 | void loop() { 9 | Serial.print("Counter: "); 10 | Serial.print(value); 11 | Serial.print(", hex: "); 12 | Serial.println(value, HEX); 13 | value += 1; 14 | delay(500); 15 | } 16 | -------------------------------------------------------------------------------- /serial/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/serial/thumbnail.png -------------------------------------------------------------------------------- /servo/lesson.json: -------------------------------------------------------------------------------- 1 | { "title": "Servo", "thumbnail": "thumbnail.png" } 2 | -------------------------------------------------------------------------------- /servo/lesson.md: -------------------------------------------------------------------------------- 1 | # Servo 2 | 3 | This is a simple demo of a servo controlled by Arduino. 4 | 5 | The servo is connected to Arduino pin number 9. Click on 6 | Run Code to start the simulation: 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /servo/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Servo myservo; 4 | 5 | void setup() { 6 | myservo.attach(9); 7 | } 8 | 9 | void loop() { 10 | for (int pos = 0; pos <= 180; pos += 1) { 11 | myservo.write(pos); 12 | delay(15); 13 | } 14 | for (int pos = 180; pos >= 0; pos -= 1) { 15 | myservo.write(pos); 16 | delay(15); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /servo/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/servo/thumbnail.png -------------------------------------------------------------------------------- /seven-segment-clock/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "7 Segment Clock", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /seven-segment-clock/lesson.md: -------------------------------------------------------------------------------- 1 | # Arduino Seven Segment Clock 2 | 3 | A simple 7-segment clock / stopwatch that counts minutes and seconds: 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /seven-segment-clock/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple 7-Segment Timer Counter (Minutes and Second). 3 | * 4 | * Drives four-segment displays, with common ANODEs connected 5 | * at pins 2, 3, 4, and 5, and segment lines at pins 6-13. 6 | * Enjoy ;-) 7 | */ 8 | 9 | #include 10 | 11 | SevSeg sevseg; 12 | 13 | void setup() { 14 | byte digits = 4; 15 | byte digitPins[] = {2, 3, 4, 5}; 16 | byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; 17 | bool resistorsOnSegments = false; 18 | byte hardwareConfig = COMMON_ANODE; 19 | bool updateWithDelays = false; 20 | bool leadingZeros = true; 21 | bool disableDecPoint = false; 22 | sevseg.begin(hardwareConfig, digits, digitPins, segmentPins, resistorsOnSegments, 23 | updateWithDelays, leadingZeros, disableDecPoint); 24 | sevseg.setBrightness(90); 25 | } 26 | 27 | int seconds = 0; 28 | int minutes = 0; 29 | unsigned long lastMillis = 0; 30 | 31 | void loop() { 32 | if (millis() - lastMillis >= 1000) { 33 | lastMillis = millis(); 34 | seconds++; 35 | if (seconds == 60) { 36 | seconds = 0; 37 | minutes++; 38 | if (minutes == 60) { 39 | minutes = 0; 40 | } 41 | } 42 | sevseg.setNumber(minutes * 100 + seconds, 2); 43 | } 44 | 45 | sevseg.refreshDisplay(); 46 | } 47 | -------------------------------------------------------------------------------- /seven-segment-clock/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/seven-segment-clock/thumbnail.png -------------------------------------------------------------------------------- /simon-game/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Simon Game", 3 | "thumbnail": "thumbnail.png", 4 | "files": ["pitches.h"] 5 | } 6 | -------------------------------------------------------------------------------- /simon-game/lesson.md: -------------------------------------------------------------------------------- 1 | # Simon Game Playground 2 | 3 | Simon Memory Game for Arduino with Sound 🎶 4 | 5 | Click the **Run Code** button to see it in action: 6 | 7 |
8 | 9 |
10 | 11 | 12 |
13 |
14 |
15 | 16 | 17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 | 28 |
29 |
30 |
31 | 32 | 33 |
34 |
35 | -------------------------------------------------------------------------------- /simon-game/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * Public Constants 3 | *************************************************/ 4 | 5 | #define NOTE_B0 31 6 | #define NOTE_C1 33 7 | #define NOTE_CS1 35 8 | #define NOTE_D1 37 9 | #define NOTE_DS1 39 10 | #define NOTE_E1 41 11 | #define NOTE_F1 44 12 | #define NOTE_FS1 46 13 | #define NOTE_G1 49 14 | #define NOTE_GS1 52 15 | #define NOTE_A1 55 16 | #define NOTE_AS1 58 17 | #define NOTE_B1 62 18 | #define NOTE_C2 65 19 | #define NOTE_CS2 69 20 | #define NOTE_D2 73 21 | #define NOTE_DS2 78 22 | #define NOTE_E2 82 23 | #define NOTE_F2 87 24 | #define NOTE_FS2 93 25 | #define NOTE_G2 98 26 | #define NOTE_GS2 104 27 | #define NOTE_A2 110 28 | #define NOTE_AS2 117 29 | #define NOTE_B2 123 30 | #define NOTE_C3 131 31 | #define NOTE_CS3 139 32 | #define NOTE_D3 147 33 | #define NOTE_DS3 156 34 | #define NOTE_E3 165 35 | #define NOTE_F3 175 36 | #define NOTE_FS3 185 37 | #define NOTE_G3 196 38 | #define NOTE_GS3 208 39 | #define NOTE_A3 220 40 | #define NOTE_AS3 233 41 | #define NOTE_B3 247 42 | #define NOTE_C4 262 43 | #define NOTE_CS4 277 44 | #define NOTE_D4 294 45 | #define NOTE_DS4 311 46 | #define NOTE_E4 330 47 | #define NOTE_F4 349 48 | #define NOTE_FS4 370 49 | #define NOTE_G4 392 50 | #define NOTE_GS4 415 51 | #define NOTE_A4 440 52 | #define NOTE_AS4 466 53 | #define NOTE_B4 494 54 | #define NOTE_C5 523 55 | #define NOTE_CS5 554 56 | #define NOTE_D5 587 57 | #define NOTE_DS5 622 58 | #define NOTE_E5 659 59 | #define NOTE_F5 698 60 | #define NOTE_FS5 740 61 | #define NOTE_G5 784 62 | #define NOTE_GS5 831 63 | #define NOTE_A5 880 64 | #define NOTE_AS5 932 65 | #define NOTE_B5 988 66 | #define NOTE_C6 1047 67 | #define NOTE_CS6 1109 68 | #define NOTE_D6 1175 69 | #define NOTE_DS6 1245 70 | #define NOTE_E6 1319 71 | #define NOTE_F6 1397 72 | #define NOTE_FS6 1480 73 | #define NOTE_G6 1568 74 | #define NOTE_GS6 1661 75 | #define NOTE_A6 1760 76 | #define NOTE_AS6 1865 77 | #define NOTE_B6 1976 78 | #define NOTE_C7 2093 79 | #define NOTE_CS7 2217 80 | #define NOTE_D7 2349 81 | #define NOTE_DS7 2489 82 | #define NOTE_E7 2637 83 | #define NOTE_F7 2794 84 | #define NOTE_FS7 2960 85 | #define NOTE_G7 3136 86 | #define NOTE_GS7 3322 87 | #define NOTE_A7 3520 88 | #define NOTE_AS7 3729 89 | #define NOTE_B7 3951 90 | #define NOTE_C8 4186 91 | #define NOTE_CS8 4435 92 | #define NOTE_D8 4699 93 | #define NOTE_DS8 4978 94 | -------------------------------------------------------------------------------- /simon-game/sketch.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Simon Game for Arduino 3 | 4 | Copyright (C) 2016, Uri Shaked 5 | 6 | Released under the MIT License. 7 | */ 8 | 9 | #include "pitches.h" 10 | 11 | /* Constants - define pin numbers for LEDs, 12 | buttons and speaker, and also the game tones: */ 13 | const byte ledPins[] = {9, 10, 11, 12}; 14 | const byte buttonPins[] = {2, 3, 4, 5}; 15 | #define SPEAKER_PIN 8 16 | 17 | #define MAX_GAME_LENGTH 100 18 | 19 | const int gameTones[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5}; 20 | 21 | /* Global variales - store the game state */ 22 | byte gameSequence[MAX_GAME_LENGTH] = {0}; 23 | byte gameIndex = 0; 24 | 25 | /** 26 | Set up the Arduino board and initialize Serial communication 27 | */ 28 | void setup() { 29 | Serial.begin(9600); 30 | for (byte i = 0; i < 4; i++) { 31 | pinMode(ledPins[i], OUTPUT); 32 | pinMode(buttonPins[i], INPUT_PULLUP); 33 | } 34 | pinMode(SPEAKER_PIN, OUTPUT); 35 | // The following line primes the random number generator. 36 | // It assumes pin A0 is floating (disconnected): 37 | randomSeed(analogRead(A0)); 38 | } 39 | 40 | /** 41 | Lights the given LED and plays the suitable tone 42 | */ 43 | void lightLedAndPlayTone(byte ledIndex) { 44 | digitalWrite(ledPins[ledIndex], HIGH); 45 | tone(SPEAKER_PIN, gameTones[ledIndex]); 46 | delay(300); 47 | digitalWrite(ledPins[ledIndex], LOW); 48 | noTone(SPEAKER_PIN); 49 | } 50 | 51 | /** 52 | Plays the current sequence of notes that the user has to repeat 53 | */ 54 | void playSequence() { 55 | for (int i = 0; i < gameIndex; i++) { 56 | byte currentLed = gameSequence[i]; 57 | lightLedAndPlayTone(currentLed); 58 | delay(50); 59 | } 60 | } 61 | 62 | /** 63 | Waits until the user pressed one of the buttons, 64 | and returns the index of that button 65 | */ 66 | byte readButtons() { 67 | while (true) { 68 | for (byte i = 0; i < 4; i++) { 69 | byte buttonPin = buttonPins[i]; 70 | if (digitalRead(buttonPin) == LOW) { 71 | return i; 72 | } 73 | } 74 | delay(1); 75 | } 76 | } 77 | 78 | /** 79 | Play the game over sequence, and report the game score 80 | */ 81 | void gameOver() { 82 | Serial.print("Game over! your score: "); 83 | Serial.println(gameIndex - 1); 84 | gameIndex = 0; 85 | delay(200); 86 | 87 | // Play a Wah-Wah-Wah-Wah sound 88 | tone(SPEAKER_PIN, NOTE_DS5); 89 | delay(300); 90 | tone(SPEAKER_PIN, NOTE_D5); 91 | delay(300); 92 | tone(SPEAKER_PIN, NOTE_CS5); 93 | delay(300); 94 | for (byte i = 0; i < 10; i++) { 95 | for (int pitch = -10; pitch <= 10; pitch++) { 96 | tone(SPEAKER_PIN, NOTE_C5 + pitch); 97 | delay(5); 98 | } 99 | } 100 | noTone(SPEAKER_PIN); 101 | delay(500); 102 | } 103 | 104 | /** 105 | Get the user's input and compare it with the expected sequence. 106 | */ 107 | bool checkUserSequence() { 108 | for (int i = 0; i < gameIndex; i++) { 109 | byte expectedButton = gameSequence[i]; 110 | byte actualButton = readButtons(); 111 | lightLedAndPlayTone(actualButton); 112 | if (expectedButton != actualButton) { 113 | return false; 114 | } 115 | } 116 | 117 | return true; 118 | } 119 | 120 | /** 121 | Plays an hooray sound whenever the user finishes a level 122 | */ 123 | void playLevelUpSound() { 124 | tone(SPEAKER_PIN, NOTE_E4); 125 | delay(150); 126 | tone(SPEAKER_PIN, NOTE_G4); 127 | delay(150); 128 | tone(SPEAKER_PIN, NOTE_E5); 129 | delay(150); 130 | tone(SPEAKER_PIN, NOTE_C5); 131 | delay(150); 132 | tone(SPEAKER_PIN, NOTE_D5); 133 | delay(150); 134 | tone(SPEAKER_PIN, NOTE_G5); 135 | delay(150); 136 | noTone(SPEAKER_PIN); 137 | } 138 | 139 | /** 140 | The main game loop 141 | */ 142 | void loop() { 143 | // Add a random color to the end of the sequence 144 | gameSequence[gameIndex] = random(0, 4); 145 | gameIndex++; 146 | if (gameIndex >= MAX_GAME_LENGTH) { 147 | gameIndex = MAX_GAME_LENGTH - 1; 148 | } 149 | 150 | playSequence(); 151 | if (!checkUserSequence()) { 152 | gameOver(); 153 | } 154 | 155 | delay(300); 156 | 157 | if (gameIndex > 0) { 158 | playLevelUpSound(); 159 | delay(300); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /simon-game/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/simon-game/thumbnail.png -------------------------------------------------------------------------------- /spaceship-game/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Spaceship Game", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /spaceship-game/lesson.md: -------------------------------------------------------------------------------- 1 | Spaceship Game from Volos Projects 2 | 3 | Click the **Run Code** button on the right to see it in action: 4 | 5 |
6 |
7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | -------------------------------------------------------------------------------- /spaceship-game/sketch.ino: -------------------------------------------------------------------------------- 1 | // Game from: Volos Projects (https://youtu.be/lOz_GuME63E) 2 | 3 | /********************************************************************* 4 | This is an example for our Monochrome OLEDs based on SSD1306 drivers 5 | 6 | Pick one up today in the adafruit shop! 7 | ------> http://www.adafruit.com/category/63_98 8 | 9 | This example is for a 128x32 size display using I2C to communicate 10 | 3 pins are required to interface (2 I2C and one reset) 11 | 12 | Adafruit invests time and resources providing this open source code, 13 | please support Adafruit and open-source hardware by purchasing 14 | products from Adafruit! 15 | 16 | Written by Limor Fried/Ladyada for Adafruit Industries. 17 | BSD license, check license.txt for more information 18 | All text above, and the splash screen must be included in any redistribution 19 | *********************************************************************/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | //#include 27 | 28 | Adafruit_SSD1306 display(128, 64); 29 | 30 | 31 | 32 | 33 | 34 | 35 | const int c = 261; 36 | const int d = 294; 37 | const int e = 329; 38 | const int f = 349; 39 | const int g = 391; 40 | const int gS = 415; 41 | const int a = 440; 42 | const int aS = 455; 43 | const int b = 466; 44 | const int cH = 523; 45 | const int cSH = 554; 46 | const int dH = 587; 47 | const int dSH = 622; 48 | const int eH = 659; 49 | const int fH = 698; 50 | const int fSH = 740; 51 | const int gH = 784; 52 | const int gSH = 830; 53 | const int aH = 880; 54 | 55 | const unsigned char PROGMEM dioda16 [] = { 56 | 57 | 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x3F, 0xF0, 0x3C, 0x00, 0x3C, 0x00, 0xFF, 0x00, 0x7F, 0xFF, 58 | 0x7F, 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x1F, 0xF0, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00 59 | 60 | }; 61 | 62 | const unsigned char PROGMEM storm [] = { 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x00, 0x0C, 65 | 0x00, 0x00, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x04, 0x00, 66 | 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x60, 0x00, 0x00, 67 | 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 68 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x01, 0x00, 69 | 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xD7, 0xFF, 0xFF, 70 | 0xE1, 0x00, 0x01, 0xBF, 0xFC, 0x1F, 0xFA, 0x80, 0x01, 0xBF, 0xF1, 0xCF, 0xFA, 0x80, 0x01, 0x3F, 71 | 0xC2, 0x37, 0xF7, 0x80, 0x01, 0xEF, 0x9C, 0x01, 0xE7, 0xC0, 0x01, 0xE0, 0x70, 0x06, 0x06, 0x80, 72 | 0x01, 0xE0, 0xC0, 0x03, 0x06, 0x80, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0x80, 0x01, 0xF8, 0x00, 0x00, 73 | 0x1D, 0xC0, 0x03, 0x70, 0x00, 0x80, 0x0C, 0x60, 0x05, 0xB0, 0x07, 0xF0, 0x08, 0x90, 0x09, 0x10, 74 | 0x1F, 0xF8, 0x09, 0xD0, 0x0B, 0x90, 0x1F, 0x7C, 0x03, 0xF0, 0x0F, 0xC0, 0xFC, 0x0F, 0x07, 0x90, 75 | 0x0D, 0x43, 0xC0, 0x03, 0x07, 0x90, 0x05, 0x64, 0x00, 0x00, 0xCF, 0x10, 0x07, 0xFC, 0x00, 0x00, 76 | 0x26, 0x10, 0x01, 0x80, 0x00, 0x00, 0x10, 0x20, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x40, 0x01, 0x80, 77 | 0x07, 0xF0, 0x01, 0x80, 0x00, 0x80, 0x07, 0xC8, 0x00, 0x80, 0x00, 0x80, 0x0B, 0xE8, 0x00, 0x80, 78 | 0x00, 0x87, 0x97, 0xE9, 0xE0, 0x80, 0x00, 0x87, 0xDF, 0xEF, 0xA0, 0x80, 0x00, 0x4B, 0xFF, 0xFF, 79 | 0xA0, 0x80, 0x00, 0x6B, 0xDF, 0xFB, 0xA3, 0x00, 0x00, 0x24, 0x97, 0xE8, 0x24, 0x00, 0x00, 0x1E, 80 | 0x1F, 0xC0, 0x2C, 0x00, 0x00, 0x07, 0xF8, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00 81 | }; 82 | 83 | 84 | 85 | void setup() { 86 | 87 | 88 | pinMode(3, INPUT_PULLUP); 89 | pinMode(12, INPUT_PULLUP); 90 | pinMode(11, INPUT_PULLUP); 91 | display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 92 | display.display(); 93 | display.clearDisplay(); 94 | display.setTextSize(0); 95 | display.drawBitmap(6, 11, storm, 48, 48, 1); 96 | display.setFont(&FreeSans9pt7b); 97 | display.setTextColor(WHITE); 98 | display.setCursor(65, 14); 99 | display.println("xWing"); 100 | display.setFont(); 101 | display.setCursor(65, 17); 102 | display.setTextSize(0); 103 | display.println("vs"); 104 | display.setCursor(0, 0); 105 | float voltaza = readVcc() / 1000; 106 | display.println(voltaza);; 107 | display.setFont(&FreeSans9pt7b); 108 | display.setCursor(65, 39); 109 | display.println("Death"); 110 | display.setFont(); 111 | display.setCursor(65, 42); 112 | display.println("star "); 113 | display.setTextSize(0); 114 | 115 | display.setCursor(65, 55); 116 | 117 | display.println("by Danko"); 118 | 119 | display.setCursor(65, 20); 120 | 121 | display.display(); 122 | 123 | 124 | 125 | display.setFont(); 126 | beep(a, 500); 127 | beep(a, 500); 128 | beep(a, 500); 129 | beep(f, 350); 130 | beep(cH, 150); 131 | beep(a, 500); 132 | beep(f, 350); 133 | beep(cH, 150); 134 | beep(a, 650); 135 | 136 | delay(500); 137 | 138 | 139 | 140 | delay(500); 141 | } 142 | int metx = 0; 143 | int mety = 0; 144 | int postoji = 0; 145 | int nep = 8; 146 | int smjer = 0; 147 | int go = 0; 148 | int rx = 95; 149 | int ry = 0; 150 | int rx2 = 95; 151 | int ry2 = 0; 152 | int rx3 = 95; 153 | int ry3 = 0; 154 | int bodovi = 0; 155 | 156 | int brzina = 3; //speed of bullet 157 | int bkugle = 1; 158 | int najmanja = 600; 159 | int najveca = 1200; 160 | int promjer = 10; 161 | 162 | int rx4 = 95; 163 | int ry4 = 0; 164 | int zivoti = 5; 165 | int poc = 0; 166 | int ispaljeno = 0; 167 | int nivo = 1; 168 | int centar = 95; 169 | unsigned long pocetno = 0; 170 | unsigned long odabrano = 0; 171 | unsigned long trenutno = 0; 172 | unsigned long nivovrije = 0; 173 | int poz = 30; 174 | void loop() { 175 | 176 | if (go == 0) { 177 | display.clearDisplay(); 178 | 179 | display.drawPixel(50, 30, 1); 180 | display.drawPixel(30, 17, 1); 181 | display.drawPixel(60, 18, 1); 182 | display.drawPixel(55, 16, 1); 183 | display.drawPixel(25, 43, 1); 184 | display.drawPixel(100, 43, 1); 185 | display.drawPixel(117, 52, 1); 186 | display.drawPixel(14, 49, 1); 187 | display.drawPixel(24, 24, 1); 188 | display.drawPixel(78, 36, 1); 189 | display.drawPixel(80, 57, 1); 190 | display.drawPixel(107, 11, 1); 191 | display.drawPixel(150, 11, 1); 192 | display.drawPixel(5, 5, 1); 193 | display.drawPixel(8, 7, 1); 194 | display.drawPixel(70, 12, 1); 195 | display.drawPixel(10, 56, 1); 196 | display.drawPixel(70, 25, 1); 197 | 198 | 199 | 200 | if (poc == 0) { 201 | pocetno = millis(); 202 | odabrano = random(400, 1200); 203 | poc = 1; 204 | } 205 | trenutno = millis(); 206 | 207 | 208 | //nivoi 209 | 210 | if ((trenutno - nivovrije) > 50000) 211 | { 212 | nivovrije = trenutno; 213 | nivo = nivo + 1; 214 | 215 | brzina = brzina + 1; //brizna neprijateljevog metka 216 | if ( nivo % 2 == 0 ) 217 | { 218 | bkugle = bkugle + 1; 219 | promjer = promjer - 1; 220 | } 221 | najmanja = najmanja - 50; 222 | najveca = najveca - 50; 223 | 224 | } 225 | 226 | 227 | 228 | if ((odabrano + pocetno) < trenutno) 229 | { 230 | poc = 0; 231 | ispaljeno = ispaljeno + 1; 232 | if (ispaljeno == 1) 233 | { rx = 95; 234 | ry = nep; 235 | } 236 | if (ispaljeno == 2) { 237 | rx2 = 95; 238 | ry2 = nep; 239 | } 240 | if (ispaljeno == 3) 241 | { 242 | rx3 = 95; 243 | ry3 = nep; 244 | } 245 | 246 | 247 | if (ispaljeno == 4) { 248 | rx4 = 95; 249 | ry4 = nep; 250 | 251 | } 252 | 253 | 254 | 255 | } 256 | 257 | 258 | if (ispaljeno > 0) 259 | { 260 | display.drawCircle(rx, ry, 2, 1); 261 | rx = rx - brzina; 262 | } 263 | 264 | if (ispaljeno > 1) 265 | { 266 | display.drawCircle(rx2, ry2, 1, 1); 267 | rx2 = rx2 - brzina; 268 | } 269 | 270 | if (ispaljeno > 2) 271 | { 272 | display.drawCircle(rx3, ry3, 4, 1); 273 | rx3 = rx3 - brzina; 274 | } 275 | 276 | if (ispaljeno > 3) 277 | { 278 | display.drawCircle(rx4, ry4, 2, 1); 279 | rx4 = rx4 - brzina; 280 | } 281 | 282 | if (digitalRead(12) == 0 && poz >= 2) { 283 | poz = poz - 2; 284 | } 285 | 286 | if (digitalRead(11) == 0 && poz <= 46) { 287 | poz = poz + 2; 288 | } 289 | 290 | 291 | if (digitalRead(3) == 0 && postoji == 0) 292 | { 293 | postoji = 1; 294 | metx = 6; 295 | mety = poz + 8; 296 | tone(9, 1200, 20); 297 | 298 | 299 | } 300 | if (postoji == 1) 301 | 302 | { 303 | metx = metx + 8 ; 304 | 305 | display.drawLine(metx, mety, metx + 4, mety, 1); 306 | } 307 | 308 | display.drawBitmap(4, poz, dioda16, 16, 16, 1); 309 | display.fillCircle(centar, nep, promjer, 1); 310 | display.fillCircle(centar + 2, nep + 3, promjer / 3, 0); 311 | 312 | display.setTextSize(1); 313 | display.setTextColor(WHITE); 314 | display.setCursor(33, 57); 315 | display.println("score:"); 316 | display.setCursor(68, 57); 317 | display.println(bodovi); 318 | 319 | display.setCursor(33, 0); 320 | display.println("lives:"); 321 | display.setCursor(68, 0); 322 | display.println(zivoti); 323 | 324 | display.setCursor(110, 0); 325 | display.println("L:"); 326 | 327 | display.setCursor(122, 0); 328 | display.println(nivo); 329 | 330 | display.setCursor(108, 57); 331 | display.println(trenutno / 1000); 332 | display.display(); 333 | 334 | if (metx > 128)postoji = 0; 335 | 336 | 337 | 338 | if (smjer == 0) { 339 | nep = nep + bkugle; 340 | } 341 | else 342 | { 343 | nep = nep - bkugle; 344 | } 345 | 346 | if (nep >= (64 - promjer)) 347 | smjer = 1; 348 | if (nep <= promjer) 349 | smjer = 0; 350 | 351 | if (mety >= nep - promjer && mety <= nep + promjer) 352 | if (metx > (centar - promjer) && metx < (centar + promjer)) 353 | { 354 | metx = -20; 355 | tone(9, 500, 20); 356 | bodovi = bodovi + 1; 357 | postoji = 0; 358 | } 359 | 360 | int pozicija = poz + 8; 361 | if (ry >= pozicija - 8 && ry <= pozicija + 8) 362 | if (rx < 12 && rx > 4) 363 | { 364 | rx = 95; 365 | ry = -50; 366 | tone(9, 100, 100); 367 | zivoti = zivoti - 1; 368 | } 369 | 370 | if (ry2 >= pozicija - 8 && ry2 <= pozicija + 8) 371 | if (rx2 < 12 && rx2 > 4) 372 | { 373 | rx2 = -50; 374 | ry2 = -50; 375 | tone(9, 100, 100); 376 | zivoti = zivoti - 1; 377 | } 378 | 379 | if (ry3 >= pozicija - 8 && ry3 <= pozicija + 8) 380 | if (rx3 < 12 && rx3 > 4) 381 | { 382 | rx3 = -50; 383 | ry3 = -50; 384 | tone(9, 100, 100); 385 | zivoti = zivoti - 1; 386 | } 387 | 388 | if (ry4 >= pozicija - 8 && ry4 <= pozicija + 8) 389 | if (rx4 < 12 && rx4 > 4) 390 | { 391 | rx4 = 200; 392 | ry4 = -50; 393 | ispaljeno = 0; 394 | tone(9, 100, 100); 395 | zivoti = zivoti - 1; 396 | } 397 | 398 | if (rx4 < 1) { 399 | ispaljeno = 0; 400 | rx4 = 200; 401 | } 402 | 403 | if (zivoti == 0) 404 | go = 1; 405 | } 406 | 407 | if (go == 1) 408 | { 409 | if (zivoti == 0) { 410 | tone(9, 200, 300); 411 | delay(300); 412 | tone(9, 250, 200); 413 | delay(200); 414 | tone(9, 300, 300); 415 | delay(300); 416 | zivoti = 5; 417 | } 418 | display.clearDisplay(); 419 | display.setFont(); 420 | display.setTextSize(2); 421 | display.setTextColor(WHITE); 422 | display.setCursor(7, 10); 423 | display.println("GAME OVER!"); 424 | display.setTextSize(1); 425 | display.setCursor(7, 30); 426 | display.println("score:"); 427 | display.setCursor(44, 30); 428 | display.println(bodovi); 429 | display.setCursor(7, 40); 430 | display.println("level:"); 431 | display.setCursor(44, 40); 432 | display.println(nivo); 433 | display.setCursor(7, 50); 434 | display.println("time(s):"); 435 | display.setCursor(60, 50); 436 | 437 | display.println(trenutno / 1000); 438 | display.display(); 439 | 440 | if (digitalRead(3) == 0) 441 | { 442 | tone(9, 280, 300); 443 | delay(300); 444 | tone(9, 250, 200); 445 | delay(200); 446 | tone(9, 370, 300); 447 | delay(300); 448 | ponovo(); 449 | } 450 | } 451 | } 452 | 453 | void ponovo() 454 | { 455 | metx = 0; 456 | mety = 0; 457 | postoji = 0; 458 | nep = 8; 459 | smjer = 0; 460 | go = 0; 461 | rx = 95; 462 | ry = 0; 463 | rx2 = 95; 464 | ry2 = 0; 465 | rx3 = 95; 466 | ry3 = 0; 467 | bodovi = 0; 468 | 469 | brzina = 3; //brizna neprijateljevog metka 470 | bkugle = 1; 471 | najmanja = 600; 472 | najveca = 1200; 473 | promjer = 12; 474 | 475 | rx4 = 95; 476 | ry4 = 0; 477 | zivoti = 5; 478 | poc = 0; 479 | ispaljeno = 0; 480 | nivo = 1; 481 | pocetno = 0; 482 | odabrano = 0; 483 | trenutno = 0; 484 | nivovrije = 0; 485 | 486 | 487 | 488 | 489 | } 490 | 491 | long readVcc() { 492 | // Read 1.1V reference against AVcc 493 | // set the reference to Vcc and the measurement to the internal 1.1V reference 494 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 495 | ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 496 | #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 497 | ADMUX = _BV(MUX5) | _BV(MUX0); 498 | #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 499 | ADMUX = _BV(MUX3) | _BV(MUX2); 500 | #else 501 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 502 | #endif 503 | 504 | delay(2); // Wait for Vref to settle 505 | ADCSRA |= _BV(ADSC); // Start conversion 506 | while (bit_is_set(ADCSRA, ADSC)); // measuring 507 | 508 | uint8_t low = ADCL; // must read ADCL first - it then locks ADCH 509 | uint8_t high = ADCH; // unlocks both 510 | 511 | long result = (high << 8) | low; 512 | 513 | result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 514 | return result; // Vcc in millivolts 515 | } 516 | 517 | 518 | void beep(int note, int duration) 519 | { 520 | //Play tone on buzzerPin 521 | tone(9, note, duration); 522 | 523 | 524 | 525 | delay(duration); 526 | 527 | 528 | 529 | noTone(9); 530 | 531 | delay(50); 532 | 533 | 534 | } 535 | 536 | -------------------------------------------------------------------------------- /spaceship-game/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/spaceship-game/thumbnail.png -------------------------------------------------------------------------------- /ssd1306/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "128x64 OLED Display", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /ssd1306/lesson.md: -------------------------------------------------------------------------------- 1 | The OLED display is connected at I²C address `0x3D`. 2 | 3 | Click the **Run Code** button on the right to see it in action: 4 | 5 | 6 | 7 | 8 | Can you change the code to display your name? 9 | -------------------------------------------------------------------------------- /ssd1306/sketch.ino: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | This is an example for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x64 pixel display using I2C to communicate 8 | 3 pins are required to interface (two I2C and one reset). 9 | 10 | Adafruit invests time and resources providing this open 11 | source code, please support Adafruit and open-source 12 | hardware by purchasing products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries, 15 | with contributions from the open source community. 16 | BSD license, check license.txt for more information 17 | All text above, and the splash screen below must be 18 | included in any redistribution. 19 | **************************************************************************/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 27 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 28 | 29 | // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 30 | #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 31 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 32 | 33 | #define NUMFLAKES 10 // Number of snowflakes in the animation example 34 | 35 | #define LOGO_HEIGHT 16 36 | #define LOGO_WIDTH 16 37 | static const unsigned char PROGMEM logo_bmp[] = 38 | { B00000000, B11000000, 39 | B00000001, B11000000, 40 | B00000001, B11000000, 41 | B00000011, B11100000, 42 | B11110011, B11100000, 43 | B11111110, B11111000, 44 | B01111110, B11111111, 45 | B00110011, B10011111, 46 | B00011111, B11111100, 47 | B00001101, B01110000, 48 | B00011011, B10100000, 49 | B00111111, B11100000, 50 | B00111111, B11110000, 51 | B01111100, B11110000, 52 | B01110000, B01110000, 53 | B00000000, B00110000 }; 54 | 55 | void setup() { 56 | Serial.begin(9600); 57 | 58 | // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally 59 | if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64 60 | Serial.println(F("SSD1306 allocation failed")); 61 | for(;;); // Don't proceed, loop forever 62 | } 63 | 64 | // Show initial display buffer contents on the screen -- 65 | // the library initializes this with an Adafruit splash screen. 66 | display.display(); 67 | delay(2000); // Pause for 2 seconds 68 | 69 | // Clear the buffer 70 | display.clearDisplay(); 71 | 72 | // Draw a single pixel in white 73 | display.drawPixel(10, 10, SSD1306_WHITE); 74 | 75 | // Show the display buffer on the screen. You MUST call display() after 76 | // drawing commands to make them visible on screen! 77 | display.display(); 78 | delay(2000); 79 | // display.display() is NOT necessary after every single drawing command, 80 | // unless that's what you want...rather, you can batch up a bunch of 81 | // drawing operations and then update the screen all at once by calling 82 | // display.display(). These examples demonstrate both approaches... 83 | 84 | testdrawline(); // Draw many lines 85 | 86 | testdrawrect(); // Draw rectangles (outlines) 87 | 88 | testfillrect(); // Draw rectangles (filled) 89 | 90 | testdrawcircle(); // Draw circles (outlines) 91 | 92 | testfillcircle(); // Draw circles (filled) 93 | 94 | testdrawroundrect(); // Draw rounded rectangles (outlines) 95 | 96 | testfillroundrect(); // Draw rounded rectangles (filled) 97 | 98 | testdrawtriangle(); // Draw triangles (outlines) 99 | 100 | testfilltriangle(); // Draw triangles (filled) 101 | 102 | testdrawchar(); // Draw characters of the default font 103 | 104 | testdrawstyles(); // Draw 'stylized' characters 105 | 106 | testscrolltext(); // Draw scrolling text 107 | 108 | testdrawbitmap(); // Draw a small bitmap image 109 | 110 | // Invert and restore display, pausing in-between 111 | display.invertDisplay(true); 112 | delay(1000); 113 | display.invertDisplay(false); 114 | delay(1000); 115 | 116 | testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps 117 | } 118 | 119 | void loop() { 120 | } 121 | 122 | void testdrawline() { 123 | int16_t i; 124 | 125 | display.clearDisplay(); // Clear display buffer 126 | 127 | for(i=0; i=0; i-=4) { 147 | display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE); 148 | display.display(); 149 | delay(1); 150 | } 151 | delay(250); 152 | 153 | display.clearDisplay(); 154 | 155 | for(i=display.width()-1; i>=0; i-=4) { 156 | display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE); 157 | display.display(); 158 | delay(1); 159 | } 160 | for(i=display.height()-1; i>=0; i-=4) { 161 | display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE); 162 | display.display(); 163 | delay(1); 164 | } 165 | delay(250); 166 | 167 | display.clearDisplay(); 168 | 169 | for(i=0; i0; i-=3) { 224 | // The INVERSE color is used so circles alternate white/black 225 | display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE); 226 | display.display(); // Update screen with each newly-drawn circle 227 | delay(1); 228 | } 229 | 230 | delay(2000); 231 | } 232 | 233 | void testdrawroundrect(void) { 234 | display.clearDisplay(); 235 | 236 | for(int16_t i=0; i0; i-=5) { 279 | // The INVERSE color is used so triangles alternate white/black 280 | display.fillTriangle( 281 | display.width()/2 , display.height()/2-i, 282 | display.width()/2-i, display.height()/2+i, 283 | display.width()/2+i, display.height()/2+i, SSD1306_INVERSE); 284 | display.display(); 285 | delay(1); 286 | } 287 | 288 | delay(2000); 289 | } 290 | 291 | void testdrawchar(void) { 292 | display.clearDisplay(); 293 | 294 | display.setTextSize(1); // Normal 1:1 pixel scale 295 | display.setTextColor(SSD1306_WHITE); // Draw white text 296 | display.setCursor(0, 0); // Start at top-left corner 297 | display.cp437(true); // Use full 256 char 'Code Page 437' font 298 | 299 | // Not all the characters will fit on the display. This is normal. 300 | // Library will draw what it can and the rest will be clipped. 301 | for(int16_t i=0; i<256; i++) { 302 | if(i == '\n') display.write(' '); 303 | else display.write(i); 304 | } 305 | 306 | display.display(); 307 | delay(2000); 308 | } 309 | 310 | void testdrawstyles(void) { 311 | display.clearDisplay(); 312 | 313 | display.setTextSize(1); // Normal 1:1 pixel scale 314 | display.setTextColor(SSD1306_WHITE); // Draw white text 315 | display.setCursor(0,0); // Start at top-left corner 316 | display.println(F("Hello, world!")); 317 | 318 | display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text 319 | display.println(3.141592); 320 | 321 | display.setTextSize(2); // Draw 2X-scale text 322 | display.setTextColor(SSD1306_WHITE); 323 | display.print(F("0x")); display.println(0xDEADBEEF, HEX); 324 | 325 | display.display(); 326 | delay(2000); 327 | } 328 | 329 | void testscrolltext(void) { 330 | display.clearDisplay(); 331 | 332 | display.setTextSize(2); // Draw 2X-scale text 333 | display.setTextColor(SSD1306_WHITE); 334 | display.setCursor(10, 0); 335 | display.println(F("scroll")); 336 | display.display(); // Show initial text 337 | delay(100); 338 | 339 | // Scroll in various directions, pausing in-between: 340 | display.startscrollright(0x00, 0x0F); 341 | delay(2000); 342 | display.stopscroll(); 343 | delay(1000); 344 | display.startscrollleft(0x00, 0x0F); 345 | delay(2000); 346 | display.stopscroll(); 347 | delay(1000); 348 | display.startscrolldiagright(0x00, 0x07); 349 | delay(2000); 350 | display.startscrolldiagleft(0x00, 0x07); 351 | delay(2000); 352 | display.stopscroll(); 353 | delay(1000); 354 | } 355 | 356 | void testdrawbitmap(void) { 357 | display.clearDisplay(); 358 | 359 | display.drawBitmap( 360 | (display.width() - LOGO_WIDTH ) / 2, 361 | (display.height() - LOGO_HEIGHT) / 2, 362 | logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1); 363 | display.display(); 364 | delay(1000); 365 | } 366 | 367 | #define XPOS 0 // Indexes into the 'icons' array in function below 368 | #define YPOS 1 369 | #define DELTAY 2 370 | 371 | void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { 372 | int8_t f, icons[NUMFLAKES][3]; 373 | 374 | // Initialize 'snowflake' positions 375 | for(f=0; f< NUMFLAKES; f++) { 376 | icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); 377 | icons[f][YPOS] = -LOGO_HEIGHT; 378 | icons[f][DELTAY] = random(1, 6); 379 | Serial.print(F("x: ")); 380 | Serial.print(icons[f][XPOS], DEC); 381 | Serial.print(F(" y: ")); 382 | Serial.print(icons[f][YPOS], DEC); 383 | Serial.print(F(" dy: ")); 384 | Serial.println(icons[f][DELTAY], DEC); 385 | } 386 | 387 | for(;;) { // Loop forever... 388 | display.clearDisplay(); // Clear the display buffer 389 | 390 | // Draw each snowflake: 391 | for(f=0; f< NUMFLAKES; f++) { 392 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE); 393 | } 394 | 395 | display.display(); // Show the display buffer on the screen 396 | delay(200); // Pause for 1/10 second 397 | 398 | // Then update coordinates of each flake... 399 | for(f=0; f< NUMFLAKES; f++) { 400 | icons[f][YPOS] += icons[f][DELTAY]; 401 | // If snowflake is off the bottom of the screen... 402 | if (icons[f][YPOS] >= display.height()) { 403 | // Reinitialize to a random position, just off the top 404 | icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width()); 405 | icons[f][YPOS] = -LOGO_HEIGHT; 406 | icons[f][DELTAY] = random(1, 6); 407 | } 408 | } 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /ssd1306/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/ssd1306/thumbnail.png -------------------------------------------------------------------------------- /tamaguino/lesson.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /tamaguino/lesson.md: -------------------------------------------------------------------------------- 1 | [Tamaguino](https://alojzjakob.github.io/Tamaguino/) is a tamagotchi clone for Arduino developed by [Alojz Jakob](Alojz Jakob). 2 | 3 | Click the **Run Code** button on the right to see it in action: 4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /task-scheduler/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Task Scheduler Playground", 3 | "thumbnail": "thumbnail.png", 4 | "coverImage": "https://storage.googleapis.com/wokwi-blog-assets/covers/task-scheduler.png" 5 | } 6 | -------------------------------------------------------------------------------- /task-scheduler/lesson.md: -------------------------------------------------------------------------------- 1 | ## Arduino Task Scheduler Playground 2 | 3 | This page shows the [Arduino TaskScheduler Library](https://github.com/arkhipenko/TaskScheduler/) in action. 4 | 5 | 6 | 7 | 8 | Click Run Code to compile and run the code, and you will see 9 | the red LED blinking in different rates, according to the 6 tasks defined 10 | in the demo code. 11 | 12 | Can you change the code so that the green LED (connected to pin 12) blinks two 13 | times per second, while the red LED keeps blinking at different rates? 14 | 15 | Built with for the Arduino community. 16 | -------------------------------------------------------------------------------- /task-scheduler/sketch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | LED blink example from TaskScheduler. 3 | Source: https://github.com/arkhipenko/TaskScheduler/tree/master/examples/Scheduler_example00_Blink 4 | */ 5 | 6 | 7 | // #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns 8 | #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass 9 | #define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only 10 | // #define _TASK_WDT_IDS // Compile with support for wdt control points and task ids 11 | // #define _TASK_LTS_POINTER // Compile with support for local task storage pointer 12 | // #define _TASK_PRIORITY // Support for layered scheduling priority 13 | // #define _TASK_MICRO_RES // Support for microsecond resolution 14 | // #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 and ESP32 ONLY) 15 | // #define _TASK_DEBUG // Make all methods and variables public for debug purposes 16 | // #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations 17 | // #define _TASK_TIMEOUT // Support for overall task timeout 18 | // #define _TASK_OO_CALLBACKS // Support for dynamic callback method binding 19 | #include 20 | 21 | // Debug and Test options 22 | #define _DEBUG_ 23 | //#define _TEST_ 24 | 25 | #ifdef _DEBUG_ 26 | #define _PP(a) Serial.print(a); 27 | #define _PL(a) Serial.println(a); 28 | #else 29 | #define _PP(a) 30 | #define _PL(a) 31 | #endif 32 | 33 | // LED_BUILTIN 13 34 | #if defined( ARDUINO_ARCH_ESP32 ) 35 | #define LED_BUILTIN 23 // esp32 dev2 kit does not have LED 36 | #endif 37 | 38 | // Scheduler 39 | Scheduler ts; 40 | 41 | /* 42 | Approach 1: LED is driven by the boolean variable; false = OFF, true = ON 43 | */ 44 | #define PERIOD1 500 45 | #define DURATION 10000 46 | void blink1CB(); 47 | Task tBlink1 ( PERIOD1 * TASK_MILLISECOND, DURATION / PERIOD1, &blink1CB, &ts, true ); 48 | 49 | /* 50 | Approac 2: two callback methods: one turns ON, another turns OFF 51 | */ 52 | #define PERIOD2 400 53 | void blink2CB_ON(); 54 | void blink2CB_OFF(); 55 | Task tBlink2 ( PERIOD2 * TASK_MILLISECOND, DURATION / PERIOD2, &blink2CB_ON, &ts, false ); 56 | 57 | /* 58 | Approach 3: Use RunCounter 59 | */ 60 | #define PERIOD3 300 61 | void blink3CB(); 62 | Task tBlink3 (PERIOD3 * TASK_MILLISECOND, DURATION / PERIOD3, &blink3CB, &ts, false); 63 | 64 | /* 65 | Approach 4: Use status request objects to pass control from one task to the other 66 | */ 67 | #define PERIOD4 200 68 | bool blink41OE(); 69 | void blink41(); 70 | void blink42(); 71 | void blink42OD(); 72 | Task tBlink4On ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink41, &ts, false, &blink41OE ); 73 | Task tBlink4Off ( PERIOD4 * TASK_MILLISECOND, TASK_ONCE, blink42, &ts, false, NULL, &blink42OD ); 74 | 75 | 76 | /* 77 | Approach 5: Two interleaving tasks 78 | */ 79 | #define PERIOD5 600 80 | bool blink51OE(); 81 | void blink51(); 82 | void blink52(); 83 | void blink52OD(); 84 | Task tBlink5On ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE ); 85 | Task tBlink5Off ( 600 * TASK_MILLISECOND, DURATION / PERIOD5, &blink52, &ts, false, NULL, &blink52OD ); 86 | 87 | 88 | /* 89 | Approach 6: RunCounter-based with random intervals 90 | */ 91 | #define PERIOD6 300 92 | void blink6CB(); 93 | bool blink6OE(); 94 | void blink6OD(); 95 | Task tBlink6 ( PERIOD6 * TASK_MILLISECOND, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD ); 96 | 97 | void setup() { 98 | // put your setup code here, to run once: 99 | #if defined(_DEBUG_) || defined(_TEST_) 100 | Serial.begin(115200); 101 | delay(TASK_SECOND); 102 | _PL("TaskScheduler Blink example"); 103 | _PL("Blinking for 10 seconds using various techniques\n"); 104 | delay(2 * TASK_SECOND); 105 | #endif 106 | pinMode(LED_BUILTIN, OUTPUT); 107 | } 108 | 109 | void loop() { 110 | ts.execute(); 111 | } 112 | 113 | inline void LEDOn() { 114 | digitalWrite( LED_BUILTIN, HIGH ); 115 | } 116 | 117 | inline void LEDOff() { 118 | digitalWrite( LED_BUILTIN, LOW ); 119 | } 120 | 121 | // === 1 ======================================= 122 | bool LED_state = false; 123 | void blink1CB() { 124 | if ( tBlink1.isFirstIteration() ) { 125 | _PP(millis()); 126 | _PL(": Blink1 - simple flag driven"); 127 | LED_state = false; 128 | } 129 | 130 | if ( LED_state ) { 131 | LEDOff(); 132 | LED_state = false; 133 | } 134 | else { 135 | LEDOn(); 136 | LED_state = true; 137 | } 138 | 139 | if ( tBlink1.isLastIteration() ) { 140 | tBlink2.restartDelayed( 2 * TASK_SECOND ); 141 | LEDOff(); 142 | } 143 | } 144 | 145 | 146 | // === 2 ====================================== 147 | void blink2CB_ON() { 148 | if ( tBlink2.isFirstIteration() ) { 149 | _PP(millis()); 150 | _PL(": Blink2 - 2 callback methods"); 151 | } 152 | 153 | LEDOn(); 154 | tBlink2.setCallback( &blink2CB_OFF ); 155 | 156 | if ( tBlink2.isLastIteration() ) { 157 | tBlink3.restartDelayed( 2 * TASK_SECOND ); 158 | LEDOff(); 159 | } 160 | } 161 | 162 | 163 | void blink2CB_OFF() { 164 | 165 | LEDOff(); 166 | tBlink2.setCallback( &blink2CB_ON ); 167 | 168 | if ( tBlink2.isLastIteration() ) { 169 | tBlink3.restartDelayed( 2 * TASK_SECOND ); 170 | LEDOff(); 171 | } 172 | } 173 | 174 | 175 | // === 3 ===================================== 176 | void blink3CB() { 177 | if ( tBlink3.isFirstIteration() ) { 178 | _PP(millis()); 179 | _PL(": Blink3 - Run Counter driven"); 180 | } 181 | 182 | if ( tBlink3.getRunCounter() & 1 ) { 183 | LEDOn(); 184 | } 185 | else { 186 | LEDOff(); 187 | } 188 | 189 | if ( tBlink3.isLastIteration() ) { 190 | tBlink4On.setOnEnable( &blink41OE ); 191 | tBlink4On.restartDelayed( 2 * TASK_SECOND ); 192 | LEDOff(); 193 | } 194 | } 195 | 196 | 197 | // === 4 ============================================= 198 | int counter = 0; 199 | bool blink41OE() { 200 | _PP(millis()); 201 | _PL(": Blink4 - Internal status request based"); 202 | counter = 0; 203 | tBlink4On.setOnEnable( NULL ); 204 | return true; 205 | } 206 | 207 | void blink41() { 208 | // _PP(millis()); 209 | // _PL(": blink41"); 210 | LEDOn(); 211 | StatusRequest* r = tBlink4On.getInternalStatusRequest(); 212 | tBlink4Off.waitForDelayed( r ); 213 | counter++; 214 | } 215 | 216 | void blink42() { 217 | // _PP(millis()); 218 | // _PL(": blink42"); 219 | LEDOff(); 220 | StatusRequest* r = tBlink4Off.getInternalStatusRequest(); 221 | tBlink4On.waitForDelayed( r ); 222 | counter++; 223 | } 224 | 225 | 226 | void blink42OD() { 227 | if ( counter >= DURATION / PERIOD4 ) { 228 | tBlink4On.disable(); 229 | tBlink4Off.disable(); 230 | 231 | tBlink5On.setOnEnable( &blink51OE ); 232 | tBlink5On.restartDelayed( 2 * TASK_SECOND ); 233 | tBlink5Off.restartDelayed( 2 * TASK_SECOND + PERIOD5 / 2 ); 234 | LEDOff(); 235 | } 236 | } 237 | 238 | 239 | // === 5 ========================================== 240 | bool blink51OE() { 241 | _PP(millis()); 242 | _PL(": Blink5 - Two interleaving tasks"); 243 | tBlink5On.setOnEnable( NULL ); 244 | return true; 245 | } 246 | void blink51() { 247 | // _PP(millis()); 248 | // _PL(": blink51"); 249 | LEDOn(); 250 | } 251 | void blink52() { 252 | // _PP(millis()); 253 | // _PL(": blink52"); 254 | LEDOff(); 255 | } 256 | void blink52OD() { 257 | tBlink6.restartDelayed( 2 * TASK_SECOND ); 258 | LEDOff(); 259 | } 260 | 261 | 262 | // === 6 ============================================ 263 | long interval6 = 0; 264 | bool blink6OE() { 265 | _PP(millis()); 266 | _PP(": Blink6 - RunCounter + Random ON interval = "); 267 | interval6 = random( 100, 901 ); 268 | tBlink6.setInterval( interval6 ); 269 | _PL( interval6 ); 270 | tBlink6.delay( 2 * TASK_SECOND ); 271 | 272 | return true; 273 | } 274 | 275 | void blink6CB() { 276 | if ( tBlink6.getRunCounter() & 1 ) { 277 | LEDOn(); 278 | tBlink6.setInterval( interval6 ); 279 | } 280 | else { 281 | LEDOff(); 282 | tBlink6.setInterval( TASK_SECOND - interval6 ); 283 | } 284 | } 285 | 286 | void blink6OD() { 287 | tBlink1.restartDelayed( 2 * TASK_SECOND ); 288 | LEDOff(); 289 | } 290 | -------------------------------------------------------------------------------- /task-scheduler/task-scheduler.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ArduinoTask SchedulerLibrary 18 | LearnArduinoProgramming 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 12 36 | 37 | 38 | 1 39 | 40 | 41 | 5 42 | 43 | 44 | 7 45 | 46 | 47 | 8 48 | 49 | 50 | 6 51 | 52 | 53 | 10 54 | 55 | 56 | 11 57 | 58 | 59 | 9 60 | 61 | 62 | 3 63 | 64 | 65 | 2 66 | 67 | 68 | 4 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /traffic-light/lesson.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Traffic Light", 3 | "thumbnail": "thumbnail.png" 4 | } 5 | -------------------------------------------------------------------------------- /traffic-light/lesson.md: -------------------------------------------------------------------------------- 1 | # Traffic Light Playground 2 | 3 | This sketch implements a simple traffic light. 4 | It goes from red to green and back. 5 | Green light blinks before going back to yellow. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | Challenge: Make the green blink before changing to yellow. 14 | -------------------------------------------------------------------------------- /traffic-light/sketch.ino: -------------------------------------------------------------------------------- 1 | #define RED 13 2 | #define YELLOW 12 3 | #define GREEN 11 4 | 5 | void setup() { 6 | pinMode(RED, OUTPUT); 7 | pinMode(YELLOW, OUTPUT); 8 | pinMode(GREEN, OUTPUT); 9 | } 10 | 11 | void loop() { 12 | digitalWrite(GREEN, HIGH); 13 | delay(3000); 14 | 15 | digitalWrite(GREEN, LOW); 16 | digitalWrite(YELLOW, HIGH); 17 | delay(500); 18 | 19 | digitalWrite(YELLOW, LOW); 20 | digitalWrite(RED, HIGH); 21 | delay(2000); 22 | 23 | digitalWrite(YELLOW, HIGH); 24 | delay(500); 25 | digitalWrite(YELLOW, LOW); 26 | digitalWrite(RED, LOW); 27 | } 28 | -------------------------------------------------------------------------------- /traffic-light/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wokwi/wokwi-playgrounds/a4cbf14c128b5dc971ad0a1dc421513075f4e297/traffic-light/thumbnail.png -------------------------------------------------------------------------------- /wokwi.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Arduino Playground", 3 | "lang": "en", 4 | "author": "Uri Shaked", 5 | "description": "Tinker with Arduino code and various hardware modules", 6 | "lessons": {} 7 | } 8 | --------------------------------------------------------------------------------