// Knihovna tlačítek od Alexandra Breviga // Setup LED Matrix // pin 12 je připojen k DataIn na displeji // pin 11 je připojen k CLK na displeji // pin 10 je připojen k LOAD na displeji LedControl lc = LedControl(6, 5, 4, 4); //nastaví 3 piny jako 12, 11 & 10 a poté nastaví 4 displeje (max je 8 displejů) //globální proměnné byte intenzita = 7; // Výchozí intenzita/jas (0-15) byte clock_mode = 0; // Výchozí režim hodin. Výchozí = 0 (základní_režim) bool random_mode = 0; // Definovat náhodný režim - mění typ zobrazení každých několik hodin. Výchozí = 0 (vypnuto) byte old_mode = clock_mode; // Uloží předchozí režim hodin, takže pokud přejdeme na datum nebo cokoli jiného, víme, do jakého režimu se vrátit. bool ampér/min = 0; // Definujte 12 nebo 24 hodinový čas. 0 = 24 hodin. 1 = 12 hodin byte change_mode_time = 0; // Podrží hodinu, kdy se režim hodin příště změní v náhodném režimu. dlouhé zpoždění bez znaménka = 500; // Mezi aktualizacemi zobrazení vždy chvíli čekáme int rtc; // Podrží výstup hodin reálného času char days = ( "Ne", "Po", "Út", "St", "Čt", "Pá", "So" ); //denní pole - používá se v režimech slide, basic_mode a mix mode (DS1307 vydává 1-7 hodnot pro den v týdnu) char daysfull = ( "Neděle", "Pondělí", "Úterý", "St", "Čtvrtek" ", "pátek", "sobota"); přípona char = ("st", "nd", "rd", "th"); //datové pole přípon, používané v režimech slide, basic_mode a jumble. např. 1st 2nd ... //definujte konstanty #define NUM_DISPLAY_MODES 3 // Režimy zobrazení čísel (první režim obsahuje nulu) #define NUM_SETTINGS_MODES 4 // Režimy nastavení čísel = 6 (první režim obsahuje nulu) # define SLIDE_DELAY 20 // Čas v milisekundách pro efekt snímku na znak v režimu snímku. Nastavte vyšší pro pomalejší efekt #define cls clear_display // Clear display RTC_DS1307 ds1307; // Vytvoření objektu RTC Button buttonA = Button(2, BUTTON_PULLUP); // Tlačítko nastavení A (pomocí knihovny tlačítek) Tlačítko tlačítkoB = Button(3, BUTTON_PULLUP); // Tlačítko nastavení B (pomocí knihovny tlačítek) void setup() ( digitalWrite(2, HIGH); // zapnutí pullup rezistoru pro tlačítko na kolíku 2 digitalWrite(3, HIGH); // zapnutí pullup odporu pro tlačítko na kolíku 3 digitalWrite(4, HIGH); // zapněte pullup rezistor pro tlačítko na kolíku 4 Serial.begin(9600); //spustí sériový provoz //inicializuje 4 maticové panely //při vytváření jsme již nastavili počet zařízení the LedControl int devices = lc.getDeviceCount(); //musíme inicializovat všechna zařízení ve smyčce pro (int address = 0; address< devices; address++) {
/*The MAX72XX is in power-saving mode on startup*/
lc.shutdown(3-address, false);
/* Set the brightness to a medium values */
lc.setIntensity(3-address, intensity);
/* and clear the display */
lc.clearDisplay(3-address);
}
//Setup DS1307 RTC
#ifdef AVR
Wire.begin();
#else
Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino
#endif
ds1307.begin(); //start RTC Clock
if (! ds1307.isrunning()) {
Serial.println("RTC is NOT running!");
ds1307.adjust(DateTime(__DATE__, __TIME__)); // sets the RTC to the date & time this sketch was compiled
}
//Show software version & hello message
printver();
//enable red led
digitalWrite(13, HIGH);
}
void loop() {
//run the clock with whatever mode is set by clock_mode - the default is set at top of code.
switch (clock_mode){
case 0:
basic_mode();
break;
case 1:
small_mode();
break;
case 2:
slide();
break;
case 3:
word_clock();
break;
case 4:
setup_menu();
break;
}
}
//plot a point on the display
void plot (byte x, byte y, byte val) {
//select which matrix depending on the x coord
byte address;
if (x >= 0 && x<= 7) {
address = 3;
}
if (x >= 8 && x<= 15) {
address = 2;
x = x - 8;
}
if (x >= 16 && x<= 23) {
address = 1;
x = x - 16;
}
if (x >= 24 && x<= 31) {
address = 0;
x = x - 24;
}
if (val == 1) {
lc.setLed(address, y, x, true);
} else {
lc.setLed(address, y, x, false);
}
}
//clear screen
void clear_display() {
for (byte address = 0; address < 4; address++) {
lc.clearDisplay(address);
}
}
//fade screen down
void fade_down() {
//fade from global intensity to 1
for (byte i = intensity; i >0; i--) ( pro (adresa bajtu = 0; adresa< 4; address++) {
lc.setIntensity(address, i);
}
delay(30); //change this to change fade down speed
}
clear_display(); //clear display completely (off)
//reset intentsity to global val
for (byte address = 0; address < 4; address++) {
lc.setIntensity(address, intensity);
}
}
//power up led test & display software version number
void printver() {
byte i = 0;
char ver_a = "MADE";
char ver_b = "IN";
char ver_c = "RUSSIA";
//test all leds.
for (byte x = 0; x <= 32; x++) {
for (byte y = 0; y <= 7; y++) {
plot(x, y, 1);
}
}
delay(300);
fade_down();
while (ver_a[i]) {
puttinychar((i * 4), 1, ver_a[i]);
delay(35);
i++;
}
delay(500);
fade_down();
i = 0;
while (ver_b[i]) {
puttinychar((i * 4), 1, ver_b[i]);
delay(35);
i++;
}
delay(500);
fade_down();
i = 0;
while (ver_c[i]) {
puttinychar((i * 4), 1, ver_c[i]);
delay(35);
i++;
}
delay(500);
fade_down();
}
// puttinychar
// Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
// This is unoptimized and simply uses plot() to draw each dot.
void puttinychar(byte x, byte y, char c)
{
byte dots;
if (c >= "A" && c<= "Z" || (c >= "a" && c<= "z")) {
c &= 0x1F; // A-Z maps to 1-26
}
else if (c >= "0" && c<= "9") {
c = (c - "0") + 32;
}
else if (c == " ") {
c = 0; // space
}
else if (c == ".") {
c = 27; // full stop
}
else if (c == ":") {
c = 28; // colon
}
else if (c == "\"") {
c = 29; // single quote mark
}
else if (c == "!") {
c = 30; // single quote mark
}
else if (c == "?") {
c = 31; // single quote mark
}
for (byte col = 0; col < 3; col++) {
dots = pgm_read_byte_near(&mytinyfont[c]);
for (char row = 0; row < 5; row++) {
if (dots & (16 >> řádek)) plot(x + sloupec, y + řádek, 1); else plot(x + sloupec, y + řádek, 0); ) ) ) void putnormalchar (bajt x, byte y, char c) ( bajt tečky; // if (c >= "A" && c<= "Z" || (c >= "a" && c<= "z")) {
// c &= 0x1F; // A-Z maps to 1-26
// }
if (c >= "A" && c<= "Z") {
c &= 0x1F; // A-Z maps to 1-26
}
else if (c >= "a" && c<= "z") {
c = (c - "a") + 41; // A-Z maps to 41-67
}
else if (c >= "0" && c<= "9") {
c = (c - "0") + 31;
}
else if (c == " ") {
c = 0; // space
}
else if (c == ".") {
c = 27; // full stop
}
else if (c == "\"") {
c = 28; // single quote mark
}
else if (c == ":") {
c = 29; // clock_mode selector arrow
}
else if (c == ">") ( c = 30; // šipka výběru režimu hodin ) else if (c >= -80 && c<= -67) {
c *= -1;
}
for (char col = 0; col < 5; col++) {
dots = pgm_read_byte_near(&myfont[c]);
for (char row = 0; row < 7; row++) {
//check coords are on screen before trying to plot
//if ((x >= 0) && (x<= 31) && (y >= 0) && (y<= 7)){
if (dots & (64 >> řádek)) ( // pouze 7 řádků. plot(x + sloupec, y + řádek, 1); ) else ( plot(x + sloupec, y + řádek, 0); ) //) ) ) ) //small_mode //zobrazení času v malých 3x5 znacích se sekundami display void small_mode() ( char textchar; // 16 znaků na displeji byte mins = 100; //mins byte secs = rtc; //seconds byte old_secs = secs; / /uchová hodnotu starých sekund – od poslední aktualizace sekund o display – používá se ke kontrole, zda se sekundy změnily cls(); //spustí hlavní smyčku hodin, dokud run_mode vrátí true while (run_mode()) ( get_time(); / /check for button press if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //pokud došlo ke změně sekund, aktualizujte je na displeji secs = rtc; if (secs != old_secs) ( //secs char buffer; itoa(secs, buffer, 10); //fix - jinak pokud num má úvodní nulu, např. "03" s, itoa to pokryje znaky s mezerou "3". if (sek< 10) {
buffer = buffer;
buffer = "0";
}
puttinychar(20, 1, ":"); //seconds colon
puttinychar(24, 1, buffer); //seconds
puttinychar(28, 1, buffer); //seconds
old_secs = secs;
}
//if minute changes change time
if (mins != rtc) {
//reset these for comparison next time
mins = rtc;
byte hours = rtc;
if (hours > < 1) {
hours = hours + ampm * 12;
}
//byte dow = rtc; // the DS1307 outputs 0 - 6 where 0 = Sunday0 - 6 where 0 = Sunday.
//byte date = rtc;
//set characters
char buffer;
itoa(hours, buffer, 10);
//fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ".
if (hours < 10) {
buffer = buffer;
//if we are in 12 hour mode blank the leading zero.
if (ampm) {
buffer = " ";
}
else {
buffer = "0";
}
}
//set hours chars
textchar = buffer;
textchar = buffer;
textchar = ":";
itoa (mins, buffer, 10);
if (mins < 10) {
buffer = buffer;
buffer = "0";
}
//set mins characters
textchar = buffer;
textchar = buffer;
//do seconds
textchar = ":";
buffer;
secs = rtc;
itoa(secs, buffer, 10);
//fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ".
if (secs < 10) {
buffer = buffer;
buffer = "0";
}
//set seconds
textchar = buffer;
textchar = buffer;
byte x = 0;
byte y = 0;
//print each char
for (byte x = 0; x < 6 ; x++) {
puttinychar(x * 4, 1, textchar[x]);
}
}
delay(50);
}
fade_down();
}
// basic_mode()
// show the time in 5x7 characters
void basic_mode()
{
cls();
char buffer; //for int to char conversion to turn rtc values into chars we can print on screen
byte offset = 0; //used to offset the x postition of the digits and centre the display when we are in 12 hour mode and the clock shows only 3 digits. e.g. 3:21
byte x, y; //used to draw a clear box over the left hand "1" of the display when we roll from 12:59 ->1:00 ve 12hodinovém režimu. //provede 12/24hodinový převod, pokud je ampm nastaveno na 1 byte hours = rtc; if (hodiny > 12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) {
hours = hours + ampm * 12;
}
//do offset conversion
if (ampm && hours < 10) {
offset = 2;
}
//set the next minute we show the date at
//set_next_date();
// initially set mins to value 100 - so it wll never equal rtc on the first loop of the clock, meaning we draw the clock display when we enter the function
byte secs = 100;
byte mins = 100;
int count = 0;
//run clock main loop as long as run_mode returns true
while (run_mode()) {
//get the time from the clock chip
get_time();
//check for button press
if (buttonA.uniquePress()) {
switch_mode();
return;
}
if (buttonB.uniquePress()) {
display_date();
return;
}
//check whether it"s time to automatically display the date
//check_show_date();
//draw the flashing: as on if the secs have changed.
if (secs != rtc) {
//update secs with new value
secs = rtc;
//draw:
plot (15 - offset, 2, 1); //top point
plot (15 - offset, 5, 1); //bottom point
count = 400;
}
//if count has run out, turn off the:
if (count == 0) {
plot (15 - offset, 2, 0); //top point
plot (15 - offset, 5, 0); //bottom point
}
else {
count--;
}
//re draw the display if button pressed or if mins != rtc i.e. if the time has changed from what we had stored in mins, (also trigggered on first entering function when mins is 100)
if (mins != rtc) {
//update mins and hours with the new values
mins = rtc;
hours = rtc;
//adjust hours of ampm set to 12 hour mode
if (hours >12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) {
hours = hours + ampm * 12;
}
itoa(hours, buffer, 10);
//if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
if (hours < 10) {
buffer = buffer;
buffer = "0";
}
//print hours
//if we in 12 hour mode and hours < 10, then don"t print the leading zero, and set the offset so we centre the display with 3 digits.
if (ampm && hours < 10) {
offset = 2;
//if the time is 1:00am clear the entire display as the offset changes at this time and we need to blank out the old 12:59
if ((hours == 1 && mins == 0)) {
cls();
}
}
else {
//else no offset and print hours tens digit
offset = 0;
//if the time is 10:00am clear the entire display as the offset changes at this time and we need to blank out the old 9:59
if (hours == 10 && mins == 0) {
cls();
}
putnormalchar(1, 0, buffer);
}
//print hours ones digit
putnormalchar(7 - offset, 0, buffer);
//print mins
//add leading zero if mins < 10
itoa (mins, buffer, 10);
if (mins < 10) {
buffer = buffer;
buffer = "0";
}
//print mins tens and ones digits
putnormalchar(19 - offset, 0, buffer);
putnormalchar(25 - offset, 0, buffer);
}
}
fade_down();
}
//like basic_mode but with slide effect
void slide() {
byte digits_old = {99, 99, 99, 99}; //old values we store time in. Set to somthing that will never match the time initially so all digits get drawn wnen the mode starts
byte digits_new; //new digits time will slide to reveal
byte digits_x_pos = {25, 19, 7, 1}; //x pos for which to draw each digit at
char old_char; //used when we use itoa to transpose the current digit (type byte) into a char to pass to the animation function
char new_char; //used when we use itoa to transpose the new digit (type byte) into a char to pass to the animation function
//old_chars - stores the 5 day and date suffix chars on the display. e.g. "mon" and "st". We feed these into the slide animation as the current char when these chars are updated.
//We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored.
//char old_chars = "AAAAA";
//plot the clock colon on the display
cls();
putnormalchar(13, 0, ":");
byte old_secs = rtc; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display
//run clock main loop as long as run_mode returns true
while (run_mode()) {
get_time();
//check for button press
if (buttonA.uniquePress()) {
switch_mode();
return;
}
if (buttonB.uniquePress()) {
display_date();
return;
}
//if secs have changed then update the display
if (rtc != old_secs) {
old_secs = rtc;
//do 12/24 hour conversion if ampm set to 1
byte hours = rtc;
if (hours >12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) {
hours = hours + ampm * 12;
}
//split all date and time into individual digits - stick in digits_new array
//rtc = secs //array pos and digit stored
//digits_new = (rtc%10); //0 - secs ones
//digits_new = ((rtc/10)%10); //1 - secs tens
//rtc = mins
digits_new = (rtc % 10); //2 - mins ones
digits_new = ((rtc / 10) % 10); //3 - mins tens
//rtc = hours
digits_new = (hours % 10); //4 - hour ones
digits_new = ((hours / 10) % 10); //5 - hour tens
//rtc = date
//digits_new = (rtc%10); //6 - date ones
//digits_new = ((rtc/10)%10); //7 - date tens
//draw initial screen of all chars. After this we just draw the changes.
//compare digits 0 to 3 (mins and hours)
for (byte i = 0; i <= 3; i++) {
//see if digit has changed...
if (digits_old[i] != digits_new[i]) {
//run 9 step animation sequence for each in turn
for (byte seq = 0; seq <= 8 ; seq++) {
//convert digit to string
itoa(digits_old[i], old_char, 10);
itoa(digits_new[i], new_char, 10);
//if set to 12 hour mode and we"re on digit 2 (hours tens mode) then check to see if this is a zero. If it is, blank it instead so we get 2.00pm not 02.00pm
if (ampm && i == 3) {
if (digits_new == 0) {
new_char = " ";
}
if (digits_old == 0) {
old_char = " ";
}
}
//draw the animation frame for each digit
slideanim(digits_x_pos[i], 0, seq, old_char, new_char);
delay(SLIDE_DELAY);
}
}
}
/*
//compare date digit 6 (ones) and (7) tens - if either of these change we need to update the date line. We compare date tens as say from Jan 31 ->Feb 01, pak jedna číslice se nezmění, pokud ((digits_old != digits_new) || (digits_old != digits_new)) ( //změňte zobrazený den. Smyčka níže prochází postupně každý ze 3 znaků, např. "MON" pro (bajt day_char = 0; day_char<=2 ; day_char++){
//run the anim sequence for each char
for (byte seq = 0; seq <=8 ; seq++){
//the day (0 - 6) Read this number into the days char array. the seconds number in the array 0-2 gets the 3 chars of the day name, e.g. m o n
slideanim(6*day_char,8,seq,old_chars,days); //6 x day_char gives us the x pos for the char
delay(SLIDE_DELAY);
}
//save the old day chars into the old_chars array at array pos 0-2. We use this next time we change the day and feed it to the animation as the current char. The updated char is fed in as the new char.
old_chars = days;
}
//change the date tens digit (if needed) and ones digit. (the date ones digit wil alwaus change, but putting this in the "if" loop makes it a bit neater code wise.)
for (byte i = 7; i >= 6; i--)( if (digits_old[i] != digits_new[i]) ( for (byte seq = 0; seq<=8 ; seq++){
itoa(digits_old[i],old_char,10);
itoa(digits_new[i],new_char,10);
slideanim(digits_x_pos[i],8,seq,old_char,new_char);
delay(SLIDE_DELAY);
}
}
}
//print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix - eg st, nd, rd, th
byte s = 3; //the pos to read our suffix array from.
byte date = rtc;
if(date == 1 || date == 21 || date == 31) {
s = 0;
}
else if (date == 2 || date == 22) {
s = 1;
}
else if (date == 3 || date == 23) {
s = 2;
}
for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){
for (byte seq = 0; seq <=8 ; seq++){
slideanim((suffix_char*6)+36,8,seq,old_chars,suffix[s]); // we pass in the old_char array char as the current char and the suffix array as the new char
delay(SLIDE_DELAY);
}
//save the suffic char in the old chars array at array pos 3 and 5. We use these chars next time we change the suffix and feed it to the animation as the current char. The updated char is fed in as the new char.
old_chars = suffix[s];
}
}//end do date line
*/
//save digita array tol old for comparison next loop
for (byte i = 0; i <= 3; i++) {
digits_old[i] = digits_new[i];
}
}//secs/oldsecs
}//while loop
fade_down();
}
//called by slide
//this draws the animation of one char sliding on and the other sliding off. There are 8 steps in the animation, we call the function to draw one of the steps from 0-7
//inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn.
void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) {
// To slide one char off and another on we need 9 steps or frames in sequence...
// seq# 0123456 <-rows of the display
// | |||||||
// seq0 0123456 START - all rows of the display 0-6 show the current characters rows 0-6
// seq1 012345 current char moves down one row on the display. We only see it"s rows 0-5. There are at display positions 1-6 There is a blank row inserted at the top
// seq2 6 01234 current char moves down 2 rows. we now only see rows 0-4 at display rows 2-6 on the display. Row 1 of the display is blank. Row 0 shows row 6 of the new char
// seq3 56 0123
// seq4 456 012 half old / half new char
// seq5 3456 01
// seq6 23456 0
// seq7 123456
// seq8 0123456 END - all rows show the new char
//from above we can see...
//currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time.
//new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time.
//if sequence number is below 7, we need to draw the current char
if (sequence < 7) {
byte dots;
// if (current_c >= "A" && || (current_c >= "a" && current_c<= "z")) {
// current_c &= 0x1F; // A-Z maps to 1-26
// }
if (current_c >= "A" && current_c<= "Z") {
current_c &= 0x1F; // A-Z maps to 1-26
}
else if (current_c >= "a" && current_c<= "z") {
current_c = (current_c - "a") + 41; // A-Z maps to 41-67
}
else if (current_c >= "0" && current_c<= "9") {
current_c = (current_c - "0") + 31;
}
else if (current_c == " ") {
current_c = 0; // space
}
else if (current_c == ".") {
current_c = 27; // full stop
}
else if (current_c == "\"") {
current_c = 28; // single quote mark
}
else if (current_c == ":") {
current_c = 29; //colon
}
else if (current_c == ">") ( current_c = 30; // šipka výběru režimu hodin ) byte curr_char_row_max = 7 - sekvence; //maximální počet řádků k vykreslení je 6 - pořadové číslo byte start_y = sekvence; //y pozice pro začátek - je stejná jako pořadové číslo. Toto započítáváme každý cyklus //vykreslíme každý řádek až do maxima řádku (vypočteno z pořadového čísla) pro (byte curr_char_row = 0; curr_char_row<= curr_char_row_max; curr_char_row++) {
for (byte col = 0; col < 5; col++) {
dots = pgm_read_byte_near(&myfont);
if (dots & (64 >> curr_char_row)) plot(x + col, y + start_y, 1); //vykreslení vedeno na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//přidej jedničku k y, takže nakreslíme další řádek o jeden dolů ) ) //nakreslí prázdný řádek mezi znaky, pokud je sekvence mezi 1 a 7. Pokud to neuděláme, dostaneme zbytky aktuálních znaků na poslední pozici vlevo na displeji if (sekvence >= 1 && sekvence<= 8) {
for (byte col = 0; col < 5; col++) {
plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1
}
}
//if sequence is above 2, we also need to start drawing the new char
if (sequence >= 2) ( //vypracujte tečky char byte; //if (new_c >= "A" && new_c<= "Z" || (new_c >= "a" && new_c<= "z")) {
// new_c &= 0x1F; // A-Z maps to 1-26
//}
if (new_c >= "A" && new_c<= "Z") {
new_c &= 0x1F; // A-Z maps to 1-26
}
else if (new_c >= "a" && new_c<= "z") {
new_c = (new_c - "a") + 41; // A-Z maps to 41-67
}
else if (new_c >= "0" && new_c<= "9") {
new_c = (new_c - "0") + 31;
}
else if (new_c == " ") {
new_c = 0; // space
}
else if (new_c == ".") {
new_c = 27; // full stop
}
else if (new_c == "\"") {
new_c = 28; // single quote mark
}
else if (new_c == ":") {
new_c = 29; // clock_mode selector arrow
}
else if (new_c == ">") ( new_c = 30; // šipka voliče režimu hodin ) bajt newcharrowmin = 6 - (sekvence - 2); //minimální číslo řádku pro vykreslení nového znaku - toto generuje výstup 6 až 0, když se naplní pořadová čísla 2-8 . Toto je minimální řádek pro vykreslení nového znakového bajtu start_y = 0; //y pozice pro začátek - je stejná jako pořadové číslo. každý řádek jej započítáváme //vykreslujeme každý řádek nahoru od minima řádku (vypočteno podle pořadového čísla ) až 6 for (byte newcharrow = newcharrowmin; newcharrow<= 6; newcharrow++) {
for (byte col = 0; col < 5; col++) {
dots = pgm_read_byte_near(&myfont);
if (dots & (64 >> newcharrow)) plot(x + col, y + start_y, 1); //vykreslení vedeno na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//přidej jedničku k y, takže nakreslíme další řádek o jeden dolů ) ) ) //vytiskne hodiny pomocí slov místo čísel void word_clock() ( cls(); char numbers = ( "jedna ", "dva", "tři", "čtyři", "pět", "šest", "sedm", "osm", "devět", "deset", "jedenáct", "dvanáct", "třináct", "čtrnáct", "patnáct", "šestnáct", "sedmnáct", "osmnáct", "devatenáct"); char numbertens = ( "deset", "dvacet", "třicet", "čtyřicet", "padesát"); //potenciálně 3 řádky pro zobrazení char str_a; char str_b; char str_c; //bajt hours_y, mins_y; //hodiny a minuty a pozice pro hodiny a minuty řádky byte hours = rtc; if (hodiny > 12) ( hodiny = hodiny - ampm * 12; ) if (hod< 1) {
hours = hours + ampm * 12;
}
get_time(); //get the time from the clock chip
byte old_mins = 100; //store mins in old_mins. We compare mins and old mins & when they are different we redraw the display. Set this to 100 initially so display is drawn when mode starts.
byte mins;
//run clock main loop as long as run_mode returns true
while (run_mode()) {
//check for button press
if (buttonA.uniquePress()) {
switch_mode();
return;
}
if (buttonB.uniquePress()) {
display_date();
}
get_time(); //get the time from the clock chip
mins = rtc; //get mins
//if mins is different from old_mins - redraw display
if (mins != old_mins) {
//update old_mins with current mins value
old_mins = mins;
//reset these for comparison next time
mins = rtc;
hours = rtc;
//make hours into 12 hour format
if (hours >12) ( hodiny = hodiny - 12; ) if (hodiny == 0) ( hodiny = 12; ) //rozdělit minimální hodnotu na dvě samostatné číslice int minsdigit = rtc % 10; byte minsdigitten = (rtc / 10) % 10; //pokud min<= 10 , then top line has to read "minsdigti past" and bottom line reads hours
if (mins < 10) {
strcpy (str_a, numbers);
strcpy (str_b, "PAST");
strcpy (str_c, numbers);
}
//if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour.
if (mins == 10) {
strcpy (str_a, numbers);
strcpy (str_b, " PAST");
strcpy (str_c, numbers);
}
//if time is not on the hour - i.e. both mins digits are not zero,
//then make first line read "hours" and 2 & 3rd lines read "minstens" "mins" e.g. "three /n twenty /n one"
else if (minsdigitten != 0 && minsdigit != 0) {
strcpy (str_a, numbers);
//if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen"
//if (mins >= 11 && min<= 19) {
if (mins <= 19) {
strcpy (str_b, numbers);
}
else {
strcpy (str_b, numberstens);
strcpy (str_c, numbers);
}
}
// if mins digit is zero, don"t print it. read read "hours" "minstens" e.g. "three /n twenty"
else if (minsdigitten != 0 && minsdigit == 0) {
strcpy (str_a, numbers);
strcpy (str_b, numberstens);
strcpy (str_c, "");
}
//if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o"clock"
else if (minsdigitten == 0 && minsdigit == 0) {
strcpy (str_a, numbers);
strcpy (str_b, "O"CLOCK");
strcpy (str_c, "");
}
}//end worknig out time
//run in a loop
//print line a "twelve"
byte len = 0;
while (str_a) {
len++;
}; //get length of message
byte offset_top = (31 - ((len - 1) * 4)) / 2; //
//plot hours line
byte i = 0;
while (str_a[i]) {
puttinychar((i * 4) + offset_top, 1, str_a[i]);
i++;
}
//hold display but check for button presses
int counter = 1000;
while (counter >0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down (); //tisk řádku b len = 0; while (str_b) ( len++; ); //získání délky zprávy offset_top = (31 - ((délka - 1) * 4)) / 2; i = 0; while (str_b[i]) ( puttinychar((i * 4) + offset_top, 1, str_b[i]); i++; ) //podržet zobrazení, ale zkontrolovat počítadlo stisknutí tlačítka = 1000; while (counter > 0)( if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down() ; //vytiskne řádek c, pokud existuje. len = 0; while (str_c) ( len++; ); //získání délky zprávy offset_top = (31 - ((délka - 1) * 4)) / 2; i = 0; while (str_c[i]) ( puttinychar((i * 4) + offset_top, 1, str_c[i]); i++; ) čítač = 1000; while (counter > 0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) fade_down(); //podržte displej prázdný, ale před dalším spuštěním zkontrolujte, zda nedošlo ke stisknutí tlačítka. čítač = 1000; while (counter > 0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) ) fade_down(); ) /// rolovací zpráva - v současnosti se nepoužívá - příliš pomalá. void scroll() ( char message = ("Ahoj"); cls(); byte p = 6; //aktuální pozice v řetězci byte chara = (0, 1, 2, 3, 4, 5); //znaky z řetězce int x = (0, 6, 12, 18, 24, 30); //xpos pro každý znakový bajt y = 0; //y pos // clear_buffer(); while (zpráva[p] != "\ 0") ( //nakreslete všech 6 znaků pro (bajt c = 0; c< 6; c++) {
putnormalchar(x[c],y,message[ chara[c] ]);
//draw a line of pixels turned off after each char,otherwise the gaps between the chars have pixels left in them from the previous char
for (byte yy = 0 ; yy < 8; yy ++) {
plot(x[c] + 5, yy, 0);
}
//take one off each chars position
x[c] = x[c] - 1;
}
//reset a char if it"s gone off screen
for (byte i = 0; i <= 5; i++) {
if (x[i] < -5) {
x[i] = 31;
chara[i] = p;
p++;
}
}
}
}
//display_date - print the day of week, date and month with a flashing cursor effect
void display_date()
{
cls();
//read the date from the DS1307
byte dow = rtc; // day of week 0 = Sunday
byte date = rtc;
byte month = rtc - 1;
//array of month names to print on the display. Some are shortened as we only have 8 characters across to play with
char monthnames = {
"January", "February", "March", "April", "May", "June", "July", "August", "Sept", "October", "November", "December"
};
//print the day name
//get length of text in pixels, that way we can centre it on the display by divindin the remaining pixels b2 and using that as an offset
byte len = 0;
while(daysfull) {
len++;
};
byte offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text
//print the name
int i = 0;
while(daysfull[i])
{
puttinychar((i*4) + offset , 1, daysfull[i]);
i++;
}
delay(1000);
fade_down();
cls();
// print date numerals
char buffer;
itoa(date,buffer,10);
offset = 10; //offset to centre text if 3 chars - e.g. 3rd
// first work out date 2 letter suffix - eg st, nd, rd, th etc
// char suffix={"st", "nd", "rd", "th" }; is defined at top of code
byte s = 3;
if(date == 1 || date == 21 || date == 31) {
s = 0;
}
else if (date == 2 || date == 22) {
s = 1;
}
else if (date == 3 || date == 23) {
s = 2;
}
//print the 1st date number
puttinychar(0+offset, 1, buffer);
//if date is under 10 - then we only have 1 digit so set positions of sufix etc one character nearer
byte suffixposx = 4;
//if date over 9 then print second number and set xpos of suffix to be 1 char further away
if (date >9)( suffixposx = 8; puttinychar(4+posun, 1, vyrovnávací paměť); offset = 8; //odsazení textu na střed, pokud jsou 4 znaky ) //vytiskne 2 znaky sufixu puttinychar(suffixposx+posun, 1, suffix[s ]); puttinychar(suffixposx+4+offset, 1, suffix[s]); zpoždění(1000); fade_down(); //vytiskne název měsíce //získáte délku textu v pixelech, takže jej můžeme vycentrovat na displeji rozdělením zbývajících pixelů b2 a použitím toho jako offsetu len = 0; while(jména měsíců) ( len++; ); offset = (31 - ((délka-1)*4)) / 2; //naše odsazení pro vycentrování textu i = 0; while(jména měsíců[i]) ( puttinychar((i*4) +offset, 1, názvy měsíců[i]); i++; ) delay(1000); fade_down(); ) //dislpay menu pro změnu režimu hodin void switch_mode() ( //pamatujte si režim, ve kterém se nacházíme. Tuto hodnotu použijeme, pokud přejdeme do režimu nastavení, takže se můžeme vrátit zpět z režimu nastavení (6) do jakéhokoli režimu, ve kterém jsme byli in. old_mode = clock_mode; char* modes = ( "Základní", "Malý", "Slide", "Slova", "Nastavení" ); byte next_clock_mode; byte firstrun = 1; //smyčka čeká na tlačítko (časový limit po 35 smyčky pro návrat do režimu X) for (int count = 0; count< 35 ; count++) {
//if user hits button, change the clock_mode
if (buttonA.uniquePress() || firstrun == 1) {
count = 0;
cls();
if (firstrun == 0) {
clock_mode++;
}
if (clock_mode >NUM_DISPLAY_MODES + 1) ( clock_mode = 0; ) //vytiskne šipku a název aktuálního režimu hodin na řádek jedna a vytiskne další název režimu hodin na řádek dva char str_top; //strcpy (str_top, "-"); strcpy(str_top, režimy); next_clock_mode = clock_mode + 1; if (režim_dalších_hodin > NUM_DISPLAY_MODES + 1) (režim_dalších_hodin = 0; ) byte i = 0; while (str_top[i]) ( putnormalchar(i * 6, 0, str_top[i]); i++; ) firstrun = 0; ) zpoždění(50); ) ) //spustí hlavní smyčku hodin tak dlouho, dokud run_mode vrátí true byte run_mode() ( //pokud je zapnutý náhodný režim... zkontrolujte hodinu, kdy změníme režim. if (random_mode) ( //pokud hodnota hodiny v režimu změny time = hours. then reurn false = tj. opustit režim. if (change_mode_time == rtc) ( //nastaví další náhodný režim hodin a čas pro jeho změnu set_next_random(); //ukončí aktuální režim. return 0; ) ) / /else return 1 - pokračujte v běhu v tomto režimu return 1; ) //nastaví další hodinu, kdy se hodiny změní režim, když je náhodný režim void set_next_random() ( //nastaví další hodinu, kdy se režim hodin změní - aktuální čas plus 1–4 hodiny get_time(); change_mode_time = rtc + random (1, 5); //pokud change_mode_time nyní překročí 23, pak jej nastavte na mezi 1 a 3:00, pokud (change_mode_time > 23) ( change_mode_time = random (1 , 4); ) //nastavení nového režimu hodin clock_mode = random(0, NUM_DISPLAY_MODES + 1); //výběr nového režimu náhodného hodin ) //zobrazení nabídky pro změnu nastavení hodin void setup_menu() ( char* set_modes = ( "Rndom", "24 Hr", "Nastavit", "Brght", "Exit"); if (ampm == 0) ( set_modes = ("12 Hr"); ) byte setting_mode = 0; byte next_setting_mode; byte firstrun = 1; //smyčka čeká na tlačítko (časový limit po 35 cyklech pro návrat do režimu X) for(int count=0; count< 35 ; count++) {
//if user hits button, change the clock_mode
if(buttonA.uniquePress() || firstrun == 1){
count = 0;
cls();
if (firstrun == 0) {
setting_mode++;
}
if (setting_mode >NUM_SETTINGS_MODES) ( setting_mode = 0; ) //vytiskne šipku a název aktuálního režimu hodin na řádek jedna a vytiskne další název režimu hodin na řádek dva char str_top; strcpy(str_top, set_modes); next_setting_mode = režim_nastavení + 1; if (režim_dalšího_nastavení > NUM_NASTAVENÍ_REŽIMŮ) (režim_dalšího_nastavení = 0; ) byte i = 0; while(str_top[i]) ( putnormalchar(i*6, 0, str_top[i]); i++; ) firstrun = 0; ) zpoždění(50); ) //vyberte přepínač režimu(setting_mode)( případ 0: set_random(); přestávka; případ 1: set_ampm(); přestávka; případ 2: set_time(); přestávka; případ 3: set_intensity(); přestávka; případ 4: //opuštění menu break; ) //změna hodin z režimu 6 (nastavení) zpět na ten, ve kterém byly před clock_mode=old_mode; ) //přepnout náhodný režim - každých pár hodin vybrat jiný režim hodin void set_random())( cls(); char text_a = "Vypnuto"; char text_b = "Zapnuto"; byte i = 0; //pokud je náhodný režim on , vypněte jej if (random_mode)( //vypne náhodný režim random_mode = 0; //vytiskne zprávu na displej while(text_a[i]) ( putnormalchar((i*6), 0, text_a[i] ) ; i++; ) ) else ( //zapnutí náhodného režimu. random_mode = 1; //nastavení hodinového režimu změní set_next_random(); //vytiskne zprávu na displej while(text_b[i]) ( putnormalchar((i * 6), 0, text_b[i]); i++; ) ) delay(1500); //nechte zprávu asi na sekundu ) //nastav 12 nebo 24 hodin void set_ampm() ( // AM/ PM nebo 24hodinový režim hodin - překlopte bit (udělá 0 na 1 nebo 1 na 0 pro režim ampm) ampm = (ampm ^ 1); cls(); ) //změna intenzity intenzity obrazovky void set_intensity() ( cls() ; byte i = 0; text char = "Jasný"; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //čekání na vstup tlačítkem, zatímco ( ! buttonA.uniquePress()) ( levelbar (0,6,(intenzita*2)+2,2); //zobrazení úrovně intenzity jako sloupec while (buttonB.isPressed()) ( if(intensity == 15) ( intenzita = 0; cls (); ) else ( intenzita++; ) //vytiskne novou hodnotu i = 0; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //zobrazení úrovně intenzity jako pruh úrovně (0,6,(intenzita*2)+ 2,2); //změňte nastavení jasu na displejích pro (adresa bajtu = 0; adresa< 4; address++) {
lc.setIntensity(address, intensity);
}
delay(150);
}
}
}
// display a horizontal bar on the screen at offset xposr by ypos with height and width of xbar, ybar
void levelbar (byte xpos, byte ypos, byte xbar, byte ybar) {
for (byte x = 0; x < xbar; x++) {
for (byte y = 0; y <= ybar; y++) {
plot(x+xpos, y+ypos, 1);
}
}
}
//set time and date routine
void set_time() {
cls();
//fill settings with current clock values read from clock
get_time();
byte set_min = rtc;
byte set_hr = rtc;
byte set_date = rtc;
byte set_mnth = rtc;
int set_yr = rtc;
//Set function - we pass in: which "set" message to show at top, current value, reset value, and rollover limit.
set_date = set_value(2, set_date, 1, 31);
set_mnth = set_value(3, set_mnth, 1, 12);
set_yr = set_value(4, set_yr, 2013, 2099);
set_hr = set_value(1, set_hr, 0, 23);
set_min = set_value(0, set_min, 0, 59);
ds1307.adjust(DateTime(set_yr, set_mnth, set_date, set_hr, set_min));
cls();
}
//used to set min, hr, date, month, year values. pass
//message = which "set" message to print,
//current value = current value of property we are setting
//reset_value = what to reset value to if to rolls over. E.g. mins roll from 60 to 0, months from 12 to 1
//rollover limit = when value rolls over
int set_value(byte message, int current_value, int reset_value, int rollover_limit){
cls();
char messages = {
"Set Mins", "Set Hour", "Set Day", "Set Mnth", "Set Year"};
//Print "set xyz" top line
byte i = 0;
while(messages[i])
{
puttinychar(i*4 , 1, messages[i]);
i++;
}
delay(2000);
cls();
//print digits bottom line
char buffer = " ";
itoa(current_value,buffer,10);
puttinychar(0 , 1, buffer);
puttinychar(4 , 1, buffer);
puttinychar(8 , 1, buffer);
puttinychar(12, 1, buffer);
delay(300);
//wait for button input
while (!buttonA.uniquePress()) {
while (buttonB.isPressed()){
if(current_value < rollover_limit) {
current_value++;
}
else {
current_value = reset_value;
}
//print the new value
itoa(current_value, buffer ,10);
puttinychar(0 , 1, buffer);
puttinychar(4 , 1, buffer);
puttinychar(8 , 1, buffer);
puttinychar(12, 1, buffer);
delay(150);
}
}
return current_value;
}
void get_time()
{
//get time
DateTime now = ds1307.now();
//save time to array
rtc = now.year();
rtc = now.month();
rtc = now.day();
rtc = now.dayOfWeek(); //returns 0-6 where 0 = Sunday
rtc = now.hour();
rtc = now.minute();
rtc = now.second();
//flash arduino led on pin 13 every second
//if ((rtc % 2) == 0) {
// digitalWrite(13, HIGH);
//}
//else {
// digitalWrite(13, LOW);
//}
//print the time to the serial port - useful for debuging RTC issues
/*
Serial.print(rtc);
Serial.print(":");
Serial.print(rtc);
Serial.print(":");
Serial.println(rtc);
*/
}
Nyní, abyste dokončili práci na zařízení, stačí provést několik jednoduchých operací:
![](https://i0.wp.com/arduinoplus.ru/wp-content/uploads/2018/08/arduino-chasi-6.jpg)
Kompilace programového kódu a jeho další načítání do paměti mikrokontroléru nějakou dobu zabere, obvykle ne více než jednu minutu. Úspěšné dokončení operace bude hlášeno v konzole Arduino IDE. Poté zbývá pouze restartovat Arduino pomocí tlačítka Reset na zařízení - jednoduché hodiny na LED matricích jsou připraveny!
![](https://i1.wp.com/arduinoplus.ru/wp-content/uploads/2018/08/arduino-7-780x590.jpg)
Připravené hodiny na Arduinu
Hodiny se nastavují pomocí dvou tlačítek. Zařízení podporuje 12- a 24hodinové formáty času, zobrazuje datum a den v týdnu a zobrazuje čas s nebo bez sekund. Je také možné změnit jas LED diod.
![](https://i1.wp.com/arduinoplus.ru/wp-content/uploads/2018/08/arduino-elektron-chasi-1-780x536.jpg)
Pravděpodobně budete chtít v budoucnu přidat další funkce (například teploměr), nebo nainstalovat zařízení do těla vlastní konstrukce - dobrých výsledků lze dosáhnout pomocí laserových řezacích strojů. Ale nyní můžete bezpečně říci, že jste sestavili plnohodnotné elektronické hodinky vlastníma rukama!
Není to tak dávno, co bylo potřeba mít doma hodiny, ale pouze elektronické, protože hodiny nemám rád, protože tikají. S pájením a leptáním obvodů mám poměrně dost zkušeností. Po prohledání internetu a přečtení nějaké literatury jsem se rozhodl zvolit nejjednodušší schéma, protože nepotřebuji hodinky s budíkem.
Toto schéma jsem zvolil, protože je snadné vyrobit si vlastní hodinky
Začněme, co tedy potřebujeme, abychom si vyrobili hodinky vlastníma rukama? No jistě, ruce, zručnost (ani velká) ve čtení schémat zapojení, páječka a součástky. Zde je úplný seznam toho, co jsem použil:
10 MHz quartz – 1 ks, mikrokontrolér ATtiny 2313, rezistory 100 Ohm – 8 ks, 3 ks. 10 kOhm, 2 kondenzátory 22 pF, 4 tranzistory, 2 tlačítka, LED indikátor 4bitový KEM-5641-ASR (RL-F5610SBAW/D15). Instalaci jsem provedl na jednostrannou DPS.
Ale v tomto schématu je chyba: celkem slušnou zátěž dostávají piny mikrokontroléru (dále jen MK), které mají na starosti řízení výbojů. Celkový proud je mnohem vyšší než maximální proud portu, ale při dynamické indikaci se MK nestihne přehřát. Aby nedošlo k poruše MK, přidáme do vybíjecích obvodů odpory 100 Ohm.
V tomto schématu je indikátor řízen podle principu dynamické indikace, podle kterého jsou segmenty indikátoru řízeny signály z odpovídajících výstupů MK. Frekvence opakování těchto signálů je více než 25 Hz a z tohoto důvodu se zdá, že záře čísel indikátorů jsou nepřetržité.
Elektronické hodinky vyrobené podle výše uvedeného schématu může zobrazovat pouze čas (hodiny a minuty) a sekundy jsou zobrazeny tečkou mezi segmenty, který bliká. Pro ovládání provozního režimu hodinek jsou v jejich struktuře umístěny tlačítkové spínače, které ovládají nastavení hodin a minut. Tento obvod je napájen z 5V zdroje. Při výrobě plošného spoje byla do obvodu zařazena zenerova dioda 5V.
![](https://i1.wp.com/igor97.ru/wp-content/uploads/2013/02/222.png)
Jelikož mám zdroj 5V, zenerovu diodu jsem z obvodu vyloučil.
K výrobě desky byl obvod aplikován pomocí žehličky. To znamená, že tištěný spoj byl vytištěn na inkoustové tiskárně na lesklý papír, lze jej převzít z moderních lesklých časopisů. Poté byl vyříznut textolit požadované velikosti. Vyšel mi rozměr 36*26 mm. Tak malá velikost je způsobena tím, že všechny díly jsou vybrány v SMD pouzdru.
Deska byla leptána pomocí chloridu železitého (FeCl3). Leptání trvalo asi hodinu, protože lázeň s deskou byla na krbu, vysoká teplota ovlivňuje dobu leptání, v desce nebyla použita měď. S teplotou to ale nepřehánějte.
Zatímco probíhal proces leptání, abych si nelámal hlavu a nepsal firmware, aby hodiny fungovaly, šel jsem na internet a našel jsem firmware pro toto schéma. Jak flashnout MK najdete i na internetu. Použil jsem programátor, který flashuje pouze ATMEGA MK.
A konečně je naše deska hotová a můžeme začít pájet hodinky. Pro pájení potřebujete 25W páječku s tenkým hrotem, aby nedošlo k popálení MK a dalších dílů. Pájení provádíme opatrně a nejlépe připájeme všechny nohy MK poprvé, ale pouze samostatně. Pro ty, kteří se nevyznají, vězte, že díly vyrobené v SMD pouzdru mají na svých vývodech cín pro rychlé pájení.
A takto vypadá deska s připájenými díly.
![](https://i2.wp.com/igor97.ru/wp-content/uploads/2013/02/45456654-1024x768.jpg)
Pamatuji si... Před třiceti lety bylo šest ukazatelů malý poklad. Každý, kdo pak dokázal vyrobit hodiny pomocí TTL logiky s takovými indikátory, byl považován za sofistikovaného odborníka ve svém oboru.
Záře indikátorů vypouštění plynu se zdála teplejší. Po pár minutách jsem byl zvědavý, jestli tyto staré lampy budou fungovat, a chtěl jsem s nimi něco udělat. Nyní je velmi snadné takové hodinky vyrobit. Vše, co potřebujete, je mikrokontrolér...
Jelikož jsem se zároveň zajímal o programování mikrokontrolérů ve vyšších jazycích, rozhodl jsem se trochu si pohrát. Pokusil jsem se sestrojit jednoduché hodiny pomocí digitálních indikátorů výboje plynu.
Účel designu
Rozhodl jsem se, že hodiny by měly mít šest číslic a čas by měl být nastaven minimálním počtem tlačítek. Kromě toho jsem chtěl zkusit použít několik nejběžnějších rodin mikrokontrolérů od různých výrobců. Chtěl jsem napsat program v C.
Indikátory vybití plynu vyžadují k provozu vysoké napětí. Ale nechtěl jsem řešit nebezpečné síťové napětí. Hodinky měly být napájeny nezávadným napětím 12 V.
Jelikož mým hlavním cílem byla hra, nenajdete zde žádný popis mechanického provedení ani nákresy těla. Pokud si přejete, můžete si hodinky sami vyměnit podle svého vkusu a zkušeností.
Zde je to, co jsem dostal:
- Zobrazení času: HH MM SS
- Indikace alarmu: HH MM --
- Režim zobrazení času: 24 hodin
- Přesnost ±1 sekunda za den (v závislosti na křemenném krystalu)
- Napájecí napětí: 12V
- Spotřeba proudu: 100 mA
Schéma hodin
Pro zařízení s šestimístným digitálním displejem byl režim multiplex přirozeným řešením.
Účel většiny prvků blokového diagramu (obrázek 1) je jasný bez komentáře. Do jisté míry nestandardním úkolem bylo vytvořit převodník úrovní TTL na řídicí signály vysokonapěťových indikátorů. Budiče anody jsou vyrobeny pomocí vysokonapěťových tranzistorů NPN a PNP. Diagram je vypůjčen od Stefana Knellera (http://www.stefankneller.de).
Čip 74141 TTL obsahuje dekodér BCD a vysokonapěťový ovladač pro každou číslici. Může být obtížné objednat jeden čip. (I když nevím, jestli je už někdo vyrábí). Ale pokud najdete indikátory vypouštění plynu, 74141 může být někde poblíž :-). V době TTL logiky neexistovala k čipu 74141 prakticky žádná alternativa. Tak zkus někde nějakou najít.
Indikátory vyžadují napětí asi 170 V. Nemá smysl vyvíjet speciální obvod pro převodník napětí, protože existuje velké množství čipů převodníku boost. Vybral jsem si levný a široce dostupný IC34063. Obvod převodníku je téměř kompletně zkopírován z datového listu MC34063. Právě k němu přibyl vypínač T13. Vnitřní spínač není vhodný pro tak vysoké napětí. Jako indukčnost pro převodník jsem použil tlumivku. Je znázorněn na obrázku 2; jeho průměr je 8 mm a jeho délka je 10 mm.
Účinnost převodníku je poměrně dobrá a výstupní napětí je relativně bezpečné. Při zatěžovacím proudu 5 mA klesne výstupní napětí na 60 V. R32 funguje jako proudový rezistor.
Pro napájení logiky je použit lineární regulátor U4. Na obvodu a desce je prostor pro záložní baterii. (3,6 V - NiMH nebo NiCd). D7 a D8 jsou Schottkyho diody a rezistor R37 je navržen tak, aby omezoval nabíjecí proud podle vlastností baterie. Pokud stavíte hodinky jen pro zábavu, nebudete potřebovat baterii D7, D8 a R37.
Konečný obvod je znázorněn na obrázku 3.
Tlačítka nastavení času jsou připojena pomocí diod. Stav tlačítek se kontroluje nastavením logické „1“ na příslušném výstupu. Jako bonus je k výstupu mikrokontroléru připojen piezo emitor. Chcete-li umlčet to ošklivé skřípání, použijte malý vypínač. K tomu by se docela hodilo kladivo, ale to je poslední možnost :-).
Seznam součástek obvodu, nákres desky plošných spojů a schéma rozložení naleznete v sekci "Ke stažení".
procesor
Toto jednoduché zařízení může ovládat téměř každý mikrokontrolér s dostatečným počtem pinů, jejichž minimální požadovaný počet je uveden v tabulce 1.
Stůl 1.
|
Funkce
|
závěry
|
Výživa |
2
|
Quartzový rezonátor |
2
|
Řízení anody |
6
|
Ovladač 74141 |
4
|
Vstup tlačítkem |
1
|
Piezo emitor |
1
|
Celkový |
16
|
|
Každý výrobce vyvíjí vlastní rodiny a typy mikrokontrolérů. Umístění čepů je u každého typu individuální. Snažil jsem se navrhnout univerzální desku pro více typů mikrokontrolérů. Deska má 20pinovou patici. Pomocí několika propojovacích vodičů jej můžete přizpůsobit různým mikrokontrolérům.
Mikrokontroléry testované v tomto obvodu jsou uvedeny níže. Můžete experimentovat s jinými typy. Výhodou schématu je možnost použití různých procesorů. Radioamatéři zpravidla používají jednu rodinu mikrokontrolérů a mají odpovídající programátor a softwarové nástroje. S mikrokontroléry jiných výrobců mohou být problémy, a tak jsem vám dal možnost vybrat si procesor z vaší oblíbené rodiny.
Všechna specifika zapínání různých mikrokontrolérů jsou reflektována v tabulkách 2...5 a obrázcích 4...7.
Tabulka 2
|
Freescale
|
|
Typ |
MC68HC908QY1 |
Quartzový rezonátor |
12 MHz |
Kondenzátory C1, C2 |
22 pF |
Program |
freescale.zip (viz sekce "Stahování") |
Nastavení |
—
|
|
Poznámka: Paralelně s křemenným rezonátorem je zapojen rezistor 10 MΩ.
Tabulka 3.
|
Mikročip
|
|
Typ |
PIC16F628A |
Quartzový rezonátor |
32,768 kHz |
Kondenzátory C1, C2 |
22 pF |
Program |
pic628.zip (viz sekce "Stahování") |
Nastavení |
Int. 4 MHz generátor - I/O RA6, MCLR OFF, WDT OFF, LVP OFF, BROUT OFF, CP OFF, PWRUP OFF |
|
Poznámka: Mikroobvod musí být v zásuvce otočen o 180°.
Tabulka 4.
|
Atmel
|
|
Typ |
ATtiny2313 |
Quartzový rezonátor |
12 MHz |
Kondenzátory C1, C2 |
15 pF |
Program |
attiny.zip (viz sekce "Stahování") |
Nastavení |
Sq. 8 MHz oscilátor, RESET ON |
|
Poznámka: Přidejte SMD součástky R a C na pin RESET (10 kΩ a 100 nF).
Tabulka 5.
|
Atmel
|
|
Typ |
AT89C2051 |
Quartzový rezonátor |
12 MHz |
Kondenzátory C1, C2 |
22 pF |
Program |
at2051.zip (viz sekce "Stahování") |
Nastavení |
--
|
|
Poznámka: Přidejte SMD součástky R a C na pin RESET (10 kΩ a 100 nF); připojte piny označené hvězdičkami k napájecí sběrnici +Ub přes 3,3 kOhm SMD odpory.
Když porovnáte kódy pro různé mikrokontroléry, uvidíte, že jsou velmi podobné. Existují rozdíly v přístupu k portům a definici funkcí přerušení a také v tom, co závisí na hardwarových komponentách.
Zdrojový kód se skládá ze dvou částí. Funkce hlavní() nakonfiguruje porty a spustí časovač, který generuje signály přerušení. Poté program prohledá stisknutá tlačítka a nastaví vhodné hodnoty času a alarmu. Tam se v hlavní smyčce porovná aktuální čas s budíkem a zapne se piezo emitor.
Druhá část je podprogram pro obsluhu přerušení časovače. Podprogram, který se volá každou milisekundu (v závislosti na schopnostech časovače), zvyšuje časové proměnné a řídí číslice na displeji. Kromě toho se kontroluje stav tlačítek.
Provozování okruhu
Při instalaci komponent a nastavení začněte u zdroje napájení. Připájejte regulátor U4 a okolní součásti. Zkontrolujte napětí 5 V pro U2 a 4,6 V pro U1. Dalším krokem je sestavení měniče vysokého napětí. Pomocí trimovacího rezistoru R36 nastavte napětí na 170 V. Pokud rozsah nastavení nestačí, mírně změňte odpor rezistoru R33. Nyní nainstalujte čip U2, tranzistory a rezistory anody a obvodu digitálního ovladače. Vstupy U2 připojte ke sběrnici GND a jeden z rezistorů R25 - R30 zapojte do série k napájecí sběrnici +Ub. Čísla indikátorů by se měla rozsvítit v odpovídajících pozicích. V poslední fázi kontroly obvodu připojte kolík 19 mikroobvodu U1 k zemi - piezo emitor by měl pípnout.
Zdrojové kódy a zkompilované programy naleznete v příslušném ZIP souboru v sekci „Ke stažení“. Po flashování programu do mikrokontroléru pečlivě zkontrolujte každý pin v pozici U1 a nainstalujte potřebné drátové a pájecí propojky. Viz obrázky mikrokontroléru výše. Pokud je mikrokontrolér naprogramován a zapojen správně, jeho generátor by měl začít pracovat. Můžete nastavit čas a budík. Pozornost! Na desce je místo ještě na jedno tlačítko - to je náhradní tlačítko pro budoucí rozšíření :-).
Zkontrolujte přesnost frekvence generátoru. Pokud není v očekávaném rozsahu, mírně změňte hodnoty kondenzátorů C1 a C2. (Pájejte malé kondenzátory paralelně nebo je vyměňte za jiné). Přesnost hodinek by se měla zlepšit.
Závěr
Malé 8bitové procesory jsou docela vhodné pro jazyky na vysoké úrovni. C nebyl původně určen pro malé mikrokontroléry, ale pro jednoduché aplikace jej v pohodě využijete. Jazyk symbolických instrukcí je vhodnější pro složité úlohy, které vyžadují kritické časy nebo maximální zatížení procesoru. Pro většinu radioamatérů jsou vhodné jak bezplatné, tak sharewarově omezené verze C kompilátoru.
Programování v C je stejné pro všechny mikrokontroléry. Musíte znát hardwarové funkce (registry a periferie) zvoleného typu mikrokontroléru. Pozor na bitové operace - jazyk C není vhodný pro manipulaci s jednotlivými bity, jak je vidět na příkladu originálu pro ATtiny.
Jsi hotov? Pak se nalaďte, uvažujte o elektronkách a sledujte...
...staré časy jsou zpět... :-)
Poznámka redakce
Úplným analogem SN74141 je mikroobvod K155ID1, vyrobený softwarem Minsk Integral.
Mikroobvod lze snadno najít na internetu.
Koncept hodin s velkými čísly
Konstrukčně se zařízení bude skládat ze dvou desek - nad sebou. První deska je matice LED, které tvoří hodiny a minuty, druhá je výkonová část (ovládání LED), logika a napájení. Díky tomuto designu budou hodinky kompaktnější (bez pouzdra přibližně 22 cm x 9 cm, tloušťka 4-5 centimetrů) + umožní přišroubovat matrici k jinému projektu, pokud se něco pokazí.
Výkonová část bude postavena na bázi budiče UL2003 a tranzistorových spínačů. Logické - na Atmega8 a DS1307. Napájení: 220V - transformátor; logická 5V (přes 7805), výkonová část - 12V (přes LM2576ADJ). K dispozici bude samostatná přihrádka pro 3V baterii pro autonomní napájení hodin reálného času - DS1307.
Uvažuji o použití Atmega8 a DS1307 (hodiny plánuji pověsit ze stropu, abych v případě výpadku proudu nemusel pokaždé tápat v nastavení), nicméně rozložení desky bude znamenat možnost provozu zařízení bez DS1307 (poprvé a možná navždy - jak to bude fungovat).
V závislosti na konfiguraci bude tedy provozní algoritmus hodinového programu následující:
Atmega8– počítadlo času podle časovače. Práce v cyklu bez přestávek: dotazování na klávesnici, úprava času (je-li to nutné), zobrazení 4 číslic a oddělovače.
Atmega8+DS1307. Práce v cyklu bez přestávek: dotazování na klávesnici, úprava času DS1307 (je-li to nutné), čtení času z DS1307, zobrazení 4 číslic a oddělovač. Nebo jiná možnost - čtení z DS1307 na časovači, zbytek ve smyčce (zatím nevím, jak nejlépe).
Segment se skládá ze 4 červených LED zapojených do série. Jedna číslice – 7 segmentů se společnou anodou. Neplánuji oddělovat segmenty pomocí vzoru osmičky, jak je tomu u konvenčních ukazatelů.
Výkonová část hodin
Výkonová část hodin je postavena na budiči UL2003 a tranzistorových spínačích VT1 a VT2.
UL2003 je zodpovědný za ovládání segmentů indikátoru, klávesy jsou pro ovládání číslic.
Oddělovač hodin a minut je ovládán samostatně (signál K8).
Segmenty, bity a separátor jsou řízeny mikrokontrolérem aplikací kladného potenciálu (tj. aplikací +5 V) na K1-K8, Z1-Z4.
Signály do segmentů a bitů musí být dodávány synchronně as určitou frekvencí, aby byl zajištěn dynamický výstup informace (hodiny a minuty).
Tranzistor BCP52 lze použít jako tranzistor VT1 (BCP53).
Schéma výkonové části hodin s velkými číslicemi
Plošný spoj sedmisegmentového indikátoru pro hodiny s velkými číslicemi
Jak jsem již uvedl dříve, hodiny se budou skládat ze dvou desek plošných spojů - indikační + logická a výkonová část.
Začněme návrhem a výrobou desky plošných spojů indikátoru.
Vývoj desky plošných spojů pro sedmisegmentový indikátor pro hodiny s velkými číslicemi
Plošný spoj sedmisegmentového indikátoru pro hodiny s velkými číslicemi ve formátu "lay" je umístěn na konci článku, v přiložených souborech. Můžete si přečíst o technologii výroby desek plošných spojů metodou LUT.
Pokud jste vše udělali správně, bude hotová DPS vypadat nějak takto.
Hotová deska plošných spojů sedmisegmentového indikátoru pro hodiny s velkými číslicemi
Montáž sedmisegmentového indikátoru
Vzhledem k tomu, že indikační deska je oboustranná, první věcí, kterou musíte udělat, je provést přechody mezi vrstvami. Dělám to pomocí nožiček nepotřebných dílů - provlékám je otvory a z obou stran připájem. Když jsou všechny přechody hotové, začistím je plochým jemným pilníkem - vypadá to velmi úhledně a pěkně.
![](https://i1.wp.com/1.bp.blogspot.com/-hF95xXQd-8w/VLqbVTXikCI/AAAAAAAAA5k/jV6bxn46t3o/s320/DSC_2758a.jpg)
Mezivrstvové lahvičky na indikační desce
Dalším krokem je ve skutečnosti sestavení indikátoru. Proč potřebujeme sadu červených (zelená, bílá, modrá) LED. Vzal jsem například tyto.
![](https://i0.wp.com/1.bp.blogspot.com/--5RzMdtR8X8/VLqbbcByoZI/AAAAAAAAA5s/JqPFOeU3mjE/s320/DSC_2768a.jpg)
Příprava na sestavení indikátoru
Při instalaci diod nezapomeňte, že děláme indikátor se společnou anodou - tzn. Diody "+" musí být spojeny dohromady. Běžné anody na PCB jsou velké kusy mědi. Nezapomeňte věnovat pozornost anodě dělícího bodu.
![](https://i1.wp.com/4.bp.blogspot.com/-Zk3gnpgvd5I/VLqboVRVCkI/AAAAAAAAA58/ukLw0vQForE/s320/DSC_2761a.jpg)
Umístění anod na desce plošných spojů indikátoru
V důsledku toho byste po 2 hodinách usilovné práce měli získat toto:
![](https://i2.wp.com/4.bp.blogspot.com/-ZwoD3SdZ3_A/VLqblVgG7oI/AAAAAAAAA50/HI_xehsbI8M/s320/DSC_2775a.jpg)
Sedmi segmentový indikátor
Digitální část hodin
Digitální část hodin s velkými čísly sestavíme podle následujícího schématu:
Hodinový diagram s velkými čísly
Obvod hodin je docela průhledný, takže nevidím žádný smysl vysvětlovat, jak to funguje. Plošný spoj ve formátu *.lay je ke stažení na konci článku. Všimněte si, že deska s plošnými spoji je určena hlavně pro díly pro povrchovou montáž.
Takže základna prvků, kterou jsem použil:
1. Diodový můstek DFA028 (postačí jakýkoli kompaktní pro povrchovou montáž);
2. Regulátory napětí LM2576ADJ v pouzdře D2PAK, 78M05 v pouzdře HSOP3-P-2,30A;
3. Tranzistorové spínače BCP53 (pouzdro SOT223) a BC847 (pouzdro SOT23);
4. mikrokontrolér Atmega8 (TQFP);
5. Hodiny reálného času DS1307 (SO8);
6. Napájení 14V 1,2A z nějakého starého zařízení;
7. Zbývající díly jsou libovolného typu, velikostně vhodné pro instalaci na desku plošných spojů.
Samozřejmě, pokud chcete použít další balíčky dílů, budete muset provést nějaké změny na PCB.
Věnujte pozornost hodnotám odporu R3 a R4 - musí být přesně takové, jak je uvedeno na diagramu - ne více, ne méně. To se provádí za účelem poskytnutí přesně 12V na výstupu regulátoru napětí LM2576ADJ. Pokud stále nemůžete najít takové hodnoty odporu, pak lze hodnotu odporu R4 vypočítat pomocí vzorce:
R4=R3(12/1,23-1) nebo R4=8,76R3
Sestavení digitální části. Verze 1, bez DS1307
Pokud jste se při výrobě plošného spoje pro hodinky řídili doporučeními uvedenými v, pak je zbytečné připomínat, že před montáží je třeba plošný spoj provrtat, odstranit všechny viditelné zkraty na něm a deska musí být pokryta tekutou kalafunou? Poté začneme s montáží hodinek.
Doporučuji začít s montáží zdroje a teprve poté osadit digitální část. Toto je obecné doporučení pro vlastní montáž zařízení. Proč? Jednoduše proto, že pokud je zdroj sestaven s chybou, můžete spálit veškerou nízkonapěťovou elektroniku, která by měla být tímto zdrojem napájena.
Pokud je vše provedeno správně, napájení by mělo okamžitě fungovat. Zkontrolujeme sestavení zdroje - změřte napětí na zkušebních bodech.
Obrázek ukazuje testovací body, ve kterých by se mělo kontrolovat napájecí napětí. Pokud napětí odpovídá deklarovanému, můžete začít s montáží digitální části hodinek. V opačném případě zkontrolujeme instalaci a funkčnost napájecích prvků.
Testovací body a hodnoty napětí pro napájení hodin
Po kontrole napájení přistoupíme k montáži digitální části hodin - instalaci všech ostatních prvků na plošný spoj. Kontrolujeme zkraty zejména v nohách mikrokontroléru Atmega a driveru UL2003.
![](https://i0.wp.com/4.bp.blogspot.com/-9GNopeNh-nE/VLqnMiiSizI/AAAAAAAAA6o/u0sSZ5jk0Us/s320/cifrch.jpg)
Instalace digitální části hodin
Vezměte prosím na vědomí, že sestavujeme hodiny BEZ instalace hodin reálného času DS1307, avšak veškeré zapojení tohoto čipu musí být dokončeno. V budoucnu, pokud bude potřeba, nám to ušetří čas na úpravu hodin pro druhou verzi, kde budou stále používány samostatné nezávislé hodiny reálného času na DS1307.
Předběžné testování mikrokontroléru ATMEGA8
Abychom mohli zkontrolovat správnost a funkčnost mikrokontroléru, potřebujeme:
1. Například programátor.
2. pro obvodové programování mikrokontroléru.
3. Program AVRDUDESHELL.
Desku hodin připojíme k datovému kabelu. Datový kabel připojíme k programátoru. Programátor pro počítač, na kterém je nainstalován program AVRDUDESHELL. Deska hodin by neměla být připojena ke zdroji 220V.
![](https://i2.wp.com/3.bp.blogspot.com/-_Gx9NBzibag/VLqo4JiW9YI/AAAAAAAAA68/d0D04W5n8JQ/s320/fuseok.png)
Úspěšné čtení dat z mikrokontroléru programem AVRDUDESHELL
Pokud se vyskytnou problémy při čtení pojistek, zkontrolujte instalaci - někde může být zkrat nebo „chybějící spojení“. Další tip - možná je mikrokontrolér v režimu nízkorychlostního programování, pak stačí přepnout programátor do tohoto režimu (