最近弄了个机器人,想给他加上个TTS模块,提升交互性。
TTS有在线、离线的多种实现方法,其中在线方法不是很必要,因为TTS相对ASR(语音识别)计算量小,算法难度低,离线的基本都能够满足需求,其中离线的又分为基于芯片的和纯软件的方法。但软件的方法目前只看到PC平台的,尚未有单片机平台的,而我的主控是Arduino平台的Atmel mega328p,并不能完成纯软件的TTS,所以考虑用硬件芯片实现,考虑到讯飞在语音领域多年的积累,选择讯飞XFS5152CE模块。
顺便说下XFS5152CE芯片(芯片资料#url#),其支持任意中英文混合文本的发音,并且支持GB2312、GBK、BIG5、UNICODE四种编码,也能自动识别常见的数字、号码、时间、 日期、度量衡符号等格式的文本,也支持部分多音字,以及五种音色等等。总之在发音效果上还是不错的。
该芯片支持三种通信方式:UART、I2C、SPI。由于我的主控同时还连接了两个UART设备,SPI通信占用端口数太多,所以我不想再用软件模拟UART设备,故而采用I2C方式,于是入坑……
网上大多数采用的都是UART方式通信,而官方例程虽然给了UART和I2C方式,但是只有基于51和STM32的,网上有部分人采用Arduino的I2C方式却都是失败了在寻求帮助???而我原本以为可以很快搞定,结果经过数天纠结,始终通信失败,而用UART通信则正常。最终看了大量相关不相关的代码后,终于发现了问题所在,在Arduino关于Wire库(也就是I2C库)的Example里面,有个SFRRanger_reader.ino的例子里写了这么一段注释:
// step 1:instruct sensor to read echoes
Wire.beginTransmission(112); // transmit to device #112 (0x70)
//the address specified in the datasheet is 224 (0xE0)
//but i2c adressing uses the high 7 bits so it's 112
等于说Arduino的I2C通信设备地址是slave设备地址的逻辑右移一位……好吧,芯片手册上写的通信地址是0x80,所以这里需要填的是0x80>>1->0x40,即 Wire.beginTransmission(0x40);
其原因在于I2C通信的时候真实传输的8位地址里最后一位是用来表明读写的,所以arduino的设计是让用户传入7位地址,而其WIRE库会再最后加上读写标志,而不排除有的库设计的时候是要求传入8位地址,其中最后一位置0,实际读写的时候进行与或运算,那么以后用I2C就要留个心,模块给出的地址如果最后一位是1,那么大概率是不含最后读写位的,否则就要仔细核对是否地址位含读写位
原文链接:http://www.straka.cn/blog/xfs5152ce_i2c_bugfix/