唯创知音WTN6040 esp32驱动代码

WTN6040 语音芯片使用记录

背景

项目需要, 使用一款语音播放芯片来实现简单的音频播放
手里的项目是ESP32平台的, 但以下驱动代码原理一样, 稍作修改即可移植到其他平台,
需要注意的是, 这款芯片的音频需要提前定制, 也可以自己买工装刷入,
总之音频数据是预置在这颗芯片内的,
主控只需要发送音频地址即可

正文

WTN6040这款IC支持多种通信方式, 具体可参考手册, 但ESP32引脚数量有限, 于是选择一线串口通信就足够了,
原理上和WS2812灯珠的驱动方式一样,
放一个时序图,
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

/**
 * @file wtn6040.c
 * @brief wtn6040 driver
 * @author William
 * @date 2022.5.10
 * @version v0.1
*/

#include "wtn6040.h"

#define WTN6040_DATA_IO (42)
#define WTN6040_T1H_US (600)
#define WTN6040_T1L_US (200)
#define WTN6040_T0H_US (200)
#define WTN6040_T0L_US (600)

static const char *TAG = "wtn6040";

/**
 * @brief 系统级精确微秒延时
*/
// static __inline void delay_us(int ts)
// {
//     uint32_t start, curr;

//     ts *= 240; //ts=240时为1us, 这里为方便在内部做微妙凑整处理

//     __asm__ __volatile__("rsr %0, ccount" : "=r"(start));

//     do
//         __asm__ __volatile__("rsr %0, ccount" : "=r"(curr));
//     while (curr - start <= ts);
// }

/**
 * @brief WTN6040一线串口通信底层函数,必须严格按照时序操作
 * @param byte: 一线语音地址或指令,如 00H -> 播放第0段语音
*/
static void wtn6040_1_line(const uint8_t byte)
{
    ESP_LOGI(TAG, "Write byte is: 0x%X.", byte);

    gpio_set_level(WTN6040_DATA_IO, 0);
    vTaskDelay(pdMS_TO_TICKS(8));

    for (size_t i = 0; i < 8; i++)
    {
        // LSB First
        if ( byte & (1 << i) )
        {
            gpio_set_level(WTN6040_DATA_IO, 1);
            usleep(WTN6040_T1H_US);
            gpio_set_level(WTN6040_DATA_IO, 0);
            usleep(WTN6040_T1L_US);
        }
        else
        {
            gpio_set_level(WTN6040_DATA_IO, 1);
            usleep(WTN6040_T0H_US);
            gpio_set_level(WTN6040_DATA_IO, 0);
            usleep(WTN6040_T0L_US);
        }
    }

    gpio_set_level(WTN6040_DATA_IO, 1);
    vTaskDelay(pdMS_TO_TICKS(4));
}

/**
 * @brief 初始化 wtn6040 一线通数据引脚初始化
*/
esp_err_t wtn6040_init(void)
{
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = (1ULL << WTN6040_DATA_IO);
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_config(&io_conf);

    gpio_set_level(WTN6040_DATA_IO, 0);
    vTaskDelay(pdMS_TO_TICKS(100));

    ESP_LOGI(TAG, "Initialize wtn6040 OK.");

    return ESP_OK;
}

