欢迎光临
我们一直在努力

语音播报系统:STM32F4驱动DAC/I2S,语音合成芯片应用

文章目录

    • 一、项目概述
    • 二、硬件准备与原理说明
      • 2.1 核心硬件清单
      • 2.2 核心原理流程图
      • 2.3 电路连接说明
        • 2.3.1 STM32与SYN6288连接
        • 2.3.2 STM32与VS1053连接(I2S方式)
        • 2.3.3 DAC输出连接(备用)
    • 三、软件环境搭建
      • 3.1 开发工具安装
      • 3.2 STM32CubeMX配置步骤
        • 3.2.1 新建工程
        • 3.2.2 外设配置
        • 3.2.3 工程生成
    • 四、代码实现
      • 4.1 代码文件结构
      • 4.2 SYN6288驱动代码
        • 文件名:syn6288.h
        • 文件名:syn6288.c
      • 4.3 VS1053驱动代码(I2S)
        • 文件名:vs1053.h
        • 文件名:vs1053.c
      • 4.4 DAC音频输出驱动代码(备用)
        • 文件名:dac_audio.h
        • 文件名:dac_audio.c
      • 4.5 主函数代码
        • 文件名:main.c
    • 五、代码编译与下载
      • 5.1 编译代码
      • 5.2 下载代码
    • 六、测试与调试
      • 6.1 硬件检查
      • 6.2 功能测试
      • 6.3 功能扩展
    • 七、常见问题解决
      • 总结

一、项目概述

你想要搭建一个基于STM32F4系列单片机的语音播报系统,核心实现STM32F4对DAC/I2S外设的驱动,并结合语音合成芯片完成语音数据的处理与播报。本教程从硬件选型、电路设计、软件环境搭建到代码实现,全程面向零基础小白,每一步都提供详细操作和可直接运行的代码,确保你能落地实现完整的语音播报功能。

二、硬件准备与原理说明

2.1 核心硬件清单

硬件名称型号/规格作用说明
STM32开发板 STM32F407ZGT6 主控芯片,驱动外设和处理数据
语音合成芯片 SYN6288(串口版) 将文字转换为语音数据
音频解码/功放模块 VS1053(支持I2S) 解码语音数据并驱动扬声器
扬声器 8Ω/0.5W 播放语音
杜邦线/面包板 通用型 电路连接
USB-TTL模块 CH340 下载程序、串口调试
电源模块 5V/3.3V 给各模块供电

2.2 核心原理流程图

#mermaid-svg-uNI8xB5MOu36IYP3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uNI8xB5MOu36IYP3 .error-icon{fill:#552222;}#mermaid-svg-uNI8xB5MOu36IYP3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uNI8xB5MOu36IYP3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uNI8xB5MOu36IYP3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uNI8xB5MOu36IYP3 .marker.cross{stroke:#333333;}#mermaid-svg-uNI8xB5MOu36IYP3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uNI8xB5MOu36IYP3 p{margin:0;}#mermaid-svg-uNI8xB5MOu36IYP3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster-label text{fill:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster-label span{color:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster-label span p{background-color:transparent;}#mermaid-svg-uNI8xB5MOu36IYP3 .label text,#mermaid-svg-uNI8xB5MOu36IYP3 span{fill:#333;color:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 .node rect,#mermaid-svg-uNI8xB5MOu36IYP3 .node circle,#mermaid-svg-uNI8xB5MOu36IYP3 .node ellipse,#mermaid-svg-uNI8xB5MOu36IYP3 .node polygon,#mermaid-svg-uNI8xB5MOu36IYP3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uNI8xB5MOu36IYP3 .rough-node .label text,#mermaid-svg-uNI8xB5MOu36IYP3 .node .label text,#mermaid-svg-uNI8xB5MOu36IYP3 .image-shape .label,#mermaid-svg-uNI8xB5MOu36IYP3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-uNI8xB5MOu36IYP3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uNI8xB5MOu36IYP3 .rough-node .label,#mermaid-svg-uNI8xB5MOu36IYP3 .node .label,#mermaid-svg-uNI8xB5MOu36IYP3 .image-shape .label,#mermaid-svg-uNI8xB5MOu36IYP3 .icon-shape .label{text-align:center;}#mermaid-svg-uNI8xB5MOu36IYP3 .node.clickable{cursor:pointer;}#mermaid-svg-uNI8xB5MOu36IYP3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uNI8xB5MOu36IYP3 .arrowheadPath{fill:#333333;}#mermaid-svg-uNI8xB5MOu36IYP3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uNI8xB5MOu36IYP3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uNI8xB5MOu36IYP3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uNI8xB5MOu36IYP3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uNI8xB5MOu36IYP3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uNI8xB5MOu36IYP3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster text{fill:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 .cluster span{color:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uNI8xB5MOu36IYP3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uNI8xB5MOu36IYP3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-uNI8xB5MOu36IYP3 .icon-shape,#mermaid-svg-uNI8xB5MOu36IYP3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uNI8xB5MOu36IYP3 .icon-shape p,#mermaid-svg-uNI8xB5MOu36IYP3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uNI8xB5MOu36IYP3 .icon-shape rect,#mermaid-svg-uNI8xB5MOu36IYP3 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uNI8xB5MOu36IYP3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uNI8xB5MOu36IYP3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uNI8xB5MOu36IYP3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

