加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入

基于ESP32的觸控智能車載氛圍燈

05/15 10:29
4392
服務(wù)支持:
技術(shù)交流群

完成交易后在“購買成功”頁面掃碼入群,即可與技術(shù)大咖們分享疑惑和經(jīng)驗、收獲成長和認同、領(lǐng)取優(yōu)惠和紅包等。

虛擬商品不可退

當前內(nèi)容為數(shù)字版權(quán)作品,購買后不支持退換且無法轉(zhuǎn)移使用。

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論
放大
電路板圖(2)
相關(guān)方案
  • 方案介紹
  • 相關(guān)文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

一、項目名稱:

車載氛圍燈

二、項目概述:

項目,旨在為車輛內(nèi)部營造一個獨特的氛圍。通過ESP32和觸摸屏,RGB LED燈條,可以在車內(nèi)創(chuàng)造出多彩的燈光效果。這些燈光可以實現(xiàn)各種模式和效果,如漸變、閃爍、呼吸等。通過連接麥克風,采樣麥克風數(shù)據(jù),燈光可以根據(jù)音樂的節(jié)奏和音量進行調(diào)整,實現(xiàn)與音樂的同步效果。此外,還可以通過觸摸屏來控制燈光的開關(guān)、顏色和模式等。

三、作品實物圖

四、演示視頻

視頻.zip (29.3 MB)

五、代碼

5.1 觸屏驅(qū)動移植代碼

#include "cst816.h"

#include <driver/i2c.h>
#include <esp_log.h>
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include <lvgl.h>
#else
#include <lvgl/lvgl.h>
#endif

#include "../lvgl_i2c_conf.h"
#include "tp_i2c.h"

#define TAG "CST816T"

static cst816t_status_t cst816t_status;
uint8_t cst816t_read_len(uint16_t reg_addr, uint8_t *data, uint8_t len) {
  uint8_t res = 0;
  res = i2c_master_write_read_device(TOUCH_I2C_PORT, CST816T_ADDR, ?_addr, 1,
                                     data, len, 1000 / portTICK_PERIOD_MS);

  return res;
}

uint8_t cst816t_chipId(void) { return 0; }
static esp_err_t cst816t_get_touch_points_num(uint8_t *touch_points_num) {
  uint8_t res = 0;
  res = cst816t_read_len(0x02, touch_points_num, 1);
  return res;
}

esp_err_t cst816t_read_pos(uint8_t *touch_points_num, uint16_t *x,
                           uint16_t *y) {
  uint8_t data[4];

  cst816t_get_touch_points_num(touch_points_num);
  if (0 == *touch_points_num) {
    *x = 0;
    *y = 0;
    return 1;
  } else {
    cst816t_read_len(0x03, data, 4);

    *x = ((data[0] & 0x0f) << 8) | data[1];
    *y = ((data[2] & 0x0f) << 8) | data[3];
  }

  return ESP_OK;
}

esp_err_t cst816t_i2c_read(uint8_t slave_addr, uint16_t register_addr,
                           uint8_t *data_buf, uint8_t len) {
  i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();

  i2c_master_start(i2c_cmd);
  i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
  i2c_master_write_byte(i2c_cmd, register_addr, I2C_MASTER_ACK);

  i2c_master_start(i2c_cmd);
  i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_READ, true);

  i2c_master_read_byte(i2c_cmd, data_buf, I2C_MASTER_NACK);
  i2c_master_stop(i2c_cmd);
  esp_err_t ret =
      i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_PERIOD_MS);
  i2c_cmd_link_delete(i2c_cmd);
  return ret;
}

esp_err_t cst816t_i2c_write8(uint8_t slave_addr, uint16_t register_addr,
                             uint8_t data) {
  i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();

  i2c_master_start(i2c_cmd);
  i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
  i2c_master_write_byte(i2c_cmd, register_addr, I2C_MASTER_ACK);

  i2c_master_start(i2c_cmd);
  i2c_master_write_byte(i2c_cmd, data, true);

  i2c_master_stop(i2c_cmd);
  esp_err_t ret =
      i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_PERIOD_MS);
  i2c_cmd_link_delete(i2c_cmd);
  return ret;
}

