// Biblioteka gumba Alexandera Breviga // Postavljanje LED matrice // pin 12 spojen je na DataIn na zaslonu // pin 11 spojen je na CLK na zaslonu // pin 10 spojen je na LOAD na zaslonu LedControl lc = LedControl(6, 5, 4, 4); //postavlja 3 pina kao 12, 11 & 10 i zatim postavlja 4 zaslona (maksimum je 8 zaslona) //globalne varijable byte intensity = 7; // Zadani intenzitet/svjetlina (0-15) byte clock_mode = 0; // Zadani način rada sata. Zadano = 0 (osnovni_način) bool random_mode = 0; // Definirajte nasumični način - mijenja vrstu prikaza svakih nekoliko sati. Zadano = 0 (isključeno) byte old_mode = clock_mode; // Pohranjuje prethodni način rada sata, tako da ako idemo na datum ili bilo što drugo, znamo na koji način da se vratimo nakon toga. bool ampm = 0; // Definirajte vrijeme od 12 ili 24 sata. 0 = 24 sata. 1 = 12 satni bajt change_mode_time = 0; // Zadržava sat kada će se način sata sljedeći put promijeniti ako je u nasumičnim načinima. dugo vrijeme kašnjenja bez predznaka = 500; // Uvijek čekamo malo između ažuriranja prikaza int rtc; // Drži izlaz sata realnog vremena char days = ( "Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"); //niz dana - koristi se u slajd, osnovni_mod i jumble način rada (DS1307 daje 1-7 vrijednosti za dan u tjednu) char daysfull = ( "nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak" ", "Petak", "Subota" ); char sufiks = ("st", "nd", "rd", "th"); //niz sufiksa datuma, koristi se u slajdovima, osnovnim_načinima i načinima džumbl. e,g, 1st 2nd ... //definirajte konstante #definirajte NUM_DISPLAY_MODES 3 // Načini prikaza brojeva (sadrži nulu kao prvi način) #definirajte NUM_SETTINGS_MODES 4 // Načini postavki brojeva = 6 (sadrži nulu kao prvi način) # definirajte SLIDE_DELAY 20 // Vrijeme u milisekundama za efekt slajda po znaku u modu slajda. Neka ovo bude veće za sporiji učinak #define cls clear_display // Čisti prikaz RTC_DS1307 ds1307; // Stvaranje RTC objekta Button buttonA = Button(2, BUTTON_PULLUP); // Postavljanje gumba A (koristeći biblioteku gumba) Button buttonB = Button(3, BUTTON_PULLUP); // Gumb za postavljanje B (pomoću biblioteke gumba) void setup() ( digitalWrite(2, HIGH); // uključite pullup otpornik za gumb na pinu 2 digitalWrite(3, HIGH); // uključite pullup otpornik za gumb na pinu 3 digitalWrite(4, HIGH); // uključite pullup otpornik za gumb na pinu 4 Serial.begin(9600); //pokrenite serijski //inicijalizirajte 4 matrične ploče //već smo postavili broj uređaja kada smo kreirali uređaji LedControl int = lc.getDeviceCount(); //moramo pokrenuti sve uređaje u petlji za (int adresa = 0; adresa< 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--) ( za (adresa bajta = 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 >> red)) plot(x + stupac, y + red, 1); else plot(x + col, y + row, 0); ) ) ) void putnormalchar(byte x, byte y, char c) (byte točkice; // 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; // strelica selektora clock_mode ) 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 >> red)) ( // samo 7 redaka. iscrtaj(x + stupac, y + red, 1); ) else ( iscrtaj(x + stupac, y + red, 0); ) //) ) ) ) //mali_mod //prikaži vrijeme u malim 3x5 znakovima s prikazom sekundi void small_mode() ( char textchar; // 16 znakova na zaslonu byte mins = 100; //mins byte secs = rtc; //seconds byte old_secs = secs; / /drži staru vrijednost sekundi - od posljednjeg vremena kada su sekunde ažurirane o prikaz - koristi se za provjeru jesu li sekunde promijenile cls(); //pokretanje glavne petlje sata sve dok run_mode vraća true while (run_mode()) ( get_time(); / /provjeri pritisak gumba if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //ako su se sekunde promijenile, ažurirajte ih na zaslonu secs = rtc; if (secs != old_secs) ( //secs char buffer; itoa(secs, buffer, 10); //fix - inače ako num ima početnu nulu, npr. "03" secs, itoa to pokriva znakovima s razmakom "3". ako (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 ujutro u 12-satnom režimu. //izvršite konverziju 12/24 sata ako je ampm postavljen na 1 bajt sati = rtc; if (sati > 12) ( sati = sati - ampm * 12; ) if (sati< 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) ( sati = sati - ampm * 12; ) if (sati< 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) ( sati = sati - ampm * 12; ) if (sati< 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 onda se jedna znamenka ne mijenja ako ((digits_old != digits_new) || (digits_old != digits_new)) ( //promijenite prikazani dan. Petlja ispod prolazi kroz svaki od 3 znaka redom, npr. "MON" za (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" && || (trenutni_c >= "a" && trenutni_c<= "z")) {
// current_c &= 0x1F; // A-Z maps to 1-26
// }
if (current_c >= "A" && struja_c<= "Z") {
current_c &= 0x1F; // A-Z maps to 1-26
}
else if (current_c >= "a" && trenutni_c<= "z") {
current_c = (current_c - "a") + 41; // A-Z maps to 41-67
}
else if (current_c >= "0" && trenutni_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; // strelica selektora clock_mode ) bajt curr_char_row_max = 7 - sekvenca; //maksimalni broj redaka za crtanje je 6 - broj sekvence bajt start_y = sekvenca; //y pozicija za početak - isto je kao broj sekvence. Uključujemo ovu svaku petlju //crtamo svaki redak do maksimuma retka (izračunatog iz broja sekvence) za (bajt 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); //nacrt vodi na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//dodaj jedan u y tako da nacrtamo sljedeći redak jedan prema dolje ) ) //nacrtaj praznu liniju između znakova ako je niz između 1 i 7. Ako to ne učinimo, dobit ćemo ostaci trenutnih znakova zadnja pozicija lijevo na zaslonu ako (sekvenca >= 1 && sekvenca<= 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) ( //odredite char byte točkice; //if (new_c >= "A" && new_c<= "Z" || (new_c >= "a" && novi_c<= "z")) {
// new_c &= 0x1F; // A-Z maps to 1-26
//}
if (new_c >= "A" && novo_c<= "Z") {
new_c &= 0x1F; // A-Z maps to 1-26
}
else if (new_c >= "a" && novi_c<= "z") {
new_c = (new_c - "a") + 41; // A-Z maps to 41-67
}
else if (new_c >= "0" && novi_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; // strelica selektora clock_mode ) byte newcharrowmin = 6 - (sekvenca - 2); //minimalni broj retka za crtanje za novi char - ovo generira izlaz od 6 do 0 kada se dodaju sekvencijski brojevi 2-8 . Ovo je minimalni redak za crtanje za novi bajt znakova start_y = 0; //y položaj od kojeg treba početi - isti je kao broj sekvence. Upisujemo svaki redak //crtamo svaki red prema gore od minimuma retka (izračunato prema broju sekvence ) do 6 za (bajt newcarrow = newcarrowmin; newcarrow<= 6; newcharrow++) {
for (byte col = 0; col < 5; col++) {
dots = pgm_read_byte_near(&myfont);
if (dots & (64 >> newcarrow)) plot(x + col, y + start_y, 1); //nacrt vodi na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//dodaj jedan u y tako da nacrtamo sljedeći redak jedan prema dolje ) ) ) //ispiši sat koristeći riječi umjesto brojeva void word_clock() ( cls(); char numbers = ( "one ", "dva", "tri", "četiri", "pet", "šest", "sedam", "osam", "devet", "deset", "jedanaest", "dvanaest", "trinaest", "četrnaest", "petnaest", "šesnaest", "sedamnaest", "osamnaest", "devetnaest"); char numberstens = ("deset", "dvadeset", "trideset", "četrdeset", "pedeset"); //potencijalno 3 retka za prikaz char str_a; char str_b; char str_c; //bajt sati_y, mins_y; //sati i minute i pozicije za sate i minute linije bajt sati = rtc; if (sati > 12) ( sati = sati - ampm * 12; ) ako (sati< 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) ( sati = sati - 12; ) if (sati == 0) ( sati = 12; ) //podijeliti mins vrijednost u dvije odvojene znamenke int minsdigit = rtc % 10; bajt minsdigitten = (rtc / 10) % 10; //ako je 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)( //provjeri pritisak gumba if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down (); //ispis linije b len = 0; dok (str_b) (len++;); //dobijte duljinu poruke offset_top = (31 - ((len - 1) * 4)) / 2; i = 0; while (str_b[i]) ( puttinychar((i * 4) + offset_top, 1, str_b[i]); i++; ) //zadrži prikaz ali provjeri brojač pritisaka gumba = 1000; while (counter > 0)( if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down() ; //ispiši liniju c ako postoji. duljina = 0; dok (str_c) (len++;); //dobijte duljinu poruke offset_top = (31 - ((len - 1) * 4)) / 2; i = 0; while (str_c[i]) ( puttinychar((i * 4) + offset_top, 1, str_c[i]); i++; ) brojač = 1000; while (brojač > 0)( //provjeri pritisak gumba if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) fade_down(); //drži zaslon praznim, ali prije ponovnog pokretanja provjeri pritiskanje gumba. brojač = 1000; while (brojač > 0)( //provjeri pritisak gumba if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) ) fade_down(); ) /// poruka o pomicanju - trenutno se ne koristi - presporo. void scroll() ( char message = ("Hello There "); cls(); byte p = 6; //trenutni položaj u nizu byte chara = (0, 1, 2, 3, 4, 5); //chara iz niza int x = (0, 6, 12, 18, 24, 30); //xpos za svaki char bajt y = 0; //y pos // clear_buffer(); while (message[p] != "\ 0") ( //nacrtaj svih 6 znakova za (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+offset, 1, buffer); offset = 8; //offset prema središnjem tekstu ako ima 4 znaka) //ispis 2 znaka sufiksa puttinychar(suffixposx+offset, 1, suffix[s) ]); puttinychar(sufiksposx+4+pomak, 1, sufiks[s]); kašnjenje (1000); fade_down(); //ispiši naziv mjeseca //dobijte duljinu teksta u pikselima, na taj način ga možemo centrirati na zaslonu dijeljenjem preostalih piksela b2 i korištenjem toga kao pomaka len = 0; dok(imena mjeseci) (len++;); pomak = (31 - ((len-1)*4)) / 2; //naš pomak za centriranje teksta i = 0; dok(imena mjeseca[i]) ( puttinychar((i*4) +pomak, 1, imena mjeseca[i]); i++; ) kašnjenje(1000); fade_down(); ) //prikaži izbornik za promjenu načina rada sata void switch_mode() ( //zapamti način rada u kojem se nalazimo. Koristimo ovu vrijednost ako idemo u način rada s postavkama, tako da se možemo vratiti iz načina s postavkama (6) u bilo koji način u kojem smo bili in. old_mode = clock_mode; char* modes = ("Basic", "Small", "Slide", "Words", "Setup"); byte next_clock_mode; byte firstrun = 1; //petlja čeka gumb (vrijeme nakon 35 petlje za povratak u mod 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; ) //ispiši strelicu i naziv trenutnog clock_modea u prvom retku i ispis sljedećeg clock_mode naziva u drugom redu char str_top; //strcpy (str_top, "-"); strcpy(str_top, načini); sljedeći_način_sata = način_sata + 1; if (next_clock_mode > NUM_DISPLAY_MODES + 1) ( next_clock_mode = 0; ) byte i = 0; while (str_top[i]) ( putnormalchar(i * 6, 0, str_top[i]); i++; ) firstrun = 0; ) kašnjenje(50); ) ) //pokretanje glavne petlje sata sve dok run_mode vraća pravi bajt run_mode() ( //ako je nasumični način rada uključen... provjerite sat kada mijenjamo način. if (random_mode) ( //ako je vrijednost sata u načinu promjene vrijeme = sati. zatim reurn false = tj. izlaz iz moda. if (change_mode_time == rtc) ( //postavi sljedeći nasumični način rada sata i vrijeme za njegovu promjenu set_next_random(); //izlaz iz trenutnog načina. return 0; ) ) / /else return 1 - nastavi raditi u ovom načinu rada return 1; ) //postavi sljedeći sat kada će sat promijeniti način rada kada je uključen nasumični način rada void set_next_random() ( //postavi sljedeći sat kada će se način rada sata promijeniti - trenutno vrijeme plus 1 - 4 sata get_time(); change_mode_time = rtc + nasumično (1, 5); //ako je change_mode_time sada preko 23, tada ga postavite na između 1 i 3 ujutro if (change_mode_time > 23) ( change_mode_time = nasumično (1 , 4); ) //postavite novi način rada sata clock_mode = random(0, NUM_DISPLAY_MODES + 1); //odaberite novi način rada slučajnog odabira sata ) //prikažite izbornik za promjenu postavki sata void setup_menu() ( char* set_modes = ( "Rndom", "24 sata", "Set", "Brght", "Exit"); if (ampm == 0) ( set_modes = ("12 Hr"); ) byte setting_mode = 0; bajt next_setting_mode; prvo pokretanje bajta = 1; //petlja čeka gumb (vrijeme nakon 35 petlji za povratak u mod 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; ) //ispiši strelicu i naziv trenutnog clock_modea u prvom redu i ispis sljedećeg clock_mode naziva u drugom redu char str_top; strcpy(str_top, set_modes); sljedeći_način_postavke = način_postavke + 1; if (next_setting_mode > NUM_SETTINGS_MODES) ( next_setting_mode = 0; ) bajt i = 0; dok(str_top[i]) ( putnormalchar(i*6, 0, str_top[i]); i++; ) prvo pokretanje = 0; ) kašnjenje(50); ) //odaberite prekidač načina(setting_mode)( slučaj 0: set_random(); break; slučaj 1: set_ampm(); break; slučaj 2: set_time(); break; slučaj 3: set_intensity(); break; slučaj 4: //izlaz iz prekida izbornika; ) //promijenite sat iz moda 6 (postavke) nazad na onaj u kojem je bio prije clock_mode=old_mode; ) //prebacivanje nasumičnog načina rada - odaberite drugi način rada sata svakih nekoliko sati void set_random())( cls(); char text_a = "Isključeno"; char text_b = "Uključeno"; byte i = 0; //ako je nasumični način uključeno, isključi ako (random_mode)( //isključi slučajni način rada random_mode = 0; //ispiši poruku na zaslonu while(text_a[i]) ( putnormalchar((i*6), 0, text_a[i] ) ; i++; ) ) else ( //uključi nasumični način rada. random_mode = 1; //postavljeni sat će se promijeniti set_next_random(); //ispiši poruku na zaslonu while(text_b[i]) ( putnormalchar((i * 6), 0, text_b[i]); i++; ) ) delay(1500); //ostavite poruku na sekundu ili tako nešto ) //postavite 12 ili 24 satni sat void set_ampm() ( // AM/ PM ili 24-satni način rada - okrenite bit (čini 0 u 1 ili 1 u 0 za ampm način) ampm = (ampm ^ 1); cls(); ) //promjena intenziteta zaslona void set_intensity() ( cls() ; byte i = 0; char text = "Bright"; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //pričekajte unos gumba dok ( ! buttonA.uniquePress()) ( traka razine (0,6,(intenzitet*2)+2,2); //prikaži razinu intenziteta kao traku while (buttonB.isPressed()) ( if(intensity == 15) ( intensity = 0; cls (); ) else ( intensity++; ) //ispis nove vrijednosti i = 0; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //prikaži razinu intenziteta kao traku razine (0,6,(intenzitet*2)+ 2,2); //promijenite postavku svjetline na zaslonima za (adresa bajta = 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);
*/
}
Sada, da biste dovršili rad na uređaju, trebate izvršiti samo nekoliko jednostavnih operacija:
Sastavljanje programskog koda i njegovo daljnje učitavanje u memoriju mikrokontrolera će potrajati neko vrijeme, obično ne više od jedne minute. Uspješan završetak operacije bit će izviješten u Arduino IDE konzoli. Nakon čega ostaje samo ponovno pokrenuti Arduino pomoću gumba Reset na uređaju - jednostavan sat na LED matricama je spreman!
Spremni sat na Arduinu
Sat se podešava pomoću dva gumba. Uređaj podržava 12- i 24-satni format vremena, prikazuje datum i dan u tjednu te prikazuje vrijeme sa ili bez sekundi. Također je moguće promijeniti svjetlinu LED dioda.
Vjerojatno ćete htjeti dodati više značajki u budućnosti (na primjer, termometar) ili instalirati uređaj u tijelo vlastitog dizajna - dobri rezultati mogu se postići pomoću strojeva za lasersko rezanje. Ali sada možete sa sigurnošću reći da ste vlastitim rukama sastavili punopravni elektronički sat!
Nedavno se pojavila potreba da imam sat u kući, ali samo elektronski, jer ne volim satove, jer otkucavaju. Imam dosta iskustva u lemljenju i jetkanju krugova. Nakon pretraživanja interneta i čitanja neke literature, odlučio sam odabrati najjednostavniju shemu, jer mi ne treba sat s budilicom.
Odabrao sam ovu shemu jer je jednostavna napravite svoj sat
Počnimo, pa što nam je potrebno da bismo napravili sat vlastitim rukama? Pa, naravno, ruke, vještina (čak ni velika) u čitanju dijagrama strujnog kruga, lemilice i dijelova. Evo kompletnog popisa onoga što sam koristio:
10 MHz kvarc – 1 kom., mikrokontroler ATtiny 2313, otpornici 100 Ohm – 8 kom., 3 kom. 10 kOhm, 2 kondenzatora od 22 pF, 4 tranzistora, 2 gumba, LED indikator 4-bitni KEM-5641-ASR (RL-F5610SBAW/D15). Izveo sam instalaciju na jednostrani PCB.
Ali postoji nedostatak u ovoj shemi: pinovi mikrokontrolera (u daljnjem tekstu MK), koji su odgovorni za kontrolu pražnjenja, primaju prilično pristojno opterećenje. Ukupna struja je mnogo veća od maksimalne struje priključka, ali s dinamičkom indikacijom MK nema vremena za pregrijavanje. Kako bismo spriječili kvar MK, dodamo otpornike od 100 Ohma u krugove pražnjenja.
U ovoj shemi, indikator se kontrolira prema principu dinamičke indikacije, prema kojem se segmenti indikatora kontroliraju signalima iz odgovarajućih izlaza MK. Brzina ponavljanja ovih signala je veća od 25 Hz i zbog toga se čini da svijetljenje indikatorskih brojeva traje neprekidno.
Elektronički satovi izrađeni prema gornjoj shemi može prikazati samo vrijeme (sati i minute), a sekunde su prikazane točkom između segmenata, koji treperi. Za upravljanje načinom rada sata, u njegovoj strukturi nalaze se prekidači s tipkama koji kontroliraju podešavanje sati i minuta. Ovaj krug se napaja iz izvora napajanja od 5V. Tijekom izrade tiskane pločice u krug je uključena 5V zener dioda.
Budući da imam napajanje od 5 V, isključio sam zener diodu iz kruga.
Za izradu ploče, krug je primijenjen pomoću željeza. Odnosno, tiskani krug je ispisan na inkjet pisaču pomoću sjajnog papira; može se uzeti iz modernih sjajnih časopisa. Nakon toga je izrezan tekstolit potrebne veličine. Ispostavilo se da je moja veličina 36*26 mm. Takva mala veličina je zbog činjenice da su svi dijelovi odabrani u SMD paketu.
Ploča je urezana željeznim kloridom (FeCl3). Jetkanje je trajalo oko sat vremena, budući da je kupka s daskom bila na kaminu, visoka temperatura utječe na vrijeme jetkanja, u ploči nije korišten bakar. Ali nemojte pretjerivati s temperaturom.
Dok je proces graviranja trajao, kako ne bih razbijao glavu i pisao firmware za rad sata, otišao sam na Internet i pronašao firmware za ovu shemu. Kako bljeskati MK također se može naći na Internetu. Koristio sam programator koji bljeska samo ATMEGA MK.
I konačno, naša ploča je spremna i možemo početi lemiti naše satove. Za lemljenje vam je potreban lemilo od 25 W s tankim vrhom kako ne biste spalili MK i ostale dijelove. Lemljenje provodimo pažljivo i po mogućnosti prvi put lemimo sve noge MK-a, ali samo odvojeno. Za one koji nisu upućeni, znajte da dijelovi izrađeni u SMD kućištu imaju lim na svojim terminalima za brzo lemljenje.
A ovako izgleda ploča sa zalemljenim dijelovima.
Sjećam se... Prije tridesetak godina šest pokazatelja bilo je malo blago. Svatko tko je tada mogao napraviti sat pomoću TTL logike s takvim indikatorima smatran je sofisticiranim stručnjakom u svom području.
Sjaj indikatora plinskog pražnjenja činio se toplijim. Nakon nekoliko minuta pitao sam se hoće li ove stare lampe raditi i htio sam nešto učiniti s njima. Sada je vrlo lako napraviti takav sat. Sve što trebate je mikrokontroler...
Budući da me u isto vrijeme zanimalo programiranje mikrokontrolera na jezicima visoke razine, odlučio sam se malo poigrati. Pokušao sam konstruirati jednostavan sat koristeći digitalne indikatore pražnjenja plina.
Svrha dizajna
Odlučio sam da sat ima šest znamenki, a da se vrijeme postavlja minimalnim brojem tipki. Osim toga, želio sam pokušati koristiti nekoliko najčešćih obitelji mikrokontrolera različitih proizvođača. Namjeravao sam napisati program u C-u.
Indikatori plinskog pražnjenja zahtijevaju visoki napon za rad. Ali nisam htio imati posla s opasnim mrežnim naponom. Sat je trebao biti napajan bezopasnim naponom od 12 V.
Budući da je moj glavni cilj bila igra, ovdje nećete pronaći opis mehaničkog dizajna ili crteže tijela. Ako želite, možete sami promijeniti sat prema svom ukusu i iskustvu.
Evo što sam dobio:
- Prikaz vremena: HH MM SS
- Indikator alarma: HH MM --
- Način prikaza vremena: 24 sata
- Preciznost ±1 sekunda po danu (ovisno o kvarcnom kristalu)
- Napon napajanja: 12 V
- Potrošnja struje: 100 mA
Dijagram sata
Za uređaj sa šesteroznamenkastim digitalnim zaslonom, multipleks način je bio prirodno rješenje.
Svrha većine elemenata blok dijagrama (slika 1) je jasna bez komentara. U određenoj mjeri, nestandardni zadatak bio je stvoriti pretvarač TTL razina u upravljačke signale indikatora visokog napona. Anodni pokretači izrađeni su pomoću visokonaponskih NPN i PNP tranzistora. Dijagram je posuđen od Stefana Knelera (http://www.stefankneller.de).
74141 TTL čip sadrži BCD dekoder i visokonaponski pokretač za svaku znamenku. Možda će biti teško naručiti jedan čip. (Iako ne znam da li ih itko više radi). Ali ako pronađete indikatore plinskog pražnjenja, 74141 bi mogao biti negdje u blizini :-). U vrijeme TTL logike praktički nije bilo alternative čipu 74141. Pa pokušajte ga negdje pronaći.
Indikatori zahtijevaju napon od oko 170 V. Nema smisla razvijati poseban krug za pretvarač napona, budući da postoji ogroman broj čipova pretvarača pojačanja. Odabrao sam jeftin i široko dostupan IC34063. Krug pretvarača gotovo je u potpunosti kopiran iz podatkovne tablice MC34063. Upravo mu je dodan T13 prekidač napajanja. Interni prekidač nije prikladan za tako visok napon. Koristio sam prigušnicu kao induktivitet za pretvarač. To je prikazano na slici 2; promjer mu je 8 mm, a duljina 10 mm.
Učinkovitost pretvarača je prilično dobra, a izlazni napon relativno siguran. Sa strujom opterećenja od 5 mA, izlazni napon pada na 60 V. R32 djeluje kao otpornik koji očitava struju.
Za napajanje logike koristi se linearni regulator U4. Na krugu i pločici postoji prostor za pomoćnu bateriju. (3,6 V - NiMH ili NiCd). D7 i D8 su Schottky diode, a otpornik R37 je dizajniran da ograniči struju punjenja prema karakteristikama baterije. Ako gradite satove samo iz zabave, neće vam trebati baterije D7, D8 i R37.
Konačni krug je prikazan na slici 3.
Tipke za podešavanje vremena spojene su preko dioda. Stanje gumba provjerava se postavljanjem logičke "1" na odgovarajući izlaz. Kao bonus značajka, piezo emiter je spojen na izlaz mikrokontrolera. Da utišate to gadno škripanje, upotrijebite mali prekidač. Za to bi bio sasvim prikladan čekić, ali ovo je krajnja opcija :-).
Popis komponenti strujnog kruga, crtež PCB-a i dijagram rasporeda mogu se pronaći u odjeljku "Preuzimanja".
CPU
Gotovo svaki mikrokontroler s dovoljnim brojem pinova, čiji je minimalni potrebni broj naveden u tablici 1, može upravljati ovim jednostavnim uređajem.
Stol 1.
|
Funkcija
|
zaključke
|
Prehrana |
2
|
Kvarcni rezonator |
2
|
Upravljanje anodama |
6
|
Vozač 74141 |
4
|
Gumb za unos |
1
|
Piezo emiter |
1
|
Ukupno |
16
|
|
Svaki proizvođač razvija vlastite obitelji i tipove mikrokontrolera. Položaj igala je individualan za svaku vrstu. Pokušao sam dizajnirati univerzalnu ploču za nekoliko vrsta mikrokontrolera. Ploča ima 20-pinsku utičnicu. S nekoliko premosnih žica možete ga prilagoditi različitim mikrokontrolerima.
Mikrokontroleri testirani u ovom krugu navedeni su u nastavku. Možete eksperimentirati s drugim vrstama. Prednost sheme je mogućnost korištenja različitih procesora. Radioamateri, u pravilu, koriste jednu familiju mikrokontrolera i imaju pripadajući programator i programske alate. Mogući su problemi s mikrokontrolerima drugih proizvođača, pa sam vam dao priliku da odaberete procesor iz svoje omiljene obitelji.
Sve specifičnosti uključivanja različitih mikrokontrolera prikazane su u tablicama 2...5 i slikama 4...7.
Tablica 2.
|
Freescale
|
|
Tip |
MC68HC908QY1 |
Kvarcni rezonator |
12 MHz |
Kondenzatori C1, C2 |
22 pF |
Program |
freescale.zip (pogledajte odjeljak "Preuzimanja") |
postavke |
—
|
|
Napomena: Otpornik od 10 MΩ spojen je paralelno s kvarcnim rezonatorom.
Tablica 3.
|
Mikročip
|
|
Tip |
PIC16F628A |
Kvarcni rezonator |
32,768 kHz |
Kondenzatori C1, C2 |
22 pF |
Program |
pic628.zip (pogledajte odjeljak "Preuzimanja") |
postavke |
Int. 4 MHz generator - I/O RA6, MCLR ISKLJUČEN, WDT ISKLJUČEN, LVP ISKLJUČEN, BROUT ISKLJUČEN, CP ISKLJUČEN, PWRUP ISKLJUČEN |
|
Napomena: Mikrokrug mora biti rotiran za 180° u utičnici.
Tablica 4.
|
Atmel
|
|
Tip |
ATtiny2313 |
Kvarcni rezonator |
12 MHz |
Kondenzatori C1, C2 |
15 pF |
Program |
attiny.zip (pogledajte odjeljak "Preuzimanja") |
postavke |
trg 8 MHz oscilator, RESET ON |
|
Napomena: dodajte SMD komponente R i C na pin RESET (10 kΩ i 100 nF).
Tablica 5.
|
Atmel
|
|
Tip |
AT89C2051 |
Kvarcni rezonator |
12 MHz |
Kondenzatori C1, C2 |
22 pF |
Program |
at2051.zip (pogledajte odjeljak "Preuzimanja") |
postavke |
--
|
|
Napomena: dodajte SMD komponente R i C na pin RESET (10 kΩ i 100 nF); spojite pinove označene zvjezdicama na sabirnicu napajanja +Ub preko SMD otpornika od 3,3 kOhm.
Kada usporedite kodove za različite mikrokontrolere, vidjet ćete da su vrlo slični. Postoje razlike u pristupu portovima i definiranju funkcija prekida, kao iu tome što ovisi o hardverskim komponentama.
Izvorni kod se sastoji od dva dijela. Funkcija glavni() konfigurira portove i pokreće mjerač vremena koji generira signale prekida. Nakon toga program skenira pritisnute gumbe i postavlja odgovarajuće vrijeme i vrijednosti alarma. Tamo se u glavnoj petlji trenutno vrijeme uspoređuje s budilicom i uključuje se piezo emiter.
Drugi dio je potprogram za rukovanje prekidima timera. Potprogram koji se poziva svake milisekunde (ovisno o mogućnostima mjerača vremena) povećava vremenske varijable i kontrolira znamenke na zaslonu. Osim toga, provjerava se status gumba.
Pokretanje kruga
Prilikom instaliranja komponenti i postavljanja, počnite s izvorom napajanja. Zalemite U4 regulator i okolne komponente. Provjerite napon od 5 V za U2 i 4,6 V za U1. Sljedeći korak je sastavljanje visokonaponskog pretvarača. Pomoću otpornika za podešavanje R36 postavite napon na 170 V. Ako raspon podešavanja nije dovoljan, malo promijenite otpor otpornika R33. Sada instalirajte U2 čip, tranzistore i otpornike kruga anode i digitalnog pogona. Spojite ulaze U2 na sabirnicu GND i spojite jedan od otpornika R25 - R30 u seriju na sabirnicu napajanja +Ub. Brojevi indikatora trebaju svijetliti na odgovarajućim mjestima. U posljednjoj fazi provjere kruga, spojite pin 19 mikro kruga U1 na masu - piezo emiter bi trebao dati zvučni signal.
Izvorne kodove i kompajlirane programe pronaći ćete u odgovarajućoj ZIP datoteci u odjeljku "Preuzimanja". Nakon učitavanja programa u mikrokontroler, pažljivo provjerite svaki pin u položaju U1 i postavite potrebne žice i zalemite kratkospojnike. Pogledajte gornje slike mikrokontrolera. Ako je mikrokontroler ispravno programiran i spojen, njegov generator bi trebao proraditi. Možete postaviti vrijeme i alarm. Pažnja! Na ploči ima mjesta za još jedan gumb - ovo je rezervni gumb za buduća proširenja :-).
Provjerite točnost frekvencije generatora. Ako nije unutar očekivanog raspona, malo promijenite vrijednosti kondenzatora C1 i C2. (Male kondenzatore lemiti paralelno ili ih zamijeniti drugima). Točnost sata trebala bi se poboljšati.
Zaključak
Mali 8-bitni procesori sasvim su prikladni za jezike visoke razine. C izvorno nije bio namijenjen malim mikrokontrolerima, ali za jednostavne aplikacije možete ga sasvim dobro koristiti. Asemblerski jezik je prikladniji za složene zadatke koji zahtijevaju kritična vremena ili maksimalno opterećenje CPU-a. Za većinu radioamatera prikladne su i besplatne i shareware ograničene verzije C prevodioca.
C programiranje je isto za sve mikrokontrolere. Morate poznavati hardverske funkcije (registri i periferija) odabranog tipa mikrokontrolera. Budite oprezni s operacijama s bitovima - jezik C nije prikladan za manipulaciju pojedinačnim bitovima, kao što se može vidjeti na primjeru originala kada je za ATtiny.
Jesi li gotov? Zatim se uključite u promatranje vakuumskih cijevi i gledajte...
...stari dani su se vratili... :-)
Napomena urednika
Potpuni analog SN74141 je mikro krug K155ID1, koji proizvodi Minsk Integral softver.
Mikrokrug se lako može pronaći na Internetu.
Koncept sata s velikim brojevima
Strukturno, uređaj će se sastojati od dvije ploče - jedna iznad druge. Prva ploča je matrica LED dioda koje formiraju sate i minute, druga je energetski dio (LED kontrola), logika i napajanje. Ovaj će dizajn sat učiniti kompaktnijim (bez kućišta, otprilike 22 cm x 9 cm, debljine 4-5 centimetara) + omogućit će zavrtanje matrice na drugi projekt ako nešto pođe po zlu.
Energetski dio će biti izgrađen na bazi UL2003 drajvera i tranzistorskih sklopki. Logično - na Atmega8 i DS1307. Napajanje: 220V - transformator; logika 5V (preko 7805), dio napajanja - 12V (preko LM2576ADJ). Tu će biti i poseban pretinac za 3V bateriju za autonomno napajanje sata realnog vremena - DS1307.
Razmišljam koristiti Atmega8 i DS1307 (planiram objesiti sat na strop, tako da u slučaju nestanka struje ne moram svaki put petljati po postavkama), međutim, izgled ploče će podrazumijevati mogućnost rada uređaja bez DS1307 (prvi put, a možda i zauvijek - kako će raditi).
Dakle, ovisno o konfiguraciji, algoritam rada satnog programa bit će sljedeći:
Atmega8– brojač vremena pomoću mjerača vremena. Rad u ciklusu bez pauza: prozivanje tipkovnice, podešavanje vremena (ako je potrebno), prikaz 4 znamenke i separatora.
Atmega8+DS1307. Rad u ciklusu bez pauza: prozivanje tipkovnice, podešavanje vremena DS1307 (ako je potrebno), očitavanje vremena sa DS1307, prikaz 4 znamenke i razdjelnik. Ili druga opcija - čitanje iz DS1307 na tajmeru, ostalo u petlji (još ne znam kako najbolje).
Segment se sastoji od 4 crvene LED diode povezane u seriju. Jedna znamenka – 7 segmenata sa zajedničkom anodom. Ne planiram odvajati segmente pomoću obrasca osmice, kao što se radi u konvencionalnim indikatorima.
Energetski dio sata
Energetski dio sata izgrađen je na UL2003 drajveru i tranzistorskim sklopkama VT1 i VT2.
UL2003 je odgovoran za kontrolu segmenata indikatora, tipke su za kontrolu znamenki.
Satni i minutni separator se upravlja odvojeno (signal K8).
Segmentima, bitovima i separatorom upravlja mikrokontroler primjenom pozitivnog potencijala (tj. primjenom +5V) na K1-K8, Z1-Z4.
Signali segmentima i bitovima moraju se isporučivati sinkrono i s određenom frekvencijom kako bi se osigurao dinamički izlaz informacija (sati i minute).
Tranzistor BCP52 može se koristiti kao tranzistor VT1 (BCP53).
Shema pogonskog dijela sata s velikim brojevima
Tiskana pločica sedmosegmentnog indikatora za sat s velikim brojevima
Kao što sam ranije rekao, sat će se sastojati od dvije tiskane pločice - indikatorska ploča + logika i energetski dio.
Počnimo s dizajnom i proizvodnjom ploče s indikatorskim krugom.
Izrada tiskane pločice za sedmosegmentni indikator za sat s velikim brojevima
Tiskana pločica sedmosegmentnog indikatora za sat s velikim brojevima u "lay" formatu nalazi se na kraju članka, u priloženim datotekama. Možete pročitati o tehnologiji izrade tiskanih pločica LUT metodom.
Ako ste sve učinili ispravno, gotova PCB će izgledati otprilike ovako.
Gotova tiskana pločica sedmosegmentnog indikatora za sat s velikim brojevima
Montaža sedmosegmentnog indikatora
Budući da je indikatorska ploča dvostrana, prvo što treba učiniti je napraviti međuslojne prijelaze. To radim pomoću nogu nepotrebnih dijelova - provlačim ih kroz rupe i lemim s obje strane. Kad su svi prijelazi dovršeni, očistim ih ravnom, finom turpijom - ispadne vrlo uredno i lijepo.
Međuslojne bočice na indikatorskoj ploči
Sljedeći korak je zapravo sastavljanje indikatora. Zašto nam treba paket crvenih (zelenih, bijelih, plavih) LED dioda. Na primjer, uzeo sam ove.
Priprema za sastavljanje indikatora
Prilikom ugradnje dioda ne zaboravite da izrađujemo indikator sa zajedničkom anodom - tj. "+" diode moraju biti spojene zajedno. Uobičajene anode na PCB-u su veliki komadi bakra. Obavezno obratite pozornost na anodu s razdjelnom točkom.
Položaj anoda na tiskanoj ploči indikatora
Kao rezultat, nakon 2 sata mukotrpnog rada trebali biste dobiti ovo:
Indikator sa sedam segmenata
Digitalni dio sata
Sastavit ćemo digitalni dio sata s velikim brojevima prema sljedećoj shemi:
Dijagram sata s velikim brojevima
Krug sata je prilično transparentan, tako da ne vidim smisla objašnjavati kako radi. Tiskanu pločicu u *.lay formatu možete preuzeti na kraju članka. Imajte na umu da je tiskana ploča uglavnom dizajnirana za dijelove za površinsku montažu.
Dakle, baza elemenata koju sam koristio:
1. Diodni most DFA028 (bilo koji kompaktni za površinsku montažu će učiniti);
2. Regulatori napona LM2576ADJ u kućištu D2PAK, 78M05 u kućištu HSOP3-P-2.30A;
3. Tranzistorske sklopke BCP53 (kućište SOT223) i BC847 (kućište SOT23);
4. Atmega8 mikrokontroler (TQFP);
5. Sat realnog vremena DS1307 (SO8);
6. Napajanje 14V 1.2A iz nekog starog uređaja;
7. Ostali dijelovi su bilo koje vrste, prikladne veličine za ugradnju na tiskanu ploču.
Naravno, ako želite koristiti druge pakete dijelova, morat ćete napraviti neke promjene na PCB-u.
Obratite pozornost na vrijednosti otpora R3 i R4 - one moraju biti točno onako kako je naznačeno na dijagramu - ni više, ni manje. Ovo je učinjeno kako bi se osiguralo točno 12 V na izlazu regulatora napona LM2576ADJ. Ako i dalje ne možete pronaći takve vrijednosti otpornika, tada se vrijednost otpora R4 može izračunati pomoću formule:
R4=R3(12/1,23-1) ili R4=8,76R3
Sastavljanje digitalnog dijela. Verzija 1, bez DS1307
Ako ste se prilikom izrade tiskane pločice za sat pridržavali preporuka navedenih u, onda je suvišno podsjetiti da je prije montaže tiskanu pločicu potrebno izbušiti, ukloniti sve vidljive kratke spojeve na njoj i ploča mora biti prekrivena tekućim kolofonijem? Zatim počinjemo sastavljati sat.
Preporučam započeti sa sastavljanjem napajanja pa tek onda instalirati digitalni dio. Ovo je opća preporuka za samostalnu montažu uređaja. Zašto? Jednostavno zato što ako je napajanje sastavljeno s greškom, možete spaliti svu niskonaponsku elektroniku koja bi se trebala napajati ovim napajanjem.
Ako je sve učinjeno ispravno, napajanje bi trebalo odmah raditi. Provjeravamo sklop napajanja - mjerimo napon na ispitnim točkama.
Slika prikazuje ispitne točke na kojima treba provjeriti napon napajanja. Ako napon odgovara deklariranom, možete početi sastavljati digitalni dio sata. Inače, vršimo provjeru ugradnje i funkcionalnosti napojnih elemenata.
Ispitne točke i vrijednosti napona za napajanje sata
Nakon provjere napajanja, prelazimo na montažu digitalnog dijela sata - ugradnju svih ostalih elemenata na tiskanu pločicu. Provjeravamo kratke spojeve, posebno u nogama Atmega mikrokontrolera i UL2003 drajvera.
Ugradnja digitalnog dijela sata
Imajte na umu da sastavljamo sat BEZ instaliranja DS1307 sata stvarnog vremena, međutim, sve ožičenje ovog čipa mora biti dovršeno. U budućnosti, ako se ukaže potreba, to će nam uštedjeti vrijeme na modificiranju sata za drugu verziju, gdje će se i dalje koristiti zasebni, neovisni sat stvarnog vremena na DS1307.
Preliminarno testiranje mikrokontrolera ATMEGA8
Za provjeru ispravnosti i funkcionalnosti mikrokontrolera potrebno nam je:
1. Programer, na primjer.
2. za unutarkružno programiranje mikrokontrolera.
3. AVRDUDESHELL program.
Spojimo ploču sata na podatkovni kabel. Spojimo podatkovni kabel na programator. Programator za računalo na kojem je instaliran program AVRDUDESHELL. Ploča sata ne bi trebala biti spojena na napajanje od 220 V.
Uspješno očitavanje podataka iz mikrokontrolera programom AVRDUDESHELL
Ako se pojave problemi pri očitavanju osigurača, provjerite instalaciju - možda negdje postoji kratki spoj ili "nedostaje spoj". Još jedan savjet - možda je mikrokontroler u načinu programiranja male brzine, tada jednostavno prebacite programator u ovaj način rada (