esp32开发与应用(项目1- 仿电报发射系统)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        前面,我们学习了屏幕驱动,学习了lvgl,也学习了触摸屏。但是很多开发,尤其是成本要求很高的场景,本身其实是用不了触摸屏的。这个时候,那就只有一个办法,屏幕配合按键使用。要是加上蜂鸣器和led,就是一个仿真的电报发射系统。问题来了,该怎么使用呢?

1、简单的场景直接创建任务操作

        如果应用比较简单,通常情况下,就是直接开启一个task,这个task循环读取key的状态,然后更新控件的状态。这是简单场景的处理方式。

2、复杂场景先进状态机再更新界面

        如果应用稍微复杂一点,比如一个应用达到几千行代码了,这个时候再用一个task来处理,就不合适了。这种情况下比较适合的做法,就是按键事件先送到状态机,状态机处理完了,然后送到一个专门的线程更新界面。这样界面归界面,程序归程序,比较简洁一点。

3、一定要动手去做实验

        虽然这个应用不复杂,但是真的去做的话,还是会遇到问题。比如,很有可能按键电路会搭错。这种上拉的按键电路知道是一回事,画出来是一回事,用面包板搭出来又是另外一回事。所以,大家一定不要怕麻烦,还是要多搭建电路,利用问题去逼着自己成长。

4、用ai先写按键代码

        走到这里,其实就可以让ai帮我们写代码。可以在之前一节的基础上编写,比如通知ai,编写一个用d25做按键的代码,按下去的时候,需要对label做自增处理,这样就可以得到下面这些内容,

#include <stdio.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#include "esp_timer.h"
#include "esp_task_wdt.h"

#include "driver/spi_master.h"
#include "driver/gpio.h"

#include "lvgl.h"

//================================================
// ILI9341 CONFIG
//================================================
#define ILI9341_SPI_HOST    SPI2_HOST
#define ILI9341_SCLK_PIN    14
#define ILI9341_MOSI_PIN    13
#define ILI9341_CS_PIN      15
#define ILI9341_DC_PIN      2
#define ILI9341_RST_PIN     4
#define ILI9341_BL_PIN      12

#define ILI9341_WIDTH       320
#define ILI9341_HEIGHT      240

//================================================
// XPT2046 TOUCH CONFIG
//================================================
#define XPT2046_SPI_HOST    SPI3_HOST
#define XPT2046_SCLK_PIN    18
#define XPT2046_MOSI_PIN    19
#define XPT2046_MISO_PIN    21
#define XPT2046_CS_PIN      5
#define XPT2046_IRQ_PIN     22

#define XPT2046_CMD_X       0xD0
#define XPT2046_CMD_Y       0x90

#define TOUCH_THRESHOLD     50

//================================================
// D25 BUTTON CONFIG
//================================================
#define D25_BUTTON_PIN      25
#define DEBOUNCE_MS         50      // Debounce time 50ms

static spi_device_handle_t ili9341_spi;
static spi_device_handle_t xpt2046_spi;

static SemaphoreHandle_t lvgl_mutex;

static lv_obj_t *label_count;
static lv_obj_t *btn_increment;
static int counter = 0;

// D25 button state variables
static bool d25_button_last_state = true;   // Last state (high = not pressed due to pull-up)
static TickType_t d25_button_last_tick = 0; // Timestamp of last state change

//================================================
// LCD SPI LOW LEVEL
//================================================
static void ili9341_send_cmd(uint8_t cmd)
{
    gpio_set_level(ILI9341_DC_PIN, 0);
    spi_transaction_t t = {
        .length = 8,
        .tx_buffer = &cmd
    };
    spi_device_transmit(ili9341_spi, &t);
}

static void ili9341_send_data(const uint8_t *data, size_t len)
{
    gpio_set_level(ILI9341_DC_PIN, 1);
    spi_transaction_t t = {
        .length = len * 8,
        .tx_buffer = data
    };
    spi_device_transmit(ili9341_spi, &t);
}

static void ili9341_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    ili9341_send_cmd(0x2A);
    uint8_t col[] = {x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF};
    ili9341_send_data(col, 4);

    ili9341_send_cmd(0x2B);
    uint8_t row[] = {y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF};
    ili9341_send_data(row, 4);

    ili9341_send_cmd(0x2C);
}

static void ili9341_flush_cb(lv_disp_drv_t *drv,
                              const lv_area_t *area,
                              lv_color_t *color_map)
{
    uint32_t w = area->x2 - area->x1 + 1;
    uint32_t h = area->y2 - area->y1 + 1;

    ili9341_set_window(area->x1, area->y1, area->x2, area->y2);

    gpio_set_level(ILI9341_DC_PIN, 1);

    spi_transaction_t t = {
        .length = w * h * 16,
        .tx_buffer = color_map
    };

    spi_device_transmit(ili9341_spi, &t);
    lv_disp_flush_ready(drv);
}

