【DIY电子作品】出门提醒设备 基于 Ai-M61-32S 之 XFS5152CE语音合成篇 Step2

[复制链接]
查看1715 | 回复12 | 2023-11-29 12:57:44 | 显示全部楼层 |阅读模式
本帖最后由 WT_0213 于 2023-11-29 12:57 编辑


                               
登录/注册后可看大图


屏幕截图 2023-11-29 115312.png

TTS语音模块:XFS5152CE语音合成模块
TTS是Text To Speech的缩写,即“从文本到语音”,是人机对话的一部分,让机器能够说话。
语音播报功能的实现方式
  • TTS语音模块,比如XFS5152、SYN6288等
  • ISD4000系列语音录放芯片分段输出
  • 可以按键、UART控制的mp3解码芯片模块
  • OTP(One Time Programable)语音芯片[定制]

其中TTS语音模块使用起来最方便灵活,OTP语音芯片最简单。
由于项目使用的是XFS5152CE,所以简单介绍一下科大讯飞的XFS5152CE语音合成模块。

性能描述
1采用XFS5152CE语音合成芯片,支持任意中文文本、英文文本合成及
中英混读。
2支持文本控制标记设置,使用便捷,同时提升了文本处理的正确率。
3.具有文本智能分析处理功能,对常见的数字、号码、时间、日期、度
量衡符号等能正确的识别和处理。
4.具有很强的多音字和中文姓氏处理能力。
5.支持内置多款播音人声可供选择。
6.支持10级语速调节。
7.支持10级音调调节。
8.支持10级音量调节。
9.支持GB2312、GBK、BIG5和UNICODE四种编码方式。
10.每次合成的文本量多达4K字节。
11.集成80种常用提示音效,适用于不同场合的信息提示、铃声、警报
等功能。
12.支持多种控制命令,如合成文本、停止合成、状态查询等。
13.板载扬声器。
14.支持三种连接方式:杜邦线接口、鳄鱼夹接口、PH2.0防呆接口。
15.通信方式:IIC通信。
16.12C地址:0x50[新版本0x30]。



                               
登录/注册后可看大图

由于协议使用的是I2C,为了方便使用封装I2C功能。
Wire.h
  1. #pragma once

  2. // #include "bouffalo_sdk.h"
  3. #include "bflb_gpio.h"
  4. #include "bl616_gpio.h"
  5. #include "bl616_glb.h"
  6. #include "bl616_glb_gpio.h"
  7. #include "../../drivers/lhal/include/hardware/i2c_reg.h"
  8. #include "bflb_i2c.h"
  9. #define lowByte(w) ((uint8_t) ((w) & 0xff))
  10. #define highByte(w) ((uint8_t) ((w) >> 8))

  11. bool getWireTimeoutFlag();
  12. bool clearWireTimeoutFlag();
  13. void setWireTimeout(int timeout, bool reset_on_timeout);
  14. void onRequest(void (*callback)());
  15. void onReceive(void (*callback)(int));
  16. void setClock(int clockFrequency);
  17. int readI2c();
  18. int available();
  19. int write_len(uint8_t *str, int len);
  20. int write_str(uint8_t *str);
  21. int write_char(unsigned char value);
  22. void endTransmission_stop(bool stop);
  23. void endTransmission();
  24. void beginTransmission(unsigned char addr);
  25. int requestFrom_stop(unsigned char addr, int quantity, bool stop);
  26. int requestFrom(unsigned char addr, int quantity);
  27. void end();
  28. void begin_addr(unsigned char addr);
  29. void begin();
