【外设移植】Ai-M6x + DY-SV17F语音播放模块

[复制链接]
查看51 | 回复4 | 2024-11-13 00:05:52 | 显示全部楼层 |阅读模式

本帖最后由 lazy 于 2024-11-13 00:14 编辑

简介

DY-SV17F一款智能语音模块,集成IO分段触发,UART串口控制,ONE_line单总线串口控制,标准MP3等7种工作模式;板载5W D类功放,可直接驱动4Ω,3~5W喇叭;支持MP3,WAV解码格式,板载32Mbit(4MByte)flash存储音频文件,可通过USB数据线连接电脑更新音频文件。

1、支持MP3、WAV解码格式。

2、支持采样率(KHz):8/11.025/12/16/22.05/24/32/44.1/48。

3、24位DAC输出,动态范围支持90dB,信噪比支持85dB。

4、板载32Mbit(4MByte)flash存储,可通过USB数据线连接电脑更新音频文件。。

5、自带5W D类功放,可直接驱动4Ω,3~5W喇叭。

6、UART串口控制语音播报功能,可控制播放,暂停,选曲,音量加减等功能,最大选曲65535首曲目,波特率9600 bps。

7、支持IO触发播放功能,8个IO口单独触发8首曲目或8个IO口组合触发255首曲目。

8、支持One_line单总线串口控制,可控制播放,暂停,选曲,音量加减等功能。

9、支持3个配置IO进行多达7种工作模式选择。

模块接口及功能定义

1.JPG

引脚定义

引脚序号 引脚名称 引脚描述
1 TXD/IO0 IO触发模式下为输入引脚IO0;UART控制模式下为TX引脚,连接控制端(MCU)的RX
2 RXD/IO1 IO触发模式下为输入引脚IO1;UART控制模式下为RX引脚,连接控制端(MCU)的TX
3 IO2 IO触发模式输入引脚IO2
4 IO3 IO触发模式输入引脚IO3
5 IO4/ONE_LINE IO触发模式输入引脚IO4;One_Line一线串口控制模式数据接收引脚
6 IO5 IO触发模式输入引脚IO5
7 IO6 IO触发模式输入引脚IO6
8 IO7 IO触发模式输入引脚IO7
9 GND 参考地端
10 CON1 模式配置引脚1
11 CON2 模式配置引脚2
12 CON3/BUSY 上电30mS内作为模式配置引脚3/ 30mS后作为BUSY信号输出,播放曲目时输出低电平(0V),播放结束输出高电平(3.3V)
13 V5 5V电源正极输入
14 V33 3.3V电源输出,最大80mA
15 DACR 右声道音频输出
16 DACL 左声道音频输出
17 SPK- 5W功放输出负,接喇叭负极
18 SPK+ 5W功放输出正,接喇叭正极

IO 输入输出特性

这个模块支持的工作模式比较多,最好上手的还是UART串口模式通信了。

IO 输入特性
符号 参数 最小 最大 单位
VIL 低电平输入 0 0.8 V
VIH 高电平输入 2.7 3.3 V
IO 输出特性
VoL 低电平输出 0 0.33 V
VoH 高电平输出 2.7 3.3 V

工作模式配置

1.PNG

DY-SV17F 路径格式说明

DY-SV17F 模块支持中英文路径指定播放和插播功能,路径使用需要按以下格式

1、指定文件夹路径

/XXX*/*MP3

2、指定根目录文件名播放

/YYY*MP3

3、指定文件夹下文件名播放

/XXX*/YYY*MP3,

说明:

1、路径 以”/”开头

2、XXX 代表文件夹的名称,YYY 代表文件名,可以中文或英文,或中英文组合,XXX 的

长度小于 8,YYY 的长度小于 8,文件夹名称没有限制,所有字母全部要求大写,不管文件

夹或文件名是否为大写,取前面几个能区分的字母或汉字,长度不能超过 8 个字节。比如有

两个文件夹为 002ABC 和 002DFG,为了能区分要取 002A 和 002D。

3、一个汉字占用两个字节,一个字母为一个字节。

4、播放文件夹中的文件:/DY*/00001*MP3

5、播放文件夹中的文件:/DY*/00255*MP3

6、播放文件夹中的文件:/DY*/65535*MP3

7、播放根目录中的文件:/00001*MP3

