پروژه ساعت هشدار دهنده و پخش کننده موسیقی با صفحه نمایش لمسی آردوینو
در این پروژه به شما نشان خواهم داد که چگونه میتوانید یک ساعت هشدار دهنده و پخش کننده موسیقی با آردوینو MP3 با صفحه نمایش لمسی آردوینو بسازید.
مرور کلی ساخت پخش کننده موسیقی با آردوینو
ویژگی های یک صفحه نمایش خانگی یک ساعت بزرگ، تاریخ و اطلاعات دما و همچنین دو دکمه برای پخشکننده موسیقی و ساعت هشدار دهنده است.
اگر وارد پخش کننده موسیقی با آردوینو شویم، میتوانیم با فشار دادن دکمه بزرگ “پخش” در وسط صفحه شروع به پخش موسیقی کنیم. درست در کنار آن، دو دکمه دیگر نیز برای پخش آهنگ قبلی یا بعدی وجود دارد.
بالای این دکمهها نوار پیشرفت آهنگ وجود دارد و در پایین صفحه یک نوار حجم صدا و دو دکمه برای کاهش و افزایش حجم صدا داریم. در گوشه سمت راست بالا، یک ساعت وجود دارد و در سمت چپ، دکمه “منو” قرار دارد که ما را به صفحه نمایش خانه باز میگرداند.
از سوی دیگر، اگر وارد ساعت هشدار دهنده شویم، میتوانیم با استفاده از دو دکمه برای تنظیم ساعتها و دقیقهها، هشدار را تنظیم کنیم.
زمانی که هشدار فعال میشود، یک آهنگ با حجم بالاتری شروع به نواختن خواهد کرد، و تا زمانی که دکمه “Dismiss” را فشار ندهیم به نواختن ادامه خواهد داد.
نحوه کار
حال بیایید نگاهی به نحوه کار این دستگاه بیندازیم. از یک برد Mega آردوینو و یک صفحه نمایش لمسی 3.2 TFT با یک حفاظ مناسب برای اتصال صفحه نمایش به برد آردوینو استفاده میکند. برای پخش موسیقی، از ماژول پخشکننده BY8001 MP3 و برای ساعت هشدار دهنده از ماژول ساعت زمان واقعی DS3231 استفاده میکند.
طرح کلی مدار
این طرح کلی مدار این پروژه است:
در اینجا میتوانیم به این نکته توجه کنیم که حفاظ TFT در حال مسدود کردن پینهای آزاد برد آردینو است، بنابراین ما باید هدرهای پین ساخته شده سفارشی بسازیم که بتوانیم آنها را بین حفاظ و آردینو قرار دهیم.
همچنین توجه داشته باشید که برای تقویت آردینو باید هدر پین اضافی را برای پین ۵ ولت روی حفاظ لحیم کنید، چون حفاظ از تمام پینهای VCC آردوینو استفاده میکند.
زمانی که همه چیز را به هم متصل کردیم میتوانیم برنامهریزی آردینو را انجام دهیم.
ماژول پخشکننده BY8001-16P MP3
BY8001-16P یک ماژول MP3 است که با کارتهای MicroSD کار میکند و از فایلهای صوتی MP3 و WAV پشتیبانی میکند. این ماژول دارای یک تقویتکننده توان ۳ وات ساخته شده داخلی است و میتواند به طور مستقیم یک بلندگوی ۳ واتی را هدایت کند.
ماژول پخشکننده MP3 را می توان با استفاده از ۵ پین ورودی یا با استفاده از یک میکروکنترلر از طریق ارتباط سریال کنترل کرد.
در اینجا توجه داشته باشید که پین درگاه سریال ماژول در ۳.۳ وات کار میکند بنابراین پین RX ماژول باید از طریق یک مقاومت 1K به پین TX آردوینو متصل شود.
همچنین به سه پورت A، Bو C توجه کنید که برای انتخاب حالتهای کنترل استفاده میشوند. برای کنترل ماژول با استفاده از یک میکروکنترلر، سه مقاومت در این پدها باید حذف شوند. می توان از پینهای شماره ۶ و ۷ برای اتصال مستقیم بلندگوهای توان پایین یا پینهای شماره ۴ و ۵ با استفاده از تقویتکننده خارجی استفاده کرد.
همانند بخش آردینو، سادهترین راه استفاده از کتابخانه BY8001 است که می توان آن را از GitHub دانلود کرد. اگر ما برخی از مثالهای نمایشی آن را باز کنیم میتوانیم ببینیم چگونه کار میکند. بنابراین پس از راهاندازی ماژول در بخش راهاندازی، میتوانیم از هر یک از توابع سفارشی ساخته شده برای کنترل ماژول استفاده کنیم.
کد منبع
حالا ما آماده ایم تا نگاهی به کد این ساعت هشدار دهنده و پخشکننده موسیقی MP3 با صفحه نمایش لمسی آردوینو بیندازیم. از آنجا که کد کمی طولانیتر است، برای درک بهتر، کد منبع برنامه را در بخشهایی با توصیف برای هر بخش قرار خواهم داد. و در پایان این مقاله من کد منبع کامل را قرار خواهم داد. چنانچه علاقمند به کار بیشتر با آردوینو و یادگیری کدنویسی با آردوینو هستید میتوانید در دوره های آموزش رباتیک صنایع آموزشی چالیک شرکت کنید.
بنابراین، ابتدا باید کتابخانههایی برای صفحه نمایش لمسی TFT، پخشکننده BY8001-16P MP3 و ماژول ساعت زمان واقعی DS3231 و همچنین کتابخانه ارتباط سریال را در نظر بگیریم. سپس ما باید داده های مناسب را ایجاد کنیم و برخی از متغیرهای مورد نیاز برای برنامه را تعریف کنیم.
#include <UTFT.h> #include <URTouch.h> #include <SoftwareSerial.h> #include <BY8001.h> #include <DS3231.h> //==== Creating Objects UTFT myGLCD(SSD1289, 38, 39, 40, 41); //Parameters should be adjusted to your Display/Schield model URTouch myTouch( 6, 5, 4, 3, 2); SoftwareSerial mp3Serial(11, 10); // RX, TX BY8001 mp3; // creating an instance of class BY8001 and call it 'mp3' DS3231 rtc(SDA, SCL); //==== Defining Fonts extern uint8_t SmallFont[]; extern uint8_t BigFont[]; extern uint8_t SevenSegNumFont[]; extern unsigned int MusicPlayerButton[0x1040]; extern unsigned int AlarmButton[0x1040]; extern unsigned int ButtonPlay[0x1AE9]; extern unsigned int ButtonPause[0x1AE9]; extern unsigned int PreviousButton[0x9C4]; extern unsigned int NextButton[0x9C4]; extern unsigned int VolumeDown[0x170]; extern unsigned int VolumeUp[0x3B8]; int x, y; // Variables for the coordinates where the display has been pressed char currentPage, playStatus; int iV = 15; int trackNum = 1; int b = 16; int aHours = 0; int aMinutes = 0; boolean alarmNotSet = true; String alarmString = ""; float currentTemperature, temperature; static word totalTime, elapsedTime, playback, minutes, seconds, lastSeconds, minutesR, secondsR; String currentClock, currentHours, currentMinutes, currentSeconds, currentDate; String timeString, hoursString, minutesString, secondsString, hoursS, minutesS, secondsS, dateS;
ما در اینجا میتوانیم به تعریف نقشه های بیتی (bitmaps) توجه کنیم. برخی از دکمههای برنامه در واقع تصاویری هستند که با استفاده از ابزار ImageConverter565 که با کتابخانه TFT میآید، به Bitmaps تبدیل میشوند.
بنابراین، این فایلهای “.c” باید در دایرکتوری فایل کد گنجانده شوند به طوری که هنگام راهاندازی سکچ(sketch) بارگذاری شوند.
در بخش راهاندازی پس از راهاندازی داده ها، ما تابع سفارشی ()drawHomeScreenرا فراخوانی میکنیم که تمام گرافیکهای صفحه نمایش خانگی را ترسیم میکند. همچنین در اینجا ما مقادیر اولیه برخی از متغیرها، مانند وضعیت پخش، زمان وقوع و تاریخ، مقدار اولیه حجم و غیره را تنظیم میکنیم.
void setup() { // Initiate display myGLCD.InitLCD(); myGLCD.clrScr(); myTouch.InitTouch(); myTouch.setPrecision(PREC_MEDIUM); // Initialize the rtc object rtc.begin(); // Music Serial.begin(9600); // set serial monitor baud rate to Arduino IDE mp3Serial.begin(9600); // BY8001 set to 9600 baud (required) mp3.setup(mp3Serial); // tell BY8001 library which serial port to use. delay(800); // allow time for BY8001 cold boot; may adjust depending on flash storage size drawHomeScreen(); // Draws the Home Screen currentPage = '0'; // Indicates that we are at Home Screen playStatus = '0'; mp3.setVolume(15); delay(100); currentTemperature = rtc.getTemp(); currentDate = rtc.getDateStr(); currentClock = rtc.getTimeStr(); timeString = rtc.getTimeStr(); currentHours = timeString.substring(0, 2); currentMinutes = timeString.substring(3, 5); currentSeconds = timeString.substring(6, 8); }
بعدی بخش حلقه است. اولین عبارت اگر درست است چون ما متغیر currentPage را برابر با ۰ قرار دادهایم که نشاندهنده این است که ما در صفحه نمایش خانگی هستیم. در اینجا با عبارت بعدی بررسی میکنیم که آیا ما تغییری در ساعت داریم و این هر ثانیه اتفاق میافتد. اکنون که از فونت هفت بخشی کتابخانههای TFT استفاده میکنیم، که از هیچ کاراکتری به جز اعداد پشتیبانی نمیکند، تنها باید اعداد را از رشتهای که با تابع ()getTimeStr برای خواندن ساعت از ماژولDS3231 RTC میآید استخراج کنیم.
بنابراین با استفاده از تابع ()substring، ساعتها، دقیقهها و ثانیهها را به متغیرهای جداگانه تبدیل میکنیم و هر بار که تغییری در ثانیه، دقیقه یا ساعت رخ میدهد، آنها را چاپ میکنیم. در مورد تاریخ و دما، مشابه، ما بررسی میکنیم که آیا تغییری در مقایسه با حالت قبلی وجود دارد.
void loop() { // Homes Screen if (currentPage == '0') { // Checks for change of the clock if ( currentClock != rtc.getTimeStr()) { timeString = rtc.getTimeStr(); hoursS = timeString.substring(0, 2); minutesS = timeString.substring(3, 5); secondsS = timeString.substring(6, 8); myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.print(secondsS, 224, 50); if ( currentMinutes != minutesS ) { myGLCD.print(minutesS, 128, 50); currentMinutes = minutesS; } if ( currentHours != hoursS ) { myGLCD.print(hoursS, 32, 50); currentHours = hoursS; } // Checks for change of the date dateS = rtc.getDateStr(); delay(10); if ( currentDate != dateS){ myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.print(rtc.getDateStr(), 153, 7); } // Checks for change of the temperature temperature = rtc.getTemp(); delay(10); if ( currentTemperature != temperature ){ myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.printNumI(temperature, 39, 7); currentTemperature = temperature; } delay(10); currentClock = rtc.getTimeStr(); }
سپس با استفاده از تابع ()my Touch.data Available بررسی میکنیم که آیا صفحه نمایش را لمس کردهایم و همچنین بررسی میکنیم که آیا آن پخشکننده موسیقی است یا دکمه زنگ هشدار. بنابراین اگر این دکمه پخشکننده موسیقی است، ابتدا تابع ()drawFrame را که یک دایره قرمز را به دور دکمه میکشد و نشان میدهد که دکمه فشرده شدهاست، فراخوانی میکنیم. همچنین این تابع سفارشی دارای یک حلقه زمانی است که برنامه را روی هم انباشته نگه میدارد تا زمانی که ما دکمه را آزاد کنیم. درست بعد از آن، متغیر ()currentPage را بر روی ۱ تنظیم میکنیم، صفحه نمایش را پاک میکنیم و تابع سفارشی ()drawMusicPlayerScreenرا که تمام گرافیکهای صفحه پخشکننده موسیقی را ترسیم میکند، فراخوانی میکنیم. مشابه، اگر ما دکمه زنگ هشدار را فشار دهیم، متغیر currentPage را بر روی ۲ تنظیم کرده و صفحه نمایش را پاک میکنیم.
// Checks whether the screen has been touched if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // If we press the Music Player Button if ((x >= 55) && (x <= 120) && (y >= 125) && (y <= 190)) { drawFrame(87, 157, 33); currentPage = '1'; myGLCD.clrScr(); delay(100); drawMusicPlayerScreen(); delay(100); } // If we press the Alarm Button if ((x >= 195) && (x <= 260) && (y >= 125) && (y <= 190)) { drawFrame(227, 160, 29); currentPage = '2'; myGLCD.clrScr(); } }
سپس، بیایید ببینیم در صفحه نمایش پخش کننده موسیقی با آردوینو اتفاقی میافتد. در اینجا ما به طور مداوم بررسی میکنیم که آیا به صفحه نمایش دست زدهایم یا خیر. اگر دکمه پخش را لمس کنیم و playStatus پخش فعلی ۰ باشد، تابع ()mp3. play TrackFromFolderرا فراخوانی خواهیم کرد که شروع به پخش اولین ترانه از کارت MicroSD خواهد کرد. در عین حال، تابع سفارشی ()drawePauseButton که دکمه مکث را رسم میکند و متغیر playStatus را بر روی ۲ تنظیم میکند را فراخوانی میکنیم. اگر کاربرد دو عبارت بعدی بسته به متغیر playStatus باشد، بین پخش و مکث آهنگ جابه جا می شویم.
// Music Player Screen if (currentPage == '1') { if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // If we press the Play Button if ((x >= 116) && (x <= 204) && (y >= 77) && (y <= 165)) { if (playStatus == '0') { drawFrame(159, 121, 42); drawPauseButton(); mp3.playTrackFromFolder(00, 001); delay(100); playStatus = '2'; return; } if (playStatus == '1') { drawFrame(159, 121, 42); drawPauseButton(); mp3.play(); delay(100); playStatus = '2'; return; } if (playStatus == '2') { drawFrame(159, 121, 42); drawPlayButton(); mp3.pause(); delay(100); playStatus = '1'; return; } }
به همین ترتیب، برای هر دکمه فشرده، ما توابع مناسب را برای اجرای مسیر قبلی یا بعدی، کاهش یا افزایش حجم، و همچنین دکمه “منو” که ما را به صفحه نمایش خانگی باز میگرداند، فراخوانی میکنیم.
// If we press the Previous Button if ((x >= 45) && (x <= 95) && (y >= 97) && (y <= 147)) { drawFrame(70, 121, 26); mp3.previousTrack(); delay(100); drawTrackBar(); } // If we press the Next Button if ((x >= 227) && (x <= 277) && (y >= 97) && (y <= 147)) { drawFrame(252, 122, 26); mp3.nextTrack(); delay(100); drawTrackBar(); } // If we press the VolumeDown Button if ((x >= 35) && (x <= 75) && (y >= 165) && (y <= 209)) { drawUnderline(45, 205, 65, 205); if (iV >= 0 & iV <= 30) { iV--; drawVolume(iV); } mp3.decreaseVolume(); delay(100); } // If we press the VolumeUp Button if ((x >= 230) && (x <= 280) && (y >= 165) && (y <= 209)) { drawUnderline(235, 205, 275, 205); if (iV >= 0 & iV <= 30) { iV++; drawVolume(iV); } mp3.increaseVolume(); delay(100); } // If we press the MENU Button if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) { myGLCD.clrScr(); drawHomeScreen(); // Draws the Home Screen currentPage = '0'; return; }
اگر عبارت بعدی برای به روز رسانی نوار پیشرفت مسیر استفاده شود.
// Updates the track bar if (playStatus == '1' || playStatus == '2') { trackPlayTime(); }
بنابراین اگر موسیقی در حال پخش است ما تابع سفارشی ()trackPlay Time را فراخوانی می کنیم که با استفاده از برخی از توابع کتابخانه پخش کننده موسیقی، مانند ()mp3.getElapsedTrackPlaybackTime، زمان سپریشده را محاسبه و چاپ میکند و همچنین زمان باقی مانده و گرافیک های نوار پیشرفت مسیر را محاسبه میکند. با استفاده از تابع سفارشی ()printClock، ساعت را در گوشه سمت راست بالا چاپ میکنیم.
// Updates the track bar void trackPlayTime() { totalTime = mp3.getTotalTrackPlaybackTime(); delay(10); elapsedTime = mp3.getElapsedTrackPlaybackTime(); delay(10); minutes = (int)elapsedTime / 60; seconds = (((float)elapsedTime / 60) - minutes) * 60; playback = totalTime - elapsedTime; minutesR = (int)playback / 60; secondsR = (((float)playback / 60) - minutesR) * 60; myGLCD.setFont(SmallFont); myGLCD.setColor(255, 255, 255); myGLCD.printNumI(minutes, 8, 48); myGLCD.print(":", 16, 48); myGLCD.printNumI((int)seconds, 24, 48, 2, '0'); myGLCD.print("-", 276, 48); myGLCD.printNumI(minutesR, 284, 48); myGLCD.print(":", 292, 48); myGLCD.printNumI((int)secondsR, 300, 48, 2, '0'); int trackBarX = map(elapsedTime, 0, totalTime, 0, 224); myGLCD.setColor(255, 0, 0); myGLCD.fillRect (48, 50, 48 + trackBarX, 50 + 8); if (totalTime == elapsedTime) { mp3.nextTrack(); delay(30); myGLCD.setColor(255, 255, 255); myGLCD.fillRect (48, 50, 48 + 224, 50 + 8); } }
بعدی صفحه نمایش ساعت هشدار دهنده است. در اینجا ابتدا تمام گرافیکها، ساعت، متن و دکمهها را رسم میکنیم و همچنین متغیر alarmNotset را تنظیم میکنیم تا درست باشد به طوری که بتوانیم وارد حلقه بعدی شویم. در اینجا با استفاده از دو دکمه H و M، زنگ هشدار را تنظیم کرده و زمانی که بر روی دکمه “set” کلیک میکنیم، مقدار زنگ هشدار در متغیر alarmString ذخیره میشود.
// Alarm Clock Screen if (currentPage == '2') { myGLCD.setFont(BigFont); myGLCD.setColor(255, 255, 255); myGLCD.print("MENU", 5, 5); myGLCD.print("Set Alarm", CENTER, 20); // Draws a colon between the hours and the minutes myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 65, 4); myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 85, 4); myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aHours, 32, 50, 2, '0'); myGLCD.printNumI(aMinutes, 128, 50, 2, '0'); myGLCD.setColor(255, 255, 255); myGLCD.drawRoundRect (42, 115, 82, 145); myGLCD.drawRoundRect (138, 115, 178, 145); myGLCD.setFont(BigFont); myGLCD.print("H", 54, 122); myGLCD.print("M", 150, 122); myGLCD.drawRoundRect (215, 60, 303, 90); myGLCD.print("SET", 236, 67); myGLCD.drawRoundRect (215, 115, 303, 145); myGLCD.print("CLEAR", 220, 122); alarmNotSet = true; while (alarmNotSet){ if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed //Set hours button if ((x >= 42) && (x <= 82) && (y >= 115) && (y <= 145)) { drawRectFrame(42, 115, 82, 145); aHours++; if(aHours >=24){ aHours = 0; } myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aHours, 32, 50, 2, '0'); } // Set minutes buttons if ((x >= 138) && (x <= 178) && (y >= 115) && (y <= 145)) { drawRectFrame(138, 115, 178, 145); aMinutes++; if(aMinutes >=60){ aMinutes = 0; } myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aMinutes, 128, 50, 2, '0'); } // Set alarm button if ((x >= 215) && (x <= 303) && (y >= 60) && (y <= 80)) { drawRectFrame(215, 60, 303, 90); if (aHours < 10 && aMinutes < 10){ alarmString = "0"+(String)aHours + ":" + "0"+ (String)aMinutes + ":" + "00"; } else if (aHours < 10 && aMinutes > 9){ alarmString = "0"+(String)aHours + ":" + (String)aMinutes + ":" + "00"; } else if (aHours > 9 && aMinutes < 10){ alarmString = (String)aHours + ":" + "0"+ (String)aMinutes + ":" + "00"; } else { alarmString = (String)aHours + ":" + (String)aMinutes + ":" + "00"; } myGLCD.setFont(BigFont); myGLCD.print("Alarm set for:", CENTER, 165); myGLCD.print(alarmString, CENTER, 191); } // Clear alarm button if ((x >= 215) && (x <= 303) && (y >= 115) && (y <= 145)) { drawRectFrame(215, 115, 303, 145); alarmString=""; myGLCD.setColor(0, 0, 0); myGLCD.fillRect(45, 165, 275, 210); } // If we press the MENU Button if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) { alarmNotSet = false; currentPage = '0'; myGLCD.clrScr(); drawHomeScreen(); // Draws the Home Screen } } } }
در اینجا توجه داشته باشید که ما باید این رشته را طوری تنظیم کنیم که همان شکلی را داشته باشد که از تابع ()getTimeString به دست میآوریم. به این ترتیب میتوانیم آنها را مقایسه کنیم و زمانی که ساعت به همان مقدار یا زمان برسد، زنگ هشدار را فعال کنیم.
اگر ما دکمه پاک کردن را فشار دهیم، رشته فلزی را پاک خواهیم کرد و اگر ما دکمه منو را فشار دهیم، ما را از حلقه خارج کرده و به صفحه نمایش خانگی بازخواهیم گرداند.
برای فعال کردن زنگ هشدار، بررسی میکنیم که آیا زنگ هشدار تنظیم شدهاست یا خیر و اگر زنگ هشدار با ساعت مطابقت داشته باشد، اولین آهنگ روی کارت MicroSD با حجم بالاتری شروع به نواختن خواهد کرد. همچنین تمام گرافیک ها را با دکمه “Dismiss” ترسیم کرده و متغیر alarmOn روی true تنظیم میکنیم. این کار ما را به حلقه بعدی میبرد که ما را قادر به خواندن آهنگ برای ادامه پخش میکند تا زمانی که دکمه “Dismiss” را فشار دهیم.
// Alarm activation if (alarmNotSet == false) { if (alarmString == rtc.getTimeStr()){ myGLCD.clrScr(); mp3.setVolume(25); mp3.playTrackByIndexNumber(1); delay(100); myGLCD.setFont(BigFont); myGLCD.setColor(255, 255, 255); myGLCD.print("ALARM", CENTER, 90); myGLCD.drawBitmap (127, 10, 65, 64, AlarmButton); myGLCD.print(alarmString, CENTER, 114); myGLCD.drawRoundRect (94, 146, 226, 170); myGLCD.print("DISMISS", CENTER, 150); boolean alarmOn = true; while (alarmOn){ if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // Stop alarm button if ((x >= 94) && (x <= 226) && (y >= 146) && (y <= 170)) { drawRectFrame(94, 146, 226, 170); alarmOn = false; alarmString=""; myGLCD.clrScr(); mp3.stopPlayback(); delay(100); currentPage = '0'; playStatus = '0'; mp3.setVolume(15); drawHomeScreen(); } } } } }
بنابراین این روشی است که کد کار میکند و شما میتوانید کد منبع کامل را در پایین مقاله پیدا کنید.
ساخت دستگاه پخش کننده موسیقی با آردوینو
با استفاده از سالیدورک (Solidwork) من طراحی را ساختم و این شکلی به نظر میرسد.
برای این پروژه من استفاده از ورقه فلزی آلومینیوم را انتخاب میکنم که آن را با اندازهگیری با استفاده از یک ابزار چندگانه برش میدهم. سپس روی لبه میزم و با کمک چند گیره و لت ورق فلزی را خم کردم.
برای بلندگوها، من یک طرح دایرهای چاپ کردم، آن را به محل متصل کردم و با استفاده از مته تمام سوراخها را ایجاد کردم.
بعد از آن، کنارهها را به شکل مناسب برش دادم و آنها را با استفاده از یک تفنگ چسب به ورق فلزی که قبلا خم شده بود محکم کردم.
در انتها جعبه فلزی ورقی را رنگ کردم و آن برای اتصال قطعات الکترونیکی آماده بود. دوباره، با استفاده از تفنگ چسب تمام اجزا را محکم کردم، همه چیز را به هم متصل کردم و در پشتی دستگاه را با استفاده از دو پیچ محکم کردم.
همین، لطفا در زیر بخش نظرات هر سوالی را بپرسید.
این کد منبع کامل دستگاه است:
/* * Arduino Touch Screen MP3 Music Player and Alarm Clock * * Crated by Dejan Nedelkovski, * www.HowToMechatronics.com * * UFTF, URTouch and DS3231 libraries made by Henning Karlsen which can be found and downloaded from his website, www.rinkydinkelectronics.com. * BY8001 MP3 Player Library made by borland of Arduino forum, Released in public domain. Dowload link: https://github.com/r0ndL/BY8001 */ #include <UTFT.h> #include <URTouch.h> #include <SoftwareSerial.h> #include <BY8001.h> #include <DS3231.h> //==== Creating Objects UTFT myGLCD(SSD1289, 38, 39, 40, 41); //Parameters should be adjusted to your Display/Schield model URTouch myTouch( 6, 5, 4, 3, 2); SoftwareSerial mp3Serial(11, 10); // RX, TX BY8001 mp3; // creating an instance of class BY8001 and call it 'mp3' DS3231 rtc(SDA, SCL); //==== Defining Fonts extern uint8_t SmallFont[]; extern uint8_t BigFont[]; extern uint8_t SevenSegNumFont[]; extern unsigned int MusicPlayerButton[0x1040]; extern unsigned int AlarmButton[0x1040]; extern unsigned int ButtonPlay[0x1AE9]; extern unsigned int ButtonPause[0x1AE9]; extern unsigned int PreviousButton[0x9C4]; extern unsigned int NextButton[0x9C4]; extern unsigned int VolumeDown[0x170]; extern unsigned int VolumeUp[0x3B8]; int x, y; // Variables for the coordinates where the display has been pressed char currentPage, playStatus; int iV = 15; int trackNum = 1; int b = 16; int aHours = 0; int aMinutes = 0; boolean alarmNotSet = true; String alarmString = ""; float currentTemperature, temperature; static word totalTime, elapsedTime, playback, minutes, seconds, lastSeconds, minutesR, secondsR; String currentClock, currentHours, currentMinutes, currentSeconds, currentDate; String timeString, hoursString, minutesString, secondsString, hoursS, minutesS, secondsS, dateS; void setup() { // Initiate display myGLCD.InitLCD(); myGLCD.clrScr(); myTouch.InitTouch(); myTouch.setPrecision(PREC_MEDIUM); // Initialize the rtc object rtc.begin(); // Music Serial.begin(9600); // set serial monitor baud rate to Arduino IDE mp3Serial.begin(9600); // BY8001 set to 9600 baud (required) mp3.setup(mp3Serial); // tell BY8001 library which serial port to use. delay(800); // allow time for BY8001 cold boot; may adjust depending on flash storage size drawHomeScreen(); // Draws the Home Screen currentPage = '0'; // Indicates that we are at Home Screen playStatus = '0'; mp3.setVolume(15); delay(100); currentTemperature = rtc.getTemp(); currentDate = rtc.getDateStr(); currentClock = rtc.getTimeStr(); timeString = rtc.getTimeStr(); currentHours = timeString.substring(0, 2); currentMinutes = timeString.substring(3, 5); currentSeconds = timeString.substring(6, 8); } void loop() { // Homes Screen if (currentPage == '0') { // Checks for change of the clock if ( currentClock != rtc.getTimeStr()) { timeString = rtc.getTimeStr(); hoursS = timeString.substring(0, 2); minutesS = timeString.substring(3, 5); secondsS = timeString.substring(6, 8); myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.print(secondsS, 224, 50); if ( currentMinutes != minutesS ) { myGLCD.print(minutesS, 128, 50); currentMinutes = minutesS; } if ( currentHours != hoursS ) { myGLCD.print(hoursS, 32, 50); currentHours = hoursS; } // Checks for change of the date dateS = rtc.getDateStr(); delay(10); if ( currentDate != dateS){ myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.print(rtc.getDateStr(), 153, 7); } // Checks for change of the temperature temperature = rtc.getTemp(); delay(10); if ( currentTemperature != temperature ){ myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.printNumI(temperature, 39, 7); currentTemperature = temperature; } delay(10); currentClock = rtc.getTimeStr(); } // Checks whether the screen has been touched if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // If we press the Music Player Button if ((x >= 55) && (x <= 120) && (y >= 125) && (y <= 190)) { drawFrame(87, 157, 33); currentPage = '1'; myGLCD.clrScr(); delay(100); drawMusicPlayerScreen(); delay(100); } // If we press the Alarm Button if ((x >= 195) && (x <= 260) && (y >= 125) && (y <= 190)) { drawFrame(227, 160, 29); currentPage = '2'; myGLCD.clrScr(); } } } // Music Player Screen if (currentPage == '1') { if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // If we press the Play Button if ((x >= 116) && (x <= 204) && (y >= 77) && (y <= 165)) { if (playStatus == '0') { drawFrame(159, 121, 42); drawPauseButton(); mp3.playTrackFromFolder(00, 001); delay(100); playStatus = '2'; return; } if (playStatus == '1') { drawFrame(159, 121, 42); drawPauseButton(); mp3.play(); delay(100); playStatus = '2'; return; } if (playStatus == '2') { drawFrame(159, 121, 42); drawPlayButton(); mp3.pause(); delay(100); playStatus = '1'; return; } } // If we press the Previous Button if ((x >= 45) && (x <= 95) && (y >= 97) && (y <= 147)) { drawFrame(70, 121, 26); mp3.previousTrack(); delay(100); drawTrackBar(); } // If we press the Next Button if ((x >= 227) && (x <= 277) && (y >= 97) && (y <= 147)) { drawFrame(252, 122, 26); mp3.nextTrack(); delay(100); drawTrackBar(); } // If we press the VolumeDown Button if ((x >= 35) && (x <= 75) && (y >= 165) && (y <= 209)) { drawUnderline(45, 205, 65, 205); if (iV >= 0 & iV <= 30) { iV--; drawVolume(iV); } mp3.decreaseVolume(); delay(100); } // If we press the VolumeUp Button if ((x >= 230) && (x <= 280) && (y >= 165) && (y <= 209)) { drawUnderline(235, 205, 275, 205); if (iV >= 0 & iV <= 30) { iV++; drawVolume(iV); } mp3.increaseVolume(); delay(100); } // If we press the MENU Button if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) { myGLCD.clrScr(); drawHomeScreen(); // Draws the Home Screen currentPage = '0'; return; } } // Updates the track bar if (playStatus == '1' || playStatus == '2') { trackPlayTime(); } // Printing the clock in the upper right corner myGLCD.setFont(BigFont); myGLCD.setColor(255, 255, 255); printClock(187, 5); } // Alarm Clock Screen if (currentPage == '2') { myGLCD.setFont(BigFont); myGLCD.setColor(255, 255, 255); myGLCD.print("MENU", 5, 5); myGLCD.print("Set Alarm", CENTER, 20); // Draws a colon between the hours and the minutes myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 65, 4); myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 85, 4); myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aHours, 32, 50, 2, '0'); myGLCD.printNumI(aMinutes, 128, 50, 2, '0'); myGLCD.setColor(255, 255, 255); myGLCD.drawRoundRect (42, 115, 82, 145); myGLCD.drawRoundRect (138, 115, 178, 145); myGLCD.setFont(BigFont); myGLCD.print("H", 54, 122); myGLCD.print("M", 150, 122); myGLCD.drawRoundRect (215, 60, 303, 90); myGLCD.print("SET", 236, 67); myGLCD.drawRoundRect (215, 115, 303, 145); myGLCD.print("CLEAR", 220, 122); alarmNotSet = true; while (alarmNotSet){ if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed //Set hours button if ((x >= 42) && (x <= 82) && (y >= 115) && (y <= 145)) { drawRectFrame(42, 115, 82, 145); aHours++; if(aHours >=24){ aHours = 0; } myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aHours, 32, 50, 2, '0'); } // Set minutes buttons if ((x >= 138) && (x <= 178) && (y >= 115) && (y <= 145)) { drawRectFrame(138, 115, 178, 145); aMinutes++; if(aMinutes >=60){ aMinutes = 0; } myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.printNumI(aMinutes, 128, 50, 2, '0'); } // Set alarm button if ((x >= 215) && (x <= 303) && (y >= 60) && (y <= 80)) { drawRectFrame(215, 60, 303, 90); if (aHours < 10 && aMinutes < 10){ alarmString = "0"+(String)aHours + ":" + "0"+ (String)aMinutes + ":" + "00"; } else if (aHours < 10 && aMinutes > 9){ alarmString = "0"+(String)aHours + ":" + (String)aMinutes + ":" + "00"; } else if (aHours > 9 && aMinutes < 10){ alarmString = (String)aHours + ":" + "0"+ (String)aMinutes + ":" + "00"; } else { alarmString = (String)aHours + ":" + (String)aMinutes + ":" + "00"; } myGLCD.setFont(BigFont); myGLCD.print("Alarm set for:", CENTER, 165); myGLCD.print(alarmString, CENTER, 191); } // Clear alarm button if ((x >= 215) && (x <= 303) && (y >= 115) && (y <= 145)) { drawRectFrame(215, 115, 303, 145); alarmString=""; myGLCD.setColor(0, 0, 0); myGLCD.fillRect(45, 165, 275, 210); } // If we press the MENU Button if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) { alarmNotSet = false; currentPage = '0'; myGLCD.clrScr(); drawHomeScreen(); // Draws the Home Screen } } } } // Alarm activation if (alarmNotSet == false) { if (alarmString == rtc.getTimeStr()){ myGLCD.clrScr(); mp3.setVolume(25); mp3.playTrackByIndexNumber(1); delay(100); myGLCD.setFont(BigFont); myGLCD.setColor(255, 255, 255); myGLCD.print("ALARM", CENTER, 90); myGLCD.drawBitmap (127, 10, 65, 64, AlarmButton); myGLCD.print(alarmString, CENTER, 114); myGLCD.drawRoundRect (94, 146, 226, 170); myGLCD.print("DISMISS", CENTER, 150); boolean alarmOn = true; while (alarmOn){ if (myTouch.dataAvailable()) { myTouch.read(); x = myTouch.getX(); // X coordinate where the screen has been pressed y = myTouch.getY(); // Y coordinates where the screen has been pressed // Stop alarm button if ((x >= 94) && (x <= 226) && (y >= 146) && (y <= 170)) { drawRectFrame(94, 146, 226, 170); alarmOn = false; alarmString=""; myGLCD.clrScr(); mp3.stopPlayback(); delay(100); currentPage = '0'; playStatus = '0'; mp3.setVolume(15); drawHomeScreen(); } } } } } } void drawHomeScreen() { myGLCD.setBackColor(0, 0, 0); // Sets the background color of the area where the text will be printed to black myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.print(rtc.getDateStr(), 153, 7); myGLCD.print("T:", 7, 7); myGLCD.printNumI(rtc.getTemp(), 39, 7); myGLCD.print("C", 82, 7); myGLCD.setFont(SmallFont); myGLCD.print("o", 74, 5); if (alarmString == "" ) { myGLCD.setColor(255, 255, 255); myGLCD.print("by www.HowToMechatronics.com", CENTER, 215); } else { myGLCD.setColor(255, 255, 255); myGLCD.print("Alarm set for: ", 68, 215); myGLCD.print(alarmString, 188, 215); } drawMusicPlayerButton(); drawAlarmButton(); drawHomeClock(); } void drawMusicPlayerScreen() { // Title myGLCD.setBackColor(0, 0, 0); // Sets the background color of the area where the text will be printed to black myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(BigFont); // Sets font to big myGLCD.print("MENU", 5, 5); // Prints the string on the screen myGLCD.setColor(255, 0, 0); // Sets color to red myGLCD.drawLine(0, 26, 319, 26); // Draws the red line myGLCD.setColor(255, 255, 255); // Sets color to white myGLCD.setFont(SmallFont); // Sets font to big myGLCD.print("by www.HowToMechatronics.com", CENTER, 215); // Prints the string on the screen // Volume Bar myGLCD.setColor(255, 255, 255); myGLCD.fillRect (78, 184, 78 + 150, 184 + 8); myGLCD.setColor(240, 196, 30); myGLCD.fillRect (78, 184, 78 + 75, 184 + 8); // Track Bar myGLCD.setColor(255, 255, 255); myGLCD.fillRect (48, 50, 48 + 224, 50 + 8); myGLCD.setFont(SmallFont); myGLCD.setColor(255, 255, 255); myGLCD.print("0:00", 8, 48); myGLCD.print("-0:00", 276, 48); drawPlayButton(); if (playStatus == '2') { drawPauseButton(); } drawPreviousButton(); drawNextButton(); drawVolumeDown(); drawVolumeUp(); } void drawMusicPlayerButton() { myGLCD.drawBitmap (55, 125, 65, 64, MusicPlayerButton); } void drawAlarmButton() { myGLCD.drawBitmap (195, 125, 65, 64, AlarmButton); } void drawPlayButton() { myGLCD.drawBitmap (118, 79, 83, 83, ButtonPlay); } void drawPauseButton() { myGLCD.drawBitmap (118, 79, 83, 83, ButtonPause); } void drawNextButton() { myGLCD.drawBitmap (227, 97, 50, 50, NextButton); } void drawPreviousButton() { myGLCD.drawBitmap (45, 97, 50, 50, PreviousButton); } void drawVolumeDown() { myGLCD.drawBitmap (50, 177, 16, 23, VolumeDown); } void drawVolumeUp() { myGLCD.drawBitmap (241, 175, 34, 28, VolumeUp); } // check for if Mp3 Player is stopped bool checkFor_mp3IsStopped() { if (mp3Serial.available() > 0) { if (mp3.getPlaybackStatus() == 0) { return true; } } else return false; } // Highlights the button when pressed void drawFrame(int x, int y, int r) { myGLCD.setColor(255, 0, 0); myGLCD.drawCircle (x, y, r); while (myTouch.dataAvailable()) myTouch.read(); myGLCD.setColor(0, 0, 0); myGLCD.drawCircle (x, y, r); } void drawRectFrame(int x1, int y1, int x2, int y2) { myGLCD.setColor(255, 0, 0); myGLCD.drawRoundRect (x1, y1, x2, y2); while (myTouch.dataAvailable()) myTouch.read(); myGLCD.setColor(255, 255, 255); myGLCD.drawRoundRect (x1, y1, x2, y2); } void drawUnderline(int x1, int y1, int x2, int y2) { myGLCD.setColor(255, 0, 0); myGLCD.drawLine (x1, y1, x2, y2); while (myTouch.dataAvailable()) myTouch.read(); myGLCD.setColor(0, 0, 0); myGLCD.drawLine (x1, y1, x2, y2); } // Sound bar void drawVolume(int x) { myGLCD.setColor(255, 255, 255); myGLCD.fillRect (78 + 5 * x, 184, 78 + 150, 184 + 8); myGLCD.setColor(240, 196, 30); myGLCD.fillRect (78, 184, 78 + 5 * x, 184 + 8); } // Clears the track bar void drawTrackBar() { myGLCD.setColor(255, 255, 255); myGLCD.fillRect (48, 50, 48 + 224, 50 + 8); } // Updates the track bar void trackPlayTime() { totalTime = mp3.getTotalTrackPlaybackTime(); delay(10); elapsedTime = mp3.getElapsedTrackPlaybackTime(); delay(10); minutes = (int)elapsedTime / 60; seconds = (((float)elapsedTime / 60) - minutes) * 60; playback = totalTime - elapsedTime; minutesR = (int)playback / 60; secondsR = (((float)playback / 60) - minutesR) * 60; myGLCD.setFont(SmallFont); myGLCD.setColor(255, 255, 255); myGLCD.printNumI(minutes, 8, 48); myGLCD.print(":", 16, 48); myGLCD.printNumI((int)seconds, 24, 48, 2, '0'); myGLCD.print("-", 276, 48); myGLCD.printNumI(minutesR, 284, 48); myGLCD.print(":", 292, 48); myGLCD.printNumI((int)secondsR, 300, 48, 2, '0'); int trackBarX = map(elapsedTime, 0, totalTime, 0, 224); myGLCD.setColor(255, 0, 0); myGLCD.fillRect (48, 50, 48 + trackBarX, 50 + 8); if (totalTime == elapsedTime) { mp3.nextTrack(); delay(30); myGLCD.setColor(255, 255, 255); myGLCD.fillRect (48, 50, 48 + 224, 50 + 8); } } void printClock(int x, int y) { if ( currentClock != rtc.getTimeStr()) { myGLCD.print(rtc.getTimeStr(), x, y); currentClock = rtc.getTimeStr(); } } void drawColon() { myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 65, 4); myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (112, 85, 4); myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (208, 65, 4); myGLCD.setColor(0, 255, 0); myGLCD.fillCircle (208, 85, 4); } void drawHomeClock() { timeString = rtc.getTimeStr(); currentHours = timeString.substring(0, 2); currentMinutes = timeString.substring(3, 5); currentSeconds = timeString.substring(6, 8); myGLCD.setFont(SevenSegNumFont); myGLCD.setColor(0, 255, 0); myGLCD.print(currentSeconds, 224, 50); myGLCD.print(currentMinutes, 128, 50); myGLCD.print(currentHours, 32, 50); drawColon(); }
لطفا در زیر بخش نظرات هر سوالی را بپرسید و فراموش نکنید که مجموعه آموزش آردوینو را بررسی کنید.