复制代码
其中
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
是arduino中的方法,主要是获取高位和低位数据
Wire.c
  1. #include "Wire.h"

  2. #define PUT_UINT32_LE(field, value)            \
  3.     do {                                       \
  4.         (field)[0] = (uint8_t)((value) >> 0);  \
  5.         (field)[1] = (uint8_t)((value) >> 8);  \
  6.         (field)[2] = (uint8_t)((value) >> 16); \
  7.         (field)[3] = (uint8_t)((value) >> 24); \
  8.     } while (0)



  9. struct bflb_device_s *i2c0;
  10. uint8_t rbuf[128];
  11. int available_count;
  12. int indexi2c;
  13. int wire_timeout;
  14. bool wire_timeout_flag;

  15. void board_i2c_pinmux_init(void)
  16. {
  17.     GLB_GPIO_Type pinlist[] = {
  18.         GLB_GPIO_PIN_30,
  19.         GLB_GPIO_PIN_31
  20.     };
  21.     GLB_GPIO_Func_Init(GPIO_FUN_I2C0, pinlist, 2);
  22. }

  23. bool bflb_i2c_isend(struct bflb_device_s *dev)
  24. {
  25.     uint32_t regval;
  26.     uint32_t reg_base;

  27.     reg_base = dev->reg_base;

  28.     regval = getreg32(reg_base + I2C_INT_STS_OFFSET);

  29.     if (regval & I2C_END_INT) {
  30.         return true;
  31.     }

  32.     return false;
  33. }

  34. bool bflb_i2c_isnak(struct bflb_device_s *dev)
  35. {
  36.     uint32_t regval;
  37.     uint32_t reg_base;

  38.     reg_base = dev->reg_base;

  39.     regval = getreg32(reg_base + I2C_INT_STS_OFFSET);

  40.     if (regval & I2C_NAK_INT) {
  41.         return true;
  42.     }

  43.     return false;
  44. }

  45. bool bflb_i2c_isbusy(struct bflb_device_s *dev)
  46. {
  47.     uint32_t regval;
  48.     uint32_t reg_base;

  49.     reg_base = dev->reg_base;

  50.     regval = getreg32(reg_base + I2C_BUS_BUSY_OFFSET);

  51.     if (regval & I2C_STS_I2C_BUS_BUSY) {
  52.         return true;
  53.     }

  54.     return false;
  55. }

  56. void bflb_i2c_enable(struct bflb_device_s *dev)
  57. {
  58.     uint32_t regval;
  59.     uint32_t reg_base;

  60.     reg_base = dev->reg_base;

  61.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
  62.     regval |= I2C_CR_I2C_M_EN;
  63.     putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
  64. }

  65. bool bflb_i2c_isenable(struct bflb_device_s *dev)
  66. {
  67.     uint32_t regval;
  68.     uint32_t reg_base;

  69.     reg_base = dev->reg_base;

  70.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
  71.     if (regval & I2C_CR_I2C_M_EN) {
  72.         return true;
  73.     }

  74.     return false;
  75. }

  76. void bflb_i2c_disable(struct bflb_device_s *dev)
  77. {
  78.     uint32_t regval;
  79.     uint32_t reg_base;

  80.     reg_base = dev->reg_base;

  81.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
  82.     regval &= ~I2C_CR_I2C_M_EN;
  83.     putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
  84.     /* Clear I2C fifo */
  85.     regval = getreg32(reg_base + I2C_FIFO_CONFIG_0_OFFSET);
  86.     regval |= I2C_TX_FIFO_CLR;
  87.     regval |= I2C_RX_FIFO_CLR;
  88.     putreg32(regval, reg_base + I2C_FIFO_CONFIG_0_OFFSET);
  89.     /* Clear I2C interrupt status */
  90.     regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
  91.     regval |= I2C_CR_I2C_END_CLR;
  92.     regval |= I2C_CR_I2C_NAK_CLR;
  93.     regval |= I2C_CR_I2C_ARB_CLR;
  94.     putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
  95. }


  96. void bflb_i2c_addr_config(struct bflb_device_s *dev, uint16_t slaveaddr, uint16_t subaddr, uint8_t subaddr_size, bool is_addr_10bit)
  97. {
  98.     uint32_t regval;
  99.     uint32_t reg_base;

  100.     reg_base = dev->reg_base;

  101.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);

  102.     if (subaddr_size > 0) {
  103.         regval |= I2C_CR_I2C_SUB_ADDR_EN;
  104.         regval &= ~I2C_CR_I2C_SUB_ADDR_BC_MASK;
  105.         regval |= ((subaddr_size - 1) << I2C_CR_I2C_SUB_ADDR_BC_SHIFT);
  106.     } else {
  107.         regval &= ~I2C_CR_I2C_SUB_ADDR_EN;
  108.     }

  109.     regval &= ~I2C_CR_I2C_SLV_ADDR_MASK;
  110.     regval |= (slaveaddr << I2C_CR_I2C_SLV_ADDR_SHIFT);
  111. #if !defined(BL602) && !defined(BL702)
  112.     if (is_addr_10bit) {
  113.         regval |= I2C_CR_I2C_10B_ADDR_EN;
  114.     } else {
  115.         regval &= ~I2C_CR_I2C_10B_ADDR_EN;
  116.     }
  117. #endif
  118.     putreg32(subaddr, reg_base + I2C_SUB_ADDR_OFFSET);
  119.     putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
  120. }

  121. void bflb_i2c_set_datalen(struct bflb_device_s *dev, uint16_t data_len)
  122. {
  123.     uint32_t regval;
  124.     uint32_t reg_base;

  125.     reg_base = dev->reg_base;

  126.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
  127.     regval &= ~I2C_CR_I2C_PKT_LEN_MASK;
  128.     regval |= ((data_len - 1) << I2C_CR_I2C_PKT_LEN_SHIFT) & I2C_CR_I2C_PKT_LEN_MASK;
  129.     putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
  130. }


  131. void bflb_i2c_set_dir(struct bflb_device_s *dev, bool is_in)
  132. {
  133.     uint32_t regval;
  134.     uint32_t reg_base;

  135.     reg_base = dev->reg_base;

  136.     regval = getreg32(reg_base + I2C_CONFIG_OFFSET);

  137.     if (is_in) {
  138.         regval |= I2C_CR_I2C_PKT_DIR;
  139.     } else {
  140.         regval &= ~I2C_CR_I2C_PKT_DIR;
  141.     }
  142.     putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
  143. }


  144. int bflb_i2c_write_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len, uint32_t timeout)
  145. {
  146.     uint32_t reg_base;
  147.     uint32_t temp = 0;
  148.     uint8_t *tmp_buf;
  149.     uint64_t start_time;

  150.     reg_base = dev->reg_base;
  151.     tmp_buf = data;
  152.     while (len >= 4) {
  153.         for (uint8_t i = 0; i < 4; i++) {
  154.             temp += (tmp_buf[i] << ((i % 4) * 8));
  155.         }
  156.         tmp_buf += 4;
  157.         len -= 4;
  158.         start_time = bflb_mtimer_get_time_ms();
  159.         while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
  160.             if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  161.                 return -ETIMEDOUT;
  162.             }
  163.         }
  164.         putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
  165.         if (!bflb_i2c_isenable(dev)) {
  166.             bflb_i2c_enable(dev);
  167.         }
  168.         temp = 0;
  169.     }

  170.     if (len > 0) {
  171.         for (uint8_t i = 0; i < len; i++) {
  172.             temp += (tmp_buf[i] << ((i % 4) * 8));
  173.         }
  174.         start_time = bflb_mtimer_get_time_ms();
  175.         while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
  176.             if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  177.                 return -ETIMEDOUT;
  178.             }
  179.         }
  180.         putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
  181.         if (!bflb_i2c_isenable(dev)) {
  182.             bflb_i2c_enable(dev);
  183.         }
  184.     }

  185.     start_time = bflb_mtimer_get_time_ms();
  186.     while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev) || bflb_i2c_isnak(dev)) {
  187.         if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  188.             return -ETIMEDOUT;
  189.         }
  190.     }
  191.     bflb_i2c_disable(dev);

  192.     return 0;
  193. }


  194. int bflb_i2c_read_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len, uint32_t timeout)
  195. {
  196.     uint32_t reg_base;
  197.     uint32_t temp = 0;
  198.     uint8_t *tmp_buf;
  199.     uint64_t start_time;

  200.     reg_base = dev->reg_base;
  201.     tmp_buf = data;

  202.     bflb_i2c_enable(dev);

  203.     while (len >= 4) {
  204.         start_time = bflb_mtimer_get_time_ms();
  205.         while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
  206.             if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  207.                 return -ETIMEDOUT;
  208.             }
  209.         }
  210.         temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);
  211.         PUT_UINT32_LE(tmp_buf, temp);
  212.         tmp_buf += 4;
  213.         len -= 4;
  214.     }

  215.     if (len > 0) {
  216.         start_time = bflb_mtimer_get_time_ms();
  217.         while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
  218.             if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  219.                 return -ETIMEDOUT;
  220.             }
  221.         }
  222.         temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);

  223.         for (uint8_t i = 0; i < len; i++) {
  224.             tmp_buf[i] = (temp >> (i * 8)) & 0xff;
  225.         }
  226.     }

  227.     start_time = bflb_mtimer_get_time_ms();
  228.     while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev)) {
  229.         if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
  230.             return -ETIMEDOUT;
  231.         }
  232.     }
  233.     bflb_i2c_disable(dev);

  234.     return 0;
  235. }



  236. /*
  237. * address: the 7-bit slave address (optional); if not specified, join the bus as a controller device.
  238. */
  239. void begin_addr(unsigned char addr) {
  240.     wire_timeout = 100;
  241.     wire_timeout_flag = false;
  242.     board_i2c_pinmux_init();
  243.     i2c0 = bflb_device_get_by_name("i2c0");
  244.     bflb_i2c_init(i2c0, 50000);
  245. }

  246. void begin() {
  247.     wire_timeout = 100;
  248.     wire_timeout_flag = false;
  249.     board_i2c_pinmux_init();
  250.     i2c0 = bflb_device_get_by_name("i2c0");
  251.     bflb_i2c_init(i2c0, 50000);
  252. }

  253. void end() {
  254.     bflb_i2c_deinit(i2c0);
  255. }
  256. /*
  257. * address: the 7-bit slave address of the device to request bytes from.
  258. *
  259. * quantity: the number of bytes to request.
  260. *
  261. * stop: true or false. true will send a stop message after the request, releasing the bus.
  262. * False will continually send a restart after the request, keeping the connection active.
  263. */

  264. int requestFrom_stop(unsigned char addr, int quantity, bool stop) {
  265.     indexi2c = 0;
  266.     bflb_i2c_disable(i2c0);
  267.     bflb_i2c_enable(i2c0);
  268.     bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
  269.     bflb_i2c_set_datalen(i2c0,quantity);
  270.     bflb_i2c_set_dir(i2c0, 1);
  271.     bflb_i2c_read_bytes(i2c0, rbuf,quantity,wire_timeout);
  272.     available_count = quantity;
  273.     if(true == stop){
  274.         bflb_i2c_disable(i2c0);
  275.     }
  276.     return 0;
  277. }

  278. int requestFrom(unsigned char addr, int quantity) {
  279.     indexi2c = 0;
  280.     bflb_i2c_disable(i2c0);
  281.     bflb_i2c_enable(i2c0);
  282.     bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
  283.     bflb_i2c_set_datalen(i2c0,quantity);
  284.     bflb_i2c_set_dir(i2c0, 1);
  285.     bflb_i2c_read_bytes(i2c0, rbuf,quantity,wire_timeout);
  286.     available_count = quantity;
  287.     return 0;
  288. }

  289. /*
  290. * address: the 7-bit address of the device to transmit to.
  291. */
  292. void beginTransmission(unsigned char addr) {
  293.     //bflb_i2c_enable(i2c0);
  294.     bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
  295.     bflb_i2c_set_dir(i2c0, 0);
  296. }

  297. /*
  298. * stop: true or false. True will send a stop message, releasing the bus after transmission.
  299. * False will send a restart, keeping the connection active.
  300. *
  301. * Returns
  302. * 0: success.
  303. * 1: data too long to fit in transmit buffer.
  304. * 2: received NACK on transmit of address.
  305. * 3: received NACK on transmit of data.
  306. * 4: other error.
  307. * 5: timeout
  308. */

  309. void endTransmission_stop(bool stop) {
  310.     bflb_i2c_disable(i2c0);
  311. }

  312. void endTransmission() {
  313.     bflb_i2c_disable(i2c0);

  314. }

  315. /*
  316. * Description
  317. * This function writes data from a peripheral device in response to a request from
  318. * a controller device, or queues bytes for transmission from a controller to
  319. * peripheral device (in-between calls to beginTransmission() and endTransmission()).
  320. * Syntax
  321. * Wire.write(value) Wire.write(string) Wire.write(data, length)
  322. * Parameters
  323. * value: a value to send as a single byte.
  324. * string: a string to send as a series of bytes.
  325. * data: an array of data to send as bytes.
  326. * length: the number of bytes to transmit.
  327. * Returns
  328. * The number of bytes written (reading this number is optional).
  329. */
  330. int write_char(unsigned char value) {
  331.     bflb_i2c_set_datalen(i2c0, 1);
  332.     bflb_i2c_write_bytes(i2c0, &value, 1,wire_timeout);
  333.   return 0;
  334. }
  335. int write_str(uint8_t *str) {
  336.     bflb_i2c_set_datalen(i2c0, strlen((const char*)str));
  337.     bflb_i2c_write_bytes(i2c0, str, strlen((const char*)str),wire_timeout);
  338.   return 0;
  339. }
  340. int write_len(uint8_t *str, int len) {
  341.     bflb_i2c_set_datalen(i2c0, len);
  342.     int ret = bflb_i2c_write_bytes(i2c0, str, len,wire_timeout);
  343.   return ret;
  344. }

  345. /*
  346. * Description
  347. * This function returns the number of bytes available for retrieval with read().
  348. * This function should be called on a controller device after a call to
  349. * requestFrom() or on a peripheral inside the onReceive() handler.
  350. * available() inherits from the Stream utility class.
  351. */

  352. int available() {
  353.     return available_count;
  354. }

  355. /*
  356. * Description
  357. * This function reads a byte that was transmitted from a peripheral device to
  358. * a controller device after a call to requestFrom() or was transmitted from a
  359. * controller device to a peripheral device. read() inherits from the Stream utility class.
  360. * Syntax
  361. * Wire.read()
  362. * Parameters
  363. * None.
  364. * Returns
  365. * The next byte received.
  366. */

  367. int readI2c() {
  368.     unsigned char ret;
  369.     if(available_count){
  370.         available_count--;
  371.         ret = rbuf[indexi2c];
  372.         indexi2c++;
  373.         return ret;
  374.     }
  375.     return 0;
  376. }

  377. /*
  378. * Description
  379. * This function modifies the clock frequency for I2C communication.
  380. * I2C peripheral devices have no minimum working clock frequency,
  381. * however 100KHz is usually the baseline.
  382. * Syntax
  383. * Wire.setClock(clockFrequency)
  384. * Parameters
  385. * clockFrequency: the value (in Hertz) of the desired communication clock.
  386. * Accepted values are 100000 (standard mode) and 400000 (fast mode).
  387. * Some processors also support 10000 (low speed mode), 1000000 (fast mode plus)
  388. * and 3400000 (high speed mode). Please refer to the specific processor documentation
  389. * to make sure the desired mode is supported.
  390. * Returns
  391. * None.
  392. */
  393. void setClock(int clockFrequency) {
  394.     bflb_i2c_deinit(i2c0);
  395.     bflb_i2c_init(i2c0, clockFrequency);
  396. }

  397. /*
  398. * Description
  399. * This function registers a function to be called when a peripheral device receives
  400. * a transmission from a controller device.
  401. * Syntax
  402. * Wire.onReceive(handler)
  403. * Parameters
  404. * handler: the function to be called when the peripheral device receives data;
  405. * this should take a single int parameter (the number of bytes read from the controller
  406. * device) and return nothing.
  407. * Returns
  408. * None.
  409. */
  410. void onReceive(void (*callback)(int)) {
  411.     //we not support slave mode yet
  412. }

  413. /*
  414. * Description
  415. * This function registers a function to be called when a controller device requests data from a peripheral device.
  416. * Syntax
  417. * Wire.onRequest(handler)
  418. * Parameters
  419. * handler: the function to be called, takes no parameters and returns nothing.
  420. * Returns
  421. * None.
  422. */
  423. void onRequest(void (*callback)()) {
  424.     //we not support slave mode yet
  425. }

  426. /*
  427. * Description
  428. * Sets the timeout for Wire transmissions in master mode.
  429. * Syntax
  430. * Wire.setWireTimeout(timeout, reset_on_timeout)
  431. * Wire.setWireTimeout()
  432. * Parameters
  433. * timeout a timeout: timeout in microseconds, if zero then timeout checking is disabled
  434. * reset_on_timeout: if true then Wire hardware will be automatically reset on timeout
  435. * When this function is called without parameters, a default timeout is configured that
  436. * should be sufficient to prevent lockups in a typical single-master configuration.
  437. * Returns
  438. * None.
  439. */
  440. void setWireTimeout(int timeout, bool reset_on_timeout) {
  441.     wire_timeout = timeout;
  442.     wire_timeout_flag = true;
  443. }

  444. /* Description
  445. * Clears the timeout flag.
  446. * Timeouts might not be enabled by default. See the documentation for Wire.setWireTimeout()
  447. * for more information on how to configure timeouts and how they work.
  448. * Syntax
  449. * Wire.clearTimeout()
  450. * Parameters
  451. * None.
  452. * Returns
  453. * bool: The current value of the flag
  454. */
  455. bool clearWireTimeoutFlag() {
  456.     wire_timeout_flag = false;
  457.   return true;
  458. }

  459. /*
  460. * Description
  461. * Checks whether a timeout has occured since the last time the flag was cleared.
  462. * This flag is set is set whenever a timeout occurs and cleared when Wire.clearWireTimeoutFlag()
  463. * is called, or when the timeout is changed using Wire.setWireTimeout().
  464. * Syntax
  465. * Wire.getWireTimeoutFlag()
  466. * Parameters
  467. * None.
  468. * Returns
  469. * bool: The current value of the flag
  470. */

  471. bool getWireTimeoutFlag() {
  472.   return wire_timeout_flag;
  473. }