串口

串口/I2S

DAC

I2S

上位机/按键输入文字指令

STM32F4主控

解析文字指令

向SYN6288发送合成指令

SYN6288合成语音数据

STM32F4接收语音数据

输出方式选择

STM32 DAC外设输出模拟音频

STM32 I2S外设传输数字音频到VS1053

功放模块放大音频

扬声器播报语音

2.3 电路连接说明

2.3.1 STM32与SYN6288连接
STM32F4引脚SYN6288引脚说明
PA9 (USART1_TX) RX 串口发送数据
PA10 (USART1_RX) TX 串口接收数据
3.3V VCC 供电
GND GND 接地
PB0 BUSY 忙状态检测
2.3.2 STM32与VS1053连接(I2S方式)
STM32F4引脚VS1053引脚说明
PC10 (SPI3_SCK) SCK I2S时钟
PC12 (SPI3_MOSI) MOSI 数据发送
PB12 CS 片选
PB13 DCS 数据/命令选择
PB15 RST 复位
3.3V VCC 供电
GND GND 接地
PA4 XDCS 数据片选
PA5 XCLK 时钟输入
2.3.3 DAC输出连接(备用)
STM32F4引脚功放模块引脚说明
PA4 (DAC_OUT1) IN+ 模拟音频输出
GND IN- 接地

三、软件环境搭建

