# [En-Huei's Repository:Prototype Practice] Week14: > last update: 又到了午夜24....QQ實驗室過夜數+1 :::info :bulb: This is the root page of En-Huei's course-taking in NTU Prototype Practice (NTU DS 5202), greetings! ::: > [course website](https://hackmd.io/@accomdemy/HJHny1ntn?fbclid=IwAR0uB-EyVc-1P7buX-8dc_FPLLvMqglfE-qAjTh3q4i-RIW5vW0n7rBrH4w) > [course slides](https://drive.google.com/drive/folders/1-cq5PQdRCdqZnpHY3pbeYFGUYU-AKXeT?usp=drive_link) [TOC] * Cross Week HyperLinks: * [Week1](https://hackmd.io/AvKCP5bcQO6sEwtX7-rTUQ?both#En-Huei%E2%80%99s-Repository%EF%BC%9APrototype-Practice-Week1%EF%BC%9AIntroduction) * [Week2](https://hackmd.io/@HCI-Lab/HJxzcTHCn) * [Week3](https://hackmd.io/@HCI-Lab/SyzdcpBCn) * [Week4](https://hackmd.io/@HCI-Lab/rkFNi6rR2) * [Week5](https://hackmd.io/@HCI-Lab/r1hBoarRn) * [Week6](https://hackmd.io/@HCI-Lab/HyaLjTHAh) * [Week7](https://hackmd.io/@HCI-Lab/BJCvoaHC3) * [Week8](https://hackmd.io/@HCI-Lab/H12OsTrA3) * [Week9](https://hackmd.io/@HCI-Lab/BkTYopSAh) * [Week10](https://hackmd.io/@HCI-Lab/BkysjTS03) * [Week11](https://hackmd.io/@HCI-Lab/HklnsarAn) * [Week12](https://hackmd.io/@HCI-Lab/HJ6hsaBAn) * [Week13](https://hackmd.io/@HCI-Lab/r1jpiTrAh) * [Week14](https://hackmd.io/@HCI-Lab/Sk2CjaHR2) * [Week15](https://hackmd.io/@HCI-Lab/SJsynTHA3) * [Week16](https://hackmd.io/@HCI-Lab/ByiLh6S0n) ## :pencil:Notes: - 14周繳交[小組專案介紹頁面](https://hackmd.io/@2u-kLCYCRs-5Ri0UKnA_gg/rJwjdeQEp),沒有個人頁面 - 針對音量感測做了優化,在實驗室環境可以做到偵測喇叭附近的突起音波,只是沒有方向性![](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6fe662de-cd0d-4c9d-9b35-7eea0ade7a51%2Fda9d7923-c08d-4cbd-8d41-948ebe5f9f2d%2FUntitled.png?table=block&id=2b2c7470-f915-488e-a1f8-74f198598f8e&spaceId=6fe662de-cd0d-4c9d-9b35-7eea0ade7a51&width=2000&userId=1b99bc9b-cd7e-44d1-b2bb-e645f450f574&cache=v2) - 原本要做螢幕顯示短片的,但因為測試從SD卡讀一張照片出來就要花1秒以上,網路上有做到影片或GIF播放之類的範例幾乎都要自洗電路,因此在最後關頭緊急換方案/函式庫,把接線改掉ㄌ![](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6fe662de-cd0d-4c9d-9b35-7eea0ade7a51%2F347fe708-7ce8-428e-9d32-dfe6e952fb23%2FUntitled.png?table=block&id=0cffc8a2-41a4-4ece-9f6e-e2daff6b2521&spaceId=6fe662de-cd0d-4c9d-9b35-7eea0ade7a51&width=1970&userId=1b99bc9b-cd7e-44d1-b2bb-e645f450f574&cache=v2) :::spoiler 最終的Demo測試程式碼 ``` c #include "Arduino.h" const int interval = 10; unsigned long loopTimer; int threshold = 60; int activeDuration = 1000; int mode; void CommonSetup() { Serial.begin(115200); // 開始輸出訊息到監控視窗 // randomly set mode to 1, 2, or 3 randomSeed(analogRead(0)); mode = random(1, 4); Serial.print("Mode:"); Serial.println(mode); } /*Volume Sensor*/ const int minVolume = 8; const int maxVolume = 30; int volume = minVolume; const float K = 0.1; int prevValue; int avgValue; long inteValue = 0; int index = 0; const int numToAvg = 100; void VolumeSensorSetup() { for (index = 0; index < numToAvg; index++) { prevValue = analogRead(A0); inteValue += prevValue; delay(10); } avgValue = inteValue / numToAvg; Serial.print("Avg Value = "); Serial.println(avgValue); inteValue = 0; index = 0; } void VolumeSensorLoopStep() { int sensorValue = analogRead(A0); // 讀取A0的值 sensorValue = sensorValue - avgValue; sensorValue = K * sensorValue + (1 - K) * prevValue; Serial.println(sensorValue); // 在監控視窗顯示讀取的值 prevValue = sensorValue; // inteValue += prevValue; // index++; // if (index >= numToAvg) { // avgValue = inteValue / numToAvg; // inteValue = 0; // index = 0; // } } /*End of Volume Sensor*/ /*MP3 Player*/ #include "DFRobotDFPlayerMini.h" #if (defined(ARDUINO_AVR_UNO) || defined(ESP8266)) // Using a soft serial port #include <SoftwareSerial.h> SoftwareSerial softSerial(/*rx =*/2, /*tx =*/3); #define FPSerial softSerial #else #define FPSerial Serial1 #endif DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); void MP3Setup() { #if (defined ESP32) FPSerial.begin(9600, SERIAL_8N1, /*rx =*/D3, /*tx =*/D2); #else FPSerial.begin(9600); #endif Serial.println(); Serial.println(F("DFRobot DFPlayer Mini Demo")); Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); if (!myDFPlayer.begin(FPSerial, /*isACK = */ true, /*doReset = */ true)) { // Use serial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while (true) ; } Serial.println(F("DFPlayer Mini online.")); myDFPlayer.setTimeOut(500); // Set serial communictaion time out 500ms //----Set volume---- myDFPlayer.volume(volume); // Set volume value (0~30). myDFPlayer.EQ(DFPLAYER_EQ_NORMAL); myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD); // myDFPlayer.loop(mode); myDFPlayer.playMp3Folder(mode); myDFPlayer.enableLoop(); } /*End of MP3 Player*/ /* TFT Display */ /* Arduino Watch Lite Version You may find full version at: https://github.com/moononournation/ArduinoWatch */ /******************************************************************************* * Start of Arduino_GFX setting * * Arduino_GFX try to find the settings depends on selected board in Arduino IDE * Or you can define the display dev kit not in the board list * Defalult pin list for non display dev kit: * Arduino Nano, Micro and more: CS: 9, DC: 8, RST: 7, BL: 6, SCK: 13, MOSI: 11, MISO: 12 * ESP32 various dev board : CS: 5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil * ESP32-C3 various dev board : CS: 7, DC: 2, RST: 1, BL: 3, SCK: 4, MOSI: 6, MISO: nil * ESP32-S2 various dev board : CS: 34, DC: 38, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil * ESP32-S3 various dev board : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil * ESP8266 various dev board : CS: 15, DC: 4, RST: 2, BL: 5, SCK: 14, MOSI: 13, MISO: 12 * Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16 * RTL8720 BW16 old patch core : CS: 18, DC: 17, RST: 2, BL: 23, SCK: 19, MOSI: 21, MISO: 20 * RTL8720_BW16 Official core : CS: 9, DC: 8, RST: 6, BL: 3, SCK: 10, MOSI: 12, MISO: 11 * RTL8722 dev board : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12 * RTL8722_mini dev board : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI: 9, MISO: 10 * Seeeduino XIAO dev board : CS: 3, DC: 2, RST: 1, BL: 0, SCK: 8, MOSI: 10, MISO: 9 * Teensy 4.1 dev board : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12 ******************************************************************************/ #include <Arduino_GFX_Library.h> const int TFT_RST = 7; #define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin /* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */ #if defined(DISPLAY_DEV_KIT) Arduino_GFX *gfx = create_default_Arduino_GFX(); #else /* !defined(DISPLAY_DEV_KIT) */ /* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */ Arduino_DataBus *bus = create_default_Arduino_DataBus(); /* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */ Arduino_GFX *gfx = new Arduino_ST7735( bus, TFT_RST /* RST */, 0 /* rotation */, false /* IPS */, 128 /* width */, 160 /* height */, 2 /* col offset 1 */, 1 /* row offset 1 */, 2 /* col offset 2 */, 1 /* row offset 2 */, false /* BGR */); #endif /* !defined(DISPLAY_DEV_KIT) */ /******************************************************************************* * End of Arduino_GFX setting ******************************************************************************/ #define BACKGROUND BLACK #define MARK_COLOR WHITE #define SUBMARK_COLOR DARKGREY // LIGHTGREY #define HOUR_COLOR WHITE #define MINUTE_COLOR BLUE // LIGHTGREY #define SECOND_COLOR RED #define SIXTIETH 0.016666667 #define TWELFTH 0.08333333 #define SIXTIETH_RADIAN 0.10471976 #define TWELFTH_RADIAN 0.52359878 #define RIGHT_ANGLE_RADIAN 1.5707963 static uint8_t conv2d(const char *p) { uint8_t v = 0; return (10 * (*p - '0')) + (*++p - '0'); } static int16_t w, h, center; static int16_t hHandLen, mHandLen, sHandLen, markLen; static float sdeg, mdeg, hdeg; static int16_t osx = 0, osy = 0, omx = 0, omy = 0, ohx = 0, ohy = 0; // Saved H, M, S x & y coords static int16_t nsx, nsy, nmx, nmy, nhx, nhy; // H, M, S x & y coords static int16_t xMin, yMin, xMax, yMax; // redraw range static int16_t hh, mm, ss; static unsigned long targetTime; // next action time static int16_t *cached_points; static uint16_t cached_points_idx = 0; static int16_t *last_cached_point; void DisplaySetup() { Serial.println("Arduino_GFX Clock example"); #ifdef GFX_EXTRA_PRE_INIT GFX_EXTRA_PRE_INIT(); #endif // Init Display if (!gfx->begin()) { Serial.println("gfx->begin() failed!"); } gfx->fillScreen(BACKGROUND); #ifdef GFX_BL pinMode(GFX_BL, OUTPUT); analogWrite(GFX_BL, 128); #endif // init LCD constant w = gfx->width(); h = gfx->height(); if (w < h) { center = w / 2; } else { center = h / 2; } hHandLen = center * 3 / 8; mHandLen = center * 2 / 3; sHandLen = center * 5 / 6; markLen = sHandLen / 6; cached_points = (int16_t *)malloc((hHandLen + 1 + mHandLen + 1 + sHandLen + 1) * 2 * 2); // Draw 60 clock marks // draw_round_clock_mark( draw_square_clock_mark( center - markLen, center, center - (markLen * 2 / 3), center, center - (markLen / 2), center); hh = conv2d(__TIME__); mm = conv2d(__TIME__ + 3); ss = conv2d(__TIME__ + 6); targetTime = ((millis() / 1000) + 1) * 1000; } void DisplayLoopStep() { unsigned long cur_millis = millis(); if (cur_millis >= targetTime) { targetTime += 1000; ss++; // Advance second if (ss == 60) { ss = 0; mm++; // Advance minute if (mm > 59) { mm = 0; hh++; // Advance hour if (hh > 23) { hh = 0; } } } } // Pre-compute hand degrees, x & y coords for a fast screen update sdeg = SIXTIETH_RADIAN * ((0.001 * (cur_millis % 1000)) + ss); // 0-59 (includes millis) nsx = cos(sdeg - RIGHT_ANGLE_RADIAN) * sHandLen + center; nsy = sin(sdeg - RIGHT_ANGLE_RADIAN) * sHandLen + center; if ((nsx != osx) || (nsy != osy)) { mdeg = (SIXTIETH * sdeg) + (SIXTIETH_RADIAN * mm); // 0-59 (includes seconds) hdeg = (TWELFTH * mdeg) + (TWELFTH_RADIAN * hh); // 0-11 (includes minutes) mdeg -= RIGHT_ANGLE_RADIAN; hdeg -= RIGHT_ANGLE_RADIAN; nmx = cos(mdeg) * mHandLen + center; nmy = sin(mdeg) * mHandLen + center; nhx = cos(hdeg) * hHandLen + center; nhy = sin(hdeg) * hHandLen + center; // redraw hands redraw_hands_cached_draw_and_erase(); ohx = nhx; ohy = nhy; omx = nmx; omy = nmy; osx = nsx; osy = nsy; delay(1); } } void draw_round_clock_mark(int16_t innerR1, int16_t outerR1, int16_t innerR2, int16_t outerR2, int16_t innerR3, int16_t outerR3) { float x, y; int16_t x0, x1, y0, y1, innerR, outerR; uint16_t c; for (uint8_t i = 0; i < 60; i++) { if ((i % 15) == 0) { innerR = innerR1; outerR = outerR1; c = MARK_COLOR; } else if ((i % 5) == 0) { innerR = innerR2; outerR = outerR2; c = MARK_COLOR; } else { innerR = innerR3; outerR = outerR3; c = SUBMARK_COLOR; } mdeg = (SIXTIETH_RADIAN * i) - RIGHT_ANGLE_RADIAN; x = cos(mdeg); y = sin(mdeg); x0 = x * outerR + center; y0 = y * outerR + center; x1 = x * innerR + center; y1 = y * innerR + center; gfx->drawLine(x0, y0, x1, y1, c); } } void draw_square_clock_mark(int16_t innerR1, int16_t outerR1, int16_t innerR2, int16_t outerR2, int16_t innerR3, int16_t outerR3) { float x, y; int16_t x0, x1, y0, y1, innerR, outerR; uint16_t c; for (uint8_t i = 0; i < 60; i++) { if ((i % 15) == 0) { innerR = innerR1; outerR = outerR1; c = MARK_COLOR; } else if ((i % 5) == 0) { innerR = innerR2; outerR = outerR2; c = MARK_COLOR; } else { innerR = innerR3; outerR = outerR3; c = SUBMARK_COLOR; } if ((i >= 53) || (i < 8)) { x = tan(SIXTIETH_RADIAN * i); x0 = center + (x * outerR); y0 = center + (1 - outerR); x1 = center + (x * innerR); y1 = center + (1 - innerR); } else if (i < 23) { y = tan((SIXTIETH_RADIAN * i) - RIGHT_ANGLE_RADIAN); x0 = center + (outerR); y0 = center + (y * outerR); x1 = center + (innerR); y1 = center + (y * innerR); } else if (i < 38) { x = tan(SIXTIETH_RADIAN * i); x0 = center - (x * outerR); y0 = center + (outerR); x1 = center - (x * innerR); y1 = center + (innerR); } else if (i < 53) { y = tan((SIXTIETH_RADIAN * i) - RIGHT_ANGLE_RADIAN); x0 = center + (1 - outerR); y0 = center - (y * outerR); x1 = center + (1 - innerR); y1 = center - (y * innerR); } gfx->drawLine(x0, y0, x1, y1, c); } } void redraw_hands_cached_draw_and_erase() { gfx->startWrite(); draw_and_erase_cached_line(center, center, nsx, nsy, SECOND_COLOR, cached_points, sHandLen + 1, false, false); draw_and_erase_cached_line(center, center, nhx, nhy, HOUR_COLOR, cached_points + ((sHandLen + 1) * 2), hHandLen + 1, true, false); draw_and_erase_cached_line(center, center, nmx, nmy, MINUTE_COLOR, cached_points + ((sHandLen + 1 + hHandLen + 1) * 2), mHandLen + 1, true, true); gfx->endWrite(); } void draw_and_erase_cached_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t color, int16_t *cache, int16_t cache_len, bool cross_check_second, bool cross_check_hour) { #if defined(ESP8266) yield(); #endif bool steep = _diff(y1, y0) > _diff(x1, x0); if (steep) { _swap_int16_t(x0, y0); _swap_int16_t(x1, y1); } int16_t dx, dy; dx = _diff(x1, x0); dy = _diff(y1, y0); int16_t err = dx / 2; int8_t xstep = (x0 < x1) ? 1 : -1; int8_t ystep = (y0 < y1) ? 1 : -1; x1 += xstep; int16_t x, y, ox, oy; for (uint16_t i = 0; i <= dx; i++) { if (steep) { x = y0; y = x0; } else { x = x0; y = y0; } ox = *(cache + (i * 2)); oy = *(cache + (i * 2) + 1); if ((x == ox) && (y == oy)) { if (cross_check_second || cross_check_hour) { write_cache_pixel(x, y, color, cross_check_second, cross_check_hour); } } else { write_cache_pixel(x, y, color, cross_check_second, cross_check_hour); if ((ox > 0) || (oy > 0)) { write_cache_pixel(ox, oy, BACKGROUND, cross_check_second, cross_check_hour); } *(cache + (i * 2)) = x; *(cache + (i * 2) + 1) = y; } if (err < dy) { y0 += ystep; err += dx; } err -= dy; x0 += xstep; } for (uint16_t i = dx + 1; i < cache_len; i++) { ox = *(cache + (i * 2)); oy = *(cache + (i * 2) + 1); if ((ox > 0) || (oy > 0)) { write_cache_pixel(ox, oy, BACKGROUND, cross_check_second, cross_check_hour); } *(cache + (i * 2)) = 0; *(cache + (i * 2) + 1) = 0; } } void write_cache_pixel(int16_t x, int16_t y, int16_t color, bool cross_check_second, bool cross_check_hour) { int16_t *cache = cached_points; if (cross_check_second) { for (uint16_t i = 0; i <= sHandLen; i++) { if ((x == *(cache++)) && (y == *(cache))) { return; } cache++; } } if (cross_check_hour) { cache = cached_points + ((sHandLen + 1) * 2); for (uint16_t i = 0; i <= hHandLen; i++) { if ((x == *(cache++)) && (y == *(cache))) { return; } cache++; } } gfx->writePixel(x, y, color); } /* End of TFT Display */ void setup() { loopTimer = millis(); CommonSetup(); VolumeSensorSetup(); MP3Setup(); DisplaySetup(); } void loop() { DisplayLoopStep(); VolumeSensorLoopStep(); // if prevValue > threshold, set the volume of MP3 player to 30 for activeDuration ms if (prevValue > threshold) { index = 0; // gradually rise to maximum volume while (volume < maxVolume) { volume++; myDFPlayer.volume(volume); VolumeSensorLoopStep(); } DisplayLoopStep(); delay(activeDuration); /* while (millis() - loopTimer < activeDuration) { VolumeSensorLoopStep(); } */ } else { index++; if (index >= 90) { index = 0; // gradually return to original volume while (volume > minVolume) { volume--; myDFPlayer.volume(volume); VolumeSensorLoopStep(); delay(5); } } } while (millis() - loopTimer < interval) { } loopTimer = millis(); } ``` ::: ## :mountain:Challenges: - (茶) - 好燙! :::spoiler :cry:首次3D列印的外殼失敗了,先以手邊的盒子大概抓元件配置的尺寸及位置 ![](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6fe662de-cd0d-4c9d-9b35-7eea0ade7a51%2Fd51cdd36-a01b-4185-82b9-e74277ba0b65%2FBoxes_(1).jpg?table=block&id=48f0ee70-017c-4525-a3a3-428b949455b6&spaceId=6fe662de-cd0d-4c9d-9b35-7eea0ade7a51&width=1970&userId=1b99bc9b-cd7e-44d1-b2bb-e645f450f574&cache=v2) ![](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6fe662de-cd0d-4c9d-9b35-7eea0ade7a51%2Fdc1cbcc3-4ae1-40d2-88f5-e547de98a040%2FBoxes_(3).jpg?table=block&id=73d90654-1808-478d-bfcd-37711e717de5&spaceId=6fe662de-cd0d-4c9d-9b35-7eea0ade7a51&width=1970&userId=1b99bc9b-cd7e-44d1-b2bb-e645f450f574&cache=v2) ![](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6fe662de-cd0d-4c9d-9b35-7eea0ade7a51%2Fa8c88bf2-d7db-4068-b2cb-f6d9936b2815%2FBoxes_(2).jpg?table=block&id=67e6a485-fe74-4609-b2c9-8c9494e13c47&spaceId=6fe662de-cd0d-4c9d-9b35-7eea0ade7a51&width=1970&userId=1b99bc9b-cd7e-44d1-b2bb-e645f450f574&cache=v2) ::: --- ## :phone:Contact Informations: > Feel free to reach me out for insteresting things~ :::spoiler :house: Location > En-Huei Wu > HCI Lab, Department of Computer Science and Information Engineering (Dertian Hall) > Room. 336, No. 170, Sec. 2, Xinhai Road, Taipei, 10617 Taiwan (R.O.C) > National Taiwan University > No. 1, Sec. 4, Roosevelt Road, Taipei, 10617 Taiwan (R.O.C) ::: - :mailbox: slime52ray@gmail.com (persona mailbox) - :mailbox: r12922105@ntu.edu.tw (school mailbox)