בַּיִת · בְּרִיאוּת · שעון רחוב LED עשה זאת בעצמך. שעון יד תוצרת בית. שעון מוכן ב-Arduino

שעון רחוב LED עשה זאת בעצמך. שעון יד תוצרת בית. שעון מוכן ב-Arduino

עם תצוגה דינמית. אין תלונות על פעולת השעון: תנועה מדויקת, הגדרות נוחות. אבל חסרון אחד גדול הוא שקשה לראות את מחווני ה-LED בשעות היום. כדי לפתור את הבעיה, עברתי לתצוגה סטטית ולדים בהירים יותר. כמו תמיד עם תוכנה, תודה רבה ל-Soir. באופן כללי, אני מביא לידיעתכם שעון חיצוני גדול עם תצוגה סטטית פונקציות ההגדרות נשארות כמו בשעונים הקודמים.

יש להם שני תצוגות - הראשית (בחוץ ברחוב) והעזרה על מחוונים - בתוך הבית, על גוף המכשיר. בהירות גבוהה מושגת באמצעות נוריות LED בהירות במיוחד, עם זרם הפעלה של 50mA, ושבבי דרייבר.

דיאגרמת מעגל של שעון אלקטרוני חיצוני עם נוריות LED בהירות

כדי להבהב את קושחת הבקר עם קבצים ולהשתמש בהגדרות הנתיכים הבאות:

מעגלים מודפסים של השעון, יחידת הבקרה והמודול החיצוני, בפורמט LAY, .


תכונות של מעגל שעון זה:

- פורמט תצוגת זמן של 24 שעות.
- תיקון דיגיטלי של דיוק שבץ.
- שליטה מובנית על ספק הכוח הראשי.
- זיכרון מיקרו-בקר לא נדיף.
- יש מדחום שמודד טמפרטורה בטווח של -55 - 125 מעלות.
- ניתן להציג לסירוגין מידע על זמן וטמפרטורה על המחוון.


לחיצה על הלחצן SET_TIME מעבירה את המחוון במעגל ממצב השעון הראשי (המציג את השעה הנוכחית). בכל המצבים, לחיצה על כפתורי הפלוס/מינוס מבצעת התקנה מואצת. שינויים בהגדרות 10 שניות לאחר שינוי הערך האחרון ייכתבו לזיכרון לא נדיף (EEPROM) וייקראו משם כאשר המתח יופעל שוב.


יתרון גדול נוסף של האפשרות המוצעת הוא שהבהירות השתנתה, כעת במזג אוויר שטוף שמש הבהירות מצוינת. מספר החוטים ירד מ-14 ל-5. אורך החוט לתצוגה הראשית (בחוץ) הוא 20 מטר. אני מרוצה מהביצועים של השעון האלקטרוני התברר כשעון פונקציונלי לחלוטין - גם ביום וגם בלילה. בברכה, סויר-אלכסנדרוביץ'.

ישנן דרכים רבות להרכיב שעון אלקטרוני במו ידיך: דיאגרמות מוצגות באופן נרחב בספרות ובאינטרנט. רוב ההטמעות המודרניות מבוססות על מיקרו-בקרים. יישום פרויקטים מסוג זה דורש לרוב מיומנויות מעשיות נרחבות וידע תיאורטי בתחום האלקטרוניקה: יכולת להשתמש בתוכנות מיוחדות, ליצור מעגלים מודפסים בבית באמצעות תחריט כלוריד ברזל והלחמה טובה. אתה צריך גם מגוון של כלים ואספקה.

עם זאת, ישנה דרך פשוטה ומשתלמת להרכיב שעון אלקטרוני במו ידיכם בבית: השתמשו בפלטפורמת Arduino. זהו מתחם תוכנה וחומרה שתוכנן במיוחד להוראת היסודות של תכנות ואלקטרוניקה. בעזרת Arduino, כל אחד, גם ללא הכשרה מוקדמת מיוחדת, יכול לבנות במו ידיו שעון אלקטרוני: אין צורך בדיאגרמות מעגלים, תוכניות הנדסיות ואפילו מלחם!

החיבור של כל הרכיבים האלקטרוניים מתבצע על לוח מגע מיוחד ("ללא הלחמה"), אשר מבטל את הסיכון לכוויות, חתכים ופציעות אחרות - לכן, אתה יכול לעבוד עם מעצב Arduino יחד עם ילדים. דרך ויזואלית להצגת דיאגרמת מעגלים תעזור לך להימנע מטעויות בעת הרכבת המכשיר.

שלב 1. רשימת רכיבים

כדי להרכיב שעון פשוט על מטריצות LED תצטרך רק כמה רכיבים זולים:

  • פלטפורמת ארדואינו. הדגמים הפשוטים ביותר יצליחו - או מיקרו;
  • לוח לחם קשר;
  • חוטי חיבור ללוח לחם;
  • מודול שעון זמן אמת Adafruit DS3231;
  • מודול מטריצת LED 32x8 MAX7219;
  • שני כפתורים.

תזדקק גם למחשב אישי וכבל USB-מיני-USB כדי לטעון את תוכנית הבקרה לזיכרון. זה הכל – אין צורך במלחם, בפסילות בידוד, בסכיני הרכבה וכלים מקצועיים נוספים: כל הפעולות מתבצעות ביד. אולי במקרים מסוימים נוח יותר להשתמש בפינצטה, אבל אתה יכול להסתדר בלעדיה.