8、播放根目录中的文件:/00255*MP3

9、播放根目录中的文件:/65535*MP3

10、使用专有串口调试助手进行路径播放测试如下图

本篇帖子主要讲解的就是UART串口模式。

UART串口模式

硬件配置说明

2.PNG

配置引脚 CON3 CON2 CON1
电平设置 1 0 0

通信格式

采用全双工串口通信;

波特率为9600,数据位:8 ,停止位1位,检验位 N。

起始码-指令类型-数据长度(n)-数据1-数据n-和检验(SM)

     指令码 :固定为AA。

     指令类型 : 用来区分指令类型。

     数据长度:指令中的数据的字节数。

     数据 :指令中的相关数据,当数据长度为1时,表示只有CMD,没有数据位。

     和检验 :为之前所有字节之和的低8位,即起始码到数据相加后取低8位。

数据格式:发送的数据或命令,高8位数据在前,低8位在后。

通信协议

以下是本芯片返回和能识别的数据定义。

1. 播放状态定义 :系统上电处于停止状态。

 00(停止) 01(播放) 02(暂停)

2. 盘符定义: 切换盘符后处于停止状态。

 USB:00 SD:01 FLASH:02 NO_DEVICE:FF

3. 音量:音量总共为31级,0-30级,上电默认为20级。

4. 播放模式定义:上电默认为单曲停止。

 全盘循环(00):按顺序播放全盘曲目,播放完后循环播放。

 单曲循环(01):一直循环播放当前曲目。

 单曲停止(02):播放完当前曲目一次停止。

 全盘随机(03):随机播放盘符内曲目。

 目录循环(04):按顺序播放当前文件夹内曲目,播放完后循环播放,目录不包含子目录。

 目录随机(05): 在当前目录内随机播放,目录不包含子目录。

 目录顺序播放(06):按顺序播放当前文件夹内曲目,播放完后停止,目录不包含子目录。

 顺序播放(07):按顺序播放全盘曲目,播放完后停止。

  1. EQ定义:上电默认EQ为NORMAL(00)。

NORMAL(00) POP(01) ROCK(02) JAZZ(03) CLASSIC(04)

6. 组合播放定义:组合播放是按文件名来组合,文件要求存储在“XY”文件夹下,可以把要组合的文件名称更改为两个字节的名称,一般建议用数字表示。如: 01.mp3,02.mp3,也可以用两个字母或一个汉字命名。

sv17f_uart.h

/**
 * @file uart.h
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2023-07-24
 *
 * @copyright Copyright (c) 2023
 *
*/
#ifndef _sv17f_UART_H_
#define _sv17f_UART_H_

/*
指令码:固定AA
指令类型:用来区分指令类型
数据长度:指令中的数据字节数
数据:指令中的相关数据,当数据长度为1时,表示只有CMD,没有数据位
和校验:为之前所有字节之和的低8位,即起始码到数据相加后取低8位。
数据格式:发送的数据或指令高8位数据在前,低8位在后。
*/

//通信协议
//1、播放状态定义:系统上电处于停止状态
#define STATUS_STOP 0x00 //停止 
#define STATUS_PLAY 0x01 //播放
#define STATUS_PAUSE 0x02 //暂停

//2、盘符定义:切换盘符后处于停止状态
#define PAN_USB 0x00 //USB
#define PAN_SD 0x01 //SD
#define PAN_FLASH 0x02 //FLASH
#define PAN_NO_DEVICE 0xFF //NO_DEVICE

//3、音量:音量总共31级,0-31级,上电默认为20级
#define VOLUME_LEVEL_0 0
#define VOLUME_LEVEL_1 1
#define VOLUME_LEVEL_2 2
#define VOLUME_LEVEL_3 3
#define VOLUME_LEVEL_4 4
#define VOLUME_LEVEL_5 5
#define VOLUME_LEVEL_6 6
#define VOLUME_LEVEL_7 7
#define VOLUME_LEVEL_8 8
#define VOLUME_LEVEL_9 9
#define VOLUME_LEVEL_10 10
#define VOLUME_LEVEL_11 11
#define VOLUME_LEVEL_12 12
#define VOLUME_LEVEL_13 13
#define VOLUME_LEVEL_14 14
#define VOLUME_LEVEL_15 15
#define VOLUME_LEVEL_16 16
#define VOLUME_LEVEL_17 17
#define VOLUME_LEVEL_18 18
#define VOLUME_LEVEL_19 19
#define VOLUME_LEVEL_20 20
#define VOLUME_LEVEL_21 21
#define VOLUME_LEVEL_22 22
#define VOLUME_LEVEL_23 23
#define VOLUME_LEVEL_24 24
#define VOLUME_LEVEL_25 25
#define VOLUME_LEVEL_26 26
#define VOLUME_LEVEL_27 27
#define VOLUME_LEVEL_28 28
#define VOLUME_LEVEL_29 29
#define VOLUME_LEVEL_30 30

