加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入

基于ESP32的触控智能车载氛围灯

05/15 10:29
2627
服务支持:
技术交流群

完成交易后在“购买成功”页面扫码入群,即可与技术大咖们分享疑惑和经验、收获成长和认同、领取优惠和红包等。

虚拟商品不可退

当前内容为数字版权作品,购买后不支持退换且无法转移使用。

加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
放大
电路板图(2)
相关方案
  • 方案介绍
  • 相关文件
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

一、项目名称:

车载氛围灯

二、项目概述:

项目,旨在为车辆内部营造一个独特的氛围。通过ESP32和触摸屏,RGB LED灯条,可以在车内创造出多彩的灯光效果。这些灯光可以实现各种模式和效果,如渐变、闪烁、呼吸等。通过连接麦克风,采样麦克风数据,灯光可以根据音乐的节奏和音量进行调整,实现与音乐的同步效果。此外,还可以通过触摸屏来控制灯光的开关、颜色和模式等。

三、作品实物图

四、演示视频

视频.zip (29.3 MB)

五、代码

5.1 触屏驱动移植代码

#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()

由于时间的原因,做完板子就没多少时间完成项目工程了,所以只能简单设计了个LVGL界面,移植触屏驱动,并且使用CircuitPython进行测试WS2812,实现一些简单的LED动画。

六、文档

文档.zip (1.35 MB)

  • 视频.zip
  • 文档.zip

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
L6472PDTR 1 STMicroelectronics Fully integrated microstepping motor driver with motion engine and SPI

ECAD模型

下载ECAD模型
$10.31 查看
L6235PD013TR 1 STMicroelectronics DMOS driver for 3-phase brushless DC motor

ECAD模型

下载ECAD模型
$10.7 查看
LSM6DS3TR-C 1 STMicroelectronics iNEMO 6DoF inertial measurement unit (IMU), for entry level / mid-tier smart phones and Portable PC platforms

ECAD模型

下载ECAD模型
$5.09 查看

相关推荐

电子产业图谱