שלב 2. הרכבת המעגל האלקטרוני

המעגל של שעון אלקטרוני עם חיווי LED באמצעות Arduino ייראה די פשוט גם עבור חובבי רדיו חסרי ניסיון. נדרשים רק כמה חוטים להרכבה. טבלת חיבור:

מודול Arduino → 32x8 MAX7219 LED מטריצת

מודול Arduino → Adafruit DS3231 שעון זמן אמת

מודול Arduino → כפתורים

D2 - כפתור 1

D3 - כפתור 2

הפין השני של הכפתורים מחובר ל-GND.

אתה רק צריך לשים לב ולזכור איך חורי המגע על לוח הלחם מחוברים זה לזה. התרשים הבא ממחיש את שיטת החיבור הפנימי של חורי מגע:


שתי שורות (1 ו-4) משני הצדדים מקוצרות אופקית - הן משמשות בדרך כלל כקו מתח +5V והארקת GND. כל המגעים הפנימיים (2 ו-3) סגורים אנכית. במקרה זה, המעגל מחולק הן אנכית והן אופקית לשני חלקים סימטריים בלתי תלויים זה בזה. זה מאפשר, למשל, להרכיב שני מכשירים שונים על לוח אחד.

התרשים של שעון אלקטרוני עם חיווי LED, כמו גם סידור האלמנטים על המעגל, מוצג באיור:

בדוק בזהירות שכל החיבורים תואמים לתרשים המוצג. כמו כן ודא שהמוליכים מאובטחים היטב בחורי המגע של המעגל.


שלב 3. קושחה של Arduino

לאחר השלמת ההרכבה והבדיקה של המעגל, אתה יכול להתחיל לטעון את תוכנית הבקרה (או "קושחה") לזיכרון Arduino.


כדי לעשות זאת, עליך להתקין את סביבת הפיתוח הרשמית החינמית - . תצטרכו גם את קוד המקור של הפרויקט, אותו תוכלו להוריד למטה בארכיון עם כל הספריות וסקיצה, ואם תצטרכו רק סקיצה, תוכלו להעתיק אותה בנפרד:

//include ספריות: #include "LedControl.h" #include // ספריית גופנים #include // שעון DS1307 #include "RTClib.h" // שעון DS1307 #include // ספריית לחצנים מאת Alexander Brevig // Setup LED Matrix // פין 12 מחובר ל-DataIn בתצוגה // פין 11 מחובר ל-CLK בתצוגה // פין 10 מחובר ל-LOAD בתצוגה LedControl lc = LedControl(6, 5, 4, 4); //מגדיר את 3 הפינים כ-12, 11 ו-10 ולאחר מכן מגדיר 4 תצוגות (מקסימום הוא 8 תצוגות) //משתנים גלובליים בתים עוצמה = 7; // ברירת מחדל של עוצמת/בהירות (0-15) byte clock_mode = 0; // מצב שעון ברירת מחדל. ברירת מחדל = 0 (basic_mode) bool random_mode = 0; // הגדר מצב אקראי - משנה את סוג התצוגה כל כמה שעות. ברירת מחדל = 0 (כבוי) byte old_mode = clock_mode; // מאחסן את מצב השעון הקודם, כך שאם נלך לתאריך או משהו כזה, אנחנו יודעים לאיזה מצב לחזור אחרי. bool ampm = 0; // הגדר זמן של 12 או 24 שעות. 0 = 24 שעות. 1 = 12 שעות byte change_mode_time = 0; // מחזיק שעה כאשר מצב השעון ישתנה בפעם הבאה אם ​​במצב אקראי. זמן השהיה ארוך לא חתום = 500; // אנחנו תמיד מחכים קצת בין עדכונים של ה-display int rtc; // מחזיק פלט שעון זמן אמת char days = ( "יום ראשון", "יום שני", "ג'", "ד'", "ה'", "שישי", "שבת" ); //day array - משמש במצבי שקופיות, basic_mode ו-Baby mode (ה-DS1307 מוציא 1-7 ערכים ליום בשבוע) char daysfull = ("יום ראשון", "שני", "שלישי", "רביעי", "חמישי ", "שישי", "שבת"); סיומת char = ("st", "nd", "rd", "th" ); //מערך סיומת תאריך, בשימוש במצבי שקופית, בסיסי_מצב וערבוב. e,g, 1st 2nd ... //define constants #define NUM_DISPLAY_MODES 3 // מצבי הצגת מספרים (מתאפיין באפס כמצב הראשון) #define NUM_SETTINGS_MODES 4 // מצבי הגדרות מספר = 6 (המתאפיין באפס כמצב הראשון) # הגדר SLIDE_DELAY 20 // הזמן באלפיות שניות עבור אפקט השקופיות לכל תו במצב שקופיות. הגדל את זה כדי לקבל אפקט איטי יותר #define cls clear_display // Clear display RTC_DS1307 ds1307; // צור אובייקט RTC Button buttonA = Button(2, BUTTON_PULLUP); // כפתור Setup A (באמצעות ספריית לחצנים) Button buttonB = Button(3, BUTTON_PULLUP); // כפתור Setup B (באמצעות ספריית לחצנים) void setup() ( digitalWrite(2, HIGH); // הפעל נגד pullup עבור כפתור בפין 2 digitalWrite(3, HIGH); // הפעל נגד pullup עבור כפתור על פין 3 digitalWrite(4, HIGH); // הפעל נגד pullup עבור כפתור על פין 4 Serial.begin(9600); התקני LedControl int = lc.getDeviceCount( //עלינו להפעיל את כל ההתקנים בלולאה עבור (כתובת int = 0; כתובת< 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--) ( עבור (כתובת בייט = 0; כתובת< 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" && ג<= "Z" || (c >= "א" && ג<= "z")) { c &= 0x1F; // A-Z maps to 1-26 } else if (c >= "0" && ג<= "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 >> שורה)) plot(x + col, y + row, 1);<= "Z" || (c >= "א" && ג<= "z")) { // c &= 0x1F; // A-Z maps to 1-26 // } if (c >= "A" && ג<= "Z") { c &= 0x1F; // A-Z maps to 1-26 } else if (c >= "א" && ג<= "z") { c = (c - "a") + 41; // A-Z maps to 41-67 } else if (c >= "0" && ג<= "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 == ">else plot(x + col, y + row, 0);<= -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 >) ) ) void putnormalchar(byte x, byte y, char c) ( byte dots; // if (c >= "A" && c<= 31) && (y >") ( c = 30; // clock_mode selector arrow ) else if (c >= -80 && c<= 7)){ if (dots & (64 >= 0) && (x< 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 ->= 0) && (י< 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 >> שורה)) ( // רק 7 שורות. plot(x + col, y + row, 1); ) else ( plot(x + col, y + row, 0); ) //) ) ) ) //small_mode //הצג את הזמן בתווים קטנים של 3x5 עם שניות תצוגה void small_mode() ( char textchar; // 16 התווים בתצוגה byte mins = 100; //mins byte secs = rtc; //seconds byte old_secs = secs; / /מחזיק ערך שניות ישן - מהפעם האחרונה שהשניות עודכנו בתצוגה - משמש כדי לבדוק אם שניות שינו את cls(); //run clock main loop כל עוד run_mode מחזירה true while (run_mode()) (get_time(); / /check for button press if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //if secs change אז עדכן אותם בתצוגה secs = rtc; if (secs != old_secs) ( //secs char buffer; itoa(secs, buffer, 10); //fix - אחרת אם ל-num יש אפס מוביל, למשל "03" שניות, itoa מכסה את זה לתווים עם רווח "3".if(secs< 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 >> שורה)) ( // רק 7 שורות. plot(x + col, y + row, 1); ) else ( plot(x + col, y + row, 0); ) //) ) ) ) //small_mode //הצג את הזמן בתווים קטנים של 3x5 עם שניות תצוגה void small_mode() ( char textchar; // 16 התווים בתצוגה byte mins = 100; //mins byte secs = rtc; //seconds byte old_secs = secs; / /מחזיק ערך שניות ישן - מהפעם האחרונה שהשניות עודכנו בתצוגה - משמש כדי לבדוק אם שניות שינו את cls(); //run clock main loop כל עוד run_mode מחזירה true while (run_mode()) (get_time(); / /check for button press if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //if secs change אז עדכן אותם בתצוגה secs = rtc; if (secs != old_secs) ( //secs char buffer; itoa(secs, buffer, 10); //fix - אחרת אם ל-num יש אפס מוביל, למשל "03" שניות, itoa מכסה את זה לתווים עם רווח "3".if(secs< 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 ->1:00 לפנות בוקר במצב 12 שעות.<=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 >//עשה המרה של 12/24 שעות אם ampm מוגדר ל-1 byte hours = rtc;<=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 >if (שעות > 12) ( שעות = שעות - אמפר * 12; ) if (שעות<= "z")) { // current_c &= 0x1F; // A-Z maps to 1-26 // } if (current_c >12) ( שעות = שעות - אמפר * 12; ) if (שעות<= "Z") { current_c &= 0x1F; // A-Z maps to 1-26 } else if (current_c >01 בפברואר אז ספרה אחת לא משתנה אם ((digits_old != digits_new) || (digits_old != digits_new)) ( //שנה את היום המוצג. הלולאה למטה עוברת דרך כל אחד משלושת התווים בתורו, למשל "MON" עבור (byte day_char = 0; day_char<= "z") { current_c = (current_c - "a") + 41; // A-Z maps to 41-67 } else if (current_c >= 6; i--)( if (digits_old[i] != digits_new[i]) ( for (byte seq = 0; seq<= "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 == ">= "A" && || (current_c >= "a" && current_c<= 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); //plot led on else plot(x + col, y + start_y, 0); //else plot off ) start_y++;//הוסף אחד ל-y כך נצייר שורה אחת למטה ) ) //שריר קו ריק בין התווים אם הרצף הוא בין 1 ל-7. אם לא נעשה זאת נקבל שאריות המיקום האחרון של התווים הנוכחיים שנותרו בתצוגה אם (רצף >= 1 && רצף<= 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) ( //לפתור נקודות בתים של char; //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; // clock_mode selector arrow ) byte newcharrowmin = 6 - (רצף - 2); //מינימום שורה num לצייר עבור char חדש - זה יוצר פלט של 6 עד 0 כאשר מוזנים מספרי רצף 2-8 . זו השורה המינימלית לצייר עבור ה-char byte start_y = 0; זהה למספר הרצף שאנו מגדילים אותו בכל שורה ) ) עד 6 עבור (בייט 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); //plot led on else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//הוסף אחד ל-y אז נצייר את השורה הבאה אחת למטה ) ) ) //מדפיס שעון באמצעות מילים ולא מספרים void word_clock() ( cls(); char numbers = ( "one ", "שתיים", "שלוש", "ארבע", "חמש", "שש", "שבע", "שמונה", "תשע", "עשר", "אחת עשרה", "שתים עשרה", "שלוש עשרה", "ארבע עשרה", "חמש עשרה", "שש עשרה", "שבע עשרה", "שמונה עשרה", "תשע עשרה" ; //באפשרות 3 שורות להצגת char str_c; //byte hours_y, mins_y;< 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) ( שעות = שעות - 12; ) if (שעות == 0) ( שעות = 12; ) //split mins value up לשתי ספרות נפרדות int minsdigit = rtc % 10;<= 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 >byte minsdigitten = (rtc / 10) % 10;<= 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)( //בדוק אם יש לחיצה על הלחצן if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down ();< 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 to center text if 4 Chars ) //הדפס את 2 תווי הסיומת puttinychar(suffixposx+offset, 1, suffix[s] ]);< 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; ) //הדפס את שם החץ ואת שם השעון_מצב הנוכחי בשורה הראשונה והדפיס את שם ה-clock_mode הבא בשורה שתיים char str_top;< 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; ) //הדפס את שם החץ ואת שם מצב השעון הנוכחי בשורה הראשונה והדפס את שם השעון הבא בשורה שתיים char str_top;< 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); */ }