// 4、播放模式定义:商店默认为单曲停止
#define LOOP_MODE_ALL 0x00 //全盘循环:按顺序播放全盘曲目,播放完后循环播放
#define LOOP_MODE_SINGLE 0x01 //单曲循环:一直循环播放当前曲目
#define LOOP_MODE_SINGLE_STOP 0x02 //单曲停止:播放完当前曲目一次停止
#define LOOP_MODE_ALL_RANDOM 0x03 //全盘随机:随机播放盘符内曲目
#define LOOP_MODE_DIR 0x04 //目录循环:按顺序播放当前文件夹内曲目,播放完后循环播放,目录不包含子目录
#define LOOP_MODE_DIR_RANDOM 0x05 //目录随机:在当前目录内随机播放,目录不包含子目录
#define LOOP_MODE_DIR_SEQUENCE 0x06 //目录顺序播放:按顺序播放当前文件夹内曲目,播放完后停止,目录不包含子目录
#define LOOP_MODE_ALL_SEQUENCE_STOP 0x07 //顺序播放按顺序播放全盘曲目,播放完后停止

// 5、EQ定义:上电默认EQ为NORMAL(00)
#define EQ_NOMARL 0x00 // NOMARL
#define EQ_POP 0x01 // POP
#define EQ_ROCK 0x02 // ROCK
#define EQ_JAZZ 0x03 // JAZZ
#define EQ_CLASSIC 0x04 // CLASSIC

/*
6、组合播放定义:组合播放是按文件名来组合,文件要求存储在“XY”文件夹下,可以巴瑶族喝的文件名称更改为两个字节的名称,一般建议用数字表示。如:01.MP3,02.mp3,也可以用两个字母或汉字命名
*/

/**
 * @brief 
 * @param volume        音量
 * @param loop_mode     循环模式
 * @param eq            音乐风格
 * @param pan           盘符指定路径
 */
struct sv17f_config_s {
    uint32_t volume;
    uint8_t loop_mode;
    uint8_t eq;
    uint8_t pan;
};

void sv17f_uart_task(void* arg);

void sv17f_init(const struct sv17f_config_s *config);

/*计算校验码*/
uint8_t check_sum(uint8_t *ck_buf, uint8_t size);

//音量设置 0xAA, 0x13, 0x01, 音量, SM
int sv17f_set_vol(uint8_t vol);
//设置循环模式 0xAA, 0x18, 0x01, 循环模式, SM
int sv17f_set_loop(uint8_t loop);
//设置循环次数 0xAA, 0x19, 0x02, 次数高, 次数低, SM
int sv17f_set_count(uint8_t count);
//EQ设置 0xAA, 0x1A, 0x01, EQ, SM
int sv17f_set_eq(uint8_t eq);
//指定曲目 0xAA, 0x07, 0x02, 曲目高, 曲目低, SM
int sv17f_set_sound(uint8_t sound);
//指定盘符指定路径 0xAA, 0x08, 长度, 盘符, 路径, SM
int sv17f_set_pan(uint8_t pan);
//切换到指定盘符径 0xAA, 0x0B, 0x01, 盘符, SM
int sv17f_set_sel_pan(uint8_t pan);
//指定曲目播放 0xAA, 0x16, 0x03, 盘符, 曲目高, 曲目低, SM
int sv17f_set_sel_sound_paly(uint8_t pan, uint16_t sound);
//指定路径播放 0xAA, 0x17, 长度, 盘符, 路径, SM
int sv17f_set_sel_dir_paly(uint8_t pan, uint8_t dir);
//选曲不播放 0xAA, 0x1F, 0x02, 曲目高, 曲目低, SM
int sv17f_check_sel_sound(uint16_t sound);

