Browse Source

Snapshot 1444697

master
commit
17fffcd619
19 changed files with 5092 additions and 0 deletions
  1. +1
    -0
      Licence note
  2. +57
    -0
      NTPSynchronisation.cpp
  3. +17
    -0
      NTPSynchronisation.h
  4. +104
    -0
      Pomodoro.cpp
  5. +43
    -0
      Pomodoro.h
  6. +186
    -0
      Pomodoro.ino
  7. +72
    -0
      README.md
  8. +55
    -0
      SegmentCharacter.h
  9. +83
    -0
      SegmentDisplay.cpp
  10. +19
    -0
      SegmentDisplay.h
  11. +34
    -0
      Timer.cpp
  12. +19
    -0
      Timer.h
  13. +3
    -0
      WifiConfig.cpp
  14. +7
    -0
      WifiConfig.h
  15. BIN
      doc/schematic.png
  16. +4125
    -0
      doc/schematic.svg
  17. BIN
      doc/tool_SevenSegmentDisplayValue.png
  18. +94
    -0
      lib/pitches.h
  19. +173
    -0
      tool/SevenSegmentDisplayValue.html

+ 1
- 0
Licence note View File

@ -0,0 +1 @@
If you find software that doesn’t have a license, that means you have no permission from the creators of the software to use, modify, or share the software. Although a code host such as GitHub may allow you to view and fork the code, this does not imply that you are permitted to use, modify, or share the software for any purpose.

+ 57
- 0
NTPSynchronisation.cpp View File