//================================================
// LCD INIT
//================================================
static void ili9341_init(void)
{
    gpio_set_level(ILI9341_RST_PIN, 0);
    vTaskDelay(pdMS_TO_TICKS(100));
    gpio_set_level(ILI9341_RST_PIN, 1);
    vTaskDelay(pdMS_TO_TICKS(120));

    ili9341_send_cmd(0x01);  // Software reset
    vTaskDelay(pdMS_TO_TICKS(120));

    ili9341_send_cmd(0x11);  // Exit sleep mode
    vTaskDelay(pdMS_TO_TICKS(120));

    ili9341_send_cmd(0x3A);  // Set pixel format
    ili9341_send_data((uint8_t[]){0x55}, 1); // 16-bit color

    ili9341_send_cmd(0x36);  // Set memory access control
    ili9341_send_data((uint8_t[]){0x28}, 1);

    ili9341_send_cmd(0x29);  // Display on

    gpio_set_level(ILI9341_BL_PIN, 1); // Turn on backlight
}

//================================================
// SPI INIT LCD
//================================================
static void ili9341_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask =
            (1ULL << ILI9341_DC_PIN) |
            (1ULL << ILI9341_RST_PIN) |
            (1ULL << ILI9341_BL_PIN),
        .mode = GPIO_MODE_OUTPUT
    };
    gpio_config(&io);

    spi_bus_config_t buscfg = {
        .mosi_io_num = ILI9341_MOSI_PIN,
        .miso_io_num = -1,
        .sclk_io_num = ILI9341_SCLK_PIN,
        .max_transfer_sz = ILI9341_WIDTH * ILI9341_HEIGHT * 2
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 20 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = ILI9341_CS_PIN,
        .queue_size = 7
    };

    spi_bus_initialize(ILI9341_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(ILI9341_SPI_HOST, &devcfg, &ili9341_spi);
}

//================================================
// SPI INIT TOUCH
//================================================
static void xpt2046_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << XPT2046_IRQ_PIN),
        .mode = GPIO_MODE_INPUT
    };
    gpio_config(&io);

    spi_bus_config_t buscfg = {
        .mosi_io_num = XPT2046_MOSI_PIN,
        .miso_io_num = XPT2046_MISO_PIN,
        .sclk_io_num = XPT2046_SCLK_PIN,
        .max_transfer_sz = 8
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 2 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = XPT2046_CS_PIN,
        .queue_size = 1
    };

    spi_bus_initialize(XPT2046_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(XPT2046_SPI_HOST, &devcfg, &xpt2046_spi);
}

//================================================
// D25 BUTTON INIT
//================================================
static void d25_button_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << D25_BUTTON_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,    // Enable internal pull-up
        .pull_down_en = GPIO_PULLDOWN_DISABLE
    };
    gpio_config(&io);
    
    // Read initial state (high = not pressed)
    d25_button_last_state = gpio_get_level(D25_BUTTON_PIN);
    d25_button_last_tick = xTaskGetTickCount();
}

//================================================
// D25 BUTTON READ WITH DEBOUNCE
//================================================
static bool d25_button_is_pressed(void)
{
    bool current_state = gpio_get_level(D25_BUTTON_PIN);
    TickType_t current_tick = xTaskGetTickCount();
    
    // Detect level change
    if (current_state != d25_button_last_state) {
        // Record change timestamp
        d25_button_last_tick = current_tick;
        d25_button_last_state = current_state;
        return false;
    }
    
    // Level stable and duration exceeds debounce time
    if ((current_tick - d25_button_last_tick) >= pdMS_TO_TICKS(DEBOUNCE_MS)) {
        // Low level = pressed (active low)
        if (current_state == 0) {
            return true;
        }
    }
    
    return false;
}

//================================================
// TOUCH READ
//================================================
static uint16_t xpt2046_read_adc(uint8_t cmd)
{
    uint8_t tx[3] = {cmd, 0, 0};
    uint8_t rx[3] = {0};

    spi_transaction_t t = {
        .length = 24,
        .tx_buffer = tx,
        .rx_buffer = rx
    };

    spi_device_transmit(xpt2046_spi, &t);

    return ((rx[1] << 8) | rx[2]) >> 3 & 0x0FFF;
}

static bool xpt2046_read_touch(uint16_t *x, uint16_t *y)
{
    if (gpio_get_level(XPT2046_IRQ_PIN) == 1) {
        return false;  // No touch detected
    }

    uint16_t raw_x = xpt2046_read_adc(XPT2046_CMD_X);
    uint16_t raw_y = xpt2046_read_adc(XPT2046_CMD_Y);
    uint16_t z1    = xpt2046_read_adc(0xB0);

    if (z1 < TOUCH_THRESHOLD) {
        return false;  // Pressure too light
    }

    // Map raw ADC values to screen coordinates
    *x = (raw_x * ILI9341_WIDTH) / 4095;
    *y = (raw_y * ILI9341_HEIGHT) / 4095;

    // Clamp values to screen boundaries
    if (*x >= ILI9341_WIDTH) *x = ILI9341_WIDTH - 1;
    if (*y >= ILI9341_HEIGHT) *y = ILI9341_HEIGHT - 1;

    return true;
}