void cst816t_init(uint16_t dev_addr) {
  if (!cst816t_status.inited) {
    cst816t_status.i2c_dev_addr = dev_addr;
    uint8_t data_buf[10];
    esp_err_t ret;

    ESP_LOGI(TAG, "Checking for CST816T Touch Controller ");

    if ((ret = cst816t_i2c_read(dev_addr, 0x15, &data_buf, 1) != ESP_OK)) {
      vTaskDelay(pdMS_TO_TICKS(10));
      ESP_LOGE(TAG, "Error reading from device: %s",
               esp_err_to_name(ret)); // Only show error the first time
                                      // return;
    }
    if ((ret = cst816t_i2c_read(dev_addr, 0xa7, &data_buf, 1) != ESP_OK)) {
      ESP_LOGE(TAG, "Error reading from device: %s",
               esp_err_to_name(ret)); // Only show error the first time
      ESP_LOGE(TAG, "device ID: %02x", data_buf[0]);
      // return;
    }

    cst816t_status.inited = true;
  }
}

bool cst816t_read(lv_indev_drv_t *drv, lv_indev_data_t *data) {

  uint8_t touch_points_num = 0;
  uint16_t x = 0;
  uint16_t y = 0;

  cst816t_read_pos(&touch_points_num, &x, &y);

#if CONFIG_LV_TOUCH_INVERT_X
  x = LV_HOR_RES_MAX - x;
#endif
#if 1
  y = 280 - y;
#endif
#if 1
  int16_t swap_buf = x;
  x = y;
  y = swap_buf;
#endif

  data->point.x = x;
  data->point.y = y;
  if (touch_points_num > 0) {
    data->state = LV_INDEV_STATE_PR;
    ESP_LOGI(TAG, "X=%u Y=%u", data->point.x, data->point.y);
    ESP_LOGV(TAG, "X=%u Y=%u", data->point.x, data->point.y);
  } else {
    data->state = LV_INDEV_STATE_REL;
  }

  return false;
}

5.2 測試用的LVGL代碼

/* LVGL Example project
 *
 * Basic project to test LVGL on ESP32 based projects.
 *
 * This example code is in the Public Domain (or CC0 licensed, at your option.)
 *
 * Unless required by applicable law or agreed to in writing, this
 * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.
 */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
#include "esp_system.h"
#include "driver/gpio.h"

/* Littlevgl specific */
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif

#include "lvgl_helpers.h"

#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    #if defined CONFIG_LV_USE_DEMO_WIDGETS
        #include "lv_examples/src/lv_demo_widgets/lv_demo_widgets.h"
    #elif defined CONFIG_LV_USE_DEMO_KEYPAD_AND_ENCODER
        #include "lv_examples/src/lv_demo_keypad_encoder/lv_demo_keypad_encoder.h"
    #elif defined CONFIG_LV_USE_DEMO_BENCHMARK
        #include "lv_examples/src/lv_demo_benchmark/lv_demo_benchmark.h"
    #elif defined CONFIG_LV_USE_DEMO_STRESS
        #include "lv_examples/src/lv_demo_stress/lv_demo_stress.h"
    #else
        #error "No demo application selected."
    #endif
#endif

/*********************
 *      DEFINES
 *********************/
#define TAG "demo"
#define LV_TICK_PERIOD_MS 1

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_tick_task(void *arg);
static void guiTask(void *pvParameter);
static void create_demo_application(void);

/**********************
 *  STATIC VARIABLES
 **********************/

static void event_handler(lv_obj_t *obj, lv_event_t event) {
  if (event == LV_EVENT_VALUE_CHANGED) {
    int n = lv_dropdown_get_selected(obj);
    printf("num: %dn", n);
  }
}

void lv_sport(void) {
  /*Create a normal drop down list*/
  // lv_obj_t *ddlist = lv_dropdown_create(lv_scr_act(), NULL);
  //   lv_dropdown_set_options(ddlist, "1n2n3n4");

  // lv_obj_align(ddlist, NULL, LV_ALIGN_IN_TOP_MID, 0, 20);
  // lv_obj_set_event_cb(ddlist, event_handler);

  /*Create a Tab view object*/

  lv_obj_t *tabview;
  tabview = lv_tabview_create(lv_scr_act(), NULL);

  /*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
  lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "計劃健身");

  /*Add content to the tabs*/
  lv_obj_t *dr_sport = lv_dropdown_create(tab1, NULL);
  lv_obj_set_width(
      dr_sport,
      lv_obj_get_width_grid(tab1, 3, 1));
  lv_dropdown_set_options(dr_sport, "Rainbown"
                                    "Cometn"
                                    "Sparkle");
  lv_obj_align(dr_sport, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 10);
}

/**********************
 *   APPLICATION MAIN
 **********************/
void app_main() {

    /* If you want to use a task to create the graphic, you NEED to create a Pinned task
     * Otherwise there can be problem such as memory corruption and so on.
     * NOTE: When not using Wi-Fi nor Bluetooth you can pin the guiTask to core 0 */
    xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 0, NULL, 1);
}