@ -0,0 +1,57 @@
#include "NTPSynchronisation.h"
const char* ntpServer="pool.ntp.org";
const long gmtOffset_sec=3600;
const int daylightOffset_sec=3600;
struct tm timeinfo;
/**
* Try to connect to the Wi-Fi, return true if success, false otherwise.
* A check of the connection will be made every timeDelay, for delayNumber tentative.
* If delayNumber is < 0 then the function will wait in indefinitely until the connection is made.
*/
bool connectWifi(int timeDelay, int delayNumber) {
int tentative=0;
WiFi.begin(wifiSsid, wifiPassword);
while(WiFi.status()!=WL_CONNECTED && (delayNumber<0 || tentative<delayNumber)) {
delay(timeDelay);
Serial.print(".");
tentative++;
}
Serial.println(" CONNECTED");
bool connected=WiFi.status()==WL_CONNECTED;
if(!connected){
disconnectWifi();
}
return connected;
}
void disconnectWifi() {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
/**
* Try to synchronize the internal clock with an NTP server.
* Return true if success, false otherwise.
* A check of the connection will be made every timeDelay, for maxNTPTentative tentatives.
*/
bool synchroniseTimeNTP(bool connectToWifi, bool disconnectWifiAfterSync, int timeDelay, int maxNTPTentative){
if(connectToWifi){
connectWifi(500,-1);
}
int tentative=0;
while(!getLocalTime(&timeinfo) && tentative<maxNTPTentative) {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
delay(timeDelay);
tentative++;
}
if(disconnectWifiAfterSync){
disconnectWifi();
}
return getLocalTime(&timeinfo);
}

+ 17
- 0
NTPSynchronisation.h View File

@ -0,0 +1,17 @@
#ifndef NTP_Synchronisation
#define NTP_Synchronisation
#include <WiFi.h>
#include "time.h"
#include "WifiConfig.h"
extern const char* ntpServer;
extern const long gmtOffset_sec;
extern const int daylightOffset_sec;
extern struct tm timeinfo;
extern bool connectWifi(int, int);
extern void disconnectWifi();
extern bool synchroniseTimeNTP(bool, bool, int, int);
#endif

+ 104
- 0
Pomodoro.cpp View File

@ -0,0 +1,104 @@
#include "Pomodoro.h"
bool useLed=true;
bool useBuzzer=true;
uint32_t timeWork=25*60*1000;
uint32_t timeShortRest=5*60*1000;
uint32_t timeLongRest=15*60*1000;
int workBetweenLongBreak=4;
int workDone=0;
bool work=true;
int currentWait=timeWork;
uint32_t timerLastValue=0;
const int pinLedWork=25;
const int pinLedShortBreak=33;
const int pinLedLongBreak=32;
const int ledFrequency=5000;
const int ledResolution=8;
const int ledChannelWork=0;
const int ledChannelShortBreak=1;
const int ledChannelLongBreak=2;
int ledWorkMaxValue=1;
int ledShortBreakMaxValue=1;
int ledLongBreakMaxValue=1;
const int pinBuzzer=27;
const int buzzerFrequency=2000;
const int buzzerResolution=8;
const int buzzerChannel=3;
void setupPomodoro(){
//pinMode(pinLedWork,OUTPUT);
//pinMode(pinLedShortBreak,OUTPUT);
//pinMode(pinLedLongBreak,OUTPUT);
ledcSetup(ledChannelWork, ledFrequency, ledResolution);
ledcSetup(ledChannelShortBreak, ledFrequency, ledResolution);
ledcSetup(ledChannelLongBreak, ledFrequency, ledResolution);
ledcAttachPin(pinLedWork, ledChannelWork);
ledcAttachPin(pinLedShortBreak, ledChannelShortBreak);
ledcAttachPin(pinLedLongBreak, ledChannelLongBreak);
ledcSetup(buzzerChannel,buzzerFrequency,buzzerResolution);
ledcAttachPin(pinBuzzer,buzzerChannel);
}
void writeToBuzzer(int note,int duration,bool continuous=false){
if(useBuzzer){
ledcWriteTone(buzzerChannel,note);
if(!continuous){
delay(duration);
ledcWriteTone(buzzerChannel,0);
}
}
}
void writeToLed(int led,int value){
if(useLed){
ledcWrite(led,value);
}
}
void displayWork(bool afterLongBreak){
Serial.println("Return to work");
writeToLed(ledChannelWork,ledWorkMaxValue);
writeToLed(ledChannelShortBreak,0);
writeToLed(ledChannelLongBreak,0);
//digitalWrite(LED_WORK,HIGH);
//digitalWrite(LED_SHORT_BREAK,LOW);
//digitalWrite(LED_LONG_BREAK,LOW);
if(afterLongBreak){
for(int i=0;i<3;i++){
writeToBuzzer(NOTE_C4,200);
writeToBuzzer(NOTE_CS4,200);
delay(500);
}
}else{
writeToBuzzer(NOTE_C1,200);
}
}
void displayShortRest(){
Serial.println("Short rest");
writeToLed(ledChannelWork,0);
writeToLed(ledChannelShortBreak,ledShortBreakMaxValue);
writeToLed(ledChannelLongBreak,0);
//digitalWrite(LED_WORK,LOW);
//digitalWrite(LED_SHORT_BREAK,HIGH);
//digitalWrite(LED_LONG_BREAK,LOW);
writeToBuzzer(NOTE_F1,200);
}
void displayLongRest(){
Serial.println("Long rest");
writeToLed(ledChannelWork,0);
writeToLed(ledChannelShortBreak,0);
writeToLed(ledChannelLongBreak,ledLongBreakMaxValue);
//digitalWrite(LED_WORK,LOW);
//digitalWrite(LED_SHORT_BREAK,LOW);
//digitalWrite(LED_LONG_BREAK,HIGH);
writeToBuzzer(NOTE_DS4,200);
writeToBuzzer(NOTE_D4,200);
}

+ 43
- 0
Pomodoro.h View File

@ -0,0 +1,43 @@
#ifndef POMODORO_H
#define POMODORO_H
#include <stdint.h>
#include "esp32-hal-ledc.h"
#include "HardwareSerial.h"
#include "lib/pitches.h"
extern bool useLed;
extern bool useBuzzer;
extern uint32_t timeWork ;
extern uint32_t timeShortRest ;
extern uint32_t timeLongRest ;
extern int workBetweenLongBreak;
extern int workDone;
extern bool work;
extern int currentWait;
extern uint32_t timerLastValue;
extern const int pinLedWork;
extern const int pinLedShortBreak;
extern const int pinLedLongBreak;
extern const int ledFrequency;
extern const int ledResolution;
extern const int ledChannelWork;
extern const int ledChannelShortBreak;
extern const int ledChannelLongBreak;
extern int ledWorkMaxValue;
extern int ledShortBreakMaxValue;
extern int ledLongBreakMaxValue;
extern const int pinBuzzer;
extern const int buzzerFrequency;
extern const int buzzerResolution;
extern const int buzzerChannel;
void setupPomodoro();
void displayWork(bool);
void displayShortRest();
void displayLongRest();
#endif

+ 186
- 0
Pomodoro.ino View File

@ -0,0 +1,186 @@
#include "Pomodoro.h"
#include "Timer.h"
#include "SegmentDisplay.h"
#include "SegmentCharacter.h"
#include "NTPSynchronisation.h"
#include <Arduino.h>
#define serialSpeed 115200
uint32_t isrCount=0;
uint32_t isrTime=0;
enum PomodoroStatus{status_work,status_shortBreak,status_longBreak,status_workAfterLongBreak};
PomodoroStatus pStatus=status_work;
uint32_t timeBeforeTransition=0;
uint32_t timeBeforeTransitionMinutes=0;
uint32_t timeBeforeTransitionSeconds=0;
enum DisplayMode{dMode_clockHourMinute,dMode_clockDayMonth,dMode_pomodoro};
DisplayMode dMode=dMode_pomodoro;
const int pinDisplayMode=4;
uint32_t debounceTime=0;
const uint32_t debounceWait=10;
bool wifiIssue=false;
bool ntpIssue=false;
TaskHandle_t taskHandleAnnouncer;
void taskAnnouncer(void * param){
switch(pStatus){
case status_work:
displayWork(false);
break;
case status_workAfterLongBreak:
displayWork(true);
break;
case status_shortBreak:
displayShortRest();
break;
case status_longBreak:
displayLongRest();
break;
default:
break;
}
if(taskHandleAnnouncer!=NULL){
vTaskDelete(taskHandleAnnouncer);
}
}
void startTaskAnnouncer(){
xTaskCreatePinnedToCore(taskAnnouncer,"taskAnnouncer",1024,NULL,1,&taskHandleAnnouncer,0);
}
void IRAM_ATTR displayModeInterrupt(){
if(xTaskGetTickCount()-debounceTime>debounceWait){
switch(dMode){
case dMode_clockHourMinute:
if(wifiIssue||ntpIssue){
dMode=dMode_pomodoro;
}else{
dMode=dMode_clockDayMonth;
}
break;
case dMode_clockDayMonth:
dMode=dMode_pomodoro;
break;
default:
dMode=dMode_clockHourMinute;
break;
}
debounceTime=xTaskGetTickCount();
}
}
void setup(){
Serial.begin(115200);
setupTimer();
setupPomodoro();
setupSegmentDisplay();
sDisplayDigitValue[0]=SC_H;
sDisplayDigitValue[1]=SC_E;
sDisplayDigitValue[2]=SC_L;
sDisplayDigitValue[3]=SC_O;
wifiIssue=!connectWifi(500,10);
if(!wifiIssue){
ntpIssue=!synchroniseTimeNTP(false,true,500,10);
}
pinMode(pinDisplayMode,INPUT_PULLUP);
attachInterrupt(pinDisplayMode, displayModeInterrupt, RISING);
startTaskAnnouncer();
}
void loop() {
powerSegmentDisplay();
delay(20);
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
isrCount=0;
isrTime=0;
// Read the interrupt count and time
portENTER_CRITICAL(&timerMux);
isrCount = isrCounter;
isrTime = lastIsrAt;
portEXIT_CRITICAL(&timerMux);
//Avoid garbage display when isrTime is bigger than the
//waiting time resulting in timeBeforeTransition overflow
if(isrTime>(timerLastValue+currentWait)){
timeBeforeTransition=0;
}else{
timeBeforeTransition=((timerLastValue+currentWait)-isrTime)/1000;
}
switch(dMode){
case dMode_clockHourMinute:
case dMode_clockDayMonth:
if(wifiIssue){
sDisplayDigitValue[0]=SC_W;
sDisplayDigitValue[1]=SC_I;
sDisplayDigitValue[2]=SC_F;
sDisplayDigitValue[3]=SC_I;
break;
}
if(ntpIssue){
sDisplayDigitValue[0]=SC_N;
sDisplayDigitValue[1]=SC_T;
sDisplayDigitValue[2]=SC_P;
sDisplayDigitValue[3]=SC_BLANK;
break;
}
getLocalTime(&timeinfo);
if(dMode==dMode_clockHourMinute){
setNumberToDisplay(timeinfo.tm_hour*100+timeinfo.tm_min);
}else{
setNumberToDisplay(timeinfo.tm_mday*100+timeinfo.tm_mon+1);
}
sDisplayDigitValue[1]=sDisplayDigitValue[1]+SC_DOT;
sDisplayDigitValue[3]=sDisplayDigitValue[3]+SC_DOT;
break;
default:
timeBeforeTransitionMinutes=timeBeforeTransition/60;
timeBeforeTransitionSeconds=timeBeforeTransition%60;
sDisplayDigitValue[0]=SC_NUMBER[timeBeforeTransitionMinutes/10];
sDisplayDigitValue[1]=SC_NUMBER[timeBeforeTransitionMinutes%10]+SC_DOT;
sDisplayDigitValue[2]=SC_NUMBER[timeBeforeTransitionSeconds/10];
sDisplayDigitValue[3]=SC_NUMBER[timeBeforeTransitionSeconds%10];
break;
}
// Pomodoro calculation
if(isrTime>=(timerLastValue+currentWait)){
timerLastValue=isrTime;
if(work){
work=false;
workDone++;
if(workDone>=workBetweenLongBreak){
currentWait=timeLongRest;
workDone=0;
//displayLongRest();
pStatus=status_longBreak;
}else{
currentWait=timeShortRest;
//displayShortRest();
pStatus=status_shortBreak;
}
}else{
currentWait=timeWork;
work=true;
if(workDone==0){
//displayWork(true);
pStatus=status_workAfterLongBreak;
}else{
//displayWork(false);
pStatus=status_work;
}
}
startTaskAnnouncer();
}
}
}