复制代码
这里修改了I2C引脚;
GLB_GPIO_Type pinlist[] = {
GLB_GPIO_PIN_30,
GLB_GPIO_PIN_31
};
默认是GLB_GPIO_PIN_14、GLB_GPIO_PIN_15.



                               
登录/注册后可看大图


然后封装,XFS5152CE模块功能代码;

XFS.h

  1. #ifndef __XFS_H
  2. #define __XFS_H

  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <stdarg.h>
  6. #include <stddef.h>
  7. #include <string.h>
  8. #include <math.h>
  9. #include <stdint.h>        //Added for uint_t
  10. #include <stdio.h>
  11. #include "bflb_mtimer.h"

  12. struct XFS_Protocol_TypeDef
  13. {
  14.     uint8_t DataHead;
  15.     uint8_t Length_HH;
  16.     uint8_t Length_LL;
  17.     uint8_t Commond;
  18.     uint8_t EncodingFormat;
  19.     const char* Text;
  20. };
  21.    
  22. /*
  23.     *| 帧头(1Byte)| 数据区长度(2Byte)|           数据区(<4KByte)          |
  24.     *|            |  高字节 | 低字节 | 命令字 | 文本编码格式 | 待合成文本 |
  25.     *|    0xFD    |  0xHH   |  0xLL  |  0x01  |   0x00~0x03  |  ... ...   |
  26.     */

  27. typedef enum
  28. {
  29.     CMD_StartSynthesis = 0x01,//语音合成命令
  30.     CMD_StopSynthesis = 0x02,//停止合成命令,没有参数
  31.     CMD_PauseSynthesis = 0x03,//暂停合成命令,没有参数
  32.     CMD_RecoverySynthesis = 0x04,//恢复合成命令,没有参数
  33.     CMD_CheckChipStatus = 0x21,//芯片状态查询命令
  34.     CMD_PowerSavingMode = 0x88,//芯片进入省电模式
  35.     CMD_NormalMode = 0xFF//芯片从省电模式返回正常工作模式
  36. } CMD_Type;//命令字
  37. void StartSynthesis(const char* str);//开始合成
  38. // void StartSynthesis(String str);//开始合成

  39. bool IIC_WriteByte(uint8_t data);
  40. void IIC_WriteByteSize(uint8_t* buff, uint32_t size);
  41. void SendCommond(CMD_Type cmd);
  42. void StopSynthesis();//停止合成
  43. void PauseSynthesis();//暂停合成
  44. void RecoverySynthesis();//恢复合成

  45. typedef enum
  46. {
  47.     GB2312 = 0x00,
  48.     GBK = 0x01,
  49.     BIG5 = 0x02,
  50.     UNICODE = 0x03
  51. } EncodingFormat_Type;//文本的编码格式
  52. void SetEncodingFormat(EncodingFormat_Type encodingFormat);

  53. typedef enum
  54. {
  55.     ChipStatus_InitSuccessful = 0x4A,//初始化成功回传
  56.     ChipStatus_CorrectCommand = 0x41,//收到正确的命令帧回传
  57.     ChipStatus_ErrorCommand = 0x45,//收到不能识别命令帧回传
  58.     ChipStatus_Busy = 0x4E,//芯片忙碌状态回传
  59.     ChipStatus_Idle = 0x4F//芯片空闲状态回传
  60. } ChipStatus_Type;//芯片回传

  61. typedef enum
  62. {
  63.     Style_Single,//?为 0,一字一顿的风格
  64.     Style_Continue//?为 1,正常合成
  65. } Style_Type; //合成风格设置 [f?]
  66. void SetStyle(Style_Type style);

  67. typedef enum
  68. {
  69.     Language_Auto,//? 为 0,自动判断语种
  70.     Language_Chinese,//? 为 1,阿拉伯数字、度量单位、特殊符号等合成为中文
  71.     Language_English//? 为 2,阿拉伯数字、度量单位、特殊符号等合成为英文
  72. } Language_Type; //合成语种设置 [g?]
  73. void SetLanguage(Language_Type language);

  74. typedef enum
  75. {
  76.     Articulation_Auto,//? 为 0,自动判断单词发音方式
  77.     Articulation_Letter,//? 为 1,字母发音方式
  78.     Articulation_Word//? 为 2,单词发音方式
  79. } Articulation_Type; //设置单词的发音方式 [h?]
  80. void SetArticulation(Articulation_Type articulation);

  81. typedef enum
  82. {
  83.     Spell_Disable,//? 为 0,不识别汉语拼音
  84.     Spell_Enable//? 为 1,将“拼音+1 位数字(声调)”识别为汉语拼音,例如: hao3
  85. } Spell_Type; //设置对汉语拼音的识别 [i?]
  86. void SetSpell(Spell_Type spell);

  87. typedef enum
  88. {
  89.     Reader_XiaoYan = 3,//? 为 3,设置发音人为小燕(女声, 推荐发音人)
  90.     Reader_XuJiu = 51,//? 为 51,设置发音人为许久(男声, 推荐发音人)
  91.     Reader_XuDuo = 52,//? 为 52,设置发音人为许多(男声)
  92.     Reader_XiaoPing = 53,//? 为 53,设置发音人为小萍(女声)
  93.     Reader_DonaldDuck = 54,//? 为 54,设置发音人为唐老鸭(效果器)
  94.     Reader_XuXiaoBao = 55//? 为 55,设置发音人为许小宝(女童声)
  95. } Reader_Type;//选择发音人 [m?]
  96. void SetReader(Reader_Type reader);

  97. typedef enum
  98. {
  99.     NumberHandle_Auto,//? 为 0,自动判断
  100.     NumberHandle_Number,//? 为 1,数字作号码处理
  101.     NumberHandle_Value//? 为 2,数字作数值处理
  102. } NumberHandle_Type; //设置数字处理策略 [n?]
  103. void SetNumberHandle(NumberHandle_Type numberHandle);

  104. typedef enum
  105. {
  106.     ZeroPronunciation_Zero,//? 为 0,读成“zero
  107.     ZeroPronunciation_O//? 为 1,读成“欧”音
  108. } ZeroPronunciation_Type; //数字“0”在读 作英文、号码时 的读法 [o?]
  109. void SetZeroPronunciation(ZeroPronunciation_Type zeroPronunciation);


  110. typedef enum
  111. {
  112.     NamePronunciation_Auto,//? 为 0,自动判断姓氏读音
  113.     NamePronunciation_Constraint//? 为 1,强制使用姓氏读音规则
  114. } NamePronunciation_Type; //设置姓名读音 策略 [r?]
  115. void SetNamePronunciation(NamePronunciation_Type namePronunciation);

  116. void SetSpeed(int speed);//设置语速 [s?] ? 为语速值,取值:0~10
  117. void SetIntonation(int intonation);//设置语调 [t?] ? 为语调值,取值:0~10
  118. void SetVolume(int volume);//设置音量 [v?] ? 为音量值,取值:0~10

  119. typedef enum
  120. {
  121.     PromptTone_Disable,//? 为 0,不使用提示音
  122.     PromptTone_Enable//? 为 1,使用提示音
  123. } PromptTone_Type; //设置提示音处理策略 [x?]
  124. void SetPromptTone(PromptTone_Type promptTone);

  125. typedef enum
  126. {
  127.     OnePronunciation_Yao,//? 为 0,合成号码“1”时读成“幺
  128.     OnePronunciation_Yi//? 为 1,合成号码“1”时读成“一”
  129. } OnePronunciation_Type; //设置号码中“1”的读法 [y?]
  130. void SetOnePronunciation(OnePronunciation_Type onePronunciation);

  131. typedef enum
  132. {
  133.     Rhythm_Diasble,//? 为 0,“ *”和“#”读出符号
  134.     Rhythm_Enable//? 为 1,处理成韵律,“*”用于断词,“#”用于停顿
  135. } Rhythm_Type; //是否使用韵律 标记“*”和“#” [z?]
  136. void SetRhythm(Rhythm_Type rhythm);


  137. void SetRestoreDefault();//恢复默认的合成参数 [d] 所有设置(除发音人设置、语种设置外)恢复为默认值

  138. void XFS5152CE(uint8_t encodingFormat);
  139. void Begin(uint8_t addr);
  140. uint8_t GetChipStatus();
  141. void TextCtrl(char c, int d);

  142. #endif
