Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Arduino.h>
- #include "esp_camera.h"
- #include <WiFi.h>
- #include "esp_http_server.h"
- // ==== AI THINKER PIN MAP ====
- #define PWDN_GPIO_NUM 32
- #define RESET_GPIO_NUM -1
- #define XCLK_GPIO_NUM 0
- #define SIOD_GPIO_NUM 26
- #define SIOC_GPIO_NUM 27
- #define Y9_GPIO_NUM 35
- #define Y8_GPIO_NUM 34
- #define Y7_GPIO_NUM 39
- #define Y6_GPIO_NUM 36
- #define Y5_GPIO_NUM 21
- #define Y4_GPIO_NUM 19
- #define Y3_GPIO_NUM 18
- #define Y2_GPIO_NUM 5
- #define VSYNC_GPIO_NUM 25
- #define HREF_GPIO_NUM 23
- #define PCLK_GPIO_NUM 22
- // ==== USER CONFIG ====
- const char* WIFI_SSID = "@@@@@@@";
- const char* WIFI_PASS = "@@@@@@@";
- constexpr int PIN_MQ2_DO = 13; // MQ-2 D0 (디지털)
- constexpr int PIN_LED_OUT = 14; // 외부 LED
- constexpr uint32_t MQ2_READ_PERIOD_MS = 3000; // 3초마다 판정
- constexpr uint32_t LED_BLINK_TIME_MS = 3000; // 감지 시 3초 점멸
- constexpr uint32_t LED_BLINK_INTERVAL = 200; // 점멸 간격
- // 상태
- uint32_t last_mq2_read_ms = 0;
- uint32_t led_blink_until = 0;
- uint32_t last_led_toggle = 0;
- bool led_state = false;
- // ==== MINIMAL MJPEG SERVER ====
- static httpd_handle_t g_httpd = NULL;
- static esp_err_t stream_handler(httpd_req_t *req) {
- httpd_resp_set_type(req, "multipart/x-mixed-replace; boundary=frame");
- while (true) {
- camera_fb_t *fb = esp_camera_fb_get();
- if (!fb) break;
- char hdr[64];
- size_t hlen = snprintf(hdr, sizeof(hdr),
- "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", fb->len);
- if (httpd_resp_send_chunk(req, hdr, hlen) != ESP_OK) { esp_camera_fb_return(fb); break; }
- if (httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len) != ESP_OK) { esp_camera_fb_return(fb); break; }
- if (httpd_resp_send_chunk(req, "\r\n", 2) != ESP_OK) { esp_camera_fb_return(fb); break; }
- esp_camera_fb_return(fb);
- vTaskDelay(10/portTICK_PERIOD_MS); // 과도한 점유 방지
- }
- return ESP_OK;
- }
- static void startStreamServer() {
- httpd_config_t cfg = HTTPD_DEFAULT_CONFIG();
- cfg.server_port = 80;
- cfg.max_open_sockets = 2;
- if (httpd_start(&g_httpd, &cfg) == ESP_OK) {
- httpd_uri_t uri{ .uri="/", .method=HTTP_GET, .handler=stream_handler, .user_ctx=NULL };
- httpd_register_uri_handler(g_httpd, &uri);
- }
- }
- // ==== CAMERA/WIFI ====
- static bool initCamera() {
- camera_config_t c{};
- c.ledc_channel = LEDC_CHANNEL_0;
- c.ledc_timer = LEDC_TIMER_0;
- c.pin_d0 = Y2_GPIO_NUM; c.pin_d1 = Y3_GPIO_NUM; c.pin_d2 = Y4_GPIO_NUM; c.pin_d3 = Y5_GPIO_NUM;
- c.pin_d4 = Y6_GPIO_NUM; c.pin_d5 = Y7_GPIO_NUM; c.pin_d6 = Y8_GPIO_NUM; c.pin_d7 = Y9_GPIO_NUM;
- c.pin_xclk = XCLK_GPIO_NUM; c.pin_pclk = PCLK_GPIO_NUM;
- c.pin_vsync = VSYNC_GPIO_NUM; c.pin_href = HREF_GPIO_NUM;
- c.pin_sscb_sda = SIOD_GPIO_NUM; c.pin_sscb_scl = SIOC_GPIO_NUM;
- c.pin_pwdn = PWDN_GPIO_NUM; c.pin_reset = RESET_GPIO_NUM;
- // 안정화 세팅
- c.xclk_freq_hz = 10000000; // 10MHz (불안정하면 20MHz로도 시험)
- c.pixel_format = PIXFORMAT_JPEG;
- c.frame_size = FRAMESIZE_QVGA; // 320x240 (필요 시 QQVGA로 더 낮춰도 됨)
- c.jpeg_quality = 20; // 압축↑, 부하↓
- c.fb_count = 1; // 단일 버퍼
- c.fb_location = CAMERA_FB_IN_DRAM; // PSRAM 회피
- c.grab_mode = CAMERA_GRAB_LATEST; // 새 프레임로 덮어쓰기 → DMA overflow 억제
- return (esp_camera_init(&c) == ESP_OK);
- }
- static void connectWiFi() {
- WiFi.mode(WIFI_STA);
- WiFi.begin(WIFI_SSID, WIFI_PASS);
- Serial.printf("Connecting to %s", WIFI_SSID);
- uint32_t t0 = millis();
- while (WiFi.status() != WL_CONNECTED) {
- delay(300); Serial.print(".");
- if (millis() - t0 > 20000) { // 20초마다 재시도
- Serial.println("\nWi-Fi retry");
- WiFi.disconnect(true); delay(300);
- WiFi.begin(WIFI_SSID, WIFI_PASS);
- t0 = millis();
- }
- }
- Serial.printf("\nIP: %s\n", WiFi.localIP().toString().c_str());
- }
- // ==== SETUP/LOOP ====
- void setup() {
- Serial.begin(115200);
- delay(200);
- pinMode(PIN_MQ2_DO, INPUT);
- pinMode(PIN_LED_OUT, OUTPUT);
- digitalWrite(PIN_LED_OUT, LOW);
- if (!initCamera()) { Serial.println("Camera init FAILED"); while(true) delay(1000); }
- Serial.println("Camera init OK");
- connectWiFi();
- startStreamServer();
- Serial.println("Open: http://<위 IP>/");
- // 첫 판정 즉시 수행되도록 보정
- last_mq2_read_ms = millis() - MQ2_READ_PERIOD_MS;
- }
- void loop() {
- uint32_t now = millis();
- // 3초마다 MQ-2 판정
- if (now - last_mq2_read_ms >= MQ2_READ_PERIOD_MS) {
- last_mq2_read_ms = now;
- int do_val = digitalRead(PIN_MQ2_DO); // 1=감지
- Serial.printf("[%lu ms] MQ2(D0)=%d -> %s\n",
- (unsigned long)now, do_val, (do_val ? "TRIGGER" : "OK"));
- if (do_val == HIGH) {
- led_blink_until = now + LED_BLINK_TIME_MS;
- // 반응성 확보: 즉시 한 번 토글
- led_state = !led_state;
- digitalWrite(PIN_LED_OUT, led_state ? HIGH : LOW);
- last_led_toggle = now;
- }
- }
- // 감지 시 LED 비차단 점멸
- if (now < led_blink_until) {
- if (now - last_led_toggle >= LED_BLINK_INTERVAL) {
- last_led_toggle = now;
- led_state = !led_state;
- digitalWrite(PIN_LED_OUT, led_state ? HIGH : LOW);
- }
- } else if (led_state) {
- led_state = false;
- digitalWrite(PIN_LED_OUT, LOW);
- }
- // WDT 여유
- delay(1);
- }
Advertisement
Add Comment
Please, Sign In to add comment