最近在做一个带提示语音的项目,需要控制语音芯片,搜了一下大多的语音芯片都是一线、二线、标准串口,但在价格上一线控制OTP的语音芯片是最便宜的。
可厂家提供的参考例程和网上分享的都是差不多的方式,用阻塞方式延时,发一字节数据基本要十多毫秒,还是自己写一个吧,顺便记录一下。
先看厂家提供的
厂家提供的虽然简单但是有硬伤吖。。。
好,言归正转,我分享一下我的想法:
大概逻辑是在定时器100uS更新中断中调用VoicePlayCommand();(简单来说就是100uS执行一次VoicePlayCommand();,也可以10uS,20uS等等,改对你要的时间间隔就好)。
然后在需要发送语音序号的地方调用PlayAssignNumber(Number);
例如:PlayAssignNumber(0x02);就发送播放语音芯片中序号为2的提示音。
app_Voice.c
#include "app_Voice.h" uint8_t *OutPtr; uint8_t *InPtr; uint8_t VoicePlay_Flag = 0; uint8_t VoiceBuff[10] = {0}; // 指令缓存,根据实际使用 e_OneLineStatus StatusStep = Restart; /** *********************************************************** * @brief 语音初始化 * @param 无 * @retval 无 * @note 无 *********************************************************** */ void app_VoiceInit(void) { InPtr = &VoiceBuff[0]; OutPtr = &VoiceBuff[0]; } /** *********************************************************** * @brief 语音控制处理 * @param 无 * @retval 无 * @note PB7,100us执行一次 *********************************************************** */ void VoicePlayCommand(void) { static uint8_t AddrData = 0; static uint8_t BitCounter = 0; static uint8_t TimCounter = 0; if (VoicePlay_Flag) { if (TimCounter) TimCounter--; switch (StatusStep) { case Restart: if (!TimCounter) { /* 处理完成默认置高电平 */ VOICE_HIGH(); // 置高电平 /* 判断缓冲区是否还有数据要处理 */ if (InPtr != OutPtr) { AddrData = *OutPtr; StatusStep = Lead; if (&VoiceBuff[(BUFF_MAX - 1)] < ++OutPtr) { OutPtr = &VoiceBuff[0]; } } else { VoicePlay_Flag = 0; } } break; case Lead: /* 引导码6mS */ VOICE_LOW(); // 置低电平 TimCounter = TM_6MS; // 引导码时长 StatusStep = OutHigh; break; case OutHigh: /* 设置高电平 */ if (!TimCounter) { VOICE_HIGH(); // 置高电平 // 设置输出高电平时长 TimCounter = (AddrData & 0x01) ? TM_600US : TM_200US; StatusStep = OutLow; } break; case OutLow: /* 设置低电平 */ if (!TimCounter) { VOICE_LOW(); // 置低电平 // 设置输出低电平时长 TimCounter = (AddrData & 0x01) ? TM_200US : TM_600US; AddrData >>= 1; // 数据移位 // 一字节数据是否处理完成 if (8 <= ++BitCounter) { BitCounter = 0; StatusStep = Restart; } else { StatusStep = OutHigh; } } break; default: break; } } } /** *********************************************************** * @brief 播放指定序号的语音 * @param PlayNumber:播放语音的地址序号 * @retval 无 * @note 无 *********************************************************** */ void PlayAssignNumber(uint8_t PlayNumber) { *InPtr = PlayNumber; if (&VoiceBuff[(BUFF_MAX - 1)] < ++InPtr) { InPtr = &VoiceBuff[0]; } VoicePlay_Flag = 1; }
app_Voice.h
#ifndef _APP_VOICE_H #define _APP_VOICE_H #define VOICE_HIGH() // 根据自己MCU的IO更改 #define VOICE_LOW() // 根据自己MCU的IO更改 #define TM_200US 2 #define TM_600US 6 #define TM_6MS 60 #define BUFF_MAX 10 typedef enum { Restart, // 重新开始 Lead, // 引导码 OutHigh, // 输出高电平 OutLow // 输出低电平 } e_OneLineStatus; void app_VoiceInit(void); void VoicePlayCommand(void); void PlayAssignNumber(uint8_t PlayNumber); #endif
main.c文件,定时器配置此处省略了。
#include "app_Voice.h" /** *********************************************************** * @brief 主函数 * @param 无 * @retval 无 * @note 无 *********************************************************** */ int main(void) { HAL_Init(); APP_SystemClockConfig(); app_VoiceInit(); PlayAssignNumber(0xF3); PlayAssignNumber(0x06); PlayAssignNumber(0x07); PlayAssignNumber(0x08); while (1) { ; } return 0; } /** *********************************************************** * @brief TIM14更新中断回调函数 * @param 无 * @retval 无 * @note 无 *********************************************************** */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { VoicePlayCommand(); }
这里演示是组合播放序号6、7、8的语音。波型分析如下:
好啦,就这么点东西了,后期有补的话再补上吧 ,先不说好不好用。