复制代码

XFS.c
  1. #include "XFS.h"
  2. #include <Wire.h>
  3. #define DBG_TAG "MAIN"
  4. #include "log.h"

  5. #define XFS_DataHead (uint8_t)0xFD

  6. uint8_t I2C_Addr;
  7. uint8_t ChipStatus;
  8. struct XFS_Protocol_TypeDef DataPack;

  9. size_t foo( const char* restrict src, uint8_t* restrict dst, size_t dst_maxlen )
  10. {
  11.     size_t idx = 0;
  12.     for( ; src[idx] && dst_maxlen; ++idx )
  13.     {
  14.         if( idx%8 == 0 )
  15.             *dst = 0;
  16.         if( src[idx] != '0' )
  17.             *dst |= 1<<(7-idx%8);
  18.         if( idx%8 == 7 )
  19.             ++dst, --dst_maxlen;
  20.     }
  21.     return (idx+7)/8;
  22. }

  23. void XFS5152CE(uint8_t encodingFormat)
  24. {
  25.   DataPack.DataHead = XFS_DataHead;
  26.   DataPack.Length_HH = 0x00;
  27.   DataPack.Length_LL = 0x00;

  28.   DataPack.Commond = 0x00;
  29.   DataPack.EncodingFormat = encodingFormat;

  30.   ChipStatus = 0x00;
  31. }


  32. void Begin(uint8_t addr)
  33. {
  34.   I2C_Addr = addr;
  35.   XFS5152CE(GB2312);
  36.   begin();
  37. }

  38. uint8_t GetChipStatus()
  39. {
  40.   uint8_t AskState[4] = {0xFD,0x00,0x01,0x21};
  41.   beginTransmission(I2C_Addr);
  42.   write_len(AskState,4);
  43.   endTransmission();
  44.   bflb_mtimer_delay_ms(100);
  45.   requestFrom(I2C_Addr, 1);
  46.   while (available())
  47.   {
  48.     ChipStatus = readI2c();
  49.   }
  50.   
  51.   LOG_F("ChipStatus=%x\r\n", ChipStatus);
  52.   return ChipStatus;
  53. }


  54. bool IIC_WriteByte(uint8_t data)
  55. {
  56.   beginTransmission(I2C_Addr);
  57.   write_char(data);
  58.   endTransmission();
  59.   // if(endTransmission()!=0)            //发送结束信号
  60.   //  {
  61.   //         bflb_mtimer_delay_ms(10);
  62.   //         return false;
  63.   //   }
  64.     bflb_mtimer_delay_ms(10);
  65.     return true;  
  66. }

  67. void IIC_WriteBytes(uint8_t* buff, uint32_t size)
  68. {
  69.   for (uint32_t i = 0; i < size; i++)
  70.   {
  71.     IIC_WriteByte(buff[i]);
  72.   }
  73. }

  74. void StartSynthesis(const char* str)
  75. {
  76.   uint16_t size = strlen(str) + 2;
  77.   DataPack.Length_HH = highByte(size);
  78.   DataPack.Length_LL = lowByte(size);
  79.   DataPack.Commond = CMD_StartSynthesis;
  80.   DataPack.Text = str;

  81.   uint8_t dst[(strlen(DataPack.Text)-1+7)/8];
  82.   size_t len = foo(DataPack.Text, dst, sizeof(dst)/sizeof(*dst) );
  83.   IIC_WriteBytes((uint8_t*)&DataPack,5);
  84.   IIC_WriteBytes(DataPack.Text, strlen(str));
  85.   
  86. }


  87. // void StartSynthesis(String str)
  88. // {
  89. //   StartSynthesis((const char*)str.c_str());
  90. // }

  91. void SendCommond(CMD_Type cmd)
  92. {
  93.   DataPack.Length_HH = 0x00;
  94.   DataPack.Length_LL = 0x01;
  95.   DataPack.Commond = cmd;
  96.   
  97.   beginTransmission(I2C_Addr);
  98.   write_len((uint8_t*)&DataPack, 4);
  99.   endTransmission();
  100. }

  101. void StopSynthesis()
  102. {
  103.   SendCommond(CMD_StopSynthesis);
  104. }

  105. void PauseSynthesis()
  106. {
  107.   SendCommond(CMD_PauseSynthesis);
  108. }

  109. void RecoverySynthesis()
  110. {
  111.   SendCommond(CMD_RecoverySynthesis);
  112. }

  113. void TextCtrl(char c, int d)
  114. {
  115.   char str[10];
  116.   if (d != -1)
  117.     sprintf(str, "[%c%d]", c, d);
  118.   else
  119.     sprintf(str, "[%c]", c);
  120.   StartSynthesis(str);
  121. }

  122. void SetEncodingFormat(EncodingFormat_Type encodingFormat)
  123. {
  124.   DataPack.EncodingFormat = encodingFormat;
  125. }

  126. void SetStyle(Style_Type style)
  127. {
  128.   TextCtrl('f', style);
  129.   while(GetChipStatus() != ChipStatus_Idle)
  130.   {
  131.      bflb_mtimer_delay_ms(30);
  132.   }
  133. }

  134. void SetLanguage(Language_Type language)
  135. {
  136.   TextCtrl('g', language);
  137.   while(GetChipStatus() != ChipStatus_Idle)
  138.   {
  139.      bflb_mtimer_delay_ms(30);
  140.   }
  141. }

  142. void SetArticulation(Articulation_Type articulation)
  143. {
  144.   TextCtrl('h', articulation);
  145.   while(GetChipStatus() != ChipStatus_Idle)
  146.   {
  147.      bflb_mtimer_delay_ms(30);
  148.   }
  149. }

  150. void SetSpell(Spell_Type spell)
  151. {
  152.   TextCtrl('i', spell);
  153.   while(GetChipStatus() != ChipStatus_Idle)
  154.   {
  155.      bflb_mtimer_delay_ms(30);
  156.   }
  157. }

  158. void SetReader(Reader_Type reader)
  159. {
  160.   TextCtrl('m', reader);
  161.   while(GetChipStatus() != ChipStatus_Idle)
  162.   {
  163.      bflb_mtimer_delay_ms(30);
  164.   }
  165. }

  166. void SetNumberHandle(NumberHandle_Type numberHandle)
  167. {
  168.   TextCtrl('n', numberHandle);
  169.   while(GetChipStatus() != ChipStatus_Idle)
  170.   {
  171.      bflb_mtimer_delay_ms(30);
  172.   }
  173. }

  174. void SetZeroPronunciation(ZeroPronunciation_Type zeroPronunciation)
  175. {
  176.   TextCtrl('o', zeroPronunciation);
  177.   while(GetChipStatus() != ChipStatus_Idle)
  178.   {
  179.      bflb_mtimer_delay_ms(30);
  180.   }
  181. }


  182. void SetNamePronunciation(NamePronunciation_Type namePronunciation)
  183. {
  184.   TextCtrl('r', namePronunciation);
  185.   while(GetChipStatus() != ChipStatus_Idle)
  186.   {
  187.      bflb_mtimer_delay_ms(30);
  188.   }
  189. }

  190. void SetSpeed(int speed)
  191. {
  192.   // speed = constrain(speed, 0, 10);
  193.   TextCtrl('s', speed);
  194.   while(GetChipStatus() != ChipStatus_Idle)
  195.   {
  196.      bflb_mtimer_delay_ms(30);
  197.   }
  198. }

  199. void SetIntonation(int intonation)
  200. {
  201.   // intonation = constrain(intonation, 0, 10);
  202.   TextCtrl('t', intonation);
  203.   while(GetChipStatus() != ChipStatus_Idle)
  204.   {
  205.      bflb_mtimer_delay_ms(30);
  206.   }
  207. }

  208. void SetVolume(int volume)
  209. {
  210.   // volume = constrain(volume, 0, 10);
  211.   TextCtrl('v', volume);
  212.   while(GetChipStatus() != ChipStatus_Idle)
  213.   {
  214.      bflb_mtimer_delay_ms(30);
  215.   }
  216. }

  217. void SetPromptTone(PromptTone_Type promptTone)
  218. {
  219.   TextCtrl('x', promptTone);
  220.   while(GetChipStatus() != ChipStatus_Idle)
  221.   {
  222.      bflb_mtimer_delay_ms(30);
  223.   }
  224. }

  225. void SetOnePronunciation(OnePronunciation_Type onePronunciation)
  226. {
  227.   TextCtrl('y', onePronunciation);
  228.   while(GetChipStatus() != ChipStatus_Idle)
  229.   {
  230.      bflb_mtimer_delay_ms(30);
  231.   }
  232. }

  233. void SetRhythm(Rhythm_Type rhythm)
  234. {
  235.   TextCtrl('z', rhythm);
  236.   while(GetChipStatus() != ChipStatus_Idle)
  237.   {
  238.      bflb_mtimer_delay_ms(30);
  239.   }
  240. }


  241. void SetRestoreDefault()
  242. {
  243.   TextCtrl('d', -1);
  244.   while(GetChipStatus() != ChipStatus_Idle)
  245.   {
  246.      bflb_mtimer_delay_ms(30);
  247.   }
  248. }