strcpy(str_top, set_modes);


הידור של קוד התוכנית וטעינתו נוספת לזיכרון המיקרו-בקר ייקח זמן מה, בדרך כלל לא יותר מדקה אחת. סיום הפעולה המוצלח ידווח בקונסולת Arduino IDE. לאחר מכן כל שנותר הוא לאתחל את הארדואינו באמצעות כפתור ה-Reset במכשיר - שעון פשוט על מטריצות LED מוכן!

שעון מוכן ב-Arduino

השעון מכוון באמצעות שני כפתורים. המכשיר תומך בפורמטים של 12 ו-24 שעות, מציג את התאריך והיום בשבוע ומציג את השעה עם או בלי שניות. אפשר גם לשנות את בהירות הנוריות.


סביר להניח שתרצו להוסיף תכונות נוספות בעתיד (לדוגמה, מדחום), או להתקין את המכשיר בגוף בעיצוב משלכם - ניתן להשיג תוצאות טובות על ידי ייצור במכונות חיתוך בלייזר. אבל עכשיו אתה יכול לומר בבטחה שהרכבת שעון אלקטרוני מן המניין במו ידיך!

אני מציע לחזרה מעגל של שעון אלקטרוני פשוט עם שעון מעורר, המיוצר על סוג PIC16F628A. יתרון גדול של שעון זה הוא מחוון LED מסוג ALS להצגת השעה. באופן אישי, אני די עייף מכל מיני צגי LCD ואני רוצה להיות מסוגל לראות את השעה מכל מקום בחדר, כולל בחושך, ולא רק ישירות עם תאורה טובה. המעגל מכיל מינימום חלקים ובעל יכולת חזרה מעולה. השעון נבדק במשך חודש, מה שהראה את אמינותו וביצועיו. אני חושב על כל התוכניות באינטרנט, זו היא הקלה ביותר להרכיב ולהפעיל.

תרשים סכמטי של שעון אלקטרוני עם שעון מעורר על מיקרו-בקר:


כפי שניתן לראות מתרשים השעון, זהו המיקרו-מעגל היחיד המשמש במכשיר זה. מהוד קוורץ של 4 מגה-הרץ משמש להגדרת תדר השעון. כדי להציג את השעה, נעשה שימוש באינדיקטורים אדומים עם אנודה משותפת. כל מחוון מורכב משתי ספרות עם נקודות עשרוניות. במקרה של שימוש ב-Piezo emitter, ניתן להשמיט את הקבל C1 - 100 μF.

אתה יכול להשתמש בכל מחוון עם אנודה משותפת, כל עוד לכל ספרה יש אנודה משלה. כדי להבטיח שהשעון האלקטרוני נראה בבירור בחושך וממרחק רב, נסו לבחור ALS גדול יותר.


תצוגת השעון דינמית. בזמן נתון מוצגת ספרה אחת בלבד, מה שמאפשר להפחית משמעותית את צריכת הזרם. האנודות של כל ספרה נשלטות על ידי מיקרו-בקר PIC16F628A. המקטעים של כל ארבע הספרות מחוברים יחד, ובאמצעות נגדים מגבילי זרם R1 ... R8, מחוברים למסופים של יציאת MK. מכיוון שהמחוון נדלק מהר מאוד, הריצוד של המספרים הופך לבלתי מורגש.


