Taula de continguts:
- Pas 1:
- Pas 2: disseny
- Pas 3: CNC
- Pas 4: electrònica
- Pas 5: Muntatge d'electrònica
- Pas 6: Cursa en sec
- Pas 7: Epoxi
- Pas 8: ajuntar-ho tot
- Pas 9: Codi
- Pas 10: Visió per ordinador: calibració
- Pas 11: Observacions de separació
Vídeo: Rellotge LED de fusta: estil analògic: 11 passos (amb imatges)
2024 Autora: John Day | [email protected]. Última modificació: 2024-01-30 08:16
És un rellotge LED de fusta d’estil analògic. No sé per què no n’he vist cap abans, tot i que els tipus digitals són molt habituals. Anyhoo, aquí estem!
Pas 1:
El projecte de rellotge contraxapat va començar com un senzill projecte d’arrencada per al router CNC. Vaig mirar projectes senzills en línia i vaig trobar aquest llum (imatge superior). També havia vist rellotges digitals que brillaven a través de xapes de fusta (imatge superior). Per tant, combinar els dos projectes era una idea òbvia. Amb l'objectiu de desafiar-me, vaig decidir no utilitzar xapes, sinó només un tros de fusta per a aquest projecte.
Pas 2: disseny
Vaig dissenyar el rellotge a Inkscape (imatge superior). El disseny és molt senzill. Vaig decidir no encaminar les traces dels cables perquè en aquest moment no estava segur de si volia anar amb cablejat radial o perimetral. (Vaig decidir anar amb cablejat perimetral finalment.) Un neopixel entra a cada un dels petits forats circulars per mostrar el temps i les hores, amb una precisió de cinc minuts. El cercle que hi ha al mig s’orientarà per acomodar l’electrònica.
Pas 3: CNC
Vaig dissenyar les rutes d’eines de MasterCAM i vaig utilitzar un technoRouter per treure el rellotge de fusta contraxapada de 3/4 polzades. Utilitzo una peça de 15 "x15" per a això, amb un malbaratament mínim. El truc és enrutar la major part de la fusta possible sense trencar-la. Deixar 0,05 "-0,1" és una bona opció per a la fusta clara. Si no esteu segur, és millor deixar-hi més fusta, perquè sempre podeu esborrar l’altra cara. Vaig acabar traient una mica massa de fusta d'algunes parts, però, per sort, els resultats no pateixen massa a causa d'això.
Nota per als usuaris sense accés a un CNC:
Aquest projecte es pot fer fàcilment amb una broca. Només heu d’establir l’aturada en un punt en què deixeu uns 0,1 de fusta a la base. Haureu de ser precisos, però no massa precisos. Al cap i a la fi, idealment ningú no veurà que tots els LED s’encenguin a al mateix temps, perquè pugueu sortir amb una mica de pendent.
Pas 4: electrònica
L’electrònica és bastant senzilla. Hi ha 24 neopíxels, dotze per mostrar les hores i dotze per mostrar els minuts, amb una precisió de cinc minuts. Un Arduino pro mini controla els neopíxels i obté temps precís mitjançant un mòdul de rellotge en temps real (RTC) DS3231. El mòdul RTC té una cèl·lula de monedes com a còpia de seguretat, de manera que no perd temps fins i tot quan l’alimentació està apagada.
Material:
Arduino pro mini (o qualsevol altre Arduino per això)
Tauler de sortida DS3231
Neopíxels en taules separades individuals
Pas 5: Muntatge d'electrònica
Vaig connectar els neopíxels en una cadena, utilitzant cables de 2,5 per als primers dotze leds i fil de quatre polzades per als dotze següents. Podria haver utilitzat longituds de filferro lleugerament menors. Després de fer la corda, la vaig provar, assegurant-me que la soldadura les articulacions eren bones. Vaig afegir un interruptor momentani per encendre tots els leds, només per mostrar-me.
Pas 6: Cursa en sec
Després d’experimentar, posar LEDs als forats i engegar-los tots, vaig quedar satisfet amb els resultats. Així que vaig lijar una mica la cara frontal i vaig aplicar una capa de PU. Més tard vaig acabar polint l’abric, però és una bona idea deixar-lo encès si no us sembla estèticament desagradable.
Pas 7: Epoxi
Després d'algunes proves amb la posició de led dins dels forats, vaig pensar que la millor discussió s'aconsegueix quan els LED es troben a uns 0,2 del final del forat. Quan ho proveu vosaltres mateixos, la brillantor dels LED serà molt diferent a cada forat. No us preocupeu; solucionarem el codi. Això és degut al tipus de broca que he utilitzat. Si tornés a fer-ho, faria servir una broca de punta de bola per als forats. Però, en qualsevol cas, per aconseguir la distància vaig barrejar una mica d'epoxi i vaig posar una mica a cada forat.
Pas 8: ajuntar-ho tot
Els LED es col·locaran a partir de la posició de l’agulla de les 12 en punt movent-se en sentit antihorari a través de totes les posicions de l’agulla de les hores i després cap a l’agulla dels minuts, passant de nou des de la marca dels 60 minuts que es mouen en sentit antihorari. Això és així quan veiem des de la part frontal el patró de LED apareix en sentit horari.
Després de curar l’epoxi durant una hora, hi vaig posar una mica d’epoxi. Aquesta vegada, he col·locat els LED als forats, assegurant-me de cobrir els cables i les juntes de soldadura amb l’epoxi. Això permet una bona difusió de la llum i assegura els cables.
Pas 9: Codi
El codi es troba a GitHub, no dubteu a modificar-lo per al vostre ús. Quan enceneu tots els LEDs al mateix nivell, la brillantor de la llum que brilla serà molt diferent a cada forat. Això es deu al diferent gruix de la fusta als forats i a la diferència de tonalitat de la fusta. Com podeu veure, el color de la fusta varia bastant a la meva peça. Per solucionar aquesta diferència de brillantor, vaig crear una matriu de nivells de brillantor de led. I va disminuir la brillantor dels LED més brillants. És un procés de prova i error i pot trigar uns quants minuts, però els resultats valen la pena.
plywoodClock.ino
// Rellotge contraxapat |
// Autor: tinkrmind |
// Atribució 4.0 Internacional (CC BY 4.0). Ets lliure de: |
// Compartir: copieu i redistribuïu el material en qualsevol mitjà o format |
// Adaptar: remesclar, transformar i construir sobre el material per a qualsevol propòsit, fins i tot comercialment. |
// Hurra! |
#incloure |
#include "RTClib.h" |
RTC_DS3231 rtc; |
#include "Adafruit_NeoPixel.h" |
#ifdef _AVR_ |
#incloure |
#endif |
# definePIN6 |
Adafruit_NeoPixel strip = Adafruit_NeoPixel (60, PIN, NEO_GRB + NEO_KHZ800); |
int hourPixel = 0; |
int minutePixel = 0; |
unsignedlong lastRtcCheck; |
String inputString = ""; // una cadena per contenir les dades entrants |
string boolean Complet = fals; // si la cadena està completa |
nivell int [24] = {31, 51, 37, 64, 50, 224, 64, 102, 95, 255, 49, 44, 65, 230, 80, 77, 102, 87, 149, 192, 67, 109, 68, 77}; |
voidsetup () { |
#ifndef ESP8266 |
mentre que (! sèrie); // per a Leonardo / Micro / Zero |
#endif |
// Això és per a Trinket 5V 16 MHz, podeu eliminar aquestes tres línies si no feu servir un Trinket |
#if definit (_AVR_ATtiny85_) |
if (F_CPU == 16000000) clock_prescale_set (clock_div_1); |
#endif |
// Codi especial de fi de bibelot |
Serial.begin (9600); |
strip.begin (); |
strip.show (); // Inicialitza tots els píxels a "off" |
if (! rtc.begin ()) { |
Serial.println ("No s'ha pogut trobar l'RTC"); |
mentre que (1); |
} |
pinMode (2, INPUT_PULLUP); |
// rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)))); |
if (rtc.lostPower ()) { |
Serial.println ("RTC ha perdut energia, permetem definir l'hora!"); |
// la línia següent estableix el RTC a la data i hora en què es va compilar aquest esbós |
rtc.adjust (DateTime (F (_ DATE_), F (_ TIME_)))); |
// Aquesta línia estableix el RTC amb una data i hora explícites, per exemple, per definir |
// El 21 de gener de 2014 a les 3:00 trucaríeu a: |
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0)); |
} |
// rtc.adjust (DateTime (2017, 11, 06, 2, 49, 0)); |
// lightUpEven (); |
// mentre (1); |
lastRtcCheck = 0; |
} |
voidloop () { |
if (millis () - lastRtcCheck> 2000) { |
Data i hora ara = rtc.now (); |
Serial.print (now.hour (), DEC); |
Serial.print (':'); |
Serial.print (now.minute (), DEC); |
Serial.print (':'); |
Serial.print (now.second (), DEC); |
Serial.println (); |
showTime (); |
lastRtcCheck = millis (); |
} |
if (! digitalRead (2)) { |
lightUpEven (); |
} |
if (stringComplete) { |
Serial.println (inputString); |
if (inputString [0] == 'l') { |
Serial.println ("Nivell"); |
lightUpEven (); |
} |
if (inputString [0] == 'c') { |
Serial.println ("Temps de visualització"); |
showTime (); |
strip.show (); |
} |
if (inputString [0] == '1') { |
Serial.println ("Encendre tots els LED"); |
lightUp (strip. Color (255, 255, 255)); |
strip.show (); |
} |
if (inputString [0] == '0') { |
Serial.println ("Tira de compensació"); |
clar (); |
strip.show (); |
} |
// # 3, 255 establiria el número 3 del led al nivell 255, 255, 255 |
if (inputString [0] == '#') { |
Temp de la cadena; |
temp = inputString.substring (1); |
int pixNum = temp.toInt (); |
temp = inputString.substring (inputString.indexOf (',') + 1); |
int intensitat = temp.toInt (); |
Serial.print ("Configuració"); |
Serial.print (pixNum); |
Serial.print ("a nivell"); |
Serial.println (intensitat); |
strip.setPixelColor (pixNum, strip. Color (intensitat, intensitat, intensitat)); |
strip.show (); |
} |
// # 3, 255, 0, 125 establiria el número 3 del led al nivell 255, 0, 125 |
if (inputString [0] == '$') { |
Temp de la cadena; |
temp = inputString.substring (1); |
int pixNum = temp.toInt (); |
int rIndex = inputString.indexOf (',') + 1; |
temp = inputString.substring (rIndex); |
int rIntensity = temp.toInt (); |
intgIndex = inputString.indexOf (',', rIndex + 1) + 1; |
temp = inputString.substring (gIndex); |
intgIntensity = temp.toInt (); |
int bIndex = inputString.indexOf (',', gIndex + 1) + 1; |
temp = inputString.substring (bIndex); |
int bIntensitat = temp.toInt (); |
Serial.print ("Configuració"); |
Serial.print (pixNum); |
Serial.print ("R a"); |
Serial.print (rIntensity); |
Serial.print ("G a"); |
Serial.print (gIntensity); |
Serial.print ("B a"); |
Serial.println (bIntensity); |
strip.setPixelColor (pixNum, strip. Color (rIntensity, gIntensity, bIntensity)); |
strip.show (); |
} |
if (inputString [0] == 's') { |
Temp de la cadena; |
int hora, minut; |
temp = inputString.substring (1); |
hora = temp.toInt (); |
int rIndex = inputString.indexOf (',') + 1; |
temp = inputString.substring (rIndex); |
minut = temp.toInt (); |
Serial.print ("Temps de visualització:"); |
Serial.print (hora); |
Serial.print (":"); |
Serial.print (minut); |
showTime (hora, minut); |
retard (1000); |
} |
inputString = ""; |
stringComplete = false; |
} |
// demora (1000); |
} |
voidserialEvent () { |
while (Serial.available ()) { |
char inChar = (char) Serial.read (); |
inputString + = inChar; |
if (inChar == '\ n') { |
stringComplete = true; |
} |
retard (1); |
} |
} |
voidclear () { |
per a (uint16_t i = 0; i <strip.numPixels (); i ++) { |
strip.setPixelColor (i, strip. Color (0, 0, 0)); |
} |
} |
voidshowTime () { |
Data i hora ara = rtc.now (); |
hourPixel = now.hour ()% 12; |
minutePixel = (now.minute () / 5)% 12 + 12; |
clar (); |
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivell [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel])); |
// strip.setPixelColor (minutPíxel, tira. Color (nivell 40 + 40 * [minut Pixel], nivell 30 + 30 * [minut Pixel], nivell 20 + 20 * [minut Pixel])); |
strip.setPixelColor (hourPixel, strip. Color (nivell [hourPixel], level [hourPixel], level [hourPixel])); |
strip.setPixelColor (minutPíxel, tira. Color (nivell [minutPíxel], nivell [minutPíxel], nivell [minutPíxel])); |
// lightUp (strip. Color (255, 255, 255)); |
strip.show (); |
} |
voidshowTime (hora int, minut int) { |
hourPixel = hora% 12; |
minutePixel = (minut / 5)% 12 + 12; |
clar (); |
// strip.setPixelColor (hourPixel, strip. Color (40 + 40 * nivell [hourPixel], 30 + 30 * level [hourPixel], 20 + 20 * level [hourPixel])); |
// strip.setPixelColor (minutPíxel, tira. Color (nivell 40 + 40 * [minut Pixel], nivell 30 + 30 * [minut Pixel], nivell 20 + 20 * [minut Pixel])); |
strip.setPixelColor (hourPixel, strip. Color (nivell [hourPixel], level [hourPixel], level [hourPixel])); |
strip.setPixelColor (minutPíxel, tira. Color (nivell [minutPíxel], nivell [minutPíxel], nivell [minutPíxel])); |
// lightUp (strip. Color (255, 255, 255)); |
strip.show (); |
} |
voidlightUp (color uint32_t) { |
per a (uint16_t i = 0; i <strip.numPixels (); i ++) { |
strip.setPixelColor (i, color); |
} |
strip.show (); |
} |
voidlightUpEven () { |
per a (uint16_t i = 0; i <strip.numPixels (); i ++) { |
strip.setPixelColor (i, strip. Color (nivell , nivell , nivell )); |
} |
strip.show (); |
} |
veure rawplywoodClock.ino allotjat amb ❤ per GitHub
Pas 10: Visió per ordinador: calibració
Vaig prendre una decisió conscient de no utilitzar xapes en aquest projecte. Si ho hagués tingut, el gruix de la fusta hauria estat el mateix davant de tots els LED. Però, com que tinc un gruix de fusta diferent davant de cada LED i perquè el color de la fusta també varia molt, la brillantor del LED és diferent per a cada LED. Per fer que tots els LED semblessin tenir la mateixa brillantor, vaig idear un enginyós truc.
Vaig escriure algun codi de processament (a GitHub) que pren una foto del rellotge i analitza la brillantor de cada LED al seu torn. A continuació, varia la potència de cada LED per intentar que tots tinguin la mateixa brillantor que el LED més feble. Ara sé que això és excessiu, però el processament d’imatges és molt divertit. I, espero desenvolupar el codi de calibratge com a biblioteca.
Podeu veure la brillantor del LED abans i després del calibratge a les fotos anteriors.
calibrateDispllay.pde
importprocessing.video. *; |
importprocessing.serial. *; |
MyPort en sèrie; |
Captura de vídeo; |
finalint numLed = 24; |
int ledNum = 0; |
// heu de tenir aquestes variables variables globals per utilitzar el PxPGetPixelDark () |
int rDark, gDark, bDark, aDark; |
int rLed, gLed, bLed, aLed; |
int rOrg, gOrg, bOrg, aOrg; |
int rTemp, gTemp, bTemp, aTemp; |
PImage ourImage; |
int runNumber = 0; |
int acceptableError = 3; |
int fet; |
int numPixelsInLed; |
long ledIntensity; |
int ledPower; |
objectiu llargIntensitat = 99999999; |
voidsetup () { |
fet = newint [numLed]; |
numPixelsInLed = newint [numLed]; |
ledIntensity = newlong [numLed]; |
ledPower = newint [numLed]; |
for (int i = 0; i <numLed; i ++) { |
ledPower = 255; |
} |
printArray (Serial.list ()); |
String portName = Serial.list () [31]; |
myPort = newSerial (this, portName, 9600); |
mida (640, 480); |
video = newCapture (això, amplada, alçada); |
video.start (); |
noStroke (); |
llis(); |
retard (1000); // Espereu que s’obri el port sèrie |
} |
voiddraw () { |
if (video.available ()) { |
if (fet [ledNum] == 0) { |
clearDisplay (); |
retard (1000); |
video.read (); |
imatge (vídeo, 0, 0, amplada, alçada); // Dibuixa el vídeo de la càmera web a la pantalla |
saveFrame ("dades / no_leds.jpg"); |
if (runNumber! = 0) { |
if ((ledIntensity [ledNum] - targetIntensity) * 100 / targetIntensity> acceptableError) { |
ledPower [ledNum] - = pow (0,75, runNumber) * 100 + 1; |
} |
if ((targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity> acceptableError) { |
ledPower [ledNum] + = pow (0,75, runNumber) * 100 + 1; |
} |
if (abs (targetIntensity - ledIntensity [ledNum]) * 100 / targetIntensity <= ErrorError acceptable) { |
fet [ledNum] = 1; |
imprimir ("Led"); |
imprimir (ledNum); |
imprimir ("fet"); |
} |
if (ledPower [ledNum]> 255) { |
ledPower [ledNum] = 255; |
} |
if (ledPower [ledNum] <0) { |
ledPower [ledNum] = 0; |
} |
} |
setLedPower (ledNum, ledPower [ledNum]); |
retard (1000); |
video.read (); |
imatge (vídeo, 0, 0, amplada, alçada); // Dibuixa el vídeo de la càmera web a la pantalla |
retard (10); |
while (myPort.available ()> 0) { |
int inByte = myPort.read (); |
// imprimir (char (inByte)); |
} |
String imageName = "dades /"; |
imageName + = str (ledNum); |
imageName + = "_ led.jpg"; |
saveFrame (imageName); |
String originalImageName = "dades / org"; |
OriginalImageName + = str (ledNum); |
originalImageName + = ". jpg"; |
if (runNumber == 0) { |
saveFrame (originalImageName); |
} |
PImage noLedImg = loadImage ("dades / no_leds.jpg"); |
PImage ledImg = loadImage (imageName); |
PImage originalImg = loadImage (originalImageName); |
noLedImg.loadPixels (); |
ledImg.loadPixels (); |
originalImg.loadPixels (); |
fons (0); |
loadPixels (); |
ledIntensity [ledNum] = 0; |
numPixelsInLed [ledNum] = 0; |
per a (int x = 0; x <ample; x ++) { |
per a (int y = 0; y <altura; y ++) { |
PxPGetPixelDark (x, y, noLedImg.pixels, amplada); |
PxPGetPixelLed (x, y, ledImg.pixels, amplada); |
PxPGetPixelOrg (x, y, OriginalImg.pixels, amplada); |
if ((rOrg + gOrg / 2 + bOrg / 3) - (rDark + gDark / 2 + bDark / 3)> 75) { |
ledIntensity [ledNum] = ledIntensity [ledNum] + (rLed + gLed / 2 + bLed / 3) - (rDark + gDark / 2 + bDark / 3); |
rTemp = 255; |
gTemp = 255; |
bTemp = 255; |
numPixelsInLed [ledNum] ++; |
} més { |
rTemp = 0; |
gTemp = 0; |
bTemp = 0; |
} |
PxPSetPixel (x, y, rTemp, gTemp, bTemp, 255, píxels, amplada); |
} |
} |
ledIntensity [ledNum] / = numPixelsInLed [ledNum]; |
if (targetIntensity> ledIntensity [ledNum] && runNumber == 0) { |
targetIntensity = ledIntensity [ledNum]; |
} |
updatePixels (); |
} |
imprimir (ledNum); |
imprimir(', '); |
print (ledPower [ledNum]); |
imprimir(', '); |
println (ledIntensity [ledNum]); |
ledNum ++; |
if (ledNum == numLed) { |
int donezo = 0; |
for (int i = 0; i <numLed; i ++) { |
donezo + = fet ; |
} |
if (donezo == numLed) { |
println ("FET"); |
for (int i = 0; i <numLed; i ++) { |
imprimir (i); |
print ("\ t"); |
println (ledPower ); |
} |
print ("nivell int ["); |
imprimir (ledNum); |
print ("] = {"); |
for (int i = 0; i <numLed-1; i ++) { |
print (ledPower ); |
imprimir(', '); |
} |
print (ledPower [numLed -1]); |
println ("};"); |
lightUpEven (); |
mentre que (cert); |
} |
print ("Intensitat objectiu"); |
if (runNumber == 0) { |
targetIntensity - = 1; |
} |
println (targetIntensity); |
ledNum = 0; |
runNumber ++; |
} |
} |
} |
voidPxPGetPixelOrg (intx, inty, int pixelArray, intpixelsWidth) { |
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels |
aOrg = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir cada component sol |
rOrg = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau () |
gOrg = (thisPixel >> 8) & 0xFF; |
bOrg = thisPixel & 0xFF; |
} |
voidPxPGetPixelDark (intx, inty, int pixelArray, intpixelsWidth) { |
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels |
aDark = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir que cada component sigui sol |
rDark = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau () |
gDark = (thisPixel >> 8) & 0xFF; |
bDark = thisPixel & 0xFF; |
} |
voidPxPGetPixelLed (intx, inty, int pixelArray, intpixelsWidth) { |
int thisPixel = pixelArray [x + y * pixelsWidth]; // obtenir els colors com a int des dels píxels |
aLed = (thisPixel >> 24) & 0xFF; // hem de canviar i emmascarar per aconseguir cada component sol |
rLed = (thisPixel >> 16) & 0xFF; // això és més ràpid que trucar a vermell (), verd (), blau () |
gLed = (thisPixel >> 8) & 0xFF; |
bLed = thisPixel & 0xFF; |
} |
voidPxPSetPixel (intx, inty, intr, intg, intb, inta, int pixelArray, intpixelsWidth) { |
a = (a << 24); |
r = r << 16; // Embalem els 4 components en un int |
g = g << 8; // per tant, hem de canviar-los al seu lloc |
color argb = a | r | g | b; // operació "o" binària "les afegeix totes en un int |
pixelArray [x + y * pixelsWidth] = argb; // finalment establim la int amb els colors en els píxels |
} |
visualitza rawcalibrateDispllay.pde allotjat amb ❤ per GitHub
Pas 11: Observacions de separació
Trampes a evitar:
* Amb la fusta, obtindreu el que pagueu. Per tant, obtingueu fusta de bona qualitat. La fusta contraxapada de bedoll és una bona opció; qualsevol fusta massissa clara també ho farà molt bé. Vaig abaratir la fusta i em sap greu la meva decisió.
* És millor perforar menys que més. Un parell de forats van quedar massa profunds per a la meva peça. I l’epoxi es mostra a la cara frontal. Es nota molt un cop ho observeu.
* Utilitzeu una broca d'extrem de bola en lloc d'un extrem recte. No he experimentat amb la punta final de la pilota, però estic segur que els resultats seran molt millors.
Estic coquetejant amb la idea de vendre’ls a Etsy o tindie. M'agradaria molt que poguéssiu comentar a continuació si creieu que té sentit:)
Recomanat:
Antena parabòlica de fusta compensada de fusta: 11 passos (amb imatges)
Antena parabòlica de fusta compensada de fusta: m’havia trobat amb alguns llocs web on diverses persones construïen les seves pròpies antenes parabòliques de focus principal, un home australià fins i tot va construir una enorme platja offset de 13 metres. Quina és la diferència? El focus principal és el que penseu quan algú diu "satèl·lit
Com fer un rellotge analògic i un rellotge digital amb tira LED mitjançant Arduino: 3 passos
Com es fabrica un rellotge analògic i un rellotge digital amb tira LED mitjançant Arduino: avui fabricarem un rellotge analògic i un amp; Rellotge digital amb Led Strip i mòdul MAX7219 Dot amb Arduino. Corregirà l’hora amb la zona horària local. El rellotge analògic pot utilitzar una tira LED més llarga, de manera que es pot penjar a la paret per convertir-se en un artista
Rellotge POV LED d'estil analògic amb Arduino Nano: 4 passos
Rellotge POV amb estil LED analògic amb Arduino Nano: és un rellotge POV amb estil analògic d’aspecte agradable
C51 Rellotge electrònic de 4 bits - Rellotge de fusta: 15 passos (amb imatges)
Rellotge electrònic de 4 bits C51: rellotge de fusta: aquest cap de setmana tenia temps lliure, així que vaig avançar i vaig muntar aquest rellotge electrònic electrònic de 4 bits de 2,18 € que vaig comprar a AliExpress fa poc
Rellotge de filament LED estil "Charlotte's Web": 10 passos (amb imatges)
Rellotge de filament LED estil "Charlotte's Web": des que vaig veure les bombetes de filament LED per primera vegada, vaig pensar que els filaments havien de ser bons per a alguna cosa, però va trigar fins a la venda tancada d'una botiga de productes electrònics locals per a mi comprar unes bombetes amb la intenció de destrossar