//================================================
// TOUCH LVGL CALLBACK
//================================================
static void touch_cb(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    uint16_t x, y;

    if (xpt2046_read_touch(&x, &y)) {
        data->state = LV_INDEV_STATE_PRESSED;
        data->point.x = x;
        data->point.y = y;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

//================================================
// UI
//================================================
static void btn_event_cb(lv_event_t *e)
{
    if (lv_event_get_code(e) == LV_EVENT_CLICKED) {

        if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
            counter++;

            char buf[32];
            sprintf(buf, "Count: %d", counter);

            lv_label_set_text(label_count, buf);

            xSemaphoreGive(lvgl_mutex);
        }
    }
}

static void ui_create(void)
{
    // Set background color to white
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_white(), 0);

    // Create counter label
    label_count = lv_label_create(lv_scr_act());
    lv_label_set_text(label_count, "Count: 0");
    lv_obj_align(label_count, LV_ALIGN_CENTER, 0, -40);

    // Create increment button
    btn_increment = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn_increment, 120, 50);
    lv_obj_align(btn_increment, LV_ALIGN_CENTER, 0, 40);

    // Create button label
    lv_obj_t *lbl = lv_label_create(btn_increment);
    lv_label_set_text(lbl, "Press");
    lv_obj_center(lbl);

    // Register button click event
    lv_obj_add_event_cb(btn_increment, btn_event_cb, LV_EVENT_CLICKED, NULL);
}

//================================================
// LVGL TICK
//================================================
static void lv_tick_cb(void *arg)
{
    lv_tick_inc(1);
}