// 查询播放状态
uint8_t sv17f_play_status(uint16_t timeout);
// 查询当前在线盘符
uint8_t sv17f_online_pan(uint16_t timeout);
// 查询当前播放盘符
uint8_t sv17f_use_pan(uint16_t timeout);
// 查询总曲目
uint8_t sv17f_sum_sound(uint16_t timeout);
// 查询当前曲目
uint8_t sv17f_cur_sound(uint16_t timeout);
// 查询文件夹目录曲目
uint16_t sv17f_dir_sound(uint16_t timeout);
// 查询文件夹目录总曲目
uint16_t sv17f_sum_dir_sound(uint16_t timeout);

// 播放
int sv17f_play();
// 暂停
int sv17f_pasue();
// 停止
int sv17f_stop();
// 上一曲
int sv17f_sound_up();
// 下一曲
int sv17f_sound_down();
// 音量加
int sv17f_vol_up();
// 音量减
int sv17f_vol_down();
// 上一文件目录
int sv17f_dir_up();
// 下一文件目录
int sv17f_dir_down();
// 结束播放
int sv17f_release();

#endif

sv17f_uart.c

/**
 * @file uart.c
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2023-07-24
 *
 * @copyright Copyright (c) 2023
 *
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <FreeRTOS.h>
#include <queue.h>
#include <timers.h>
#include <task.h>
#include "bflb_uart.h"
#include "bflb_gpio.h"
#include "sv17f_uart.h"
#include "log.h"

/*控制指令*/
/* 播放*/
uint8_t CMD_PLAY[4] = { 0xAA, 0x02, 0x00, 0xAC };
/* 暂停*/
uint8_t CMD_PAUSE[4] = { 0xAA, 0x03, 0x00, 0xAD };
/* 停止*/
uint8_t CMD_STOP[4] = { 0xAA, 0x04, 0x00, 0xAE };
/* 上一曲*/
uint8_t CMD_SOUND_UP[4] = { 0xAA, 0x05, 0x00, 0xAF };
/* 下一曲*/
uint8_t CMD_SOUND_DOWN[4] = { 0xAA, 0x06, 0x00, 0xB0 };
/* 音量加*/
uint8_t CMD_VOL_UP[4] = { 0xAA, 0x14, 0x00, 0xBE };
/* 音量减*/
uint8_t CMD_VOL_DOWN[4] = { 0xAA, 0x15, 0x00, 0xBF };
/* 上一文件目录*/
uint8_t CMD_DIR_UP[4] = { 0xAA, 0x0E, 0x00, 0xB8 };
/* 下一文件目录*/
uint8_t CMD_DIR_DOWN[4] = { 0xAA, 0x0F, 0x00, 0xB9 };
/* 结束播放*/
uint8_t CMD_RELEASE[4] = { 0xAA, 0x10, 0x00, 0xBA };

/*查询指令*/
/*查询播放状态 返回:AA 01 01 播放状态 SM*/
uint8_t CMD_QUERY_STATUS[4] = { 0xAA, 0x01, 0x00, 0xAB };
/*查询当前在线盘符 返回:AA 09 01 盘符 SM*/
uint8_t CMD_QUERY_PAN[4] = { 0xAA, 0x09, 0x00, 0xB3 };
/*查询当前播放盘符 返回:AA 0A 01 盘符 SM*/
uint8_t CMD_QUERY_PLAY_PAN[4] = { 0xAA, 0x0A, 0x00, 0xB4 };
/*查询总曲目 返回:AA 0C 02 总曲目高 总曲目低 SM*/
uint8_t CMD_QUERY_SUM_SOUND[4] = { 0xAA, 0x0C, 0x00, 0xB6 };
/*查询当前曲目 返回:AA 0D 02 曲目高 曲目低 SM*/
uint8_t CMD_QUERY_CUR_SOUND[4] = { 0xAA, 0x0D, 0x00, 0xB7 };
/*查询文件夹目录曲目 返回:AA 11 02 曲目高 曲目低 SM*/
uint8_t CMD_QUERY_DIR_SOUND[4] = { 0xAA, 0x11, 0x00, 0xBB };
/*查询文件夹目录总曲目 返回:AA 12 02 曲目高 曲目低 SM*/
uint8_t CMD_QUERY_SUM_DIR_SOUND[4] = { 0xAA, 0x12, 0x00, 0xBC };