כפתורים רגעיים משמשים להגדרת דקות, שעות ושעון מעורר. פין 10 משמש כמוצא לאות האזעקה, ומפל של טרנזיסטורים VT1,2 משמש כמגבר. פולט הקול הוא אלמנט פיזואלקטרי מסוג ZP. כדי לשפר את עוצמת הקול, ניתן להחליף אותו ברמקול קטן.


השעון מופעל ממקור 5V מיוצב. זה יכול להיות מופעל גם על ידי סוללות. לשעון 9 מצבי תצוגה. המעבר בין המצבים מתבצע באמצעות הלחצנים "+" ו- "-". לפני הצגת הקריאות עצמן, רמז קצר לגבי שם המצב מוצג על המחוונים. משך הצגת הרמז הוא שנייה אחת.


באמצעות כפתור "תיקון", השעון המעורר עובר למצב הגדרות. במקרה זה, מוצגת הנחיה לטווח קצר למשך חצי שנייה, ולאחר מכן הערך המותאם מתחיל להבהב. תיקון הקריאות מתבצע באמצעות כפתורי "+" ו- "-". כאשר אתה לוחץ על הכפתור במשך זמן רב, מצב החזרה האוטומטית מופעל בתדירות שצוינה. כל הערכים, למעט שעות, דקות ושניות, נכתבים ל-EEPROM ומשוחזרים לאחר מחזור ההפעלה.


אם לא נלחץ על כפתור תוך מספר שניות, השעון האלקטרוני עובר למצב תצוגת זמן. על ידי לחיצה על כפתור "הפעלה/כיבוי" השעון המעורר נדלק או כבה, פעולה זו מאושרת על ידי צליל קצר. כאשר השעון המעורר דולק, הנקודה בספרה מסדר נמוך של המחוון נדלקת. חשבתי איפה לשים את השעון במטבח, והחלטתי להרכיב אותו ישירות לכיריים הגז :) החומר נשלח על ידי in_sane.


דון במאמר שעון מעורר אלקטרוני

שלום חנוני! החלק הראשון של המאמר דן בעקרונות השגת זמן מדויק בשעון תוצרת בית. בואו נלך רחוק יותר ונחשוב איך ועל מה עדיף להציג הפעם.

1. התקני פלט