//================================================
// D25 BUTTON TASK
//================================================
static void d25_button_task(void *pvParameter)
{
    while (1) {
        // Check if D25 button is pressed (with debounce)
        if (d25_button_is_pressed()) {
            printf("D25 Button pressed!\n");
            
            // Acquire LVGL mutex and update counter
            if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
                counter++;
                
                char buf[40];
                sprintf(buf, "Count: %d", counter);
                lv_label_set_text(label_count, buf);
                
                xSemaphoreGive(lvgl_mutex);
            }
            
            // Prevent multiple triggers from a single press
            vTaskDelay(pdMS_TO_TICKS(200));
        }
        
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

//================================================
// MAIN
//================================================
void app_main(void)
{
    printf("START\n");

    // Create mutex for LVGL operations
    lvgl_mutex = xSemaphoreCreateMutex();

    // Initialize LCD SPI and display
    ili9341_spi_init();
    ili9341_init();

    // Initialize touch controller SPI
    xpt2046_spi_init();

    // Initialize D25 button
    d25_button_init();

    // Initialize LVGL
    lv_init();

    // Create timer for LVGL tick
    esp_timer_handle_t timer;
    esp_timer_create_args_t args = {
        .callback = lv_tick_cb,
        .name = "lv_tick"
    };
    esp_timer_create(&args, &timer);
    esp_timer_start_periodic(timer, 1000); // 1ms tick

    // Initialize display buffer
    static lv_disp_draw_buf_t draw_buf;
    static lv_color_t buf1[ILI9341_WIDTH * 20];
    static lv_color_t buf2[ILI9341_WIDTH * 20];

    lv_disp_draw_buf_init(&draw_buf, buf1, buf2, ILI9341_WIDTH * 20);

    // Register display driver
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = ILI9341_WIDTH;
    disp_drv.ver_res = ILI9341_HEIGHT;
    disp_drv.flush_cb = ili9341_flush_cb;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);

    // Register touch input driver
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_cb;
    lv_indev_drv_register(&indev_drv);

    // Create UI
    ui_create();

    // Create D25 button detection task
    xTaskCreate(d25_button_task, "d25_button_task", 2048, NULL, 5, NULL);

    // Add main task to watchdog
    esp_task_wdt_add(NULL);

    // Main loop
    while (1) {
        esp_task_wdt_reset();       // Reset watchdog
        lv_timer_handler();         // Handle LVGL tasks
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

5、编译和测试

        代码写好后,直接copy过去编一下。因为本身代码内容就是ok的,让ai添加的内容不多,所以生成的代码很容易是对的。接着,直接编译烧录即可。如果跑起来没什么问题,就可以按键按下去试试了。

        功能没问题的情况下,再看看逻辑对不对。

6、再加上蜂鸣器

        前面我们已经有屏幕、触摸屏和按键了,试想一下,再加上d26蜂鸣器呢?即,按下去的时候,蜂鸣器响,松开的时候,停止。当然这个时候,如果继续让ai做,也是可以的。但是,我们会发现代码到达一定的行数时,ai会摆烂,国内国外的ai都是如此。或许是能力不行,或许是市场策略的考虑,用商业ai模型或许好一点。这个时候,就需要自己在ai基础上,稍微修改一下代码,其实也是可以的。比如,我们可以这么修改,

#include <stdio.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#include "esp_timer.h"
#include "esp_task_wdt.h"

#include "driver/spi_master.h"
#include "driver/gpio.h"

#include "lvgl.h"

//================================================
// ILI9341 CONFIG
//================================================
#define ILI9341_SPI_HOST    SPI2_HOST
#define ILI9341_SCLK_PIN    14
#define ILI9341_MOSI_PIN    13
#define ILI9341_CS_PIN      15
#define ILI9341_DC_PIN      2
#define ILI9341_RST_PIN     4
#define ILI9341_BL_PIN      12

#define ILI9341_WIDTH       320
#define ILI9341_HEIGHT      240

//================================================
// XPT2046 TOUCH CONFIG
//================================================
#define XPT2046_SPI_HOST    SPI3_HOST
#define XPT2046_SCLK_PIN    18
#define XPT2046_MOSI_PIN    19
#define XPT2046_MISO_PIN    21
#define XPT2046_CS_PIN      5
#define XPT2046_IRQ_PIN     22

#define XPT2046_CMD_X       0xD0
#define XPT2046_CMD_Y       0x90

#define TOUCH_THRESHOLD     50

//================================================
// D25 / D26 CONFIG
//================================================
#define D25_BUTTON_PIN      25
#define D26_BUZZER_PIN      26
#define DEBOUNCE_MS         50

//================================================
// GLOBAL
//================================================
static spi_device_handle_t ili9341_spi;
static spi_device_handle_t xpt2046_spi;

static SemaphoreHandle_t lvgl_mutex;

static lv_obj_t *label_count;
static lv_obj_t *btn_increment;
static int counter = 0;

static bool d25_button_last_state = true;
static TickType_t d25_button_last_tick = 0;

//================================================
// LCD LOW LEVEL
//================================================
static void ili9341_send_cmd(uint8_t cmd)
{
    gpio_set_level(ILI9341_DC_PIN, 0);
    spi_transaction_t t = {
        .length = 8,
        .tx_buffer = &cmd
    };
    spi_device_transmit(ili9341_spi, &t);
}

static void ili9341_send_data(const uint8_t *data, size_t len)
{
    gpio_set_level(ILI9341_DC_PIN, 1);
    spi_transaction_t t = {
        .length = len * 8,
        .tx_buffer = data
    };
    spi_device_transmit(ili9341_spi, &t);
}

static void ili9341_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    ili9341_send_cmd(0x2A);
    uint8_t col[] = {x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF};
    ili9341_send_data(col, 4);

    ili9341_send_cmd(0x2B);
    uint8_t row[] = {y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF};
    ili9341_send_data(row, 4);

    ili9341_send_cmd(0x2C);
}

static void ili9341_flush_cb(lv_disp_drv_t *drv,
                              const lv_area_t *area,
                              lv_color_t *color_map)
{
    uint32_t w = area->x2 - area->x1 + 1;
    uint32_t h = area->y2 - area->y1 + 1;

    ili9341_set_window(area->x1, area->y1, area->x2, area->y2);

    gpio_set_level(ILI9341_DC_PIN, 1);

    spi_transaction_t t = {
        .length = w * h * 16,
        .tx_buffer = color_map
    };

    spi_device_transmit(ili9341_spi, &t);
    lv_disp_flush_ready(drv);
}

//================================================
// LCD INIT
//================================================
static void ili9341_init(void)
{
    gpio_set_level(ILI9341_RST_PIN, 0);
    vTaskDelay(pdMS_TO_TICKS(100));
    gpio_set_level(ILI9341_RST_PIN, 1);
    vTaskDelay(pdMS_TO_TICKS(120));

    ili9341_send_cmd(0x11);
    vTaskDelay(pdMS_TO_TICKS(120));

    ili9341_send_cmd(0x3A);
    ili9341_send_data((uint8_t[]){0x55}, 1);

    ili9341_send_cmd(0x36);
    ili9341_send_data((uint8_t[]){0x28}, 1);

    ili9341_send_cmd(0x29);

    gpio_set_level(ILI9341_BL_PIN, 1);
}

//================================================
// SPI LCD INIT
//================================================
static void ili9341_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask =
            (1ULL << ILI9341_DC_PIN) |
            (1ULL << ILI9341_RST_PIN) |
            (1ULL << ILI9341_BL_PIN),
        .mode = GPIO_MODE_OUTPUT
    };
    gpio_config(&io);

    spi_bus_config_t buscfg = {
        .mosi_io_num = ILI9341_MOSI_PIN,
        .miso_io_num = -1,
        .sclk_io_num = ILI9341_SCLK_PIN,
        .max_transfer_sz = ILI9341_WIDTH * ILI9341_HEIGHT * 2
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 20 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = ILI9341_CS_PIN,
        .queue_size = 7
    };

    spi_bus_initialize(ILI9341_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(ILI9341_SPI_HOST, &devcfg, &ili9341_spi);
}

