文章目录
-
- 一、项目概述
- 二、硬件准备与原理说明
-
- 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连接
| PA9 (USART1_TX) | RX | 串口发送数据 |
| PA10 (USART1_RX) | TX | 串口接收数据 |
| 3.3V | VCC | 供电 |
| GND | GND | 接地 |
| PB0 | BUSY | 忙状态检测 |
2.3.2 STM32与VS1053连接(I2S方式)
| 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输出连接(备用)
| PA4 (DAC_OUT1) | IN+ | 模拟音频输出 |
| GND | IN- | 接地 |
三、软件环境搭建
3.1 开发工具安装
3.2 STM32CubeMX配置步骤
3.2.1 新建工程
3.2.2 外设配置
- 点击“Clock Configuration”,将HSE设置为8MHz,PLL倍频设置为168,系统时钟配置为168MHz。
- 点击“Connectivity” → “USART1”,模式选择“Asynchronous”(异步模式)。
- 参数:波特率9600,数据位8,停止位1,校验位None,收发使能。
- 点击“Connectivity” → “SPI3”,模式选择“I2S Master Transmit”(I2S主机发送)。
- 参数:标准I2S,采样率44.1kHz,数据长度16位,时钟极性低。
- 点击“Analog” → “DAC”,启用DAC1 Channel1(PA4)。
- PB0(SYN6288 BUSY):输入模式,上拉。
- PB12、PB13、PB15、PA4、PA5(VS1053控制引脚):输出模式,推挽输出,上拉,速度中速。
3.2.3 工程生成
四、代码实现
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 编译代码
5.2 下载代码
六、测试与调试
6.1 硬件检查
6.2 功能测试
- 检查串口波特率是否为9600(SYN6288默认波特率)。
- 检查VS1053复位是否正常,I2S时钟是否配置正确。
- 检查DAC输出是否有模拟信号(可用示波器测量PA4引脚)。


