initial commit
This commit is contained in:
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
.DS_Store
|
||||
.pio
|
||||
.vscode
|
||||
|
||||
# kicad Temporary files
|
||||
*.000
|
||||
*.bak
|
||||
*.bck
|
||||
*.kicad_pcb-bak
|
||||
*.kicad_sch-bak
|
||||
*.kicad_prl
|
||||
*.sch-bak
|
||||
*~
|
||||
_autosave-*
|
||||
*.tmp
|
||||
*-save.pro
|
||||
*-save.kicad_pcb
|
||||
fp-info-cache
|
||||
|
||||
# Netlist files (exported from Eeschema)
|
||||
*.net
|
||||
|
||||
# Autorouter files (exported from Pcbnew)
|
||||
*.dsn
|
||||
*.ses
|
||||
|
||||
# Exported BOM files
|
||||
*.xml
|
||||
*.csv
|
||||
|
||||
# other files
|
||||
CAD/Leo_muziekdoos_ESP32/~$ESP32 Pins.xlsx
|
||||
5
esp32nixie/.gitignore
vendored
Normal file
5
esp32nixie/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
BIN
esp32nixie/doc/Scheme_Nixie_Clock_MCU_NCM109_v1.1-min-1.jpg
Normal file
BIN
esp32nixie/doc/Scheme_Nixie_Clock_MCU_NCM109_v1.1-min-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 510 KiB |
BIN
esp32nixie/doc/hv5122.pdf
Normal file
BIN
esp32nixie/doc/hv5122.pdf
Normal file
Binary file not shown.
39
esp32nixie/include/README
Normal file
39
esp32nixie/include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
46
esp32nixie/lib/README
Normal file
46
esp32nixie/lib/README
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
21
esp32nixie/platformio.ini
Normal file
21
esp32nixie/platformio.ini
Normal file
@@ -0,0 +1,21 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp-wrover-kit]
|
||||
platform = espressif32
|
||||
board = esp-wrover-kit
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
paulstoffregen/Time@^1.6.1
|
||||
jchristensen/Timezone@^1.2.4
|
||||
khoih-prog/ESP_WifiManager@^1.10.2
|
||||
raronoff/clickButton
|
||||
lib_ldf_mode = deep+
|
||||
monitor_speed = 115200
|
||||
137
esp32nixie/src/LEDControl.h
Normal file
137
esp32nixie/src/LEDControl.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
ESP32 NTP Nixie Tube Clock Program
|
||||
|
||||
LEDControl.h - LED Control Code
|
||||
*/
|
||||
|
||||
#ifndef LED_CONTROL_H
|
||||
#define LED_CONTROL_H
|
||||
|
||||
// A 24 bit color type
|
||||
typedef struct {
|
||||
byte red;
|
||||
byte green;
|
||||
byte blue;
|
||||
}
|
||||
RGB24;
|
||||
|
||||
// Misc color definitions
|
||||
RGB24 black = { 0, 0, 0};
|
||||
RGB24 blue = { 0, 0, 127};
|
||||
RGB24 green = { 0, 127, 0};
|
||||
RGB24 cyan = { 0, 127, 127};
|
||||
RGB24 red = {127, 0, 0};
|
||||
RGB24 magenta = {127, 0, 127};
|
||||
RGB24 yellow = {127, 127, 0};
|
||||
RGB24 white = {127, 127, 127};
|
||||
|
||||
#define LED_RED_CHANNEL 1
|
||||
#define LED_GREEN_CHANNEL 2
|
||||
#define LED_BLUE_CHANNEL 3
|
||||
|
||||
// LEDControl Class Definition
|
||||
class LEDControl {
|
||||
public:
|
||||
// Class constructor
|
||||
LEDControl(int _redPin, int _greenPin, int _bluePin) {
|
||||
|
||||
// Save incoming pin assignments
|
||||
redPin = _redPin;
|
||||
greenPin = _greenPin;
|
||||
bluePin = _bluePin;
|
||||
|
||||
// Set up the output pins for the RGB LED
|
||||
pinMode(redPin, OUTPUT);
|
||||
pinMode(greenPin, OUTPUT);
|
||||
pinMode(bluePin, OUTPUT);
|
||||
|
||||
// Each channel is set up for 12kHz and 10-bit resolution
|
||||
ledcSetup(LED_RED_CHANNEL, 12000, 10);
|
||||
ledcSetup(LED_GREEN_CHANNEL, 12000, 10);
|
||||
ledcSetup(LED_BLUE_CHANNEL, 12000, 10);
|
||||
|
||||
ledcAttachPin(redPin, LED_RED_CHANNEL);
|
||||
ledcAttachPin(greenPin, LED_GREEN_CHANNEL);
|
||||
ledcAttachPin(bluePin, LED_BLUE_CHANNEL);
|
||||
|
||||
// Turn off RGB LEDs
|
||||
ledcWrite(LED_RED_CHANNEL, 0);
|
||||
ledcWrite(LED_GREEN_CHANNEL, 0);
|
||||
ledcWrite(LED_BLUE_CHANNEL, 0);
|
||||
}
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colors are a transition r - g - b - back to r.
|
||||
RGB24 colorWheel(int wheelPos) {
|
||||
RGB24 color;
|
||||
|
||||
wheelPos %= 256;
|
||||
|
||||
if (wheelPos < 85) {
|
||||
color.red = 255 - wheelPos * 3;
|
||||
color.green = wheelPos * 3;
|
||||
color.blue = 0;
|
||||
}
|
||||
else if (wheelPos < 170) {
|
||||
wheelPos -= 85;
|
||||
color.red = 0;
|
||||
color.green = 255 - wheelPos * 3;
|
||||
color.blue = wheelPos * 3;
|
||||
}
|
||||
else {
|
||||
wheelPos -= 170;
|
||||
color.red = wheelPos * 3;
|
||||
color.green = 0;
|
||||
color.blue = 255 - wheelPos * 3;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
// Set the RGB LEDs color
|
||||
void setLEDColor(byte red, byte green, byte blue) {
|
||||
red = gammaArray[red];
|
||||
green = gammaArray[green];
|
||||
blue = gammaArray[blue];
|
||||
|
||||
// Change 8 bits to 10 bits
|
||||
int rred = map(red, 0, 255, 0, 1023);
|
||||
int rgrn = map(green, 0, 255, 0, 1023);
|
||||
int rblu = map(blue, 0, 255, 0, 1023);
|
||||
|
||||
// Use PWM to control LED brightness
|
||||
ledcWrite(LED_RED_CHANNEL, rred);
|
||||
ledcWrite(LED_GREEN_CHANNEL, rgrn);
|
||||
ledcWrite(LED_BLUE_CHANNEL, rblu);
|
||||
}
|
||||
|
||||
// Set the RGB LEDs color
|
||||
void setLEDColor(RGB24 color) {
|
||||
setLEDColor(color.red, color.green, color.blue);
|
||||
}
|
||||
|
||||
private:
|
||||
// Private data
|
||||
int redPin, greenPin, bluePin;
|
||||
|
||||
// Gamma correction array
|
||||
const byte gammaArray [256] = {
|
||||
0, 0, 0, 0, 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, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
|
||||
115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
|
||||
144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
|
||||
177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
|
||||
215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
168
esp32nixie/src/NTP.h
Normal file
168
esp32nixie/src/NTP.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
ESP32 NTP Nixie Tube Clock Program
|
||||
|
||||
NTP.h - Network Time Protocol Functions
|
||||
*/
|
||||
|
||||
#ifndef NTP_H
|
||||
#define NTP_H
|
||||
|
||||
#include <TimeLib.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
// Define the time between sync events
|
||||
#define SYNC_INTERVAL_HOURS 1
|
||||
#define SYNC_INTERVAL_MINUTES (SYNC_INTERVAL_HOURS * 60L)
|
||||
#define SYNC_INTERVAL_SECONDS (SYNC_INTERVAL_MINUTES * 60L)
|
||||
|
||||
#define NTP_SERVER_NAME "time.nist.gov" // NTP request server
|
||||
#define NTP_SERVER_PORT 123 // NTP requests are to port 123
|
||||
#define LOCALPORT 2390 // Local port to listen for UDP packets
|
||||
#define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message
|
||||
#define RETRIES 20 // Times to try getting NTP time before failing
|
||||
|
||||
class NTP {
|
||||
public:
|
||||
NTP(NixieTubeShield& shield) : _shield(shield) {
|
||||
// Login succeeded so set UDP local port
|
||||
udp.begin(LOCALPORT);
|
||||
};
|
||||
|
||||
static NTP& getInstance() {
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
static void createSingleton(NixieTubeShield& shield) {
|
||||
NTP* ntp = new NTP(shield);
|
||||
_instance = ntp;
|
||||
}
|
||||
|
||||
// Get NTP time with retries on access failure
|
||||
time_t getTime() {
|
||||
unsigned long result;
|
||||
|
||||
for (int i = 0; i < RETRIES; i++) {
|
||||
result = _getTime();
|
||||
if (result != 0) {
|
||||
// Update RTC
|
||||
tmElements_t tm;
|
||||
breakTime(result, tm);
|
||||
_shield.setRTCDateTime(tm);
|
||||
return result;
|
||||
}
|
||||
Serial.println("Problem getting NTP time. Retrying...");
|
||||
delay(300);
|
||||
}
|
||||
Serial.println("NTP Problem - Could not obtain time. Falling back to RTC");
|
||||
|
||||
return _getRTCTime();
|
||||
}
|
||||
|
||||
private:
|
||||
// Static NTP instance
|
||||
static NTP* _instance;
|
||||
|
||||
// NTP Time Provider Code
|
||||
time_t _getTime() {
|
||||
// Set all bytes in the buffer to 0
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
|
||||
// Initialize values needed to form NTP request
|
||||
packetBuffer[0] = 0xE3; // LI, Version, Mode
|
||||
packetBuffer[2] = 0x06; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 0x31;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 0x31;
|
||||
packetBuffer[15] = 0x34;
|
||||
|
||||
// All NTP fields initialized, now send a packet requesting a timestamp
|
||||
udp.beginPacket(NTP_SERVER_NAME, NTP_SERVER_PORT);
|
||||
udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
udp.endPacket();
|
||||
|
||||
// Wait a second for the response
|
||||
delay(1000);
|
||||
|
||||
// Listen for the response
|
||||
if (udp.parsePacket() == NTP_PACKET_SIZE) {
|
||||
udp.read(packetBuffer, NTP_PACKET_SIZE); // Read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
|
||||
// Convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long) packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long) packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long) packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long) packetBuffer[43];
|
||||
|
||||
Serial.println("Got NTP time");
|
||||
|
||||
return secsSince1900 - 2208988800UL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get system time from real-time clock
|
||||
time_t _getRTCTime() {
|
||||
bool isRTCAvailable = true;
|
||||
tmElements_t m;
|
||||
_shield.getRTCTime(m);
|
||||
|
||||
byte prevSeconds = m.Second;
|
||||
unsigned long RTC_ReadingStartTime = millis();
|
||||
|
||||
Serial.print("Real-time clock: ");
|
||||
Serial.print(m.Hour);
|
||||
Serial.print(":");
|
||||
Serial.println(m.Minute);
|
||||
Serial.print(":");
|
||||
Serial.println(m.Second);
|
||||
|
||||
while (prevSeconds == m.Second) {
|
||||
_shield.getRTCTime(m);
|
||||
if ((millis() - RTC_ReadingStartTime) > 3000) {
|
||||
Serial.println("Warning! RTC did not respond!");
|
||||
isRTCAvailable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set system time if RTC is available
|
||||
if (isRTCAvailable) {
|
||||
Serial.println("Got time from RTC");
|
||||
return makeTime(m);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Instance of shield
|
||||
NixieTubeShield& _shield;
|
||||
|
||||
// A UDP instance to let us send and receive packets over UDP
|
||||
WiFiUDP udp;
|
||||
|
||||
// Buffer to hold outgoing and incoming packets
|
||||
byte packetBuffer[NTP_PACKET_SIZE];
|
||||
};
|
||||
|
||||
NTP* NTP::_instance = 0;
|
||||
|
||||
time_t getNTPTime() {
|
||||
return NTP::getInstance().getTime();
|
||||
}
|
||||
|
||||
// Initialize the NTP code
|
||||
void initNTP(NixieTubeShield& shield) {
|
||||
// Create instance of NTP class
|
||||
NTP::createSingleton(shield);
|
||||
|
||||
// Set the time provider to NTP
|
||||
setSyncProvider(getNTPTime);
|
||||
|
||||
// Set the interval between NTP calls
|
||||
setSyncInterval(SYNC_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
#endif
|
||||
304
esp32nixie/src/NixieTubeShield.h
Normal file
304
esp32nixie/src/NixieTubeShield.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
ESP32 NTP Nixie Tube Clock Program
|
||||
|
||||
NixieTubeShield.h - Interface to Nixie Tube Shield
|
||||
*/
|
||||
|
||||
#ifndef NIXIE_TUBE_SHIELD_H
|
||||
#define NIXIE_TUBE_SHIELD_H
|
||||
|
||||
#include "ClickButton.h"
|
||||
#include <Wire.h>
|
||||
#include "LEDControl.h"
|
||||
#include "Tone.h"
|
||||
|
||||
// ***************************************************************
|
||||
// ESP32 Pin Configuration
|
||||
// ***************************************************************
|
||||
|
||||
#define LED_GREEN 14
|
||||
#define LED_RED 13
|
||||
#define LED_BLUE 15
|
||||
#define HV_ENABLE 17 //TODO
|
||||
#define LATCH_ENABLE 5
|
||||
#define NEON_DOTS 25
|
||||
#define MODE_BUTTON 12
|
||||
#define UP_BUTTON 16
|
||||
#define DOWN_BUTTON 4
|
||||
#define BUZZER_PIN 32
|
||||
|
||||
#define DS1307_ADDRESS 0x68
|
||||
|
||||
// ***************************************************************
|
||||
// Digit Data Definitions
|
||||
// Each digit, except blank, has a single active low bit in a
|
||||
// field of 10 bits
|
||||
// ***************************************************************
|
||||
#define DIGIT_0 0
|
||||
#define DIGIT_1 1
|
||||
#define DIGIT_2 2
|
||||
#define DIGIT_3 3
|
||||
#define DIGIT_4 4
|
||||
#define DIGIT_5 5
|
||||
#define DIGIT_6 6
|
||||
#define DIGIT_7 7
|
||||
#define DIGIT_8 8
|
||||
#define DIGIT_9 9
|
||||
#define DIGIT_BLANK 0xFF
|
||||
|
||||
#define BLANK_DIGIT 10
|
||||
|
||||
#define UpperDotsMask 0x80000000
|
||||
#define LowerDotsMask 0x40000000
|
||||
|
||||
ClickButton setButton(MODE_BUTTON, LOW, CLICKBTN_PULLUP);
|
||||
ClickButton upButton(UP_BUTTON, LOW, CLICKBTN_PULLUP);
|
||||
ClickButton downButton(DOWN_BUTTON, LOW, CLICKBTN_PULLUP);
|
||||
|
||||
// Class Definition
|
||||
class NixieTubeShield : public LEDControl {
|
||||
unsigned int SymbolArray[10]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
|
||||
|
||||
public:
|
||||
|
||||
// Class Constructor
|
||||
NixieTubeShield() : LEDControl(LED_RED, LED_GREEN, LED_BLUE) {
|
||||
|
||||
// Setup output pins
|
||||
pinMode(HV_ENABLE, OUTPUT);
|
||||
pinMode(LATCH_ENABLE, OUTPUT);
|
||||
pinMode(NEON_DOTS, OUTPUT);
|
||||
pinMode(MODE_BUTTON, INPUT_PULLUP);
|
||||
pinMode(UP_BUTTON, INPUT_PULLUP);
|
||||
pinMode(DOWN_BUTTON, INPUT_PULLUP);
|
||||
//pinMode(NEON_DOTS_LOWER, OUTPUT);
|
||||
|
||||
// Set default outputs
|
||||
digitalWrite(HV_ENABLE, LOW);
|
||||
digitalWrite(LATCH_ENABLE, LOW);
|
||||
digitalWrite(NEON_DOTS, LOW);
|
||||
|
||||
setButton.debounceTime = 20; // Debounce timer in ms
|
||||
setButton.multiclickTime = 30; // Time limit for multi clicks
|
||||
setButton.longClickTime = 2000; // time until "held-down clicks" register
|
||||
|
||||
upButton.debounceTime = 20; // Debounce timer in ms
|
||||
upButton.multiclickTime = 30; // Time limit for multi clicks
|
||||
upButton.longClickTime = 2000; // time until "held-down clicks" register
|
||||
|
||||
downButton.debounceTime = 20; // Debounce timer in ms
|
||||
downButton.multiclickTime = 30; // Time limit for multi clicks
|
||||
downButton.longClickTime = 2000; // time until "held-down clicks" register
|
||||
|
||||
// Initialize digit storage to all ones so all digits are off
|
||||
for (int i = 0; i < 6; i++) {
|
||||
digits[i] = DIGIT_BLANK;
|
||||
}
|
||||
}
|
||||
|
||||
// High voltage control
|
||||
void hvEnable(boolean state) {
|
||||
digitalWrite(HV_ENABLE, state ? HIGH : LOW);
|
||||
}
|
||||
|
||||
// Neon lamp control
|
||||
void dotsEnable(boolean state) {
|
||||
digitalWrite(NEON_DOTS, state ? HIGH : LOW);
|
||||
dotsEnabled = state;
|
||||
}
|
||||
|
||||
// Set the NX1 (most significant) digit
|
||||
void setNX1Digit(int d) {
|
||||
digits[5] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
// Set the NX2 digit
|
||||
void setNX2Digit(int d) {
|
||||
digits[4] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
// Set the NX3 digit
|
||||
void setNX3Digit(int d) {
|
||||
digits[3] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
// Set the NX4 digit
|
||||
void setNX4Digit(int d) {
|
||||
digits[2] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
// Set the NX5 digit
|
||||
void setNX5Digit(int d) {
|
||||
digits[1] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
// Set the NX6 (least significant) digit
|
||||
void setNX6Digit(int d) {
|
||||
digits[0] = NUMERIC_DIGITS[d];
|
||||
}
|
||||
|
||||
void show() {
|
||||
digitalWrite(LATCH_ENABLE, LOW); // allow data input (Transparent mode)
|
||||
unsigned long Var32=0;
|
||||
|
||||
//-------- REG 1 -----------------------------------------------
|
||||
Var32=0;
|
||||
|
||||
Var32|=(unsigned long)(SymbolArray[digits[0]])<<20; // s2
|
||||
Var32|=(unsigned long)(SymbolArray[digits[1]])<<10; //s1
|
||||
Var32|=(unsigned long) (SymbolArray[digits[2]]); //m2
|
||||
|
||||
if (dotsEnabled) Var32|=LowerDotsMask;
|
||||
else Var32&=~LowerDotsMask;
|
||||
|
||||
if (dotsEnabled) Var32|=UpperDotsMask;
|
||||
else Var32&=~UpperDotsMask;
|
||||
|
||||
SPI.transfer(Var32>>24);
|
||||
SPI.transfer(Var32>>16);
|
||||
SPI.transfer(Var32>>8);
|
||||
SPI.transfer(Var32);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//-------- REG 0 -----------------------------------------------
|
||||
Var32=0;
|
||||
|
||||
Var32|=(unsigned long)(SymbolArray[digits[3]])<<20; // m1
|
||||
Var32|=(unsigned long)(SymbolArray[digits[4]])<<10; //h2
|
||||
Var32|=(unsigned long)SymbolArray[digits[5]]; //h1
|
||||
|
||||
if (dotsEnabled) Var32|=LowerDotsMask;
|
||||
else Var32&=~LowerDotsMask;
|
||||
|
||||
if (dotsEnabled) Var32|=UpperDotsMask;
|
||||
else Var32&=~UpperDotsMask;
|
||||
|
||||
SPI.transfer(Var32>>24);
|
||||
SPI.transfer(Var32>>16);
|
||||
SPI.transfer(Var32>>8);
|
||||
SPI.transfer(Var32);
|
||||
|
||||
digitalWrite(LATCH_ENABLE, HIGH); // latching data
|
||||
}
|
||||
|
||||
// Do anti-poisoning routine and then turn off all tubes
|
||||
void doAntiPoisoning(void) {
|
||||
bool dots = false;
|
||||
dotsEnable(false);
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 11; i++) {
|
||||
setNX1Digit(i);
|
||||
setNX2Digit(i);
|
||||
setNX3Digit(i);
|
||||
setNX4Digit(i);
|
||||
setNX5Digit(i);
|
||||
setNX6Digit(i);
|
||||
|
||||
// Make the changes visible
|
||||
show();
|
||||
|
||||
// Small delay
|
||||
delay(500);
|
||||
|
||||
setLEDColor(i%3==0?255:0, i%3==1?255:0, i%3==2?255:0);
|
||||
dots = !dots;
|
||||
dotsEnable(dots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processButtons() {
|
||||
setButton.Update();
|
||||
upButton.Update();
|
||||
downButton.Update();
|
||||
}
|
||||
|
||||
bool isSetButtonClicked() {
|
||||
return (setButton.clicks > 0);
|
||||
}
|
||||
|
||||
bool isSetButtonLongClicked() {
|
||||
return (setButton.clicks < 0);
|
||||
}
|
||||
|
||||
bool isUpButtonClicked() {
|
||||
return (upButton.clicks > 0);
|
||||
}
|
||||
|
||||
bool isUpButtonLongClicked() {
|
||||
return (upButton.clicks < 0);
|
||||
}
|
||||
|
||||
bool isDownButtonClicked() {
|
||||
return (downButton.clicks > 0);
|
||||
}
|
||||
|
||||
bool isDownButtonLongClicked() {
|
||||
return (downButton.clicks < 0);
|
||||
}
|
||||
|
||||
void getRTCTime(tmElements_t &m) {
|
||||
Wire.beginTransmission(DS1307_ADDRESS);
|
||||
Wire.write(zero);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(DS1307_ADDRESS, 7);
|
||||
|
||||
m.Second = bcdToDec(Wire.read());
|
||||
m.Minute = bcdToDec(Wire.read());
|
||||
m.Hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
|
||||
m.Wday = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
|
||||
m.Day = bcdToDec(Wire.read());
|
||||
m.Month = bcdToDec(Wire.read());
|
||||
m.Year = bcdToDec(Wire.read());
|
||||
}
|
||||
|
||||
void setRTCDateTime(const tmElements_t &m) {
|
||||
Wire.beginTransmission(DS1307_ADDRESS);
|
||||
Wire.write(zero); //stop Oscillator
|
||||
|
||||
Wire.write(decToBcd(m.Second));
|
||||
Wire.write(decToBcd(m.Minute));
|
||||
Wire.write(decToBcd(m.Hour));
|
||||
Wire.write(decToBcd(m.Wday));
|
||||
Wire.write(decToBcd(m.Day));
|
||||
Wire.write(decToBcd(m.Month));
|
||||
Wire.write(decToBcd(m.Year));
|
||||
|
||||
Wire.write(zero); //start
|
||||
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
private:
|
||||
byte decToBcd(byte val) {
|
||||
// Convert normal decimal numbers to binary coded decimal
|
||||
return ( (val / 10 * 16) + (val % 10) );
|
||||
}
|
||||
|
||||
byte bcdToDec(byte val) {
|
||||
// Convert binary coded decimal to normal decimal numbers
|
||||
return ( (val / 16 * 10) + (val % 16) );
|
||||
}
|
||||
|
||||
// Private data
|
||||
// Array of codes for each nixie digit
|
||||
int NUMERIC_DIGITS[11] = {
|
||||
DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4,
|
||||
DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9,
|
||||
DIGIT_BLANK
|
||||
};
|
||||
|
||||
byte zero = 0x00; //workaround for issue #527
|
||||
int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week;
|
||||
|
||||
// Storage for codes for each nixie digit
|
||||
// Digit order is: NX6, NX5, NX4, NX3, NX2, NX1
|
||||
uint16_t digits[6];
|
||||
|
||||
bool dotsEnabled = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
124
esp32nixie/src/Tone.h
Normal file
124
esp32nixie/src/Tone.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#ifndef TONE_H
|
||||
#define TONE_H
|
||||
|
||||
/*************************************************
|
||||
* Public Constants
|
||||
*************************************************/
|
||||
|
||||
#define NOTE_B0 31
|
||||
#define NOTE_C1 33
|
||||
#define NOTE_CS1 35
|
||||
#define NOTE_D1 37
|
||||
#define NOTE_DS1 39
|
||||
#define NOTE_E1 41
|
||||
#define NOTE_F1 44
|
||||
#define NOTE_FS1 46
|
||||
#define NOTE_G1 49
|
||||
#define NOTE_GS1 52
|
||||
#define NOTE_A1 55
|
||||
#define NOTE_AS1 58
|
||||
#define NOTE_B1 62
|
||||
#define NOTE_C2 65
|
||||
#define NOTE_CS2 69
|
||||
#define NOTE_D2 73
|
||||
#define NOTE_DS2 78
|
||||
#define NOTE_E2 82
|
||||
#define NOTE_F2 87
|
||||
#define NOTE_FS2 93
|
||||
#define NOTE_G2 98
|
||||
#define NOTE_GS2 104
|
||||
#define NOTE_A2 110
|
||||
#define NOTE_AS2 117
|
||||
#define NOTE_B2 123
|
||||
#define NOTE_C3 131
|
||||
#define NOTE_CS3 139
|
||||
#define NOTE_D3 147
|
||||
#define NOTE_DS3 156
|
||||
#define NOTE_E3 165
|
||||
#define NOTE_F3 175
|
||||
#define NOTE_FS3 185
|
||||
#define NOTE_G3 196
|
||||
#define NOTE_GS3 208
|
||||
#define NOTE_A3 220
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
#define NOTE_C4 262
|
||||
#define NOTE_CS4 277
|
||||
#define NOTE_D4 294
|
||||
#define NOTE_DS4 311
|
||||
#define NOTE_E4 330
|
||||
#define NOTE_F4 349
|
||||
#define NOTE_FS4 370
|
||||
#define NOTE_G4 392
|
||||
#define NOTE_GS4 415
|
||||
#define NOTE_A4 440
|
||||
#define NOTE_AS4 466
|
||||
#define NOTE_B4 494
|
||||
#define NOTE_C5 523
|
||||
#define NOTE_CS5 554
|
||||
#define NOTE_D5 587
|
||||
#define NOTE_DS5 622
|
||||
#define NOTE_E5 659
|
||||
#define NOTE_F5 698
|
||||
#define NOTE_FS5 740
|
||||
#define NOTE_G5 784
|
||||
#define NOTE_GS5 831
|
||||
#define NOTE_A5 880
|
||||
#define NOTE_AS5 932
|
||||
#define NOTE_B5 988
|
||||
#define NOTE_C6 1047
|
||||
#define NOTE_CS6 1109
|
||||
#define NOTE_D6 1175
|
||||
#define NOTE_DS6 1245
|
||||
#define NOTE_E6 1319
|
||||
#define NOTE_F6 1397
|
||||
#define NOTE_FS6 1480
|
||||
#define NOTE_G6 1568
|
||||
#define NOTE_GS6 1661
|
||||
#define NOTE_A6 1760
|
||||
#define NOTE_AS6 1865
|
||||
#define NOTE_B6 1976
|
||||
#define NOTE_C7 2093
|
||||
#define NOTE_CS7 2217
|
||||
#define NOTE_D7 2349
|
||||
#define NOTE_DS7 2489
|
||||
#define NOTE_E7 2637
|
||||
#define NOTE_F7 2794
|
||||
#define NOTE_FS7 2960
|
||||
#define NOTE_G7 3136
|
||||
#define NOTE_GS7 3322
|
||||
#define NOTE_A7 3520
|
||||
#define NOTE_AS7 3729
|
||||
#define NOTE_B7 3951
|
||||
#define NOTE_C8 4186
|
||||
#define NOTE_CS8 4435
|
||||
#define NOTE_D8 4699
|
||||
#define NOTE_DS8 4978
|
||||
|
||||
#define TONE_CHANNEL 5
|
||||
|
||||
class Tone {
|
||||
public:
|
||||
Tone() {
|
||||
}
|
||||
|
||||
void begin(uint8_t pin) {
|
||||
ledcSetup(TONE_CHANNEL, 1E5, 12);
|
||||
ledcAttachPin(pin,TONE_CHANNEL);
|
||||
}
|
||||
|
||||
void play(unsigned int freq, unsigned long duration) {
|
||||
ledcWriteTone(TONE_CHANNEL, freq);
|
||||
// TODO
|
||||
//tone(_pin, freq, duration);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
ledcWrite(TONE_CHANNEL,0);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _pin;
|
||||
};
|
||||
|
||||
#endif
|
||||
521
esp32nixie/src/main.cpp
Normal file
521
esp32nixie/src/main.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
ESP32 NTP Nixie Tube Clock Program
|
||||
|
||||
This hardware/software combination implements a Nixie tube digital clock that
|
||||
never needs setting as it gets the current time and date by polling
|
||||
Network Time Protocol (NTP) servers on the Internet. The clock's time
|
||||
is synchronized to NTP time periodically. Use of the TimeZone
|
||||
library means that Daylight Savings Time (DST) is automatically
|
||||
taken into consideration so no time change buttons are necessary.
|
||||
Clock can run in 24 hour or 12 hour mode.
|
||||
|
||||
This program uses the WiFiManager library to allow WiFi credentials to be set
|
||||
via a web interface.
|
||||
|
||||
How it works:
|
||||
|
||||
When the program is first started it creates a wireless access point called NixieClock
|
||||
that the user needs to connect to and then if the user points his/her browser to
|
||||
192.168.4.1, a page is presented that allows the credentials for the actual WiFi network
|
||||
to be entered. This only needs to be done once since the credentials will be stored in
|
||||
EEPROM and will be used from that point forward.
|
||||
|
||||
Once WiFi connection has been established, it uses NTP to initialize the real-time clock (RTC).
|
||||
If ESP32 cannot connect to the WiFi network using the stored crecentials, it will fall back
|
||||
to the real-time clock (RTC).
|
||||
|
||||
Press the mode button to enter WiFi AP configuration mode.
|
||||
Long-press the mode button to reset the ESP32.
|
||||
|
||||
The hardware consists of the following parts:
|
||||
ESP32
|
||||
Nixie Tubes Clock Arduino Shield NCS314 for xUSSR IN-14 Nixie Tubes from eBay
|
||||
|
||||
The connections between the ESP32 board and the Nixie Clock Shield are as follows:
|
||||
|
||||
ESP32 Pin Shield Pin Function
|
||||
--------------------------------------------------------------------
|
||||
GIOP18 SCK / avr19 SPI Clock
|
||||
GIOP23 MOSI / avr17 Master Out Slave In (data from ESP32->clock)
|
||||
5 (SS) LE / avr16 Latch Enable
|
||||
25 DOT1 -- Neon dot 1
|
||||
25 DOT2 -- Neon dot 2
|
||||
14 PWM1 / avr12 Green LED drive
|
||||
13 PWM2 / avr15 Red LED drive
|
||||
15 PWM3 / avr5 Blue LED drive
|
||||
17 SHTDN High voltage enable
|
||||
12 SET / avr23 Set (mode) button
|
||||
16 UP / avr24 Up button
|
||||
4 DOWN / avr25 Down button
|
||||
32 BUZZER /avr4 Buzzer pin
|
||||
|
||||
The ESP32 is powered (via Vin) with 5VDC from a 5 volt regulator driven from
|
||||
the 12 VDC supply. The shield is powered directly from the 12 VDC supply.
|
||||
|
||||
Based on ESP8266_NTPNixieClock by Craig A. Lindley and NixeTubesShieldNCS314 by GRA & AFCH.
|
||||
|
||||
Copyright (c) 2019 Tomer Verona
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <driver/dac.h>
|
||||
#include <WiFi.h>
|
||||
#include <SPI.h>
|
||||
#include <TimeLib.h>
|
||||
#include <Timezone.h>
|
||||
#include <DNSServer.h>
|
||||
#include <WebServer.h>
|
||||
//#include <WiFiManager.h>
|
||||
|
||||
#include "LEDControl.h"
|
||||
#include "NixieTubeShield.h"
|
||||
#include "NTP.h"
|
||||
|
||||
// ***************************************************************
|
||||
// Start of user configuration items
|
||||
// ***************************************************************
|
||||
|
||||
// Name of AP when configuring WiFi credentials
|
||||
#define AP_NAME "NixieClock"
|
||||
|
||||
// Checks WiFi connection. Reset after this time, if WiFi is not connected
|
||||
#define WIFI_CHK_TIME_SEC 3600
|
||||
#define WIFI_CHK_TIME_MS (WIFI_CHK_TIME_SEC * 1000)
|
||||
|
||||
// Set to false for 24 hour time mode
|
||||
#define HOUR_FORMAT_12 true
|
||||
|
||||
// Nixie tubes are turned off at night to increase their lifetime
|
||||
// Clock off and on times are in 24 hour format
|
||||
#define CLOCK_OFF_HOUR 23
|
||||
#define CLOCK_ON_HOUR 07
|
||||
|
||||
// Suppress leading zeros
|
||||
// Set to false to having leading zeros displayed
|
||||
#define SUPPRESS_LEADING_ZEROS true
|
||||
|
||||
// Define the timezone in which the clock will operate
|
||||
// See the Timezone library for details
|
||||
// US Pacific Time Zone (Las Vegas, Los Angeles)
|
||||
TimeChangeRule usPDT = {"PDT", Second, Sun, Mar, 2, -420};
|
||||
TimeChangeRule usPST = {"PST", First, Sun, Nov, 2, -480};
|
||||
Timezone TZ(usPDT, usPST);
|
||||
|
||||
// ***************************************************************
|
||||
// End of user configuration items
|
||||
// ***************************************************************
|
||||
|
||||
// Instantiate the Nixie Tube Shield object
|
||||
NixieTubeShield SHIELD;
|
||||
|
||||
// Instantiate the WifiManager object
|
||||
//WiFiManager wifiManager;
|
||||
|
||||
// ***************************************************************
|
||||
// Utility Functions
|
||||
// ***************************************************************
|
||||
|
||||
// Misc variables
|
||||
int previousMinute = 0;
|
||||
int minutes = 0;
|
||||
boolean dotToggle = false;
|
||||
boolean clockOn = true;
|
||||
|
||||
// This function is called once a second
|
||||
void updateDisplay(void) {
|
||||
|
||||
// Get the current time and date
|
||||
// Get the time for specified timezone
|
||||
time_t localTime = TZ.toLocal(now());
|
||||
|
||||
// Determine if clock should be on or off
|
||||
int hr = hour(localTime);
|
||||
|
||||
// Clock is on between these hours
|
||||
if ((hr >= CLOCK_ON_HOUR) && (hr < CLOCK_OFF_HOUR)) {
|
||||
if (!clockOn) {
|
||||
clockOn = true;
|
||||
Serial.println("Clock is On");
|
||||
|
||||
// Clock should be on so turn high voltage on
|
||||
SHIELD.hvEnable(true);
|
||||
}
|
||||
} else {
|
||||
if (clockOn) {
|
||||
clockOn = false;
|
||||
|
||||
Serial.println("Clock is Off");
|
||||
|
||||
// Clock is going off so shut things down in an orderly fashion
|
||||
// First turn off the high voltage so the nixie's go off
|
||||
SHIELD.hvEnable(false);
|
||||
|
||||
// Next turn off the dots
|
||||
SHIELD.dotsEnable(false);
|
||||
SHIELD.setNX1Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX2Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX3Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX4Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX5Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX6Digit(BLANK_DIGIT);
|
||||
SHIELD.show();
|
||||
|
||||
// Finally turn the LEDs off as well
|
||||
SHIELD.setLEDColor(black);
|
||||
}
|
||||
|
||||
// No need to continue as the clock is effectively off
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current minute
|
||||
minutes = minute(localTime);
|
||||
|
||||
// Dispatch events in priority order
|
||||
|
||||
// 60 minute event is anti-poisoning routine
|
||||
if ((minutes != previousMinute) && (minutes == 0)) {
|
||||
previousMinute = minutes;
|
||||
|
||||
// Set all LEDs to red to indicate anti-poisoning
|
||||
SHIELD.setLEDColor(red);
|
||||
|
||||
// Do anti-poisoning function
|
||||
SHIELD.doAntiPoisoning();
|
||||
}
|
||||
|
||||
// 15 minute event is rainbow display
|
||||
else if ((minutes != previousMinute) && (minutes != 0) && ((minutes % 15) == 0)) {
|
||||
previousMinute = minutes;
|
||||
|
||||
// Turn off dots
|
||||
SHIELD.dotsEnable(false);
|
||||
|
||||
// Blank all nixie tube digits
|
||||
SHIELD.setNX1Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX2Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX3Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX4Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX5Digit(BLANK_DIGIT);
|
||||
SHIELD.setNX6Digit(BLANK_DIGIT);
|
||||
|
||||
// Blank the nixie tubes
|
||||
SHIELD.show();
|
||||
|
||||
// Cycle the LEDs through rainbows of color
|
||||
for (int cycles = 0; cycles < 4; cycles++) {
|
||||
for (int cycle = 0; cycle < 256; cycle += 16) {
|
||||
// Set the LED's color
|
||||
SHIELD.setLEDColor(SHIELD.colorWheel(cycle));
|
||||
delay(400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10 minute event is the date display
|
||||
else if ((minutes != previousMinute) && (minutes != 0) && ((minutes % 10) == 0)) {
|
||||
previousMinute = minutes;
|
||||
|
||||
// Turn off dots
|
||||
SHIELD.dotsEnable(false);
|
||||
|
||||
// Set all LEDs to blue to indicate date display
|
||||
SHIELD.setLEDColor(blue);
|
||||
|
||||
SHIELD.dotsEnable(true);
|
||||
|
||||
// Get the current month 1..12
|
||||
int now_mon = month(localTime);
|
||||
|
||||
// Display the NX1 digit
|
||||
if (now_mon >= 10) {
|
||||
SHIELD.setNX1Digit(now_mon / 10);
|
||||
} else {
|
||||
if (SUPPRESS_LEADING_ZEROS) {
|
||||
SHIELD.setNX1Digit(BLANK_DIGIT);
|
||||
} else {
|
||||
SHIELD.setNX1Digit(0);
|
||||
}
|
||||
}
|
||||
// Display the NX2 digit
|
||||
SHIELD.setNX2Digit(now_mon % 10);
|
||||
|
||||
// Get the current day 1..31
|
||||
int now_day = day(localTime);
|
||||
|
||||
// Display the NX3 digit
|
||||
if (now_day >= 10) {
|
||||
SHIELD.setNX3Digit(now_day / 10);
|
||||
} else {
|
||||
if (SUPPRESS_LEADING_ZEROS) {
|
||||
SHIELD.setNX3Digit(BLANK_DIGIT);
|
||||
} else {
|
||||
SHIELD.setNX3Digit(0);
|
||||
}
|
||||
}
|
||||
// Display the NX4 digit
|
||||
SHIELD.setNX4Digit(now_day % 10);
|
||||
|
||||
// Get the current year
|
||||
int now_year = year(localTime) - 2000;
|
||||
|
||||
// Display the NX5 digit
|
||||
if (now_year >= 10) {
|
||||
SHIELD.setNX5Digit(now_year / 10);
|
||||
} else {
|
||||
if (SUPPRESS_LEADING_ZEROS) {
|
||||
SHIELD.setNX5Digit(BLANK_DIGIT);
|
||||
} else {
|
||||
SHIELD.setNX5Digit(0);
|
||||
}
|
||||
}
|
||||
// Display the NX6 digit
|
||||
SHIELD.setNX6Digit(now_year % 10);
|
||||
|
||||
// Display date on clock
|
||||
SHIELD.show();
|
||||
|
||||
// Delay for date display
|
||||
delay(10000);
|
||||
|
||||
} else {
|
||||
// Display the time
|
||||
|
||||
int now_hour;
|
||||
float colorInc;
|
||||
|
||||
// Make the dots blink off and on
|
||||
if (dotToggle) {
|
||||
dotToggle = false;
|
||||
SHIELD.dotsEnable(true);
|
||||
|
||||
} else {
|
||||
dotToggle = true;
|
||||
SHIELD.dotsEnable(false);
|
||||
}
|
||||
|
||||
// Set the LED's color depending upon the hour
|
||||
// Get the current hour
|
||||
if (HOUR_FORMAT_12) {
|
||||
// Using 12 hour format
|
||||
now_hour = hourFormat12(localTime);
|
||||
// Calculate the color of the LEDs based on the hour in 12 hour format
|
||||
colorInc = 256 / 12.0;
|
||||
} else {
|
||||
// Using 24 hour format
|
||||
now_hour = hour(localTime);
|
||||
// Calculate the color of the LEDs based on the hour in 24 hour format
|
||||
colorInc = 256 / 24.0;
|
||||
}
|
||||
// Set the shields's LED color
|
||||
SHIELD.setLEDColor(SHIELD.colorWheel(colorInc * now_hour));
|
||||
|
||||
// Display the NX1 digit
|
||||
if (now_hour >= 10) {
|
||||
SHIELD.setNX1Digit(now_hour / 10);
|
||||
} else {
|
||||
if (SUPPRESS_LEADING_ZEROS) {
|
||||
SHIELD.setNX1Digit(BLANK_DIGIT);
|
||||
} else {
|
||||
SHIELD.setNX1Digit(0);
|
||||
}
|
||||
}
|
||||
// Display the NX2 digit
|
||||
SHIELD.setNX2Digit(now_hour % 10);
|
||||
|
||||
// Get the current minute
|
||||
int now_min = minute(localTime);
|
||||
|
||||
// Display the NX3 digit
|
||||
SHIELD.setNX3Digit(now_min / 10);
|
||||
|
||||
// Display the NX4 digit
|
||||
SHIELD.setNX4Digit(now_min % 10);
|
||||
|
||||
// Get the current second
|
||||
int now_sec = second(localTime);
|
||||
|
||||
// Display the NX5 digit
|
||||
SHIELD.setNX5Digit(now_sec / 10);
|
||||
|
||||
// Display the NX6 digit
|
||||
SHIELD.setNX6Digit(now_sec % 10);
|
||||
|
||||
// Display time on clock
|
||||
SHIELD.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Get WiFi SSID
|
||||
String WIFI_GetSSID() {
|
||||
// wifi_config_t conf;
|
||||
// esp_wifi_get_config(WIFI_IF_STA, &conf);
|
||||
// return String(reinterpret_cast<const char*>(conf.sta.ssid));
|
||||
return String("iot");
|
||||
}
|
||||
|
||||
// Get WiFi Password
|
||||
String WIFI_GetPassword() {
|
||||
// wifi_config_t conf;
|
||||
// esp_wifi_get_config(WIFI_IF_STA, &conf);
|
||||
// return String(reinterpret_cast<const char*>(conf.sta.password));
|
||||
return String("Rijnstraat214");
|
||||
}
|
||||
|
||||
// Attempt to connect to WiFi
|
||||
void WIFI_Connect() {
|
||||
WiFi.disconnect();
|
||||
Serial.println("Connecting to WiFi...");
|
||||
WiFi.begin(WIFI_GetSSID().c_str(), WIFI_GetPassword().c_str());
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
delay (250);
|
||||
SHIELD.setLEDColor(black);
|
||||
Serial.print(".");
|
||||
delay (250);
|
||||
SHIELD.setLEDColor(green);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.println("");
|
||||
Serial.println("WiFi Connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
} else {
|
||||
Serial.println("Wifi NOT connected");
|
||||
}
|
||||
}
|
||||
|
||||
void WIFI_StartAccessPoint() {
|
||||
// Starts an access point with the specified name
|
||||
// and goes into a blocking loop awaiting configuration
|
||||
Serial.println("Starting Wifi AP");
|
||||
//WiFiManager wifiManager;
|
||||
//wifiManager.startConfigPortal(AP_NAME);
|
||||
}
|
||||
|
||||
// ***************************************************************
|
||||
// Program Setup
|
||||
// ***************************************************************
|
||||
|
||||
void setup() {
|
||||
// Turn off the high voltage for the clock
|
||||
SHIELD.hvEnable(false);
|
||||
|
||||
// Turn off DAC channels
|
||||
dac_output_disable(DAC_CHANNEL_1);
|
||||
dac_output_disable(DAC_CHANNEL_2);
|
||||
dac_i2s_disable();
|
||||
|
||||
Wire.begin();
|
||||
|
||||
// Configure serial interface
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println();
|
||||
|
||||
pinMode(LATCH_ENABLE, OUTPUT);
|
||||
|
||||
// Setup SPI interface to defaults for shield
|
||||
SPI.begin();
|
||||
SPI.setDataMode (SPI_MODE2); // Mode 2 SPI
|
||||
SPI.setClockDivider(2000000); // SCK = 2MHz
|
||||
|
||||
// Reset saved settings for testing purposes
|
||||
// Should be commented out for normal operation
|
||||
// wifiManager.resetSettings();
|
||||
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
Serial.println(WIFI_GetSSID());
|
||||
Serial.println(WIFI_GetPassword());
|
||||
|
||||
// If WiFi setup is not configured, start access point
|
||||
// Otherwise, connect to WiFi
|
||||
if (0 == WIFI_GetSSID().length()) {
|
||||
WIFI_StartAccessPoint();
|
||||
} else {
|
||||
WIFI_Connect();
|
||||
}
|
||||
delay(100);
|
||||
|
||||
initNTP(SHIELD);
|
||||
|
||||
// Set all LEDs to black or off
|
||||
SHIELD.setLEDColor(black);
|
||||
|
||||
// Turn off the dots
|
||||
SHIELD.dotsEnable(false);
|
||||
|
||||
// Turn on the high voltage for the clock
|
||||
SHIELD.hvEnable(true);
|
||||
|
||||
// Do the anti poisoning routine
|
||||
SHIELD.doAntiPoisoning();
|
||||
|
||||
Serial.println("\nReady!\n");
|
||||
}
|
||||
|
||||
// ***************************************************************
|
||||
// Program Loop
|
||||
// ***************************************************************
|
||||
|
||||
unsigned long nextConnectionCheckTime = 0;
|
||||
int previousSecond = 0;
|
||||
|
||||
void loop() {
|
||||
// Check WiFi connectivity
|
||||
if (millis() > nextConnectionCheckTime) {
|
||||
Serial.print("\n\nChecking WiFi... ");
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println("WiFi connection lost. Reconnecting...");
|
||||
WIFI_Connect();
|
||||
} else {
|
||||
Serial.println("Wifi connected");
|
||||
}
|
||||
nextConnectionCheckTime = millis() + WIFI_CHK_TIME_MS;
|
||||
}
|
||||
|
||||
// Process button status
|
||||
SHIELD.processButtons();
|
||||
|
||||
// If set button is pressed, enter Wifi AP mode
|
||||
if (SHIELD.isSetButtonClicked()) {
|
||||
WIFI_StartAccessPoint();
|
||||
}
|
||||
|
||||
// If set button is long-pressed, restart ESP
|
||||
if (SHIELD.isSetButtonLongClicked()) {
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
// Update the display only if time has changed
|
||||
if (timeStatus() != timeNotSet) {
|
||||
if (second() != previousSecond) {
|
||||
previousSecond = second();
|
||||
|
||||
// Display updated once a second
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
11
esp32nixie/test/README
Normal file
11
esp32nixie/test/README
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
||||
Reference in New Issue
Block a user