אז יש לנו פלטפורמה מסוימת (ארדואינו, פטל, בקר PIC/AVR/STM וכו'), והמשימה היא לחבר אליה איזושהי חיווי. ישנן אפשרויות רבות שנשקול.

תצוגת פלחים

הכל פשוט כאן. מחוון הקטע מורכב מנוריות LED רגילות, המחוברות פשוט למיקרו-בקר באמצעות נגדי מרווה.

היזהרו מתנועה!

יתרונות: פשטות העיצוב, זוויות צפייה טובות, מחיר נמוך.
חסרונות: כמות המידע המוצג מוגבלת.
ישנם שני סוגים של עיצובי מחוון, עם קתודה משותפת ואנודה משותפת בפנים זה נראה בערך כך (דיאגרמה מאתר היצרן).

יש 1001 מאמרים על איך לחבר LED למיקרו-בקר, גוגל יכולה לעזור. הקשיים מתחילים כשאנחנו רוצים ליצור שעון גדול - אחרי הכל, להסתכל על מחוון קטן זה לא נוח במיוחד. אז אנחנו צריכים את האינדיקטורים הבאים (תמונה מ-eBay):

הם מופעלים על ידי 12V, והם פשוט לא יפעלו ישירות מהמיקרו-בקר. זה המקום שבו המיקרו-מעגל בא לעזרתנו. CD4511, בדיוק למטרה זו. זה לא רק ממיר נתונים מקו 4 סיביות למספרים הרצויים, אלא גם מכיל מתג טרנזיסטור מובנה לאספקת מתח למחוון. לפיכך, במעגל נצטרך לקבל מתח "כוח" של 9-12V, וממיר ירידה נפרד (לדוגמה L7805) כדי להפעיל את ה"לוגיקה" של המעגל.

אינדיקטורים של מטריקס

בעיקרו של דבר, מדובר באותן נוריות LED, רק בצורה של מטריצה ​​8x8. תמונה מאיביי:

הם נמכרים באיביי בצורה של מודולים בודדים או בלוקים מוכנים, למשל 4 חלקים. ניהולם פשוט מאוד - מיקרו-מעגל כבר מולחם על המודולים MAX7219, הבטחת פעולתם וחיבורם למיקרו-בקר באמצעות 5 חוטים בלבד. יש הרבה ספריות עבור Arduino, כל אחד יכול להסתכל על הקוד.
יתרונות: מחיר נמוך, זוויות צפייה טובות ובהירות.
חסרונות: רזולוציה נמוכה. אבל עבור משימת ההסקה, הזמן מספיק.

מחווני LCD

מחווני LCD יכולים להיות גרפיים או טקסטים.

גרפיים יקרים יותר, אבל הם מאפשרים לך להציג מידע מגוון יותר (לדוגמה, גרף של לחץ אטמוספרי). טקסטים זולים יותר וקלים יותר לעבודה, הם גם מאפשרים להציג פסאודו-גרפיקה - אפשר לטעון סמלים מותאמים אישית לתצוגה.

העבודה עם מחוון LCD מקוד אינה קשה, אבל יש חיסרון מסוים - המחוון דורש קווי בקרה רבים (מ-7 עד 12) מהמיקרו-בקר, וזה לא נוח. לכן, הסינים העלו את הרעיון של שילוב מחוון LCD עם בקר i2c, שבסופו של דבר היה נוח מאוד - מספיקים רק 4 חוטים לחיבור (תמונה מ-eBay).


מחווני LCD הם די זולים (אם קונים אותם באיביי), גדולים, קלים לחיבור ויכולים להציג מגוון מידע. השלילי היחיד הוא שזוויות הצפייה אינן גדולות במיוחד.

מחווני OLED

הם המשך משופר של הגרסה הקודמת. הם נעים מקטנים וזולים באלכסון של 1.1" ועד גדולים ויקרים. צילום מאיביי.

למעשה, הם טובים בכל דבר מלבד המחיר. באשר לאינדיקטורים קטנים, בגודל 0.9-1.1 אינץ', אז (חוץ מלמידת העבודה עם i2c) קשה למצוא להם שימוש מעשי.

מחווני פריקת גז (IN-14, IN-18)

אינדיקטורים אלה פופולריים כעת מאוד, ככל הנראה בשל "צליל הצינור החם של האור" והמקוריות של העיצוב.


(תמונה מאת nocrotec.com)

דיאגרמת החיבור שלהם היא קצת יותר מסובכת, כי מחוונים אלה משתמשים במתח של 170V להצתה. ממיר מ-12V=>180V יכול להתבצע על מיקרו-מעגל MAX771. מיקרו-מעגל סובייטי משמש לאספקת מתח למחוונים K155ID1, אשר נוצר במיוחד למטרה זו. מחיר ההנפקה לייצור עצמי: כ-500 רובל לכל מחוון ו-100 רובל עבור K155ID1, כל שאר החלקים, כפי שכתבו במגזינים ישנים, "אינם במחסור". הקושי העיקרי כאן הוא שגם IN-xx וגם K155ID1 הופסקו מזמן, ותוכלו לקנות אותם רק בשווקי רדיו או בכמה חנויות מיוחדות.

2. בחירת פלטפורמה

פחות או יותר הבנו את התצוגה כל שנותר הוא להחליט באיזו פלטפורמת חומרה הכי כדאי להשתמש. יש כאן כמה אפשרויות (אני לא שוקל תוצרת בית, כי מי שיודע לחבר לוח ולהלחים מעבד לא צריך את המאמר הזה).

ארדואינו

האפשרות הקלה ביותר למתחילים. הלוח המוגמר זול (כ-$10 באיביי עם משלוח חינם) ויש לו את כל המחברים הדרושים לתכנות. תמונה מאיביי:

יש מספר עצום של ספריות שונות עבור Arduino (לדוגמה, עבור אותם מסכי LCD, מודולים בזמן אמת), Arduino תואם חומרה עם מודולים נוספים שונים.
החיסרון העיקרי: המורכבות של איתור באגים (רק דרך קונסולת היציאה הטורית) ומעבד חלש למדי בסטנדרטים מודרניים (2KB RAM ו-16MHz).
היתרון העיקרי: אתה יכול לעשות הרבה דברים, כמעט בלי לטרוח עם הלחמה, לקנות מתכנת ולוחות חיווט אתה רק צריך לחבר את המודולים זה לזה.

מעבדי STM של 32 סיביות

למי שרוצה משהו חזק יותר, יש לוחות מוכנים עם מעבדי STM, למשל לוח עם STM32F103RBT6 ומסך TFT. תמונה מאיביי:

כאן כבר יש לנו איתור באגים מלא ב-IDE מלא (מבין כל השונים, הכי אהבתי את ה-Coocox IDE), עם זאת, נצטרך מתכנת-debugger ST-LINK נפרד עם מחבר JTAG (הבעיה המחיר הוא 20-40 דולר באיביי). לחילופין, ניתן לרכוש את לוח הפיתוח STM32F4Discovery, עליו כבר מובנה מתכנת זה, וניתן להשתמש בו בנפרד.

פטל PI

ולבסוף, למי שרוצה אינטגרציה מלאה עם העולם המודרני, ישנם מחשבים עם לוח יחיד עם לינוקס, כנראה שכבר ידוע לכולם - Raspberry PI. תמונה מאיביי:

מדובר במחשב מן המניין עם לינוקס, גיגה-בייט של זיכרון RAM ומעבד 4 ליבות על הסיפון. פאנל של 40 פינים ממוקם בקצה הלוח, המאפשר לחבר ציוד היקפי שונים (ניתן להשיג פינים מקוד, למשל ב-Python, שלא לדבר על C/C++), יש גם USB סטנדרטי בצורת 4 מחברים (ניתן לחבר WiFi). יש גם HDMI סטנדרטי.
הכוח של הלוח מספיק, למשל, לא רק כדי להציג את השעה, אלא גם כדי להפעיל שרת HTTP לקביעת פרמטרים באמצעות ממשק אינטרנט, טעינת תחזית מזג אוויר דרך האינטרנט, וכן הלאה. באופן כללי, יש הרבה מקום להתעופף.

יש רק קושי אחד עם Raspberry (ומעבדי STM32) - הפינים שלו משתמשים בלוגיקה של 3V, ורוב המכשירים החיצוניים (למשל מסכי LCD) פועלים "בדרך הישנה" מ-5V. כמובן שאפשר לחבר את זה ככה, ובאופן עקרוני זה יעבוד, אבל זו לא שיטה לגמרי נכונה, וחבל להרוס לוח של 50$. הדרך הנכונה היא להשתמש ב"ממיר רמת לוגיקה", שעולה רק 1-2$ באיביי.
תמונה מאיביי:

עכשיו זה מספיק כדי לחבר את המכשיר שלנו דרך מודול כזה, וכל הפרמטרים יהיו עקביים.

ESP8266

השיטה אקזוטית למדי, אך די מבטיחה בשל הקומפקטיות והעלות הנמוכה של הפתרון. תמורת מעט מאוד כסף (בערך 4-5$ באיביי) תוכלו לקנות מודול ESP8266 המכיל מעבד ו-WiFi על הסיפון.
תמונה מאיביי:

בתחילה, מודולים כאלה נועדו כגשר WiFi להחלפה באמצעות יציאה טורית, אך חובבים כתבו קושחה חלופית רבות המאפשרות להם לעבוד עם חיישנים, התקני i2c, PWM וכו'. באופן היפותטי, זה בהחלט אפשרי לקבל זמן מ- שרת NTP ופלט אותו באמצעות i2c לתצוגה. למי שרוצה לחבר הרבה ציוד היקפי שונה, ישנם לוחות NodeMCU מיוחדים עם מספר גדול של פינים, המחיר הוא כ-500 רובל (כמובן באיביי):

השלילי היחיד הוא של-ESP8266 יש מעט מאוד זיכרון RAM (תלוי בקושחה, מ-1 עד 32 KB), אבל זה הופך את המשימה למעניינת עוד יותר. מודולי ה-ESP8266 משתמשים בלוגיקה של 3V, כך שממיר הרמות שלמעלה גם יועיל כאן.

זה מסיים את סיור ההיכרות עם מוצרי אלקטרוניקה תוצרת בית, המחבר מאחל לכולם ניסויים מוצלחים.

במקום מסקנה

בסופו של דבר הסתפקתי בשימוש ב-Raspberry PI עם מחוון טקסט שהוגדר לעבוד עם פסאודו-גרפיקה (שהתברר כי זול יותר ממסך גרפי באותו אלכסון). צילמתי תמונה של מסך השעון בשולחן העבודה בזמן כתיבת מאמר זה.

השעון מציג את הזמן המדויק שנלקח מהאינטרנט ומזג האוויר, המעודכן מ-Yandex, כל זה כתוב ב-Python, ועובד די טוב כבר כמה חודשים. במקביל, פועל על השעון שרת FTP, המאפשר (בשילוב עם העברת פורטים בנתב) לעדכן את הקושחה בו לא רק מהבית, אלא גם מכל מקום שיש אינטרנט. כבונוס, משאבי פטל מספיקים באופן עקרוני לחיבור מצלמה ו/או מיקרופון עם יכולת ניטור מרחוק של הדירה, או לשלוט במודולים/ממסרים/חיישנים שונים. אתה יכול להוסיף כל מיני "טובים", כגון חיווי LED של דואר נכנס, וכן הלאה.

נ.ב: למה eBay?
כפי שניתן לראות, ניתנו מחירים או תמונות מ-eBay עבור כל המכשירים. מדוע זה כך? למרבה הצער, החנויות שלנו פועלות לרוב לפי העיקרון "נקנו ב-$1, נמכרו ב-$3, וחיות על 2 האחוזים האלה". כדוגמה פשוטה, Arduino Uno R3 עולה (בזמן כתיבת שורות אלו) 3600 רובל בסנט פטרסבורג, ו-350 רובל באיביי עם משלוח חינם מסין. ההבדל הוא באמת סדר גודל, ללא כל הגזמה ספרותית. כן, תצטרכו לחכות חודש כדי לאסוף את החבילה בסניף הדואר, אבל לדעתי הבדל כזה במחיר שווה את זה. אבל עם זאת, אם מישהו צריך את זה עכשיו ובדחיפות, אז כנראה יש בחירה בחנויות המקומיות, כאן כל אחד מחליט בעצמו.

אני מציג לתשומת לבך אלקטרוני שעון מיקרו-בקר. מעגל השעון פשוט מאוד, מכיל מינימום חלקים וניתן לחזור עליו על ידי חובבי רדיו מתחילים.

העיצוב מורכב על מיקרו-בקר ושעון זמן אמת DS1307. מחוון LED בן ארבע ספרות, שבע מקטעים משמש כאינדיקטור לשעה הנוכחית (בהיר במיוחד, בצבע כחול, שנראה טוב בחושך, ובו בזמן, השעון ממלא תפקיד של לילה אוֹר). השעון נשלט על ידי שני כפתורים. הודות לשימוש בשבב השעון בזמן אמת DS1307, אלגוריתם התוכנית התברר כפשוט למדי. המיקרו-בקר מתקשר עם שעון זמן אמת באמצעות אפיק I2C, ומאורגן על ידי תוכנה.

דיאגרמת שעון:

למרבה הצער, יש שגיאה בתרשים:
- יש לחבר את מסופי MK לבסיסי הטרנזיסטור:
РВ0 עד Т4, РВ1 עד Т3, РВ2 עד Т2, РВ3 עד Т1
או שנה את החיבור של אספני הטרנזיסטור לספרות המחוון:
T1 ל-DP1…..T4 ל-DP4

חלקים המשמשים במעגל השעון:

♦ בקר ATTiny26:

♦ שעון זמן אמת DS1307:

♦ מחוון LED בן 4 ספרות שבע מקטעים – FYQ-5641UB-21 עם קתודה משותפת (בהיר במיוחד, כחול):

♦ קוורץ 32.768 קילו-הרץ, עם קיבולת כניסה של 12.5 pF (ניתן לקחת מלוח האם של המחשב), דיוק השעון תלוי בקוורץ זה:

♦ כל הטרנזיסטורים הם מבני NPN, אתה יכול להשתמש בכל (KT3102, KT315 והאנלוגים הזרים שלהם), השתמשתי ב-BC547S
♦ מייצב מתח מיקרו-מעגל מסוג 7805
♦ כל הנגדים בהספק של 0.125 וואט
♦ קבלים קוטביים למתח פעולה שאינו נמוך ממתח האספקה
♦ ספק כוח גיבוי DS1307 – תא ליתיום 3 וולט CR2032

כדי להפעיל את השעון, ניתן להשתמש בכל מטען סלולרי מיותר (במקרה זה, אם המתח ביציאת המטען הוא בטווח של 5 וולט ± 0.5 וולט, חלק מהמעגל - מייצב מתח על שבב מסוג 7805 - יכול להיות מחוסל)
צריכת הזרם של המכשיר היא 30 mA.
אינך צריך להתקין את סוללת הגיבוי עבור שעון ה-DS1307, אך לאחר מכן, אם החשמל נכבה, יהיה צורך להגדיר שוב את השעה הנוכחית.
המעגל המודפס של המכשיר אינו נתון העיצוב הורכב במארז משעון מכני פגום. הנורית (בתדירות מהבהב של 1 הרץ, מהפין SQW DS1307) משמשת להפרדה בין השעות והדקות על המחוון.

הגדרות המיקרו-בקר הן מהמפעל: תדר שעון - 1 מגה-הרץ, אין צורך לגעת בסיביות FUSE.

אלגוריתם פעולת שעון(ב-Algorithm Builder):

1. הגדרת מצביע המחסנית
2. הגדרת טיימר T0:
— תדר SK/8
- פסיקות גלישה (בתדר מוגדר מראש זה, ההפסקה נקראת כל 2 אלפיות שניות)
3. אתחול היציאות (הפינים PA0-6 ו-PB0-3 מוגדרים כפלט, PA7 ו-PB6 כקלט)
4. אתחול האפיק I2C (פינים PB4 ו-PB5)
5. בדיקת הביט השביעי (CH) של האפס של ה-DS1307
6. הפעלת פסיקה גלובלית
7. נכנסים ללולאה ובודקים אם כפתור נלחץ

כאשר מופעלת בפעם הראשונה, או מופעלת שוב אם אין כוח גיבוי ל-DS307, השעה הנוכחית מאופסת להגדרה המקורית. במקרה זה: לחצן S1 – לקביעת השעה, לחצן S2 – מעבר לספרה הבאה. זמן מוגדר - שעות ודקות נכתבות ל-DS1307 (שניות מוגדרות לאפס), ופין SQW/OUT (פין 7) מוגדר ליצור פולסים של גל ריבועי בתדר של 1 הרץ.
כאשר אתה לוחץ על כפתור S2 (S4 - בתוכנית), הפסקה גלובלית מושבתת, התוכנית נכנסת לתת שגרת תיקון הזמן. במקרה זה, באמצעות הכפתורים S1 ו-S2, נקבעים עשרות ויחידות דקות, ולאחר מכן, מ-0 שניות, לחיצה על כפתור S2 מתעדת את הזמן המעודכן ב-DS1307, פותרת את ההפרעה הגלובלית וחוזרת לתוכנית הראשית.

השעון הראה דיוק טוב, אובדן הזמן לחודש היה 3 שניות.
כדי לשפר את הדיוק, מומלץ לחבר קוורץ ל-DS1307, כפי שמצוין בגליון הנתונים:

התוכנית כתובה בסביבת אלגוריתם בונה.
באמצעות תוכנית השעון כדוגמה, אתה יכול להכיר את האלגוריתם לתקשורת בין המיקרו-בקר להתקנים אחרים באמצעות אפיק I2C (כל שורה מוערת בפירוט באלגוריתם).

תמונה של המכשיר והמעגל המודפס המורכב בפורמט lay מקורא האתר Anatoly Pilguk, על כך תודה רבה לו!

המכשיר משתמש ב: טרנזיסטורים - SMD BC847 ונגדים CHIP

מצורפים למאמר:

(42.9 KiB, 3,233 כניסות)

(6.3 KiB, 4,183 כניסות)

(3.1 KiB, 2,662 כניסות)

(312.1 KiB, 5,932 כניסות)


הגרסה השנייה של תוכנית השעון ב-AB (למי שלא יכול להוריד את העליונה)

(11.4 KiB, 1,947 כניסות)