【美好生活好搭拍客】专注力提升神器
本帖最后由 ngxxczlwh 于 2020-6-22 23:11 编辑【设计背景】 低学龄孩子写作业是令许多家长头疼的事。孩子们写一会儿作业就喊着要吃东西、喝水或是上厕所,不能高效安静地完成作业,家长们看着只能干着急。孩子小,注意力不集中是其中的原因之一,孩子缺少这方面的训练,也是孩子不能专注做事的主要原因之一。怎样训练孩子在一段时间内集中注意力,专注于写作业呢?
思考良久,我就想创作一个可以用来培养孩子的专注力的作品,陪伴并训练孩子在一段时间内专心地写作业。
【功能描述】
1.在孩子准备写作业前,提醒孩子做好准备。
2.孩子写作业过程中,若有交互需求,给3次机会和孩子交流,并温馨提醒孩子专心写作业。
3.倒计时。默认给孩子30分钟时间专心写作业,倒计时时间到了,询问作业写好了没有,若孩子作业写完了,给与孩子激励和表扬,鼓励孩子的进步;若孩子作业没有完成,也要用激励性的语言给孩子加油,同时提醒孩子休息10分钟,为下一段学习时间做好准备。倒计时功能应该是独立的,其他的生活场景也可以随时使用倒计时功能,比如:洗澡、阅读、看电视、玩游戏等等。
4.其他简单的语音交互功能。
5.简单娱乐功能,如:语音点播歌曲。
【视频演示】//player.bilibili.com/player.html?bvid=BV1n5411W7Cx
【物料清单】
1.Nano主控板及扩展板
因为本作品中使用了语音识别等开源硬件,因此在主控板上选择了arduino平台的Nano板子作为主控板,小巧又便宜,适合编程造物。为了方便使用和调试,还选配了一块扩展板。
2.Ds1302时钟模块
这是一款非常实用的时钟模块,为系统提供准确的时间信息,断电不掉时。
3.TM1650 4位数码管(带冒号)
TM1650 4位数码管,IIC总线驱动。
4.语音识别模块
这是一款在淘宝上买的语音识别模块,价格有些小贵,但本系统设计的目标需要语音交互,少不了语音识别模块。
它也是iic总线驱动的,这样可以节省系统的引脚。
5.MP3语音模块及TF卡
MP3语音模块,用于语音交互,播放语音。TF卡用于存储语音交互时需要播放的MP3文件。
6.简易功放模块
简易功放,用于将MP3模块解码的声音文件放大输出到喇叭。
7.小喇叭
【电路连接】
【程序编写】
1.主程序部分
#include <TM1650.h> //TM1650数码管
#include <Wire.h> //I2C语音识别模块
#include <ThreeWire.h> //DS1302时钟模块所用头文件
#include <RtcDS1302.h> //DS1302时钟模块头文件
#include <mp3.h> //MP3音频模块头文件
#include <ASR.h> //语音识别模块头文件
TM1650 dis_1650; //数码管实例化
bool dotflag=false; //控制数码管中间冒号
bool isDaojishi=false; //记录是否在倒计时中
bool isWorking=false; //记录是否在学习中
uint8_t miao='0'; //监控秒数的变化,以显示冒号
unsigned alarm_hour; //倒计时时刻的时分秒
unsigned alarm_minute; //倒计时时刻的分
unsigned alarm_second; //倒计时时刻的秒
//时钟对象实例化
ThreeWire myWire(10,11,9); // IO, SCLK, CE(DS1302时钟模块的三个引脚)
RtcDS1302<ThreeWire> Rtc(myWire);
RtcDateTime now;
//MP3对象实例化
const int dq = A1;
MP3 mp3(dq);
//ASR语音识别对象实例化
ASR myAsr;
//系统初始化部分
void setup() {
Wire.begin(); //Join the bus as master
myAsr.init(); //修改词条请在ASR.CPP文件中修改此方法;
dis_1650.init();//TM1650数码管初始化部分
delay(1000);
//初始化mp3模块,设置音量
mp3.Init(); //MP3音频模块初始化
delay(200);
mp3.Volume_Set(15); //设置MP3音频模块音量,最大值30
//初始化随机种子
randomSeed(analogRead(0));
//初始化时钟模块
Rtc.Begin();
#if 0
//设置的时间是可以掉电保存的,第一次设置完成后,可以将此段注释掉,即将1改为0,然后重新下载一次程序
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
Rtc.SetDateTime(compiled);
//添加的词条和识别模式是可以掉电保存的,第一次设置完成后,可以将此段注释掉,即将1改为0,然后重新下载一次程序
myAsr.AddWords();
#endif
}
//倒计时函数,minute为倒计时的分钟数
void daoJiShi(unsigned minute){
isDaojishi=true;
RtcDateTime now = Rtc.GetDateTime();
alarm_second=now.Second();
alarm_minute=(now.Minute()+minute)%60;
alarm_hour=((now.Minute()+minute)/60+now.Hour())%24;
}
//displayTime为在数码管显示时间的函数
#define countof(a) (sizeof(a) / sizeof(a))
void displayTime()
{
// RtcDateTime now = Rtc.GetDateTime();
now =Rtc.GetDateTime();
char datestring;
snprintf_P(datestring,
countof(datestring),
PSTR("%02u%02u"),//%04u %02u:%02u:%02u"),
//dt.Month(),
//dt.Day(),
//dt.Year(),
now.Hour(),
now.Minute()
//dt.Second()
);
//Serial.print(datestring);
dis_1650.displayString(datestring);
if(miao!=now.Second()) {
dotflag=!dotflag;
miao=now.Second();
}
dis_1650.setDot(1,dotflag);
//Serial.println("displayTime is working");
}
//判断倒计时时间是否到了
bool isTime()
{
//Serial.println("isTime is working.");
if((now.Second()==alarm_second) and (now.Minute()==alarm_minute) and (now.Hour() ==alarm_hour))
{
mp3.Song_Select(11); //倒计时时间到了,播放提示音:时间到
isDaojishi=false;
return true;
}
else
return false;
}
//我要(想)写作业函数,完成写作业的整个交互流程
void iWanttoWork()
{
Serial.println("iWanttoWork is working.");
isWorking=true; //记录状态:要开始写作业了
mp3.Song_Select(9); //询问是否需要花5分钟时间准备一下
unsigned char result;
result=myAsr.Listening(); //监听语音,并将语音识别的结果赋给result
while (result!=11) //回答为“不需要准备”对应11
{
if (result==12) //回复:需要准备一下,给5分钟时间准备。
{
mp3.Song_Select(10);
daoJiShi(5); //5分钟准备时间倒计时
while(!isTime()) //5分钟倒计时期间停在此处:显示时间、监听语音
{
displayTime(); //数码管显示时间
result=myAsr.Listening();
if (result==14){ //准备好了,跳出循环
mp3.Song_Select(16); //准备好了的应答
break;
}
}
break;
}
result=myAsr.Listening(); //监听语音,并将语音识别的结果赋给result
displayTime();
}
mp3.Song_Select(12); //播报:开始写作业
daoJiShi(30); //写作业倒计时开始
unsigned char countSpeak=0; //记录写作业过程中讲话的次数,只回应前3次
while (!isTime()) //写作业的倒计时30分钟期间,程序停在此循环,完成:显示时间、监听语音并做相应的应答
{
displayTime();
result=myAsr.Listening();
switch(result)
{
case 2:
case 3:
case 7:
case 8: if(countSpeak<=3){countSpeak++;mp3.Song_Select(random(4,6));}break; //回应3次(呼叫、听歌、吃东西、喝水)
case 13:mp3.Song_Select(15);return; //作业写完了,提前退出本函数。
}
}
mp3.Song_Select(13);//询问作业是否完成
while (true) //确认作业是否完成
{
displayTime();
result=myAsr.Listening();
if(result==13) //完成作业的应答
{mp3.Song_Select(15);break;}
if(result==21) //作业未完成的应答
{mp3.Song_Select(14);break;}
}
}
//主循环程序
void loop() {
//显示时间
displayTime();
//判断倒计时时间是否到了
isTime();
// if((now.Second()==alarm_second) and (now.Minute()==alarm_minute) and (now.Hour() ==alarm_hour))
// {
// mp3.Song_Select(11);
// isDaojishi=false;
// }
///////////////////////////////////////////////////开始语音识别
unsigned char result;
unsigned char indexMp3;
result=myAsr.Listening(); //监听语音,并将语音识别结果赋给result
//Serial.println(result);
switch(result){
case 2:mp3.Song_Select(random(1,4));break; //呼叫鸡飞飞的应答
case 1:
case 5:
case 10:
case 15:
case 20:
case 30: if(!isDaojishi) {mp3.Song_Select(8);daoJiShi(result);}break; //倒计时的处理
case 9: mp3.Song_Select(random(6,8));break; //我回来了
case 4: if(!isWorking) iWanttoWork();break; //我要写作业
case 3: indexMp3=random(30,46);mp3.Song_Select(indexMp3);break; //我要听音乐的处理:随机播放30-46区间的MP3文件
case 7: mp3.Song_Select(17);break; //我要吃东西
case 16:if (indexMp3>30) mp3.Pre();break; //上一首
case 17: if(indexMp3<45) mp3.Next();break; //下一首
case 18: mp3.Stop();break; //停止播放音乐
//default:mp3.Song_Select(18);Serial.println("what are you saying?");//其他情况
}
}
2.语音识别部分
2.1语音识别模块头文件(ASR.h)
#ifndef_ASR_H_
#define _ASR_H_
#include <Wire.h>
#define I2C_ADDR 0x79
#define ASR_RESULT_ADDR 100
//识别结果存放处,通过不断读取此地址的值判断是否识别到语音,不同的值对应不同的语音,
#define ASR_WORDS_ERASE_ADDR 101//擦除所有词条
#define ASR_MODE_ADDR 102
//识别模式设置,值范围1~3
//1:循环识别模式。状态灯常亮(默认模式)
//2:口令模式,以第一个词条为口令。状态灯常灭,当识别到口令词时常亮,等待识别到新的语音,并且读取识别结果后即灭掉
//3:按键模式,按下开始识别,不按不识别。支持掉电保存。状态灯随按键按下而亮起,不按不亮
#define ASR_ADD_WORDS_ADDR 160//词条添加的地址,支持掉电保存
class ASR{
public:
ASR(uint8_t asr_mode=1);
void init();
bool WireWriteByte(uint8_t val);
bool WireWriteDataArray(uint8_t reg,uint8_t *val,unsigned int len);
int WireReadDataArray( uint8_t reg, uint8_t *val, unsigned int len);
bool ASRAddWords(unsigned char idNum,unsigned char *words);
void AddWords(); //自定义词条的函数
unsigned char Listening(); //监听语音
private:
uint8_t ASRMode;
};
#endif /*end _ASR_H_ */
2.2 语音识别模块函数实现部分
#include<ASR.h>
#include<Arduino.h>
ASR::ASR(uint8_t asr_mode)
{
ASRMode=asr_mode;
}
bool ASR::WireWriteByte(uint8_t val)
{
Wire.beginTransmission(I2C_ADDR);
Wire.write(val);
if( Wire.endTransmission() != 0 ) {
return false;
}
return true;
}
bool ASR::WireWriteDataArray(uint8_t reg,uint8_t *val,unsigned int len)
{
unsigned int i;
Wire.beginTransmission(I2C_ADDR);
Wire.write(reg);
for(i = 0; i < len; i++) {
Wire.write(val);
}
if( Wire.endTransmission() != 0 ) {
return false;
}
return true;
}
int ASR::WireReadDataArray( uint8_t reg, uint8_t *val, unsigned int len)
{
unsigned char i = 0;
/* Indicate which register we want to read from */
if (!WireWriteByte(reg)) {
return -1;
}
Wire.requestFrom(I2C_ADDR, len);
while (Wire.available()) {
if (i >= len) {
return -1;
}
val = Wire.read();
i++;
}
/* Read block data */
return i;
}
/*
* 添加词条函数,
* idNum:词条对应的识别号,1~255随意设置。识别到该号码对应的词条语音时,
* 会将识别号存放到ASR_RESULT_ADDR处,等待主机读取,读取后清0
* words:要识别汉字词条的拼音,汉字之间用空格隔开
* 执行该函数,词条是自动往后排队添加的。
*/
bool ASR::ASRAddWords(unsigned char idNum,unsigned char *words)
{
Wire.beginTransmission(I2C_ADDR);
Wire.write(ASR_ADD_WORDS_ADDR);
Wire.write(idNum);
Wire.write(words,strlen(words));
if( Wire.endTransmission() != 0 ) {
delay(10);
return false;
}
delay(10);
return true;
}
void ASR::init()
{
uint8_t ASRMode = 1;//1:循环识别模式 2:口令模式,以第一个词条为口令 3按键模式,按下开始识别
Wire.begin();
Serial.begin(9600);
if(WireWriteDataArray(ASR_MODE_ADDR,&ASRMode,1))
Serial.println("ASR Module Initialization complete");
else
Serial.println("ASR Module Initialization fail");
Serial.println("Start");
}
void ASR::AddWords()
{
uint8_t ASRMode = 1;//1:循环识别模式 2:口令模式,以第一个词条为口令 3按键模式,按下开始识别
Wire.begin();
Serial.begin(9600);
WireWriteDataArray(ASR_WORDS_ERASE_ADDR,NULL,0);
delay(60);//擦除需要一定的时间
ASRAddWords(1,"dao ji shi yi fen zhong"); //倒计时1分钟
ASRAddWords(2,"ji fei fei"); //鸡飞飞
ASRAddWords(3,"wo yao ting yin yue"); //我要听音乐
ASRAddWords(3,"wo xiang ting yin yue"); //我想听音乐
ASRAddWords(3,"wo xiang ting ge"); //我想听歌
ASRAddWords(3,"wo xiang ting ge"); //我要听歌
ASRAddWords(4,"wo yao xie zuo ye"); //我要写作业
ASRAddWords(5,"dao ji shi wu fen zhong"); //倒计时5分钟
ASRAddWords(4,"wo yao kai shi xie zuo ye"); //我要开始写作业
//ASRAddWords(6,"wo yao xie zuo ye"); //我要写作业啦
ASRAddWords(7,"wo yao chi dong xi"); //我要吃东西
ASRAddWords(7,"wo xiang chi dong xi"); //我想吃东西
ASRAddWords(7,"wo du zi e le"); //我肚子饿了
ASRAddWords(8,"wo yao he shui"); //我要喝水
ASRAddWords(10,"dao ji shi shi fen zhong"); //倒计时10分钟
ASRAddWords(15,"dao ji shi shi wu fen zhong"); //倒计时15分钟
ASRAddWords(20,"dao ji shi er shi fen zhong"); //倒计时20分钟
ASRAddWords(30,"dao ji shi san shi fen zhong"); //倒计时30分钟
ASRAddWords(30,"dao ji shi ban ge xiao shi"); //倒计时30分钟
ASRAddWords(9,"hui lai le"); //我回来了
ASRAddWords(9,"hui lai la"); //我回来啦
ASRAddWords(11,"wo yi jing zhun bei hao le"); //我已经准备好了
ASRAddWords(11,"bu xu yao"); //不需要
ASRAddWords(12,"wo qu zhun bei yi xia"); //我去准备一下
ASRAddWords(12,"wo xu yao zhun bei yi xia"); //我需要准备一下
ASRAddWords(12,"wo yao zhun bei yi xia"); //我要准备一下
ASRAddWords(13,"wan cheng le"); //完成了
ASRAddWords(13,"xie hao le"); //写好了
ASRAddWords(13,"xie wan le"); //写完了
ASRAddWords(14,"zhun bei hao le"); //准备好了
ASRAddWords(16,"shang yi shou ge"); //上一首歌
ASRAddWords(17,"xia yi shou ge"); //下一首歌
ASRAddWords(18,"ting zhi bo fang"); //停止播放
ASRAddWords(18,"yin yue ting"); //音乐停
ASRAddWords(21,"mei you wan cheng"); //没有完成
ASRAddWords(21,"mei you xie hao"); //没有写好
ASRAddWords(21,"mei you xie wan"); //没有写完
if(WireWriteDataArray(ASR_MODE_ADDR,&ASRMode,1))
Serial.println("ASR Module Initialization complete");
else
Serial.println("ASR Module Initialization fail");
Serial.println("Start");
}
//监听函数,监听语音并将识别的结果以result返回
unsigned char ASR::Listening()
{
unsigned char result;
WireReadDataArray(ASR_RESULT_ADDR,&result,1);
return result;
}
3.其他程序模块
本系统中还使用了其他的模块,诸如MP3音频模块、DS1302时钟模块、TM1650数码管模块,但由于在arduino平台上使用这些模块很方便,相比语音识别模块这些模块的头文件和范例程序在arduino IDE中很容易获取和使用,在此就不一一罗列了。
在arduino IDE上获取所需模块的库文件的方法:项目->加载库->管理库,在弹出的“库管理器”窗口中输入关键词即可搜索到所需的库文件了。
【关于名字】
为了让孩子喜欢这个作品,并愿意和它一起学习训练专注力,培养良好的学习习惯,我和女儿商量,一起给这个作品起了一个名字:鸡飞飞。
“鸡飞飞”是女儿喜欢的音频节目《凯叔讲故事》中《口袋神探》里的一个可爱的角色。
页:
[1]