复制代码

                               
登录/注册后可看大图

语音播报内容 文件头 speak.h,
该文件是为了方式播报内容乱码错乱。文件需要保存为 ANSI;
  1. char* hello[] = {"主人", "出门记得带手机和钥匙"};
复制代码


                               
登录/注册后可看大图
主程序代码 :main.c
  1. #include "bflb_mtimer.h"
  2. #include "board.h"
  3. #include "bflb_gpio.h"
  4. #include "Wire.h"
  5. #include "XFS.h"
  6. #include "speak.h"
  7. #define DBG_TAG "MAIN"
  8. #include "log.h"

  9. /*超时设置,示例为30S*/
  10. static uint32_t LastSpeakTime = 0;
  11. #define SpeakTimeOut 10000


  12. /**
  13.     @brief  初始化语音合成
  14.     @param  无
  15.     @retval 无
  16. */

  17. uint8_t n = 1;
  18. static void XFS_Init()
  19. {
  20.     Begin(0x30);//设备i2c地址,地址为0x50
  21.     bflb_mtimer_delay_ms(n);
  22.     SetReader(Reader_XuXiaoBao);        //设置发音人
  23.     bflb_mtimer_delay_ms(n);
  24.     SetEncodingFormat(GB2312);           //文本的编码格式
  25.     bflb_mtimer_delay_ms(n);
  26.     SetLanguage(Language_Auto);                 //语种判断
  27.     bflb_mtimer_delay_ms(n);
  28.     SetStyle(Style_Continue);            //合成风格设置
  29.     bflb_mtimer_delay_ms(n);
  30.     SetArticulation(Articulation_Letter);  //设置单词的发音方式
  31.     bflb_mtimer_delay_ms(n);
  32.     SetSpeed(6);                         //设置语速1~10
  33.     bflb_mtimer_delay_ms(n);
  34.     SetIntonation(5);                    //设置语调1~10
  35.     bflb_mtimer_delay_ms(n);
  36.     SetVolume(10);                        //设置音量1~10
  37.     bflb_mtimer_delay_ms(n);
  38. }

  39. unsigned char result = 0xFF;

  40. struct bflb_device_s *gpio;

  41. void gpio_isr() {
  42.     bool isH = bflb_gpio_read(gpio, GPIO_PIN_13);
  43.     if(isH){
  44.         bflb_gpio_set(gpio, GPIO_PIN_12);
  45.         if(GetChipStatus() == ChipStatus_Idle){
  46.             StartSynthesis(hello[1]);
  47.         }
  48.         bflb_mtimer_delay_ms(3000);
  49.     }else{
  50.         bflb_gpio_reset(gpio, GPIO_PIN_12);
  51.     }
  52. }

  53. int main(void)
  54. {
  55.     board_init();

  56.     gpio = bflb_device_get_by_name("gpio");

  57.     bflb_gpio_init(gpio, GPIO_PIN_12, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);

  58.     bflb_gpio_int_init(gpio, GPIO_PIN_13, GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL);
  59.     bflb_gpio_int_mask(gpio, GPIO_PIN_0, false);
  60.     bflb_irq_attach(gpio->irq_num, gpio_isr, gpio);
  61.     bflb_irq_enable(gpio->irq_num);
  62.    
  63.     XFS_Init();
  64.     StartSynthesis(hello[0]);
  65.     while(GetChipStatus() != ChipStatus_Idle)
  66.     {
  67.         bflb_mtimer_delay_ms(30);
  68.     }

  69.    
  70.     // SetReader(Reader_XuJiu);        //设置发音人;   
  71.     StartSynthesis(hello[1]);
  72.     while(GetChipStatus() != ChipStatus_Idle)
  73.     {
  74.         bflb_mtimer_delay_ms(30);
  75.     }
  76.    
  77.     while (1) {
  78.         bflb_mtimer_delay_ms(500);
  79.     }
  80. }