//================================================
// TOUCH INIT
//================================================
static void xpt2046_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << XPT2046_IRQ_PIN),
        .mode = GPIO_MODE_INPUT
    };
    gpio_config(&io);

    spi_bus_config_t buscfg = {
        .mosi_io_num = XPT2046_MOSI_PIN,
        .miso_io_num = XPT2046_MISO_PIN,
        .sclk_io_num = XPT2046_SCLK_PIN,
        .max_transfer_sz = 8
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 2 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = XPT2046_CS_PIN,
        .queue_size = 1
    };

    spi_bus_initialize(XPT2046_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(XPT2046_SPI_HOST, &devcfg, &xpt2046_spi);
}

//================================================
// BUZZER INIT (D26)
//================================================
static void buzzer_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << D26_BUZZER_PIN),
        .mode = GPIO_MODE_OUTPUT
    };
    gpio_config(&io);

    gpio_set_level(D26_BUZZER_PIN, 1);
}

//================================================
// D25 BUTTON
//================================================
static void d25_button_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << D25_BUTTON_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE
    };
    gpio_config(&io);

    d25_button_last_state = gpio_get_level(D25_BUTTON_PIN);
    d25_button_last_tick = xTaskGetTickCount();
}

//================================================
// TOUCH
//================================================
static uint16_t xpt2046_read_adc(uint8_t cmd)
{
    uint8_t tx[3] = {cmd, 0, 0};
    uint8_t rx[3] = {0};

    spi_transaction_t t = {
        .length = 24,
        .tx_buffer = tx,
        .rx_buffer = rx
    };

    spi_device_transmit(xpt2046_spi, &t);

    return ((rx[1] << 8) | rx[2]) >> 3;
}

static bool xpt2046_read_touch(uint16_t *x, uint16_t *y)
{
    if (gpio_get_level(XPT2046_IRQ_PIN)) return false;

    uint16_t raw_x = xpt2046_read_adc(XPT2046_CMD_X);
    uint16_t raw_y = xpt2046_read_adc(XPT2046_CMD_Y);

    *x = raw_x * ILI9341_WIDTH / 4095;
    *y = raw_y * ILI9341_HEIGHT / 4095;

    return true;
}

//================================================
// LVGL TOUCH
//================================================
static void touch_cb(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    uint16_t x, y;
    if (xpt2046_read_touch(&x, &y)) {
        data->state = LV_INDEV_STATE_PRESSED;
        data->point.x = x;
        data->point.y = y;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

//================================================
// UI
//================================================
static void btn_event_cb(lv_event_t *e)
{
    if (lv_event_get_code(e) == LV_EVENT_CLICKED) {
 
        if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
            counter++;
 
            char buf[32];
            sprintf(buf, "Count: %d", counter);
 
            lv_label_set_text(label_count, buf);
 
            xSemaphoreGive(lvgl_mutex);
        }
    }
}

//================================================
// UI
//================================================
static void ui_create(void)
{
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_white(), 0);

    label_count = lv_label_create(lv_scr_act());
    lv_label_set_text(label_count, "Count: 0");
    lv_obj_align(label_count, LV_ALIGN_CENTER, 0, -40);

    btn_increment = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn_increment, 120, 50);
    lv_obj_align(btn_increment, LV_ALIGN_CENTER, 0, 40);

    lv_obj_t *lbl = lv_label_create(btn_increment);
    lv_label_set_text(lbl, "Press");
    lv_obj_center(lbl);

    // Register button click event
    lv_obj_add_event_cb(btn_increment, btn_event_cb, LV_EVENT_CLICKED, NULL);
}

//================================================
// LVGL TICK
//================================================
static void lv_tick_cb(void *arg)
{
    lv_tick_inc(1);
}