/*设置指令 */
/*音量设置 0xAA, 0x13, 0x01, 音量, SM*/
uint8_t VOL_SET[5] = { 0xAA, 0x13, 0x01, 0x00, 0x00 };
/*设置循环模式 0xAA, 0x18, 0x01, 循环模式, SM*/
uint8_t LOOP_SET[5] = { 0xAA, 0x18, 0x01, 0x00, 0x00 };
/*设置循环次数 0xAA, 0x19, 0x02, 次数高, 次数低, SM*/
uint8_t LOOP_COUNT_SET[6] = { 0xAA, 0x19, 0x02, 0x00, 0x00, 0x00 };
/*EQ设置 0xAA, 0x1A, 0x01, EQ, SM*/
uint8_t EQ_SET[5] = { 0xAA, 0x1A, 0x01, 0x00, 0x00 };
/*指定曲目 0xAA, 0x07, 0x02, 曲目高, 曲目低, SM*/
uint8_t SEL_SOUND_SET[6] = { 0xAA, 0x07, 0x02, 0x00, 0x00, 0x00 };
/*指定盘符指定路径 0xAA, 0x08, 长度, 盘符, 路径, SM*/
uint8_t PAN_SET[6] = { 0xAA, 0x08, 0x00, 0x00, 0x00, 0x00 };
/*切换到指定盘符径 0xAA, 0x0B, 0x01, 盘符, SM*/
uint8_t SEL_PAN_SET[5] = { 0xAA, 0x0B, 0x01, 0x00, 0x00 };
/*指定曲目播放 0xAA, 0x16, 0x03, 盘符, 曲目高, 曲目低, SM*/
uint8_t SEL_PAN_SOUND_SET[7] = { 0xAA, 0x16, 0x03, 0x00, 0x00, 0x00, 0x00 };
/*指定路径播放 0xAA, 0x17, 长度, 盘符, 路径, SM*/
uint8_t SEL_DIR_SOUND_SET[6] = { 0xAA, 0x17, 0x00, 0x00, 0x00, 0x00 };
/*选曲不播放 0xAA, 0x1F, 0x02, 曲目高, 曲目低, SM*/
uint8_t CHECK_SOUND_SET[6] = { 0xAA, 0x1F, 0x02, 0x00, 0x00, 0x00 };

static void sv17f_uart_init(void);

static struct bflb_device_s *sound_uart;
static char uart_buff[8] = { 0 };
xQueueHandle sound_queue;
extern xQueueHandle rf_queue;

void sv17f_CMD_LOG(uint8_t *cmd_buf, uint8_t size)
{
    printf("sv17f_CMD_LOG: ");
    for (int i = 0; i < size; i++) {
        printf("0x%02X ", cmd_buf[i]);
    }
    printf("\r\n");
}

/*计算校验码*/
uint8_t check_sum(uint8_t *ck_buf, uint8_t size)
{
    uint8_t checkSum = 0x00;
    for (int i = 0; i < size; i++) {
        checkSum += ck_buf[i];
    }
    return checkSum;
}