3.1 开发工具安装

  • 下载并安装STM32CubeMX(版本6.9.0及以上):用于配置STM32外设,生成初始化代码。
  • 下载并安装Keil MDK-ARM(版本5.38及以上):用于编写、编译和下载代码。
  • 安装STM32F407的器件库:在Keil中添加STM32F407ZGT6的器件支持包。
  • 3.2 STM32CubeMX配置步骤

    3.2.1 新建工程
  • 打开STM32CubeMX,点击“New Project”。
  • 在搜索框输入“STM32F407ZGT6”,选择对应芯片,点击“Start Project”。
  • 3.2.2 外设配置
  • 时钟配置:
    • 点击“Clock Configuration”,将HSE设置为8MHz,PLL倍频设置为168,系统时钟配置为168MHz。
  • USART1配置(用于与SYN6288通信):
    • 点击“Connectivity” → “USART1”,模式选择“Asynchronous”(异步模式)。
    • 参数:波特率9600,数据位8,停止位1,校验位None,收发使能。
  • I2S3配置(用于与VS1053通信):
    • 点击“Connectivity” → “SPI3”,模式选择“I2S Master Transmit”(I2S主机发送)。
    • 参数:标准I2S,采样率44.1kHz,数据长度16位,时钟极性低。
  • DAC配置(备用输出):
    • 点击“Analog” → “DAC”,启用DAC1 Channel1(PA4)。
  • GPIO配置:
    • PB0(SYN6288 BUSY):输入模式,上拉。
    • PB12、PB13、PB15、PA4、PA5(VS1053控制引脚):输出模式,推挽输出,上拉,速度中速。
  • 3.2.3 工程生成
  • 点击“Project Manager”,设置工程名称(如“VoiceBroadcast_System”)、保存路径,工具链选择“MDK-ARM”。
  • 点击“Code Generator”,勾选“Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”。
  • 点击“Generate Code”,生成工程后用Keil打开。
  • 四、代码实现

    4.1 代码文件结构

    生成的工程基础上,新增以下文件:

    • syn6288.c/syn6288.h:SYN6288语音合成芯片驱动
    • vs1053.c/vs1053.h:VS1053音频解码模块驱动
    • dac_audio.c/dac_audio.h:DAC音频输出驱动
    • main.c:主函数,业务逻辑实现

    4.2 SYN6288驱动代码

    文件名:syn6288.h

    #ifndef __SYN6288_H
    #define __SYN6288_H

    #include "stm32f4xx_hal.h"

    // 引脚定义
    #define SYN6288_BUSY_PIN GPIO_PIN_0
    #define SYN6288_BUSY_PORT GPIOB

    // 串口句柄(与CubeMX配置的USART1句柄一致)
    extern UART_HandleTypeDef huart1;

    // 函数声明
    // 初始化SYN6288(主要是GPIO初始化,串口已由CubeMX初始化)
    void SYN6288_Init(void);
    // 检查SYN6288忙状态
    uint8_t SYN6288_CheckBusy(void);
    // 发送文字合成语音指令(GB2312编码)
    void SYN6288_SendText(const char *text);
    // 停止语音播报
    void SYN6288_StopPlay(void);

    #endif

    文件名:syn6288.c

    #include "syn6288.h"
    #include "string.h"

    // SYN6288初始化
    void SYN6288_Init(void)
    {
    // BUSY引脚已由CubeMX初始化,此处仅做状态确认
    HAL_GPIO_WritePin(SYN6288_BUSY_PORT, SYN6288_BUSY_PIN, GPIO_PIN_SET);
    }

    // 检查SYN6288忙状态:1-忙,0-空闲
    uint8_t SYN6288_CheckBusy(void)
    {
    return HAL_GPIO_ReadPin(SYN6288_BUSY_PORT, SYN6288_BUSY_PIN);
    }

    // 发送文字合成指令
    void SYN6288_SendText(const char *text)
    {
    if(text == NULL || strlen(text) == 0)
    {
    return;
    }

    // SYN6288指令格式:[0xFD][0x00][数据长度][命令字][文字内容][0x00]
    uint8_t cmd_buf[256] = {0};
    uint16_t text_len = strlen(text);
    uint16_t total_len = text_len + 3; // 命令字+文字+结束符

    // 填充指令头
    cmd_buf[0] = 0xFD; // 帧头
    cmd_buf[1] = (total_len >> 8) & 0xFF; // 数据长度高8位
    cmd_buf[2] = total_len & 0xFF; // 数据长度低8位
    cmd_buf[3] = 0x01; // 合成播放命令

    // 填充文字内容
    memcpy(&cmd_buf[4], text, text_len);
    cmd_buf[4 + text_len] = 0x00; // 结束符

    // 等待芯片空闲
    while(SYN6288_CheckBusy() == 1);

    // 串口发送指令
    HAL_UART_Transmit(&huart1, cmd_buf, 4 + text_len + 1, 1000);
    }

    // 停止播放
    void SYN6288_StopPlay(void)
    {
    uint8_t stop_cmd[] = {0xFD, 0x00, 0x02, 0x02, 0x00};
    HAL_UART_Transmit(&huart1, stop_cmd, sizeof(stop_cmd), 1000);
    }

    4.3 VS1053驱动代码(I2S)

    文件名:vs1053.h

    #ifndef __VS1053_H
    #define __VS1053_H

    #include "stm32f4xx_hal.h"

    // 引脚定义
    #define VS1053_CS_PIN GPIO_PIN_12
    #define VS1053_CS_PORT GPIOB

    #define VS1053_DCS_PIN GPIO_PIN_13
    #define VS1053_DCS_PORT GPIOB

    #define VS1053_RST_PIN GPIO_PIN_15
    #define VS1053_RST_PORT GPIOB

    #define VS1053_XDCS_PIN GPIO_PIN_4
    #define VS1053_XDCS_PORT GPIOA

    #define VS1053_XCLK_PIN GPIO_PIN_5
    #define VS1053_XCLK_PORT GPIOA

    // I2S句柄(与CubeMX配置的SPI3(I2S)句柄一致)
    extern SPI_HandleTypeDef hi2s3;

    // VS1053寄存器定义
    #define VS1053_REG_MODE 0x00
    #define VS1053_REG_STATUS 0x01
    #define VS1053_REG_BASS 0x02
    #define VS1053_REG_CLOCKF 0x03
    #define VS1053_REG_DECODE 0x04
    #define VS1053_REG_VOLUME 0x0B

    // 函数声明
    void VS1053_Init(void);
    void VS1053_Reset(void);
    void VS1053_WriteReg(uint8_t reg, uint16_t value);
    uint16_t VS1053_ReadReg(uint8_t reg);
    void VS1053_SetVolume(uint8_t vol); // 音量0-100
    void VS1053_PlayAudio(uint8_t *data, uint16_t len);

    #endif

    文件名:vs1053.c

    #include "vs1053.h"
    #include "delay.h" // 需自行添加延时函数(基于HAL_Delay)

    // 引脚操作宏
    #define VS1053_CS_H() HAL_GPIO_WritePin(VS1053_CS_PORT, VS1053_CS_PIN, GPIO_PIN_SET)
    #define VS1053_CS_L() HAL_GPIO_WritePin(VS1053_CS_PORT, VS1053_CS_PIN, GPIO_PIN_RESET)

    #define VS1053_DCS_H() HAL_GPIO_WritePin(VS1053_DCS_PORT, VS1053_DCS_PIN, GPIO_PIN_SET)
    #define VS1053_DCS_L() HAL_GPIO_WritePin(VS1053_DCS_PORT, VS1053_DCS_PIN, GPIO_PIN_RESET)

    #define VS1053_RST_H() HAL_GPIO_WritePin(VS1053_RST_PORT, VS1053_RST_PIN, GPIO_PIN_SET)
    #define VS1053_RST_L() HAL_GPIO_WritePin(VS1053_RST_PORT, VS1053_RST_PIN, GPIO_PIN_RESET)

    #define VS1053_XDCS_H() HAL_GPIO_WritePin(VS1053_XDCS_PORT, VS1053_XDCS_PIN, GPIO_PIN_SET)
    #define VS1053_XDCS_L() HAL_GPIO_WritePin(VS1053_XDCS_PORT, VS1053_XDCS_PIN, GPIO_PIN_RESET)

    // VS1053初始化
    void VS1053_Init(void)
    {
    // 复位引脚置高
    VS1053_RST_H();
    HAL_Delay(10);

    // 复位VS1053
    VS1053_Reset();

    // 配置模式寄存器:SM_SDINEW=1, SM_RESET=0
    VS1053_WriteReg(VS1053_REG_MODE, 0x0800);
    HAL_Delay(10);

    // 配置时钟:12.288MHz晶振,倍频至49.152MHz
    VS1053_WriteReg(VS1053_REG_CLOCKF, 0x6000);
    HAL_Delay(10);

    // 设置低音增强
    VS1053_WriteReg(VS1053_REG_BASS, 0x00FF);
    HAL_Delay(10);

    // 设置音量(默认50%)
    VS1053_SetVolume(50);
    HAL_Delay(10);
    }

    // VS1053硬件复位
    void VS1053_Reset(void)
    {
    VS1053_CS_H();
    VS1053_DCS_H();
    VS1053_XDCS_H();

    VS1053_RST_L();
    HAL_Delay(100);
    VS1053_RST_H();
    HAL_Delay(100);
    }

    // 写VS1053寄存器
    void VS1053_WriteReg(uint8_t reg, uint16_t value)
    {
    VS1053_CS_L();
    VS1053_DCS_H();

    // 发送写寄存器指令:0x02 << 1 | 寄存器地址
    uint8_t cmd = (0x02 << 1) | (reg & 0x0F);
    HAL_SPI_Transmit(&hi2s3, &cmd, 1, 100);

    // 发送寄存器值(高8位+低8位)
    uint8_t data[2] = { (value >> 8) & 0xFF, value & 0xFF };
    HAL_SPI_Transmit(&hi2s3, data, 2, 100);

    VS1053_CS_H();
    HAL_Delay(1);
    }

    // 读VS1053寄存器
    uint16_t VS1053_ReadReg(uint8_t reg)
    {
    uint16_t value = 0;
    uint8_t temp[2] = {0};

    VS1053_CS_L();
    VS1053_DCS_H();

    // 发送读寄存器指令:0x03 << 1 | 寄存器地址
    uint8_t cmd = (0x03 << 1) | (reg & 0x0F);
    HAL_SPI_Transmit(&hi2s3, &cmd, 1, 100);

    // 读取寄存器值
    HAL_SPI_Receive(&hi2s3, temp, 2, 100);
    value = (temp[0] << 8) | temp[1];

    VS1053_CS_H();
    HAL_Delay(1);

    return value;
    }

    // 设置音量(0-100,0最大,100最小)
    void VS1053_SetVolume(uint8_t vol)
    {
    if(vol > 100) vol = 100;
    // VS1053音量寄存器格式:左声道|右声道,0x00最大,0xFE最小
    uint16_t vol_val = (vol * 0xFE) / 100;
    vol_val = (vol_val << 8) | vol_val;
    VS1053_WriteReg(VS1053_REG_VOLUME, vol_val);
    }

    // 播放音频数据(I2S传输)
    void VS1053_PlayAudio(uint8_t *data, uint16_t len)
    {
    if(data == NULL || len == 0) return;

    VS1053_XDCS_L();
    // 通过I2S发送音频数据
    HAL_I2S_Transmit(&hi2s3, (uint16_t*)data, len/2, 1000);
    VS1053_XDCS_H();
    }

    4.4 DAC音频输出驱动代码(备用)

    文件名:dac_audio.h

    #ifndef __DAC_AUDIO_H
    #define __DAC_AUDIO_H

    #include "stm32f4xx_hal.h"

    // DAC句柄(与CubeMX配置的DAC1句柄一致)
    extern DAC_HandleTypeDef hdac;

    // 函数声明
    void DAC_Audio_Init(void);
    void DAC_PlayAudio(uint16_t *audio_data, uint32_t len, uint16_t sample_rate);

    #endif

    文件名:dac_audio.c

    #include "dac_audio.h"
    #include "tim.h" // 需配置定时器触发DAC(TIM6,1kHz)

    // DAC音频初始化(配置定时器触发DAC输出)
    void DAC_Audio_Init(void)
    {
    // 启用DAC通道1,定时器6触发
    HAL_DAC_Start(&hdac, DAC_CHANNEL_1);

    // 配置定时器6(用于DAC输出速率控制)
    HAL_TIM_Base_Start(&htim6);
    }

    // DAC播放音频数据(16位PCM数据,采样率sample_rate)
    void DAC_PlayAudio(uint16_t *audio_data, uint32_t len, uint16_t sample_rate)
    {
    if(audio_data == NULL || len == 0) return;

    // 计算采样间隔(微秒)
    uint32_t delay_us = 1000000 / sample_rate;

    for(uint32_t i=0; i<len; i++)
    {
    // DAC输出12位数据(0-4095),将16位数据转换为12位
    uint16_t dac_data = audio_data[i] >> 4;
    HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_data);

    // 延时控制采样率
    for(uint32_t j=0; j<delay_us; j++)
    {
    __NOP();
    }
    }
    }

    4.5 主函数代码

    文件名:main.c

    /* USER CODE BEGIN Header */
    /**
    ******************************************************************************
    * @file : main.c
    * @brief : Main program body
    ******************************************************************************
    * @attention
    *
    * Copyright (c) 2024 STMicroelectronics.
    * All rights reserved.
    *
    * This software is licensed under terms that can be found in the LICENSE file
    * in the root directory of this software component.
    * If no LICENSE file comes with this software, it is provided AS-IS.
    *
    ******************************************************************************
    */

    /* USER CODE END Header */
    /* Includes ——————————————————————*/
    #include "main.h"
    #include "dac.h"
    #include "i2s.h"
    #include "spi.h"
    #include "tim.h"
    #include "usart.h"
    #include "gpio.h"

    /* Private includes ———————————————————-*/
    /* USER CODE BEGIN Includes */
    #include "syn6288.h"
    #include "vs1053.h"
    #include "dac_audio.h"
    #include "string.h"
    /* USER CODE END Includes */

    /* Private typedef ———————————————————–*/
    /* USER CODE BEGIN PTD */

    /* USER CODE END PTD */

    /* Private define ————————————————————*/
    /* USER CODE BEGIN PD */
    // 输出方式选择:1-I2S+VS1053,2-DAC
    #define OUTPUT_MODE 1
    /* USER CODE END PD */

    /* Private macro ————————————————————-*/
    /* USER CODE BEGIN PM */

    /* USER CODE END PM */

    /* Private variables ———————————————————*/

    /* USER CODE BEGIN PV */

    /* USER CODE END PV */

    /* Private function prototypes ———————————————–*/
    void SystemClock_Config(void);
    /* USER CODE BEGIN PFP */

    /* USER CODE END PFP */

    /* Private user code ———————————————————*/
    /* USER CODE BEGIN 0 */

    /* USER CODE END 0 */

    /**
    * @brief The application entry point.
    * @retval int
    */

    int main(void)
    {
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration——————————————————–*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_SPI3_Init();
    MX_DAC_Init();
    MX_TIM6_Init();
    /* USER CODE BEGIN 2 */

    // 初始化各模块
    SYN6288_Init();
    #if OUTPUT_MODE == 1
    VS1053_Init(); // I2S+VS1053模式
    #elif OUTPUT_MODE == 2
    DAC_Audio_Init(); // DAC模式
    #endif

    // 测试文字(GB2312编码,确保Keil工程编码为GB2312)
    char test_text[] = "欢迎使用STM32F4语音播报系统,当前音量为50%";

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
    // 发送合成指令
    SYN6288_SendText(test_text);

    // 等待播放完成
    while(SYN6288_CheckBusy() == 1)
    {
    HAL_Delay(100);
    }

    // 播放完成后延时5秒再次播放
    HAL_Delay(5000);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
    }

    /**
    * @brief System Clock Configuration
    * @retval None
    */

    void SystemClock_Config(void)
    {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
    */

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
    Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
    */

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
    Error_Handler();
    }
    }

    /* USER CODE BEGIN 4 */

    /* USER CODE END 4 */

    /**
    * @brief This function is executed in case of error occurrence.
    * @retval None
    */

    void Error_Handler(void)
    {
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
    }

    #ifdef USE_FULL_ASSERT
    /**
    * @brief Reports the name of the source file and the source line number
    * where the assert_param error has occurred.
    * @param file: pointer to the source file name
    * @param line: assert_param error line source number
    * @retval None
    */

    void assert_failed(uint8_t *file, uint32_t line)
    {
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\\r\\n", file, line) */

    /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */

    五、代码编译与下载

    5.1 编译代码

  • 在Keil中打开生成的工程,将新增的.c文件添加到工程的“Source Group”中。
  • 点击“魔法棒”图标,进入“Target”选项卡,设置“Stack Size”为0x400,“Heap Size”为0x200。
  • 点击“Build”或“Rebuild”编译工程,确保无错误、无警告。
  • 5.2 下载代码

  • 连接STM32开发板到电脑,安装对应的调试器驱动(如J-Link、ST-Link)。
  • 在Keil中点击“Download”按钮,将编译后的代码下载到STM32芯片中。
  • 六、测试与调试

    6.1 硬件检查

  • 确认所有电路连接正确,无虚焊、短路。
  • 给各模块供电(STM32 5V,SYN6288/VS1053 3.3V)。
  • 6.2 功能测试

  • 下载代码后,复位STM32开发板。
  • 观察扬声器是否播放预设的测试文字“欢迎使用STM32F4语音播报系统,当前音量为50%”。
  • 若播放异常:
    • 检查串口波特率是否为9600(SYN6288默认波特率)。
    • 检查VS1053复位是否正常,I2S时钟是否配置正确。
    • 检查DAC输出是否有模拟信号(可用示波器测量PA4引脚)。
  • 6.3 功能扩展

  • 可通过串口接收上位机发送的文字,修改main.c中的test_text为串口接收的数据。
  • 可添加按键控制音量、暂停/播放功能。
  • 可扩展SYN6288的更多指令(如设置语速、音调)。
  • 七、常见问题解决

  • SYN6288不响应:检查串口接线(TX/RX是否交叉)、BUSY引脚是否上拉、供电是否稳定。
  • VS1053无声音:检查I2S配置、音量是否设置过大/过小、复位是否完成。
  • DAC输出噪声大:增加滤波电容(100nF)在DAC输出引脚,降低采样率或优化延时函数。
  • 总结

  • 本语音播报系统核心分为三部分:SYN6288完成文字转语音数据、STM32F4驱动DAC/I2S外设、VS1053/DAC完成音频输出,硬件连接需严格按照引脚定义执行。
  • 软件实现上,先通过STM32CubeMX完成外设初始化配置,再编写各模块驱动代码,主函数实现核心业务逻辑,编译下载后可直接测试。
  • 调试时优先检查硬件连接和供电,再排查串口/I2S通信参数、模块复位状态等软件配置,确保各模块协同工作。
  • 赞(0)
    未经允许不得转载:171主机测评 » 语音播报系统:STM32F4驱动DAC/I2S,语音合成芯片应用
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址