/**
 * @brief 播放结束或者待机状态发此命令调节音量,E0H音量最小,EFH音量最大,共16级
 * @param vol: range = 0x00~0x0f
*/
void wtn6040_volume_adjust(uint8_t vol)
{
    uint8_t volume;

    if (vol > 0x0F) {
        ESP_LOGE(TAG, "wtn6040 volume must be 0~15, your input is %d, it`s over range!", vol);
        return;
    }

    volume = 0xE0 + vol;
    wtn6040_1_line(volume);
    ESP_LOGI(TAG, "Set volume level %d.", vol);
    // wtn6040_1_line(AUDIO_CLICK); //音量试听

    if (vol == 0) {
        gpio_set_level(WTN6040_DATA_IO, 0);
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}

/**
 * @brief 播放指定音频或停止播放
 * @param index: 16位指令/地址
*/
void wtn6040_audio_set(const uint8_t index)
{
    switch (index)
    {
    case AUDIO_MUTE:
        ESP_LOGI(TAG, "Play AUDIO_MUTE.");
        wtn6040_1_line(AUDIO_MUTE);
        break;
    case AUDIO_WELCOME:
        ESP_LOGI(TAG, "Play AUDIO_WELCOME.");
        wtn6040_1_line(AUDIO_WELCOME);
        break;
    case AUDIO_CLICK:
        ESP_LOGI(TAG, "Play AUDIO_CLICK.");
        wtn6040_1_line(AUDIO_CLICK);
        break;
    case AUDIO_SAFE:
        ESP_LOGI(TAG, "Play AUDIO_SAFE.");
        wtn6040_1_line(AUDIO_SAFE);
        break;
    case AUDIO_DANGER:
        ESP_LOGI(TAG, "Play AUDIO_DANGER.");
        wtn6040_1_line(AUDIO_DANGER);
        wtn6040_1_line(CMD_PLAY_CYCLE);
        break;
    case AUDIO_BYE:
        ESP_LOGI(TAG, "Play AUDIO_BYE.");
        wtn6040_1_line(AUDIO_BYE);
        break;

    default:
        ESP_LOGI(TAG, "Stop play audio.");
        wtn6040_1_line(CMD_PLAY_STOP);
        break;
    }
}

void wtn6040_test(void)
{
    ESP_LOGI(TAG, "Running test code about wtn6040 audio control.");

    wtn6040_1_line(CMD_PLAY_SERIES);
    wtn6040_1_line(AUDIO_DANGER);
    wtn6040_1_line(CMD_PLAY_SERIES);
    wtn6040_1_line(AUDIO_WELCOME);
    wtn6040_1_line(CMD_PLAY_SERIES);
    wtn6040_1_line(AUDIO_BYE);
    wtn6040_1_line(CMD_PLAY_SERIES);
    wtn6040_1_line(AUDIO_SAFE);
    wtn6040_1_line(CMD_PLAY_SERIES);
    wtn6040_1_line(AUDIO_CLICK);
}

/**
 * @file wtn6040.h
 * @author William
 * @date 2022.5.10
*/

/* ------------------------------------------------------
        |   index   |       brief       |
        |   -----   |       -----       |
        |   0x00    |      20ms静音     |
        |   0x01    |       报警音      |
        |   0x02    |      开机音乐      |
        |   0x03    |      关机音乐      |
        |   0x04    |      安全音效      |
        |   0x05    |     按键点击音     |
   ------------------------------------------------------ */

#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>
#include <stdlib.h>

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

#include "esp_err.h"
#include "esp_log.h"

#include "bsp_board.h"
#include "sys/unistd.h"
#include "driver/rmt.h"


/* 一线语音命令码 */
#define CMD_PLAY_CYCLE  (0xF2)  //循环播放当前语音:执行此命令可循环播放当前段语音,可在语音播放/语音停止时发送,可被其他指令打断
#define CMD_PLAY_SERIES (0xF3)  //连码播放:F3H+语音地址A,F3H+语音地址B,F3H+语音地址C
#define CMD_INSERT_MUTE (0xF8)  //插入静音:F8H+静音时间(10MS为单位)
#define CMD_PLAY_STOP   (0xFE)  //停止播放当前语音

/* 芯片预定义音频地址 */
enum {
    AUDIO_MUTE = 0x00,  //20ms静音
    AUDIO_DANGER,       //报警音
    AUDIO_WELCOME,      //开机欢迎音
    AUDIO_BYE,          //关机音
    AUDIO_SAFE,         //安全音
    AUDIO_CLICK,        //点击音
};

/**
 * @brief 初始化 wtn6040 一线通数据引脚
*/
esp_err_t wtn6040_init(void);

/**
 * @brief 播放结束或者待机状态发此命令调节音量,E0H音量最小,EFH音量最大,共16级
*/
void wtn6040_volume_adjust(uint8_t vol);

/**
 * @brief 播放指定音频或停止播放
 * @param index: 16位指令/地址
*/
void wtn6040_audio_set(uint8_t index);

/**
 * @brief 测试接口,播放一遍预定义音频
*/
void wtn6040_test(void);


#ifdef __cplusplus
}
#endif

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值