/* Creates a semaphore to handle concurrent call to lvgl stuff
 * If you wish to call *any* lvgl function from other threads/tasks
 * you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;

static void guiTask(void *pvParameter) {

    (void) pvParameter;
    xGuiSemaphore = xSemaphoreCreateMutex();

    lv_init();

    /* Initialize SPI or I2C bus used by the drivers */
    lvgl_driver_init();

    lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 != NULL);

    /* Use double buffered when not working with monochrome displays */
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    lv_color_t* buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2 != NULL);
#else
    static lv_color_t *buf2 = NULL;
#endif

    static lv_disp_buf_t disp_buf;

    uint32_t size_in_px = DISP_BUF_SIZE;

#if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820         
    || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A    
    || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D     
    || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306

    /* Actual size in pixels, not bytes. */
    size_in_px *= 8;
#endif

    /* Initialize the working buffer depending on the selected display.
     * NOTE: buf2 == NULL when using monochrome displays. */
    lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);

    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.flush_cb = disp_driver_flush;

#if defined CONFIG_DISPLAY_ORIENTATION_PORTRAIT || defined CONFIG_DISPLAY_ORIENTATION_PORTRAIT_INVERTED
    disp_drv.rotated = 1;
#endif

    /* When using a monochrome display we need to register the callbacks:
     * - rounder_cb
     * - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    disp_drv.rounder_cb = disp_driver_rounder;
    disp_drv.set_px_cb = disp_driver_set_px;
#endif

    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /* Register an input device when enabled on the menuconfig */
#if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.read_cb = touch_driver_read;
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    lv_indev_drv_register(&indev_drv);
#endif

    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &lv_tick_task,
        .name = "periodic_gui"
    };
    esp_timer_handle_t periodic_timer;
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));

    /* Create the demo application */
    lv_sport();

    while (1) {
        /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
        vTaskDelay(pdMS_TO_TICKS(10));

        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
       }
    }

    /* A task should NEVER return */
    free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    free(buf2);
#endif
    vTaskDelete(NULL);
}

static void lv_tick_task(void *arg) {
    (void) arg;

    lv_tick_inc(LV_TICK_PERIOD_MS);
}

5.3 測試RGB燈的Python代碼

# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
This example repeatedly displays all available animations, at a five second interval.

For NeoPixel FeatherWing. Update pixel_pin and pixel_num to match your wiring if using
a different form of NeoPixels.

This example does not work on SAMD21 (M0) boards.
"""
import board
import neopixel

from adafruit_led_animation.animation.blink import Blink
from adafruit_led_animation.animation.comet import Comet
from adafruit_led_animation.animation.sparkle import Sparkle
from adafruit_led_animation.animation.rainbow import Rainbow
from adafruit_led_animation.color import PURPLE, WHITE, AMBER, JADE, MAGENTA, ORANGE

# Update to match the pin connected to your NeoPixels
pixel_pin = board.D6
# Update to match the number of NeoPixels you have connected
pixel_num = 16

pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=0.5, auto_write=False)

blink = Blink(pixels, speed=0.5, color=JADE)
colorcycle = ColorCycle(pixels, speed=0.4, colors=[MAGENTA, ORANGE])
comet = Comet(pixels, speed=0.01, color=PURPLE, tail_length=10, bounce=True)
sparkle = Sparkle(pixels, speed=0.1, color=PURPLE, num_sparkles=10)
rainbow = Rainbow(pixels, speed=0.1, period=2)

animations = AnimationSequence(
    comet,
    blink,
    sparkle,
    rainbow,
    advance_interval=5,
    auto_clear=True,
)

while True:
    animations.animate()

由于時間的原因,做完板子就沒多少時間完成項目工程了,所以只能簡單設(shè)計了個LVGL界面,移植觸屏驅(qū)動,并且使用CircuitPython進行測試WS2812,實現(xiàn)一些簡單的LED動畫。

六、文檔

文檔.zip (1.35 MB)

  • 視頻.zip
  • 文檔.zip

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
AD8361ARMZ-REEL 1 Analog Devices Inc LF to 2.5 GHz TruPwr&trade; Detector

ECAD模型

下載ECAD模型
$7.33 查看
A3979SLPTR-T 1 Allegro MicroSystems LLC Stepper Motor Controller, 2.5A, NMOS, PDSO28, 1.20 MM HEIGHT, LEAD FREE, MO-153AET, TSSOP-28

ECAD模型

下載ECAD模型
$8.4 查看
AD22293Z 1 Analog Devices Inc Precision ±1.7 g, ±5 g, ±18 g Dual-Axis iMEMS&reg; Accelerometer
暫無數(shù)據(jù) 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