+ 72
- 0
README.md View File

@ -0,0 +1,72 @@
# Pomodoro on ESP-32
Implementation of the Pomodoro technique on the ESP-32 microcontroller.
Each transition between work and rest cycle is indicated by one or multiple physical stimulus (melody and/or color).
A display indicates the progression of the timer and double as an NTP clock.
## Table of content
* [Pomodoro](#pomodoro)
* [Electronic circuit](#electronic-circuit)
* [Schematic](#schematic)
* [Materials](#materials)
* [Note on the seven-segments display and shift-register](#note-on-the-seven-segments-display-and-shift-register)
* [Software](#software)
* [Design](#design)
* [Dependency](#dependency)
* [Tool](#tool)
* [Seven-segment display value](#seven-segment-display-value)
## Pomodoro
Pomodoro is a time management technique that use a timer to break down task and rest period.
## Electronic circuit
### Schematic
![schematic picture](doc/schematic.png)
### Materials
|Type|Designation|Quantity|
|-|-|-:|
|System on a chip|ESP-WROOM-32|1|
|4 digit 7 segment display|HS420561K-32|1|
|8-bit shift register|SN74HC595N|1|
|Transistor|PN2222|4|
|Diode||3|
|Passive buzzer||1|
|Momentary Switch||1|
|Resistor|220 Ω|11|
|Resistor|4.7 kΩ|4|
#### **Note on the seven-display segment and shift-register**
You might have notice that it's not the prettiest way to use a 4-digits seven-segments display.
Initially I wanted to use one shift-register per digit, but as I found only one SN74HC595N on my parts bins, I ultimately decided to make do. The result is a bit messier but works.
## Software
### Design
This software make use of the two core of the ESP-32, and it's FreeRTOS implementation to have two tasks:
1. Display the time remaining on the clock and use interrupt to count each second passed.
2. Alarm the user of a transition between task and rest with the use of melody and visual cue.
### Dependency
Ignoring the common library use in almost every project (like `stdint.h`, `Arduino.h`, `esp32-hal-ledc.h` or `HardwareSerial.h`), the code make use of:
* [pitches.h from arduino](https://github.com/arduino/arduino-examples/blob/main/examples/02.Digital/toneMelody/pitches.h) to create melody using the piezo speaker. Included in [lib/pitches.h](lib/pitches.h) for ease of deployment.
## Tool
### **Seven-segment display value**
To ease the transition between physical segment and binary/hexadecimal code, I created a small HTML tool [tool/SevenSegmentDisplayValue.html](tool/SevenSegmentDisplayValue.html).
![segmentDisplayConverter.html in action](doc/tool_SevenSegmentDisplayValue.png)

+ 55
- 0
SegmentCharacter.h View File

@ -0,0 +1,55 @@
#ifndef SEGMENT_CHARACTER_H
#define SEGMENT_CHARACTER_H
#include <Arduino.h>
const byte SC_A=0xCF;
const byte SC_B=0xDA;
const byte SC_C=0x1B;
const byte SC_D=0xDC;
const byte SC_E=0x9B;
const byte SC_F=0x8B;
const byte SC_G=0x5B;
const byte SC_H=0xCE;
const byte SC_I=0x0A;
const byte SC_J=0x5C;
const byte SC_K=0x00;
const byte SC_L=0x1A;
const byte SC_M=0x4F;
const byte SC_N=0xC8;
const byte SC_O=0x5F;
const byte SC_o=0xD8;
const byte SC_P=0x8F;
const byte SC_Q=0xC7;
const byte SC_R=0x88;
const byte SC_S=0xD3;
const byte SC_T=0x9A;
const byte SC_U=0x5E;
const byte SC_V=0x58;
const byte SC_W=0x16;
const byte SC_X=0x00;
const byte SC_Y=0xD6;
const byte SC_Z=0x00;
const byte SC_0=0x5F;
const byte SC_1=0x44;
const byte SC_2=0x9D;
const byte SC_3=0xD5;
const byte SC_4=0xC6;
const byte SC_5=0xD3;
const byte SC_6=0xDA;
const byte SC_7=0x45;
const byte SC_8=0xDF;
const byte SC_9=0xD7;
const byte SC_NUMBER[]={
SC_0,SC_1,SC_2,SC_3,SC_4,SC_5,SC_6,SC_7,SC_8,SC_9
};
const byte SC_BLANK=0x00;
const byte SC_DOT=0x20;
const byte SC_EQUAL=0x90;
const byte SC_MINUS=0x80;
const byte SC_UNDERSCORE=0x10;
#endif

+ 83
- 0
SegmentDisplay.cpp View File

@ -0,0 +1,83 @@
/*
Command a four-digits seven-segments display.
Use sDisplayDigitValue[] to change the digits values.
The digits are listed from left to right.
You can use SegmentCharacter.h to get the binary code for a given character.
Example:
void setup(){
sDisplayDigitValue[0]=SC_4;
sDisplayDigitValue[1]=SC_NUMBER[1];
sDisplayDigitValue[2]=SC_EQUAL;
sDisplayDigitValue[3]=SC_A;
}
void loop(){
powerSegmentDisplay();
delay(20);
}
*/
#include "SegmentDisplay.h"
const int pinSDisplayShiftRegisterSER=23;
const int pinSDisplayShiftRegisterRCLK=22;
const int pinSDisplayShiftRegisterSRCLK=5;
const byte pinSDisplayDigit[4]={17,18,19,21};
byte sDisplayDigitValue[]={0,0,0,0};
void setupSegmentDisplay(){
pinMode(pinSDisplayShiftRegisterSER,OUTPUT);
pinMode(pinSDisplayShiftRegisterRCLK,OUTPUT);
pinMode(pinSDisplayShiftRegisterSRCLK,OUTPUT);
for(int i=0;i<sizeof(pinSDisplayDigit);i++){
pinMode(pinSDisplayDigit[i],OUTPUT);
digitalWrite(pinSDisplayDigit[i],LOW);
}
}
void powerSegmentDisplay(){
for (int x=0; x<4; x++){
for (int j=0; j<4; j++){
digitalWrite(pinSDisplayDigit[j],LOW);
}
digitalWrite(pinSDisplayShiftRegisterRCLK,LOW);
shiftOut(pinSDisplayShiftRegisterSER,pinSDisplayShiftRegisterSRCLK,MSBFIRST,sDisplayDigitValue[x]);
digitalWrite(pinSDisplayShiftRegisterRCLK,HIGH);
digitalWrite(pinSDisplayDigit[x],HIGH);
delay(1);
}
for (int j=0; j<4; j++){
digitalWrite(pinSDisplayDigit[j],LOW);
}
}
/**
* Set a number to be display using all the available digits.
* First digit is E if the number is > 9999 or <-999.
*/
void setNumberToDisplay(int number){
if(number<0){
sDisplayDigitValue[0]=SC_MINUS;
if(number<-999){
sDisplayDigitValue[0]=SC_E;
}
number=number*-1;
}else{
sDisplayDigitValue[0]=SC_NUMBER[number/1000];
}
int n=number%1000;
sDisplayDigitValue[1]=SC_NUMBER[n/100];
n=n%100;
sDisplayDigitValue[2]=SC_NUMBER[n/10];
n=n%10;
sDisplayDigitValue[3]=SC_NUMBER[n];
if(number>9999){
sDisplayDigitValue[0]=SC_E;
}
}

+ 19
- 0
SegmentDisplay.h View File

@ -0,0 +1,19 @@
#ifndef SEGMENT_DISPLAY_H
#define SEGMENT_DISPLAY_H
#include <Arduino.h>
#include "SegmentCharacter.h"
extern const int pinSDisplayShiftRegisterSER;
extern const int pinSDisplayShiftRegisterRCLK;
extern const int pinSDisplayShiftRegisterSRCLK;
extern const byte pinSDisplayDigit[];
extern byte sDisplayDigitValue[];
extern void setupSegmentDisplay();
extern void powerSegmentDisplay();
extern void setNumberToDisplay(int);
#endif

+ 34
- 0
Timer.cpp View File

@ -0,0 +1,34 @@
#include "Timer.h"
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
volatile uint32_t isrCounter = 0;
volatile uint32_t lastIsrAt = 0;
void IRAM_ATTR onTimer(){
// Increment the counter and set the time of ISR
portENTER_CRITICAL_ISR(&timerMux);
isrCounter++;
lastIsrAt = millis();
portEXIT_CRITICAL_ISR(&timerMux);
// Give a semaphore that we can check in the loop
xSemaphoreGiveFromISR(timerSemaphore, NULL);
// It is safe to use digitalRead/Write here if you want to toggle an output
}
void setupTimer(){
// Create semaphore to inform us when the timer has fired
timerSemaphore = xSemaphoreCreateBinary();
// Use 1st timer of 4 (counted from zero).
// Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
// info).
timer = timerBegin(0, 80, true);
// Attach onTimer function to our timer.
timerAttachInterrupt(timer, &onTimer, true);
// Set alarm to call onTimer function every second (value in microseconds).
// Repeat the alarm (third parameter)
timerAlarmWrite(timer, 1000000, true);
// Start an alarm
timerAlarmEnable(timer);
}

+ 19
- 0
Timer.h View File

@ -0,0 +1,19 @@
//#pragma once
#ifndef TIMER_SETUP_H
#define TIMER_SETUP_H
#include <stdint.h>
#include <FreeRTOS.h>
#include <freertos/semphr.h>
#include <esp32-hal-timer.h>
extern hw_timer_t * timer;
extern volatile SemaphoreHandle_t timerSemaphore;
extern portMUX_TYPE timerMux;
extern volatile uint32_t isrCounter;
extern volatile uint32_t lastIsrAt;
void IRAM_ATTR onTimer();
void setupTimer();
#endif

+ 3
- 0
WifiConfig.cpp View File

@ -0,0 +1,3 @@
#include "WifiConfig.h"
const char *wifiSsid="YourSSIDHere";
const char *wifiPassword="YourPSKHere";

+ 7
- 0
WifiConfig.h View File

@ -0,0 +1,7 @@
#ifndef WIFI_CONFIG_H
#define WIFI_CONFIG_H
extern const char *wifiSsid;
extern const char *wifiPassword;
#endif

BIN
doc/schematic.png View File

Before After
Width: 970  |  Height: 682  |  Size: 27 KiB

+ 4125
- 0
doc/schematic.svg
File diff suppressed because it is too large
View File


BIN
doc/tool_SevenSegmentDisplayValue.png View File

Before After
Width: 806  |  Height: 425  |  Size: 30 KiB

+ 94
- 0
lib/pitches.h View File

@ -0,0 +1,94 @@
/*************************************************
* 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

+ 173
- 0
tool/SevenSegmentDisplayValue.html View File

@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seven-segment display value</title>
<style>
body{
display: grid;
grid-template-columns: auto auto;
justify-items: center;
}
.display{
display: grid;
grid-template-areas:
"f a a a b x y"
"f v v v b x y"
"f v v v b x y"
"g g g g g x y"
"e w w w c x y"
"e w w w c x y"
"e d d d c x o";
height: 400px;
width: 280px;
}
.seg{
border:1px solid black;
background-color: grey;
cursor: pointer;
}
#a{
grid-area: a;
}
#b{
grid-area: b;
}
#c{
grid-area: c;
}
#d{
grid-area: d;
}
#e{
grid-area: e;
}
#f{
grid-area: f;
}
#g{
grid-area: g;
}
#v{
grid-area: v;
}
#w{
grid-area: w;
}
#o{
grid-area: o;
}
.activated{
background-color: red!important;
}
td{
font-size: large;
width: 150px;
}
td, th{
border:1px solid black;
padding: 5px;
}
table{
border-collapse: collapse;;
}
#result{
margin-top: 20px;
}
</style>
<script>
segmentValue=0;
binElem=null;
hexElem=null;
binPaddedElem=null;
hexPaddedElem=null;
window.onload=()=>{
binElem=document.getElementById("bin");
hexElem=document.getElementById("hex");
binPaddedElem=document.getElementById("binPadded");
hexPaddedElem=document.getElementById("hexPadded");
displayResult();
};
function displayResult(){
binElem.innerHTML=segmentValue;
binPadded.innerHTML=String(segmentValue).padStart(8,"0");
hexElem.innerHTML=parseInt(segmentValue,2).toString(16).toUpperCase();
hexPaddedElem.innerHTML="0x"+hexElem.innerHTML;
}
function clickSegment(elem){
elementValue=0;
switch (elem.id) {
case "a":
elementValue=1;
break;
case "b":
elementValue=100;
break;
case "c":
elementValue=1000000;
break;
case "d":
elementValue=10000;
break;
case "e":
elementValue=1000;
break;
case "f":
elementValue=10;
break;
case "g":
elementValue=10000000;
break;
case "o":
elementValue=100000;
break;
default:
break;
}
if(elem.classList.contains("activated")){
elem.classList.remove("activated");
segmentValue-=elementValue;
}else{
elem.classList.add("activated");
segmentValue+=elementValue;
}
displayResult();
}
</script>
</head>
<body>
<div class="display">
<div id="a" onClick="clickSegment(this)" class="seg"></div>
<div id="f" onClick="clickSegment(this)" class="seg"></div>
<div id="b" onClick="clickSegment(this)" class="seg"></div>
<div id="g" onClick="clickSegment(this)" class="seg"></div>
<div id="e" onClick="clickSegment(this)" class="seg"></div>
<div id="c" onClick="clickSegment(this)" class="seg"></div>
<div id="d" onClick="clickSegment(this)" class="seg"></div>
<div id="o" onClick="clickSegment(this)" class="seg"></div>
</div>
<div id="info">
<h1>Seven-segment display value</h1>
<div id="description">Click any number of segments on the display on the left to get the corresponding values.</div>
<table id="result">
<tr>
<th>Type</th>
<th>Value</th>
<th>Padded</th>
</tr>
<tr>
<td>Binary</td>
<td id="bin"></td>
<td id="binPadded"></td>
</tr>
<tr>
<td>Hexadecimal</td>
<td id="hex"></td>
<td id="hexPadded"></td>
</tr>
</table>
</div>
</body>
</html>

Loading…
Cancel
Save