Guest User

바보

a guest
Oct 6th, 2025
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.37 KB | None | 0 0
  1. #include <Arduino.h>
  2. #include "esp_camera.h"
  3. #include <WiFi.h>
  4. #include "esp_http_server.h"
  5.  
  6. // ==== AI THINKER PIN MAP ====
  7. #define PWDN_GPIO_NUM 32
  8. #define RESET_GPIO_NUM -1
  9. #define XCLK_GPIO_NUM 0
  10. #define SIOD_GPIO_NUM 26
  11. #define SIOC_GPIO_NUM 27
  12. #define Y9_GPIO_NUM 35
  13. #define Y8_GPIO_NUM 34
  14. #define Y7_GPIO_NUM 39
  15. #define Y6_GPIO_NUM 36
  16. #define Y5_GPIO_NUM 21
  17. #define Y4_GPIO_NUM 19
  18. #define Y3_GPIO_NUM 18
  19. #define Y2_GPIO_NUM 5
  20. #define VSYNC_GPIO_NUM 25
  21. #define HREF_GPIO_NUM 23
  22. #define PCLK_GPIO_NUM 22
  23.  
  24. // ==== USER CONFIG ====
  25. const char* WIFI_SSID = "@@@@@@@";
  26. const char* WIFI_PASS = "@@@@@@@";
  27.  
  28. constexpr int PIN_MQ2_DO = 13; // MQ-2 D0 (디지털)
  29. constexpr int PIN_LED_OUT = 14; // 외부 LED
  30.  
  31. constexpr uint32_t MQ2_READ_PERIOD_MS = 3000; // 3초마다 판정
  32. constexpr uint32_t LED_BLINK_TIME_MS = 3000; // 감지 시 3초 점멸
  33. constexpr uint32_t LED_BLINK_INTERVAL = 200; // 점멸 간격
  34.  
  35. // 상태
  36. uint32_t last_mq2_read_ms = 0;
  37. uint32_t led_blink_until = 0;
  38. uint32_t last_led_toggle = 0;
  39. bool led_state = false;
  40.  
  41. // ==== MINIMAL MJPEG SERVER ====
  42. static httpd_handle_t g_httpd = NULL;
  43.  
  44. static esp_err_t stream_handler(httpd_req_t *req) {
  45. httpd_resp_set_type(req, "multipart/x-mixed-replace; boundary=frame");
  46. while (true) {
  47. camera_fb_t *fb = esp_camera_fb_get();
  48. if (!fb) break;
  49. char hdr[64];
  50. size_t hlen = snprintf(hdr, sizeof(hdr),
  51. "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", fb->len);
  52. if (httpd_resp_send_chunk(req, hdr, hlen) != ESP_OK) { esp_camera_fb_return(fb); break; }
  53. if (httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len) != ESP_OK) { esp_camera_fb_return(fb); break; }
  54. if (httpd_resp_send_chunk(req, "\r\n", 2) != ESP_OK) { esp_camera_fb_return(fb); break; }
  55. esp_camera_fb_return(fb);
  56. vTaskDelay(10/portTICK_PERIOD_MS); // 과도한 점유 방지
  57. }
  58. return ESP_OK;
  59. }
  60.  
  61. static void startStreamServer() {
  62. httpd_config_t cfg = HTTPD_DEFAULT_CONFIG();
  63. cfg.server_port = 80;
  64. cfg.max_open_sockets = 2;
  65. if (httpd_start(&g_httpd, &cfg) == ESP_OK) {
  66. httpd_uri_t uri{ .uri="/", .method=HTTP_GET, .handler=stream_handler, .user_ctx=NULL };
  67. httpd_register_uri_handler(g_httpd, &uri);
  68. }
  69. }
  70.  
  71. // ==== CAMERA/WIFI ====
  72. static bool initCamera() {
  73. camera_config_t c{};
  74. c.ledc_channel = LEDC_CHANNEL_0;
  75. c.ledc_timer = LEDC_TIMER_0;
  76. c.pin_d0 = Y2_GPIO_NUM; c.pin_d1 = Y3_GPIO_NUM; c.pin_d2 = Y4_GPIO_NUM; c.pin_d3 = Y5_GPIO_NUM;
  77. c.pin_d4 = Y6_GPIO_NUM; c.pin_d5 = Y7_GPIO_NUM; c.pin_d6 = Y8_GPIO_NUM; c.pin_d7 = Y9_GPIO_NUM;
  78. c.pin_xclk = XCLK_GPIO_NUM; c.pin_pclk = PCLK_GPIO_NUM;
  79. c.pin_vsync = VSYNC_GPIO_NUM; c.pin_href = HREF_GPIO_NUM;
  80. c.pin_sscb_sda = SIOD_GPIO_NUM; c.pin_sscb_scl = SIOC_GPIO_NUM;
  81. c.pin_pwdn = PWDN_GPIO_NUM; c.pin_reset = RESET_GPIO_NUM;
  82.  
  83. // 안정화 세팅
  84. c.xclk_freq_hz = 10000000; // 10MHz (불안정하면 20MHz로도 시험)
  85. c.pixel_format = PIXFORMAT_JPEG;
  86. c.frame_size = FRAMESIZE_QVGA; // 320x240 (필요 시 QQVGA로 더 낮춰도 됨)
  87. c.jpeg_quality = 20; // 압축↑, 부하↓
  88. c.fb_count = 1; // 단일 버퍼
  89. c.fb_location = CAMERA_FB_IN_DRAM; // PSRAM 회피
  90. c.grab_mode = CAMERA_GRAB_LATEST; // 새 프레임로 덮어쓰기 → DMA overflow 억제
  91.  
  92. return (esp_camera_init(&c) == ESP_OK);
  93. }
  94.  
  95. static void connectWiFi() {
  96. WiFi.mode(WIFI_STA);
  97. WiFi.begin(WIFI_SSID, WIFI_PASS);
  98. Serial.printf("Connecting to %s", WIFI_SSID);
  99. uint32_t t0 = millis();
  100. while (WiFi.status() != WL_CONNECTED) {
  101. delay(300); Serial.print(".");
  102. if (millis() - t0 > 20000) { // 20초마다 재시도
  103. Serial.println("\nWi-Fi retry");
  104. WiFi.disconnect(true); delay(300);
  105. WiFi.begin(WIFI_SSID, WIFI_PASS);
  106. t0 = millis();
  107. }
  108. }
  109. Serial.printf("\nIP: %s\n", WiFi.localIP().toString().c_str());
  110. }
  111.  
  112. // ==== SETUP/LOOP ====
  113. void setup() {
  114. Serial.begin(115200);
  115. delay(200);
  116.  
  117. pinMode(PIN_MQ2_DO, INPUT);
  118. pinMode(PIN_LED_OUT, OUTPUT);
  119. digitalWrite(PIN_LED_OUT, LOW);
  120.  
  121. if (!initCamera()) { Serial.println("Camera init FAILED"); while(true) delay(1000); }
  122. Serial.println("Camera init OK");
  123.  
  124. connectWiFi();
  125. startStreamServer();
  126. Serial.println("Open: http://<위 IP>/");
  127.  
  128. // 첫 판정 즉시 수행되도록 보정
  129. last_mq2_read_ms = millis() - MQ2_READ_PERIOD_MS;
  130. }
  131.  
  132. void loop() {
  133. uint32_t now = millis();
  134.  
  135. // 3초마다 MQ-2 판정
  136. if (now - last_mq2_read_ms >= MQ2_READ_PERIOD_MS) {
  137. last_mq2_read_ms = now;
  138.  
  139. int do_val = digitalRead(PIN_MQ2_DO); // 1=감지
  140. Serial.printf("[%lu ms] MQ2(D0)=%d -> %s\n",
  141. (unsigned long)now, do_val, (do_val ? "TRIGGER" : "OK"));
  142.  
  143. if (do_val == HIGH) {
  144. led_blink_until = now + LED_BLINK_TIME_MS;
  145. // 반응성 확보: 즉시 한 번 토글
  146. led_state = !led_state;
  147. digitalWrite(PIN_LED_OUT, led_state ? HIGH : LOW);
  148. last_led_toggle = now;
  149. }
  150. }
  151.  
  152. // 감지 시 LED 비차단 점멸
  153. if (now < led_blink_until) {
  154. if (now - last_led_toggle >= LED_BLINK_INTERVAL) {
  155. last_led_toggle = now;
  156. led_state = !led_state;
  157. digitalWrite(PIN_LED_OUT, led_state ? HIGH : LOW);
  158. }
  159. } else if (led_state) {
  160. led_state = false;
  161. digitalWrite(PIN_LED_OUT, LOW);
  162. }
  163.  
  164. // WDT 여유
  165. delay(1);
  166. }
  167.  
Advertisement
Add Comment
Please, Sign In to add comment