复制代码


                               
登录/注册后可看大图

修改CMakeLists.txt
  1. cmake_minimum_required(VERSION 3.15)

  2. include(proj.conf)

  3. find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE})
  4. # User
  5. <font color="#ff0000">sdk_add_compile_definitions(-DCONFIG_CLI_CMD_ENABLE)</font>
  6. #sdk_add_compile_definitions(-DBL616_DHCP_DEBUG)

  7. <font color="#ff0000">target_sources(app PRIVATE
  8.                    Wire.c
  9.                    XFS.c)</font>

  10. sdk_add_include_directories(.)

  11. sdk_set_main_file(main.c)

  12. project(helloworld)
复制代码

相关功能模块封装完成,下一步硬件连线。
092423xvffcw0wc8f8gvzo.png
Ai-M61-32S GPIO 接口定义。
Ai-M61-32S XFS5152CE
3.3v VCC
GLB_GPIO_PIN_30 SCL
GLB_GPIO_PIN_31 SDA
GND GND
实物图:
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=1530779914881216466&skey=@crypt_3423.jpg
连接部分:
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=9219082090240887084&skey=@crypt_3423.jpg
红外感应:
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=7578602263740674244&skey=@crypt_3423.jpg
完整 组件结构:
_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=6818250206480683564&skey=@crypt_3423.jpg