/*音量设置 0xAA, 0x13, 0x01, 音量, SM*/
int sv17f_set_vol(uint8_t vol)
{
    if (vol > 0x30) {
        vol = 0x30;
    } else if (vol < 0x00) {
        vol = 0x00;
    }
    VOL_SET[3] = vol;
    VOL_SET[4] = check_sum(VOL_SET, 5);
    sv17f_CMD_LOG(VOL_SET, 5);
    int ret;
    ret = bflb_uart_put(sound_uart, VOL_SET, sizeof(VOL_SET));

    return ret;
}
/*设置循环模式 0xAA, 0x18, 0x01, 循环模式, SM*/
int sv17f_set_loop(uint8_t loop)
{
    LOOP_SET[3] = loop;
    LOOP_SET[4] = check_sum(LOOP_SET, 5);
    int ret;
    sv17f_CMD_LOG(LOOP_SET, 5);
    ret = bflb_uart_put(sound_uart, LOOP_SET, sizeof(LOOP_SET));
    return ret;
}
/*设置循环次数 0xAA, 0x19, 0x02, 次数高, 次数低, SM*/
int sv17f_set_count(uint8_t count)
{
    LOOP_COUNT_SET[3] = (count >> 8) & 0xFF;
    LOOP_COUNT_SET[4] = count & 0xFF;
    LOOP_COUNT_SET[5] = check_sum(LOOP_COUNT_SET, 6);
    int ret;
    ret = bflb_uart_put(sound_uart, LOOP_COUNT_SET, sizeof(LOOP_COUNT_SET));
    return ret;
}
/*EQ设置 0xAA, 0x1A, 0x01, EQ, SM*/
int sv17f_set_eq(uint8_t eq)
{
    int ret;
    EQ_SET[3] = eq;
    EQ_SET[4] = check_sum(EQ_SET, 5);
    sv17f_CMD_LOG(EQ_SET, 5);
    ret = bflb_uart_put(sound_uart, EQ_SET, sizeof(EQ_SET));
    return ret;
}
/*指定曲目(会播放)*/
int sv17f_set_sound(uint8_t sound)
{
    int ret;
    SEL_SOUND_SET[3] = sound >> 8 & 0xFF;
    SEL_SOUND_SET[4] = sound & 0xFF;
    SEL_SOUND_SET[5] = check_sum(SEL_SOUND_SET, 6);
    ret = bflb_uart_put(sound_uart, SEL_SOUND_SET, sizeof(SEL_SOUND_SET));
    return ret;
}
/*指定盘符指定路径 0xAA, 0x08, 长度, 盘符, 路径, SM*/
int sv17f_set_pan(uint8_t pan)
{
    int ret;
    PAN_SET[3] = (pan >> 8) & 0xFF;
    PAN_SET[4] = pan & 0xFF;
    PAN_SET[5] = check_sum(PAN_SET, 6);
    sv17f_CMD_LOG(PAN_SET, 6);
    ret = bflb_uart_put(sound_uart, PAN_SET, sizeof(PAN_SET));
    return ret;
}
/*切换到指定盘符径 0xAA, 0x0B, 0x01, 盘符, SM*/
int sv17f_set_sel_pan(uint8_t pan)
{
    int ret;
    SEL_PAN_SET[3] = pan;
    SEL_PAN_SET[4] = check_sum(SEL_PAN_SET, 5);
    sv17f_CMD_LOG(SEL_PAN_SET, 5);
    ret = bflb_uart_put(sound_uart, SEL_PAN_SET, sizeof(SEL_PAN_SET));
    return ret;
}
/*指定曲目播放 0xAA, 0x16, 0x03, 盘符, 曲目高, 曲目低, SM*/
int sv17f_set_sel_sound_paly(uint8_t pan, uint16_t sound)
{
    int ret;
    SEL_PAN_SOUND_SET[3] = pan;
    SEL_PAN_SOUND_SET[4] = sound >> 8 & 0xFF;
    SEL_PAN_SOUND_SET[5] = sound & 0xFF;
    SEL_PAN_SOUND_SET[6] = check_sum(SEL_PAN_SOUND_SET, 7);
    sv17f_CMD_LOG(SEL_PAN_SOUND_SET, 7);
    ret = bflb_uart_put(sound_uart, SEL_PAN_SOUND_SET, sizeof(SEL_PAN_SOUND_SET));
    return ret;
}
/*指定路径播放 0xAA, 0x17, 长度, 盘符, 路径, SM*/
int sv17f_set_sel_dir_paly(uint8_t pan, uint8_t dir)
{
    int ret;
    // SEL_DIR_SOUND_SET[2] = 盘符长度+路径长度=1+路径长度;
    SEL_DIR_SOUND_SET[3] = pan;
    SEL_DIR_SOUND_SET[4] = dir;
    SEL_DIR_SOUND_SET[5] = check_sum(SEL_DIR_SOUND_SET, 7);
    ret = bflb_uart_put(sound_uart, SEL_DIR_SOUND_SET, sizeof(SEL_DIR_SOUND_SET));
    return ret;
}

/*选曲不播放 1-65535*/
int sv17f_check_sel_sound(uint16_t sound)
{
    int ret;
    CHECK_SOUND_SET[3] = sound >> 8 & 0xFF;
    CHECK_SOUND_SET[4] = sound & 0xFF;
    CHECK_SOUND_SET[5] = check_sum(CHECK_SOUND_SET, 6);
    ret = bflb_uart_put(sound_uart, CHECK_SOUND_SET, sizeof(CHECK_SOUND_SET));
    return ret;
}