//================================================
// D25 TASK + BUZZER CONTROL
//================================================
static void d25_button_task(void *arg)
{
    bool last_state = 1;

    while (1) {

        bool cur = gpio_get_level(D25_BUTTON_PIN);

        if (last_state == 1 && cur == 0) {

            gpio_set_level(D26_BUZZER_PIN, 0); 

            printf("PRESS\n");

            if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
                counter++;

                char buf[32];
                sprintf(buf, "Count: %d", counter);
                lv_label_set_text(label_count, buf);

                xSemaphoreGive(lvgl_mutex);
            }
        }

        if (last_state == 0 && cur == 1) {
            gpio_set_level(D26_BUZZER_PIN, 1); 
            printf("RELEASE\n");
        }

        last_state = cur;

        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

//================================================
// MAIN
//================================================
void app_main(void)
{
    printf("START\n");

    lvgl_mutex = xSemaphoreCreateMutex();

    ili9341_spi_init();
    ili9341_init();

    xpt2046_spi_init();

    d25_button_init();
    buzzer_init();   // <<< 新增

    lv_init();

    esp_timer_handle_t timer;
    esp_timer_create_args_t args = {
        .callback = lv_tick_cb,
        .name = "lv_tick"
    };
    esp_timer_create(&args, &timer);
    esp_timer_start_periodic(timer, 1000);

    static lv_disp_draw_buf_t draw_buf;
    static lv_color_t buf1[ILI9341_WIDTH * 20];
    static lv_color_t buf2[ILI9341_WIDTH * 20];

    lv_disp_draw_buf_init(&draw_buf, buf1, buf2, ILI9341_WIDTH * 20);

    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = ILI9341_WIDTH;
    disp_drv.ver_res = ILI9341_HEIGHT;
    disp_drv.flush_cb = ili9341_flush_cb;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);

    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_cb;
    lv_indev_drv_register(&indev_drv);

    ui_create();

    xTaskCreate(d25_button_task, "btn", 2048, NULL, 5, NULL);

    esp_task_wdt_add(NULL);

    while (1) {
        esp_task_wdt_reset();
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

7、最后加上LED

        如果想做的再好一点,就可以加一个闪烁的led。比如选用d23连接gpio led就行。这种情况下就没必要ai编程了,手动加一下就好。

#include <stdio.h>
#include <string.h>
 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
 
#include "esp_timer.h"
#include "esp_task_wdt.h"
 
#include "driver/spi_master.h"
#include "driver/gpio.h"
 
#include "lvgl.h"
 
//================================================
// ILI9341 CONFIG
//================================================
#define ILI9341_SPI_HOST    SPI2_HOST
#define ILI9341_SCLK_PIN    14
#define ILI9341_MOSI_PIN    13
#define ILI9341_CS_PIN      15
#define ILI9341_DC_PIN      2
#define ILI9341_RST_PIN     4
#define ILI9341_BL_PIN      12
 
#define ILI9341_WIDTH       320
#define ILI9341_HEIGHT      240
 
//================================================
// XPT2046 TOUCH CONFIG
//================================================
#define XPT2046_SPI_HOST    SPI3_HOST
#define XPT2046_SCLK_PIN    18
#define XPT2046_MOSI_PIN    19
#define XPT2046_MISO_PIN    21
#define XPT2046_CS_PIN      5
#define XPT2046_IRQ_PIN     22
 
#define XPT2046_CMD_X       0xD0
#define XPT2046_CMD_Y       0x90
 
#define TOUCH_THRESHOLD     50
 
//================================================
// D25 / D26 / D23 CONFIG
//================================================
#define D25_BUTTON_PIN      25
#define D26_BUZZER_PIN      26
#define D23_LED_PIN         23
#define DEBOUNCE_MS         50
 
//================================================
// GLOBAL
//================================================
static spi_device_handle_t ili9341_spi;
static spi_device_handle_t xpt2046_spi;
 
static SemaphoreHandle_t lvgl_mutex;
 
static lv_obj_t *label_count;
static lv_obj_t *btn_increment;
static int counter = 0;
 
static bool d25_button_last_state = true;
static TickType_t d25_button_last_tick = 0;
 
//================================================
// LCD LOW LEVEL
//================================================
static void ili9341_send_cmd(uint8_t cmd)
{
    gpio_set_level(ILI9341_DC_PIN, 0);
    spi_transaction_t t = {
        .length = 8,
        .tx_buffer = &cmd
    };
    spi_device_transmit(ili9341_spi, &t);
}
 
static void ili9341_send_data(const uint8_t *data, size_t len)
{
    gpio_set_level(ILI9341_DC_PIN, 1);
    spi_transaction_t t = {
        .length = len * 8,
        .tx_buffer = data
    };
    spi_device_transmit(ili9341_spi, &t);
}
 
static void ili9341_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    ili9341_send_cmd(0x2A);
    uint8_t col[] = {x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF};
    ili9341_send_data(col, 4);
 
    ili9341_send_cmd(0x2B);
    uint8_t row[] = {y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF};
    ili9341_send_data(row, 4);
 
    ili9341_send_cmd(0x2C);
}
 
static void ili9341_flush_cb(lv_disp_drv_t *drv,
                              const lv_area_t *area,
                              lv_color_t *color_map)
{
    uint32_t w = area->x2 - area->x1 + 1;
    uint32_t h = area->y2 - area->y1 + 1;
 
    ili9341_set_window(area->x1, area->y1, area->x2, area->y2);
 
    gpio_set_level(ILI9341_DC_PIN, 1);
 
    spi_transaction_t t = {
        .length = w * h * 16,
        .tx_buffer = color_map
    };
 
    spi_device_transmit(ili9341_spi, &t);
    lv_disp_flush_ready(drv);
}
 
//================================================
// LCD INIT
//================================================
static void ili9341_init(void)
{
    gpio_set_level(ILI9341_RST_PIN, 0);
    vTaskDelay(pdMS_TO_TICKS(100));
    gpio_set_level(ILI9341_RST_PIN, 1);
    vTaskDelay(pdMS_TO_TICKS(120));
 
    ili9341_send_cmd(0x11);
    vTaskDelay(pdMS_TO_TICKS(120));
 
    ili9341_send_cmd(0x3A);
    ili9341_send_data((uint8_t[]){0x55}, 1);
 
    ili9341_send_cmd(0x36);
    ili9341_send_data((uint8_t[]){0x28}, 1);
 
    ili9341_send_cmd(0x29);
 
    gpio_set_level(ILI9341_BL_PIN, 1);
}
 
//================================================
// SPI LCD INIT
//================================================
static void ili9341_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask =
            (1ULL << ILI9341_DC_PIN) |
            (1ULL << ILI9341_RST_PIN) |
            (1ULL << ILI9341_BL_PIN),
        .mode = GPIO_MODE_OUTPUT
    };
    gpio_config(&io);
 
    spi_bus_config_t buscfg = {
        .mosi_io_num = ILI9341_MOSI_PIN,
        .miso_io_num = -1,
        .sclk_io_num = ILI9341_SCLK_PIN,
        .max_transfer_sz = ILI9341_WIDTH * ILI9341_HEIGHT * 2
    };
 
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 20 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = ILI9341_CS_PIN,
        .queue_size = 7
    };
 
    spi_bus_initialize(ILI9341_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(ILI9341_SPI_HOST, &devcfg, &ili9341_spi);
}
 