_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=1732363731106040783&skey=@crypt_3423.jpg
到这里基于 Ai-M61-32S “出门提醒设备 ”软硬件已完成。下一步就是外壳了。

_cgi-bin_mmwebwx-bin_webwxgetmsgimg__&MsgID=5685162183093430268&skey=@crypt_3423.jpg

本帖被以下淘专辑推荐:

回复

使用道具 举报

WT_0213 | 2023-11-29 13:00:41 | 显示全部楼层
本帖最后由 WT_0213 于 2023-11-29 13:49 编辑

目前遇到的问题是,3.3V电压有点低,虽然能驱动XFS5152CE模块,不过声音不太正常。5V供电被红外占用了。暂时先这样。
视频地址
【总是人生愁】第一次在B站发视频,求关注!】 https://www.bilibili.com/video/B ... are_source=copy_web

回复 支持 反对

使用道具 举报

干簧管 | 2023-11-29 13:20:52 | 显示全部楼层
用一分二的杜邦线接出5V
回复 支持 反对

使用道具 举报

qwe2079282957 | 2023-11-29 14:00:41 | 显示全部楼层
干簧管 发表于 2023-11-29 13:20
用一分二的杜邦线接出5V

直接剥皮接上
回复 支持 反对

使用道具 举报

方源 | 2023-11-29 16:13:29 | 显示全部楼层
回复

使用道具 举报

lazy | 2023-11-30 09:37:19 | 显示全部楼层
有点意思
回复

使用道具 举报

lazy | 2023-11-30 09:47:45 | 显示全部楼层
很不错
回复

使用道具 举报

干簧管 | 2023-12-4 14:33:31 | 显示全部楼层
非常不错
回复

使用道具 举报

WT_0213 | 2023-12-4 14:36:04 | 显示全部楼层
回复 支持 反对

使用道具 举报

心云 | 2023-12-31 12:24:02 | 显示全部楼层
强👍
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则