前言
通过本文的学习,读者将能够了解STM32和JQ8900的工作原理和特点,掌握通过串口通信控制JQ8900的方法,以及实现基本音频播放功能的技巧。希望本文对于读者在嵌入式系统开发中使用STM32控制JQ8900有所帮助。
一、语音播报的作用?
提供信息:语音播报可以传达重要的消息、通知和警报,让人们了解和理解相关的信息。
方便无障碍使用:对于视觉障碍者或其他身体残障者来说,语音播报是获取信息的重要途径,可以帮助他们参与到社会活动中。
提醒和提醒:语音播报可以用于提醒人们执行某项任务或活动,如闹钟和提醒功能。
娱乐和娱乐:语音播报可以用于娱乐目的,如播放音乐、播放有声读物或讲笑话等。
注:要买一个喇叭一起用
二、使用步骤
1.JQ8900.c
代码如下(示例):
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "JQ8900.h"
// 初始化单线 UART 接口(实际上这里只是初始化了一个 GPIO 引脚)
void Init_One_line_Uart(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能 GPIOB 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 设置 GPIOB.12 为推挽输出模式,速度为 50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 将 GPIOB.12 置高电平
GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
// 用于控制 JQ8900 指令发送的函数
void SendData(u8 addr)
{
u8 i;
sda(1); // 拉高 SDA 线
delay_us(700);
sda(0); // 拉低 SDA 线
delay_us(3200);
for (i = 0; i < 8; i++) {
sda(1); // 拉高 SDA 线
if (addr & 0x01) { // 如果当前位为高电平
delay_us(600);
sda(0); // 拉低 SDA 线
delay_us(210);
} else { // 如果当前位为低电平
delay_us(210);
sda(0); // 拉低 SDA 线
delay_us(600);
}
addr >>= 1; // 右移一位
}
sda(1); // 最后拉高 SDA 线
}
// 播放下一首
void Next(void)
{
SendData(0x15); // 发送下一首指令
}
// 播放上一首
void Previous(void)
{
SendData(0x14); // 发送上一首指令
}
// 设置音量
void Set_volume(u8 vol)
{
SendData(0x0a); // 清除数字
SendData(vol); // 发送音量值
SendData(0x00);
SendData(0x0c); // 设置音量指令
}
// 播报天气信息
void Voive_Weather(uint16_t num)
{
SendData(0x0a);
SendData(0x01);
SendData(0x01 * num);
SendData(0x0b);
}
// 播放指定编号的语音文件
void Voive_Play(uint16_t num)
{
SendData(0x0a);
SendData(0x02);
SendData(0x01 * num);
SendData(0x0b);
}
// 播报数字
void Voice_Num(uint16_t num)
{
if(num < 10) {
SendData(0x0a);
SendData(0x01 * num);
SendData(0x0b);
} else if(num == 10) {
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
} else if(num > 10) {
int i = num % 10; // 计算个位
int j = num % 100 / 10; // 计算十位
SendData(0x0a);
SendData(0x01 * j);
SendData(0x0b);
delay_ms(700);
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x01 * i);
SendData(0x0b);
} else if (num == 20) {
int i = num % 10; // 计算个位
SendData(0x0a);
SendData(0x02);
SendData(0x0b);
delay_ms(800);
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
} else if(num < 0) {
SendData(0x0a);
SendData(0x01);
SendData(0x06);
SendData(0x0b);
delay_ms(2000);
int i = num % 10; // 计算个位
int j = num % 100 / 10; // 计算十位
SendData(0x0a);
SendData(0x01 * j);
SendData(0x0b);
delay_ms(700);
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x01 * i);
SendData(0x0b);
}
}
// 播报时间
void voice_time(uint16_t Hour, uint16_t Min)
{
int i = Hour % 10; // 计算小时个位
int j = Hour % 100 / 10; // 计算小时十位
int x = Min % 10; // 计算分钟个位
int y = Min % 100 / 10; // 计算分钟十位
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x01 * i);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x04);
SendData(0x05);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x01 * y);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x04);
SendData(0x01);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x01 * x);
SendData(0x0b);
delay_ms(1000);
SendData(0x0a);
SendData(0x04);
SendData(0x02);
SendData(0x0b);
delay_ms(1000);
}
1、Init_One_line_Uart 函数只初始化了一个 GPIO 引脚作为输出,这可能不是标准的 UART 初始化方法,而是一个特定于单线通信的设置。
2、SendData 函数通过改变 SDA 线的状态来发送数据,看起来像是模拟 I2C 或者某种脉冲编码调制(PCM)协议。
3、 其他函数如 Next, Previous, Set_volume, Voive_Weather, Voive_Play, Voice_Num, 和 voice_time 都是通过 SendData 来发送不同的命令给 JQ8900 模块,以实现不同的功能。
2.JQ8900.h
代码如下(示例):
#ifndef _JQ8900_H
#define _JQ8900_H
#include "stm32f10x.h"
#include <stdint.h> // 包含标准整型定义
// 初始化单线 UART 接口(实际是 GPIO 引脚)
void Init_One_line_Uart(void);
// 快速设置或复位 GPIOB.12 的电平状态
#define SDA_HIGH() GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET)
#define SDA_LOW() GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET)
// 配置 USART1 的接收中断使能/禁用 (仅供内部使用)
#define ITConfig(EN) EN ? USART_ITConfig(USART1, USART_IT_RXNE, ENABLE) : USART_ITConfig(USART1, USART_IT_RXNE, DISABLE)
/**
* @brief 向 JQ8900 模块发送数据
* @param addr 数据地址或命令码
*/
void SendData(uint8_t addr);
/**
* @brief 控制播放下一首曲目
*/
void Next(void);
/**
* @brief 控制播放上一首曲目
*/
void Previous(void);
/**
* @brief 设置 JQ8900 模块的音量
* @param vol 音量级别 (0-最大值)
*/
void Set_volume(uint8_t vol);
/**
* @brief 播报数字
* @param num 要播报的数字
*/
void Voice_Num(uint16_t num);
/**
* @brief 播放指定编号的语音文件
* @param num 语音文件编号
*/
void Voice_Play(uint16_t num);
/**
* @brief 播报天气信息
* @param num 天气信息编号
*/
void Voice_Weather(uint16_t num);
/**
* @brief 播报时间
* @param Hour 小时数
* @param Min 分钟数
*/
void Voice_Time(uint16_t Hour, uint16_t Min);
#endif // _JQ8900_H
3、main.c文件
代码如下(示例):
#include "stm32f10x.h"
#include "JQ8900.h"
#include "delay.h"
// 定义播放状态变量
volatile uint8_t is_playing = 1;
int main(void)
{
Init_One_line_Uart();
while (1)
{
// 设置音量
SendData(0x0a);
SendData(0x02);
SendData(0x00);
SendData(0x0c);
// 播报地址1
SendData(0x11);
SendData(0x0a);
SendData(0x01);
SendData(0x0b);
// 播放一段时间后暂停
delay_ms(5000); // 播放5秒
if (is_playing) {
// 发送暂停命令
SendData(0x16); // 暂停命令
is_playing = 0;
} else {
// 发送播放命令
SendData(0x17); // 播放命令
is_playing = 1;
}
// 等待一段时间再恢复播放
delay_ms(5000); // 等待5秒
}
}
注意事项
实际命令码:请务必参考 JQ8900 的官方文档,找到正确的暂停和播放命令码,并用它们替换上面代码中的 0x16 和 0x17。
用户交互:上述代码只是简单地在固定时间间隔内切换播放状态。为了实现真正的用户交互(如通过按键控制),您需要设置按键检测逻辑,可能是通过 GPIO 中断或者定时器轮询的方式来实现。
延迟函数:确保 delay_ms 函数已经正确实现并且适用于 STM32 平台。如果不适用,请使用合适的延时函数,例如 HAL 库中的 HAL_Delay()。
线程安全:如果您打算在中断上下文中改变 is_playing 变量的状态,记得使用原子操作或者禁用中断以防止竞态条件。
硬件连接:确保硬件连接正确无误,特别是与 JQ8900 相关的电源、地线以及通信接口。
总结
灵活可控:可以通过编写代码或者使用现成的库函数来实现与模块的通信和控制,能够满足多种语音播放的需求。
易于使用:可以使用按键、触摸屏等外部触发方式来触发语音播放,操作简单方便。
可扩展性强:可以将语音播放与其他功能结合,实现更多样化的语音播报应用。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_63037616/article/details/144796652
|