//================================================
// TOUCH INIT
//================================================
static void xpt2046_spi_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << XPT2046_IRQ_PIN),
        .mode = GPIO_MODE_INPUT
    };
    gpio_config(&io);
 
    spi_bus_config_t buscfg = {
        .mosi_io_num = XPT2046_MOSI_PIN,
        .miso_io_num = XPT2046_MISO_PIN,
        .sclk_io_num = XPT2046_SCLK_PIN,
        .max_transfer_sz = 8
    };
 
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 2 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = XPT2046_CS_PIN,
        .queue_size = 1
    };
 
    spi_bus_initialize(XPT2046_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(XPT2046_SPI_HOST, &devcfg, &xpt2046_spi);
}
 
//================================================
// BUZZER INIT (D26)
//================================================
static void buzzer_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << D26_BUZZER_PIN) | (1ULL << D23_LED_PIN),
        .mode = GPIO_MODE_OUTPUT
    };
    gpio_config(&io);
 
    gpio_set_level(D26_BUZZER_PIN, 1);
    gpio_set_level(D23_LED_PIN,    0);
}
 
//================================================
// D25 BUTTON
//================================================
static void d25_button_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << D25_BUTTON_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE
    };
    gpio_config(&io);
 
    d25_button_last_state = gpio_get_level(D25_BUTTON_PIN);
    d25_button_last_tick = xTaskGetTickCount();
}
 
//================================================
// TOUCH
//================================================
static uint16_t xpt2046_read_adc(uint8_t cmd)
{
    uint8_t tx[3] = {cmd, 0, 0};
    uint8_t rx[3] = {0};
 
    spi_transaction_t t = {
        .length = 24,
        .tx_buffer = tx,
        .rx_buffer = rx
    };
 
    spi_device_transmit(xpt2046_spi, &t);
 
    return ((rx[1] << 8) | rx[2]) >> 3;
}
 
static bool xpt2046_read_touch(uint16_t *x, uint16_t *y)
{
    if (gpio_get_level(XPT2046_IRQ_PIN)) return false;
 
    uint16_t raw_x = xpt2046_read_adc(XPT2046_CMD_X);
    uint16_t raw_y = xpt2046_read_adc(XPT2046_CMD_Y);
 
    *x = raw_x * ILI9341_WIDTH / 4095;
    *y = raw_y * ILI9341_HEIGHT / 4095;
    return true;
}
 
//================================================
// LVGL TOUCH
//================================================
static void touch_cb(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    uint16_t x, y;
    if (xpt2046_read_touch(&x, &y)) {
        data->state = LV_INDEV_STATE_PRESSED;
        data->point.x = x;
        data->point.y = y;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}
 
//================================================
// UI
//================================================
static void btn_event_cb(lv_event_t *e)
{
    if (lv_event_get_code(e) == LV_EVENT_CLICKED) {
 
        if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
            counter++;
 
            char buf[32];
            sprintf(buf, "Count: %d", counter);
 
            lv_label_set_text(label_count, buf);
 
            xSemaphoreGive(lvgl_mutex);
        }
    }
}
 