/* 查询播放状态*/
uint8_t sv17f_play_status(uint16_t timeout)
{
    int ret = bflb_uart_put(sound_uart, CMD_QUERY_STATUS, 4);
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[5] = { 0 };
    printf("sv17f_play_status: ");
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        printf("0x%02x ", tmp);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 5; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            printf("0x%02x ", tmp);
            memset(rx_buf, 0, 5);
        }
    }
    printf("\r\n ");
    sv17f_CMD_LOG(rx_buf, 5);
    return rx_buf[3];
}

/* 查询当前在线盘符*/
uint8_t sv17f_online_pan(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_PAN, sizeof(CMD_QUERY_PAN));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[5] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 5; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 5);
        }
    }
    sv17f_CMD_LOG(rx_buf, 5);
    return rx_buf[3];
}

/* 查询当前播放盘符*/
uint8_t sv17f_use_pan(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_PLAY_PAN, sizeof(CMD_QUERY_PLAY_PAN));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    };
    int i;
    uint8_t rx_buf[5] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 5; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 5);
        }
    }
    sv17f_CMD_LOG(rx_buf, 5);
    return rx_buf[3];
}

/* 查询总曲目*/
uint8_t sv17f_sum_sound(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_SUM_SOUND, sizeof(CMD_QUERY_SUM_SOUND));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[6] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 6; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 6);
        }
    }
    sv17f_CMD_LOG(rx_buf, 6);
    return rx_buf[3] << 8 + rx_buf[4];
}
/* 查询当前曲目*/
uint8_t sv17f_cur_sound(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_CUR_SOUND, sizeof(CMD_QUERY_CUR_SOUND));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[6] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 6; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 6);
        }
    }
    sv17f_CMD_LOG(rx_buf, 6);
    return rx_buf[3] << 8 + rx_buf[4];
}

/* 查询文件夹目录曲目*/
uint16_t sv17f_dir_sound(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_DIR_SOUND, sizeof(CMD_QUERY_DIR_SOUND));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[6] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 6; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 6);
        }
    }
    sv17f_CMD_LOG(rx_buf, 6);
    uint16_t result = rx_buf[3] << 8;
    return result + rx_buf[4];
}
/* 查询文件夹目录总曲目*/
uint16_t sv17f_sum_dir_sound(uint16_t timeout)
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_QUERY_SUM_DIR_SOUND, sizeof(CMD_QUERY_SUM_DIR_SOUND));
    while (!bflb_uart_rxavailable(sound_uart) && (--timeout)) {
        bflb_mtimer_delay_ms(1);
    }
    int i;
    uint8_t rx_buf[6] = { 0 };
    while (bflb_uart_rxavailable(sound_uart)) {
        uint8_t tmp = bflb_uart_getchar(sound_uart);
        if (tmp == 0xAA) {
            rx_buf[0] = tmp;
            for (i = 1; i < 6; i++) {
                rx_buf[i] = bflb_uart_getchar(sound_uart);
            }
        } else {
            memset(rx_buf, 0, 6);
        }
    }
    sv17f_CMD_LOG(rx_buf, 6);
    uint16_t result = rx_buf[3] << 8;
    return result + rx_buf[4];
}

/* 播放*/
int sv17f_play()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_PLAY, sizeof(CMD_PLAY));
    return ret;
}
/* 暂停*/
int sv17f_pasue()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_PAUSE, sizeof(CMD_PAUSE));
    return ret;
}
/* 停止*/
int sv17f_stop()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_STOP, sizeof(CMD_STOP));
    return ret;
}
/* 上一曲*/
int sv17f_sound_up()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_SOUND_UP, sizeof(CMD_SOUND_UP));
    return ret;
}
/* 下一曲*/
int sv17f_sound_down()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_SOUND_DOWN, sizeof(CMD_SOUND_DOWN));
    return ret;
}
/* 音量加*/
int sv17f_vol_up()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_VOL_UP, sizeof(CMD_VOL_UP));
    return ret;
}
/* 音量减*/
int sv17f_vol_down()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_VOL_DOWN, sizeof(CMD_VOL_DOWN));
    return ret;
}
/* 上一文件目录*/
int sv17f_dir_up()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_DIR_UP, sizeof(CMD_DIR_UP));
    return ret;
}
/* 下一文件目录*/
int sv17f_dir_down()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_DIR_DOWN, sizeof(CMD_DIR_DOWN));
    return ret;
}
/* 结束播放*/
int sv17f_release()
{
    int ret;
    ret = bflb_uart_put(sound_uart, CMD_RELEASE, sizeof(CMD_RELEASE));
    return ret;
}