//================================================
// UI
//================================================
static void ui_create(void)
{
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_white(), 0);
 
    label_count = lv_label_create(lv_scr_act());
    lv_label_set_text(label_count, "Count: 0");
    lv_obj_align(label_count, LV_ALIGN_CENTER, 0, -40);
 
    btn_increment = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn_increment, 120, 50);
    lv_obj_align(btn_increment, LV_ALIGN_CENTER, 0, 40);
 
    lv_obj_t *lbl = lv_label_create(btn_increment);
    lv_label_set_text(lbl, "Press");
    lv_obj_center(lbl);
 
    // Register button click event
    lv_obj_add_event_cb(btn_increment, btn_event_cb, LV_EVENT_CLICKED, NULL);
}
 
//================================================
// LVGL TICK
//================================================
static void lv_tick_cb(void *arg)
{
    lv_tick_inc(1);
}
 
//================================================
// D25 TASK + BUZZER CONTROL
//================================================
static void d25_button_task(void *arg)
{
    bool last_state = 1;
 
    while (1) {
 
        bool cur = gpio_get_level(D25_BUTTON_PIN);
 
        if (last_state == 1 && cur == 0) {
 
            gpio_set_level(D26_BUZZER_PIN, 0); 
            gpio_set_level(D23_LED_PIN,    1);
 
            printf("PRESS\n");
 
            if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
                counter++;
 
                char buf[32];
                sprintf(buf, "Count: %d", counter);
                lv_label_set_text(label_count, buf);
 
                xSemaphoreGive(lvgl_mutex);
            }
        }
 
        if (last_state == 0 && cur == 1) {
            gpio_set_level(D26_BUZZER_PIN, 1); 
            gpio_set_level(D23_LED_PIN,    0);

            printf("RELEASE\n");
        }
 
        last_state = cur;
 
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}
 
//================================================
// MAIN
//================================================
void app_main(void)
{
    printf("START\n");
 
    lvgl_mutex = xSemaphoreCreateMutex();
 
    ili9341_spi_init();
    ili9341_init();
 
    xpt2046_spi_init();
 
    d25_button_init();
    buzzer_init();   // <<< 新增
 
    lv_init();
 
    esp_timer_handle_t timer;
    esp_timer_create_args_t args = {
        .callback = lv_tick_cb,
        .name = "lv_tick"
    };
    esp_timer_create(&args, &timer);
    esp_timer_start_periodic(timer, 1000);
 
    static lv_disp_draw_buf_t draw_buf;
    static lv_color_t buf1[ILI9341_WIDTH * 20];
    static lv_color_t buf2[ILI9341_WIDTH * 20];
 
    lv_disp_draw_buf_init(&draw_buf, buf1, buf2, ILI9341_WIDTH * 20);
 
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = ILI9341_WIDTH;
    disp_drv.ver_res = ILI9341_HEIGHT;
    disp_drv.flush_cb = ili9341_flush_cb;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);
 
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touch_cb;
    lv_indev_drv_register(&indev_drv);
 
    ui_create();
 
    xTaskCreate(d25_button_task, "btn", 2048, NULL, 5, NULL);
 
    esp_task_wdt_add(NULL);
 
    while (1) {
        esp_task_wdt_reset();
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

内容概要:本文介绍了基于改进Retinex算法的视频图像增强技术研究,并提供了相应的Matlab代码实现。Retinex理论源于人类视觉系统对光照变化的适应性,通过分离图像的照度反射分量,有效提升图像的亮度、对比度和色彩保真度。文中所提出的改进算法旨在克服传统Retinex方法中存在的光晕伪影、噪声放大和计算复杂等问题,可能引入了如多尺度分解、颜色校正或自适应滤波等优化策略,从而实现更自然、清晰的图像增强效果。该研究特别适用于低光照、雾霾、水下拍摄等恶劣成像条件下的视频图像处理,提升后续视觉分析的准确性。; 适合人群:具备一定图像处理基础和Matlab编程经验的科研人员、研究生及工程技术人员,尤其是从事计算机视觉、视频监控、遥感影像、医学影像或无人机视觉导航等领域研究的专业人士。; 使用场景及目标:① 解决实际应用中因光照不足或环境干扰导致的图像质量下降问题;② 学习和掌握Retinex算法的核心思想及其改进方法;③ 获取可直接运行和调试的Matlab代码,作为相关课题研究或项目开发的技术参考。; 阅读建议:此资源以Matlab代码实现为核心,建议读者在阅读时结合代码逐行分析,理解算法的每一步实现细节。同时,应尝试使用不同的测试图像进行实验,调整算法参数,观察增强效果的变化,从而深入理解算法的性能特点和优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值