void sv17f_init(const struct sv17f_config_s *config)
{
    sv17f_set_vol(config->volume);
    sv17f_set_loop(config->loop_mode);
    sv17f_set_eq(config->eq);
}

void sv17f_uart_task(void *arg)
{
    char *buf = NULL;
    sound_queue = xQueueCreate(1, 8);
    struct sv17f_config_s sv17f_cfg = {
        .volume = VOLUME_LEVEL_30,
        .loop_mode = LOOP_MODE_SINGLE_STOP,
        .eq = EQ_NOMARL,
        .pan = PAN_SD
    };

    sv17f_uart_init();
    sv17f_init(&sv17f_cfg);
    while (1) {
        buf = pvPortMalloc(8);
        memset(buf, 0, 8);
        xQueueReceive(sound_queue, buf, portMAX_DELAY);
        sv17f_set_sound(1);
        // sv17f_set_pan(config->pan);
        LOG_E("播放状态: 0x%02x \r\n", sv17f_play_status(2000));
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

/**
 * @brief
 *
*/
static void sv17f_uart_init()
{
    struct bflb_device_s *gpio;

    struct bflb_uart_config_s sound_cfg = {
        .baudrate = 9600,
        .data_bits = UART_DATA_BITS_8,
        .stop_bits = UART_STOP_BITS_1,
        .parity = UART_PARITY_NONE,
        .flow_ctrl = 0,
        .tx_fifo_threshold = 4,
        .rx_fifo_threshold = 4,
    };

    gpio = bflb_device_get_by_name("gpio");

    sound_uart = bflb_device_get_by_name("uart1");

    bflb_gpio_uart_init(gpio, GPIO_PIN_25, GPIO_UART_FUNC_UART1_TX);
    bflb_gpio_uart_init(gpio, GPIO_PIN_26, GPIO_UART_FUNC_UART1_RX);

    bflb_uart_init(sound_uart, &sound_cfg);
}

配合上篇

【外设移植】Ai-M6x + SI4432无线模块 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45477&fromuid=16612 (出处: 物联网开发者社区-安信可论坛)

帖子,可以实现门铃功能了。千米范围门铃你敢信。😄

这里代码把上篇帖子的代码分成了发送端和接收端为了增加了设备id防止被其他设备触发。

接收端 cgi-bin_mmwebwx-bin_webwxgetmsgimg_&MsgID=8437901253870657778&skey=@crypt_3423.jpg

cgi-bin_mmwebwx-bin_webwxgetmsgimg_&MsgID=9079182557962470535&skey=@crypt_3423.jpg

发送端

cgi-bin_mmwebwx-bin_webwxgetmsgimg_&MsgID=894954276998131004&skey=@crypt_3423c.jpg

目前做的这个小东西当门铃?😄 有点过分。

我有个想法,这个如果用来找电动车、自行车、小汽车比较不错。

毕竟空旷场景超远距离传输数据呢。

说干就干呢,下篇就是加外壳然后DIY妥妥的找车神器。就是这个声音怎么能放的最大千米范围内能听到那种。😕

【【外设移植】Ai-M6x + DY-SV17F语音播放模块】 https://www.bilibili.com/video/BV1H5mhYDEZi/?share_source=copy_web&vd_source=addf5eba933a94affcf41637a0ea1365

回复

使用道具 举报

lazy | 2024-11-13 00:05:53 | 显示全部楼层
源码

Ai-M6X_SI4432.zip

33 KB, 下载次数: 0

回复

使用道具 举报

爱笑 | 2024-11-13 08:44:01 | 显示全部楼层
很棒~
用心做好保姆工作
回复

使用道具 举报

WT_0213 | 2024-11-13 10:55:05 | 显示全部楼层
回复

使用道具 举报

很棒
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则