0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

使用Ai-M61-32S制作出門(mén)提醒設(shè)備

安信可科技 ? 來(lái)源:安信可科技 ? 2025-01-21 11:40 ? 次閱讀

一、簡(jiǎn)介

二、紅外感應(yīng)篇

三、XFS5152CE語(yǔ)音合成篇

四、外殼篇

01

簡(jiǎn)介

本項(xiàng)目設(shè)計(jì)初衷是為了提醒自己出門(mén)不要忘記帶東西——“身”、“手”、“鑰”、“錢(qián)” (身份證,手機(jī),鑰匙,錢(qián)包)等。不過(guò)現(xiàn)在好像都在線(xiàn)支付了,錢(qián)包都不帶了。筆者覺(jué)得后期可以改造成播報(bào)天氣等,提醒帶傘等等。

項(xiàng)目最初設(shè)計(jì)是使用安信可24G雷達(dá)傳感器模塊人體微動(dòng)感應(yīng)檢測(cè)模組“Rd-03” 來(lái)做。由于手上剛好有一個(gè)"HC-SR501 紅外感應(yīng)電子模塊傳感器" 模塊,所以這次先用這個(gè)試試。

02

紅外感應(yīng)篇

硬件相關(guān)

紅外感應(yīng)模塊:HC-SR501

語(yǔ)音合成播報(bào)模塊:XFS5152

開(kāi)發(fā)板:Ai-M61-32S

GPIO 全稱(chēng) General Purpose Input Output(通用輸入 / 輸出),博流系列芯片的 GPIO 外設(shè)主要有以下功能。

普通輸入輸出帶上下拉

復(fù)用功能帶上下拉

模擬功能

外部中斷(上升沿、下降沿、高電平、低電平)

硬件消抖

驅(qū)動(dòng)能力控制

bl mcu sdk 的引腳配置方式分為兩種。

GPIO 復(fù)用功能通過(guò)專(zhuān)門(mén)的 pinmux table ,用戶(hù)只需要修改 table 中的相關(guān)引腳的功能,程序會(huì)自動(dòng)配置這些引腳。pinmux table 位于 bsp/board/xxx_board 目錄下 pinmux_config.h 文件。

通過(guò)標(biāo)準(zhǔn)的 GPIO 設(shè)備接口配置引腳,缺點(diǎn)是只能配置普通的輸入輸出和中斷功能,復(fù)用功能建議還是使用 table 進(jìn)行配置。

PIR 傳感器如何工作?

**絕對(duì)零 (0 開(kāi)爾文/-273.5 *C) 以上的每個(gè)物體都會(huì)以紅外輻射的形式發(fā)出熱能。物體越熱,它發(fā)出的輻射就越多。輻射對(duì)人眼是不可見(jiàn)的,PIR傳感器專(zhuān)門(mén)設(shè)計(jì)用于檢測(cè)這種輻射水平。

PIR 傳感器由兩個(gè)主要部分組成,可以看到的熱釋電傳感器是圓形的,中間有一個(gè)矩形晶體。

一種稱(chēng)為菲涅爾透鏡的特殊透鏡,可將紅外信號(hào)聚焦到熱釋電傳感器上。

熱釋電傳感器熱釋電傳感器由一個(gè)窗口和兩個(gè)由涂層硅制成的矩形槽組成,它允許紅外線(xiàn)通過(guò)并阻擋任何其他輻射。傳感器的設(shè)計(jì)使得一個(gè)可以抵消另一個(gè),這樣傳感器就可以抵消環(huán)境輻射并檢測(cè)輻射模式的變化。

當(dāng)沒(méi)有檢測(cè)到運(yùn)動(dòng)時(shí),產(chǎn)生的輸出信號(hào)為零,因?yàn)閭鞲衅髡跈z測(cè)背景輻射。但是,當(dāng)傳感器的任何一半截獲運(yùn)動(dòng)時(shí),都會(huì)導(dǎo)致傳感器兩部分之間的電壓電平發(fā)生變化,這就是檢測(cè)運(yùn)動(dòng)的方式。

菲涅耳透鏡

菲涅耳透鏡由一系列刻在塑料上的同心凹槽組成。這些輪廓充當(dāng)單獨(dú)的折射表面,在焦點(diǎn)處聚集平行光線(xiàn)。因此,菲涅耳透鏡能夠像傳統(tǒng)光學(xué)透鏡一樣聚焦光線(xiàn)。

實(shí)際上,為了增加 PIR 傳感器的范圍和視野,透鏡被分成幾個(gè)面部分,每個(gè)部分都是一個(gè)單獨(dú)的菲涅爾透鏡。

HC-SR501 PIR 運(yùn)動(dòng)傳感器模塊引出線(xiàn)

HC-SR501 模塊具有三個(gè)引腳。模塊絲印被菲涅耳透鏡遮擋,請(qǐng)參考下面給出的引腳排列。施加 5V – 12V 電源和接地,傳感器輸出在檢測(cè)到運(yùn)動(dòng)時(shí)變?yōu)楦唠娖?,在空閑時(shí)變?yōu)榈碗娖剑ㄎ礄z測(cè)到運(yùn)動(dòng))。

觸發(fā)器選擇跳線(xiàn)

有兩種觸發(fā)模式?jīng)Q定傳感器在檢測(cè)到運(yùn)動(dòng)時(shí)如何反應(yīng)。

單觸發(fā)模式:持續(xù)運(yùn)動(dòng)將導(dǎo)致單觸發(fā)。

多重觸發(fā)模式:不斷的運(yùn)動(dòng)會(huì)引起一系列的觸發(fā)。

L - 在此設(shè)置中,傳感器將處于單觸發(fā)模式,在此模式下,當(dāng)檢測(cè)到運(yùn)動(dòng)時(shí)輸出變高。并在延時(shí)電位器設(shè)定的一定時(shí)間內(nèi)保持高電平。任何其他類(lèi)型的檢測(cè)都會(huì)被阻止,直到輸出變低。

H - 選擇這些設(shè)置將設(shè)置多重觸發(fā)模式。在這種模式下,當(dāng)檢測(cè)到運(yùn)動(dòng)時(shí)輸出變高,高電平周期由設(shè)置的電位器決定。但與單觸發(fā)模式不同的是,進(jìn)一步檢測(cè)不會(huì)被阻止并且可以連續(xù)觸發(fā),當(dāng)未檢測(cè)到移動(dòng)時(shí),引腳變?yōu)榈碗娖健?/p>

靈敏度調(diào)整

PIR 傳感器背面有一個(gè)電位器,用于調(diào)節(jié)靈敏度。在電位器的幫助下,可以調(diào)整設(shè)備的靈敏度。順時(shí)針旋轉(zhuǎn)電位器會(huì)增加靈敏度,逆時(shí)針旋轉(zhuǎn)電位器會(huì)降低靈敏度。

延時(shí)調(diào)整

傳感器背面的另一個(gè)鍋設(shè)置輸出將保持高電平的時(shí)間以及在檢測(cè)到運(yùn)動(dòng)后順時(shí)針轉(zhuǎn)動(dòng)鍋會(huì)增加延遲,逆時(shí)針轉(zhuǎn)動(dòng)鍋會(huì)減少延遲。

3.3V 穩(wěn)壓器

該模塊帶有一個(gè) 3.3V 穩(wěn)壓器,因此它可以由 4.5V 至 12V 電源供電。雖然 5V 是常用的。

保護(hù)二極管

該模塊帶有一個(gè)保護(hù)二極管,用于保護(hù)二極管免受反向電壓和電流的影響。

HC-SR501 PIR 傳感器模塊故障排除

PIR 傳感器無(wú)法正常工作可能有多種原因。需要通過(guò)一些測(cè)試來(lái)找出問(wèn)題的根本原因。

傳感器的工作電壓為 4.8V 至 20V,因此無(wú)法使用 3.3V 為傳感器供電。

在某些情況下會(huì)看到鏡頭頂部積聚了灰塵,因此 PIR 傳感器可能會(huì)停止工作。

如果上述方法均無(wú)效,請(qǐng)嘗試旋轉(zhuǎn)電位器。如果將電位計(jì)的靈敏度設(shè)置為最低,那么這可能是傳感器不工作的原因。

在測(cè)試了所有方法后,如果傳感器不工作,那么您可以確定您手中的傳感器有故障。

部分代碼

#include "bflb\_mtimer.h"
#include "board.h"
#include "bflb\_gpio.h"
#include "locale.h"


#define DBG\_TAG "MAIN"
#include "log.h"


struct bflb\_device\_s *gpio;


int main(void)
{
board\_init();


gpio = bflb\_device\_get\_by\_name("gpio");
bflb\_gpio\_init(gpio, GPIO\_PIN\_13, GPIO\_INPUT | GPIO\_PULLDOWN | GPIO\_SMT\_EN | GPIO\_DRV\_0);
bflb\_gpio\_init(gpio, GPIO\_PIN\_12, GPIO\_OUTPUT | GPIO\_PULLUP | GPIO\_SMT\_EN | GPIO\_DRV\_0);
while (1) {
bool isH = bflb\_gpio\_read(gpio, GPIO\_PIN\_13);
if(isH){
bflb\_gpio\_set(gpio, GPIO\_PIN\_12);
}else{
bflb\_gpio\_reset(gpio, GPIO\_PIN\_12);
}
LOG\_F("是否有人=%d\r\n", isH);
bflb\_mtimer\_delay\_ms(500);
}
}

Step1:構(gòu)建項(xiàng)目并實(shí)現(xiàn) Ai-M61-32S 與 人體紅外感應(yīng)模塊 HC-SR501 連接,并獲取狀態(tài)值。

默認(rèn)燈光是關(guān)閉的:

15ad5ba6-d718-11ef-9310-92fbcf53809c.jpg

檢測(cè)有人經(jīng)過(guò)時(shí),紅燈亮起。

15b7d342-d718-11ef-9310-92fbcf53809c.jpg

03

XFS5152CE語(yǔ)音合成篇

15c6769a-d718-11ef-9310-92fbcf53809c.png

TTS 語(yǔ)音模塊:XFS5152CE 語(yǔ)音合成模塊

TTS 是 Text To Speech 的縮寫(xiě),即“從文本到語(yǔ)音”,是人機(jī)對(duì)話(huà)的一部分,讓機(jī)器能夠說(shuō)話(huà)。

語(yǔ)音播報(bào)功能的實(shí)現(xiàn)方式* TTS 語(yǔ)音模塊,比如 XFS5152、SYN6288 等

ISD4000 系列語(yǔ)音錄放芯片分段輸出

可以按鍵、UART 控制的 mp3 解碼芯片模塊

OTP(One Time Programable)語(yǔ)音芯片[定制]

其中 TTS 語(yǔ)音模塊使用起來(lái)最方便靈活,OTP 語(yǔ)音芯片最簡(jiǎn)單。

由于項(xiàng)目使用的是 XFS5152CE,所以簡(jiǎn)單介紹一下科大訊飛的 XFS5152CE 語(yǔ)音合成模塊。

性能描述

1 采用 XFS5152CE 語(yǔ)音合成芯片,支持任意中文文本、英文文本合成及中英混讀。

2 支持文本控制標(biāo)記設(shè)置,使用便捷,同時(shí)提升了文本處理的正確率。

3具有文本智能分析處理功能,對(duì)常見(jiàn)的數(shù)字、號(hào)碼、時(shí)間、日期、度量衡符號(hào)等能正確的識(shí)別和處理。

4.具有很強(qiáng)的多音字和中文姓氏處理能力。

5.支持內(nèi)置多款播音人聲可供選擇。

6.支持 10 級(jí)語(yǔ)速調(diào)節(jié)。

7.支持 10 級(jí)音調(diào)調(diào)節(jié)。

8.支持 10 級(jí)音量調(diào)節(jié)。

9.支持 GB2312、GBK、BIG5 和 UNICODE 四種編碼方式。

10.每次合成的文本量多達(dá) 4K 字節(jié)。

11.集成 80 種常用提示音效,適用于不同場(chǎng)合的信息提示、鈴聲、警報(bào)

等功能。

12.支持多種控制命令,如合成文本、停止合成、狀態(tài)查詢(xún)等。

13.板載揚(yáng)聲器。

14.支持三種連接方式:杜邦線(xiàn)接口、鱷魚(yú)夾接口、PH2.0 防呆接口。

15.通信方式:IIC 通信。

16.12C 地址:0x50[新版本 0x30]。

由于協(xié)議使用的是 I2C,為了方便使用封裝 I2C 功能。

Wire.h

#pragma once


// #include "bouffalo\_sdk.h"
#include "bflb\_gpio.h"
#include "bl616\_gpio.h"
#include "bl616\_glb.h"
#include "bl616\_glb\_gpio.h"
#include "../../drivers/lhal/include/hardware/i2c\_reg.h"
#include "bflb\_i2c.h"
#define lowByte(w) ((uint8\_t) ((w) & 0xff))
#define highByte(w) ((uint8\_t) ((w) >> 8))


bool getWireTimeoutFlag();
bool clearWireTimeoutFlag();
void setWireTimeout(int timeout, bool reset\_on\_timeout);
void onRequest(void (*callback)());
void onReceive(void (*callback)(int));
void setClock(int clockFrequency);
int readI2c();
int available();
int write\_len(uint8_t *str, int len);
int write\_str(uint8_t *str);
int write\_char(unsigned char value);
void endTransmission\_stop(bool stop);
void endTransmission();
void beginTransmission(unsigned char addr);
int requestFrom\_stop(unsigned char addr, int quantity, bool stop);
int requestFrom(unsigned char addr, int quantity);
void end();
void begin\_addr(unsigned char addr);
void begin();

其中

#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))

這是 Arduino 中的方法,主要是獲取高位和低位數(shù)據(jù)

Wire.c

#include "Wire.h"


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






struct bflb_device_s *i2c0;
uint8_t rbuf[128];
int available_count;
int indexi2c;
int wire_timeout;
bool wire_timeout_flag;


void board_i2c_pinmux_init(void)
{
    GLB_GPIO_Type pinlist[] = {
        GLB_GPIO_PIN_30,
        GLB_GPIO_PIN_31
    };
    GLB_GPIO_Func_Init(GPIO_FUN_I2C0, pinlist, 2);
}


bool bflb_i2c_isend(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_INT_STS_OFFSET);


    if (regval & I2C_END_INT) {
        return true;
    }


    return false;
}


bool bflb_i2c_isnak(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_INT_STS_OFFSET);


    if (regval & I2C_NAK_INT) {
        return true;
    }


    return false;
}


bool bflb_i2c_isbusy(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_BUS_BUSY_OFFSET);


    if (regval & I2C_STS_I2C_BUS_BUSY) {
        return true;
    }


    return false;
}


void bflb_i2c_enable(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
    regval |= I2C_CR_I2C_M_EN;
    putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
}


bool bflb_i2c_isenable(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
    if (regval & I2C_CR_I2C_M_EN) {
        return true;
    }


    return false;
}


void bflb_i2c_disable(struct bflb_device_s *dev)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
    regval &= ~I2C_CR_I2C_M_EN;
    putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
    /* Clear I2C fifo */
    regval = getreg32(reg_base + I2C_FIFO_CONFIG_0_OFFSET);
    regval |= I2C_TX_FIFO_CLR;
    regval |= I2C_RX_FIFO_CLR;
    putreg32(regval, reg_base + I2C_FIFO_CONFIG_0_OFFSET);
    /* Clear I2C interrupt status */
    regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
    regval |= I2C_CR_I2C_END_CLR;
    regval |= I2C_CR_I2C_NAK_CLR;
    regval |= I2C_CR_I2C_ARB_CLR;
    putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
}




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


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);


    if (subaddr_size > 0) {
        regval |= I2C_CR_I2C_SUB_ADDR_EN;
        regval &= ~I2C_CR_I2C_SUB_ADDR_BC_MASK;
        regval |= ((subaddr_size - 1) << I2C_CR_I2C_SUB_ADDR_BC_SHIFT);
    } else {
        regval &= ~I2C_CR_I2C_SUB_ADDR_EN;
    }


    regval &= ~I2C_CR_I2C_SLV_ADDR_MASK;
    regval |= (slaveaddr << I2C_CR_I2C_SLV_ADDR_SHIFT);
#if !defined(BL602) && !defined(BL702)
    if (is_addr_10bit) {
        regval |= I2C_CR_I2C_10B_ADDR_EN;
    } else {
        regval &= ~I2C_CR_I2C_10B_ADDR_EN;
    }
#endif
    putreg32(subaddr, reg_base + I2C_SUB_ADDR_OFFSET);
    putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
}


void bflb_i2c_set_datalen(struct bflb_device_s *dev, uint16_t data_len)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
    regval &= ~I2C_CR_I2C_PKT_LEN_MASK;
    regval |= ((data_len - 1) << I2C_CR_I2C_PKT_LEN_SHIFT) & I2C_CR_I2C_PKT_LEN_MASK;
    putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
}




void bflb_i2c_set_dir(struct bflb_device_s *dev, bool is_in)
{
    uint32_t regval;
    uint32_t reg_base;


    reg_base = dev->reg_base;


    regval = getreg32(reg_base + I2C_CONFIG_OFFSET);


    if (is_in) {
        regval |= I2C_CR_I2C_PKT_DIR;
    } else {
        regval &= ~I2C_CR_I2C_PKT_DIR;
    }
    putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
}




int bflb_i2c_write_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len, uint32_t timeout)
{
    uint32_t reg_base;
    uint32_t temp = 0;
    uint8_t *tmp_buf;
    uint64_t start_time;


    reg_base = dev->reg_base;
    tmp_buf = data;
    while (len >= 4) {
        for (uint8_t i = 0; i < 4; i++) {
            temp += (tmp_buf[i] << ((i % 4) * 8));
        }
        tmp_buf += 4;
        len -= 4;
        start_time = bflb_mtimer_get_time_ms();
        while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
            if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
                return -ETIMEDOUT;
            }
        }
        putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
        if (!bflb_i2c_isenable(dev)) {
            bflb_i2c_enable(dev);
        }
        temp = 0;
    }


    if (len > 0) {
        for (uint8_t i = 0; i < len; i++) {
            temp += (tmp_buf[i] << ((i % 4) * 8));
        }
        start_time = bflb_mtimer_get_time_ms();
        while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
            if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
                return -ETIMEDOUT;
            }
        }
        putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
        if (!bflb_i2c_isenable(dev)) {
            bflb_i2c_enable(dev);
        }
    }


    start_time = bflb_mtimer_get_time_ms();
    while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev) || bflb_i2c_isnak(dev)) {
        if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
            return -ETIMEDOUT;
        }
    }
    bflb_i2c_disable(dev);


    return 0;
}




int bflb_i2c_read_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len, uint32_t timeout)
{
    uint32_t reg_base;
    uint32_t temp = 0;
    uint8_t *tmp_buf;
    uint64_t start_time;


    reg_base = dev->reg_base;
    tmp_buf = data;


    bflb_i2c_enable(dev);


    while (len >= 4) {
        start_time = bflb_mtimer_get_time_ms();
        while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
            if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
                return -ETIMEDOUT;
            }
        }
        temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);
        PUT_UINT32_LE(tmp_buf, temp);
        tmp_buf += 4;
        len -= 4;
    }


    if (len > 0) {
        start_time = bflb_mtimer_get_time_ms();
        while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
            if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
                return -ETIMEDOUT;
            }
        }
        temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);


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


    start_time = bflb_mtimer_get_time_ms();
    while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev)) {
        if ((bflb_mtimer_get_time_ms() - start_time) > timeout) {
            return -ETIMEDOUT;
        }
    }
    bflb_i2c_disable(dev);


    return 0;
}






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


void begin() {
    wire_timeout = 100;
    wire_timeout_flag = false;
    board_i2c_pinmux_init();
    i2c0 = bflb_device_get_by_name("i2c0");
    bflb_i2c_init(i2c0, 50000);
}


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


int requestFrom_stop(unsigned char addr, int quantity, bool stop) {
    indexi2c = 0;
    bflb_i2c_disable(i2c0);
    bflb_i2c_enable(i2c0);
    bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
    bflb_i2c_set_datalen(i2c0,quantity);
    bflb_i2c_set_dir(i2c0, 1);
    bflb_i2c_read_bytes(i2c0, rbuf,quantity,wire_timeout);
    available_count = quantity;
    if(true == stop){
        bflb_i2c_disable(i2c0);
    }
    return 0;
}


int requestFrom(unsigned char addr, int quantity) {
    indexi2c = 0;
    bflb_i2c_disable(i2c0);
    bflb_i2c_enable(i2c0);
    bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
    bflb_i2c_set_datalen(i2c0,quantity);
    bflb_i2c_set_dir(i2c0, 1);
    bflb_i2c_read_bytes(i2c0, rbuf,quantity,wire_timeout);
    available_count = quantity;
    return 0;
}


/*
 * address: the 7-bit address of the device to transmit to.
 */
void beginTransmission(unsigned char addr) {
    //bflb_i2c_enable(i2c0);
    bflb_i2c_addr_config(i2c0, addr, 0, 0, false);
    bflb_i2c_set_dir(i2c0, 0);
}


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


void endTransmission_stop(bool stop) {
    bflb_i2c_disable(i2c0);
}


void endTransmission() {
    bflb_i2c_disable(i2c0);


}


/*
 * Description
 * This function writes data from a peripheral device in response to a request from
 * a controller device, or queues bytes for transmission from a controller to
 * peripheral device (in-between calls to beginTransmission() and endTransmission()).
 * Syntax
 * Wire.write(value) Wire.write(string) Wire.write(data, length)
 * Parameters
 * value: a value to send as a single byte.
 * string: a string to send as a series of bytes.
 * data: an array of data to send as bytes.
 * length: the number of bytes to transmit.
 * Returns
 * The number of bytes written (reading this number is optional).
 */
int write_char(unsigned char value) {
    bflb_i2c_set_datalen(i2c0, 1);
    bflb_i2c_write_bytes(i2c0, &value, 1,wire_timeout);
  return 0;
}
int write_str(uint8_t *str) {
    bflb_i2c_set_datalen(i2c0, strlen((const char*)str));
    bflb_i2c_write_bytes(i2c0, str, strlen((const char*)str),wire_timeout);
  return 0;
}
int write_len(uint8_t *str, int len) {
    bflb_i2c_set_datalen(i2c0, len);
    int ret = bflb_i2c_write_bytes(i2c0, str, len,wire_timeout);
  return ret;
}


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


int available() {
    return available_count;
}


/*
 * Description
 * This function reads a byte that was transmitted from a peripheral device to
 * a controller device after a call to requestFrom() or was transmitted from a
 * controller device to a peripheral device. read() inherits from the Stream utility class.
 * Syntax
 * Wire.read()
 * Parameters
 * None.
 * Returns
 * The next byte received.
 */


int readI2c() {
    unsigned char ret;
    if(available_count){
        available_count--;
        ret = rbuf[indexi2c];
        indexi2c++;
        return ret;
    }
    return 0;
}


/*
 * Description
 * This function modifies the clock frequency for I2C communication.
 * I2C peripheral devices have no minimum working clock frequency,
 * however 100KHz is usually the baseline.
 * Syntax
 * Wire.setClock(clockFrequency)
 * Parameters
 * clockFrequency: the value (in Hertz) of the desired communication clock.
 * Accepted values are 100000 (standard mode) and 400000 (fast mode).
 * Some processors also support 10000 (low speed mode), 1000000 (fast mode plus)
 * and 3400000 (high speed mode). Please refer to the specific processor documentation
 * to make sure the desired mode is supported.
 * Returns
 * None.
 */
void setClock(int clockFrequency) {
    bflb_i2c_deinit(i2c0);
    bflb_i2c_init(i2c0, clockFrequency);
}


/*
 * Description
 * This function registers a function to be called when a peripheral device receives
 * a transmission from a controller device.
 * Syntax
 * Wire.onReceive(handler)
 * Parameters
 * handler: the function to be called when the peripheral device receives data;
 * this should take a single int parameter (the number of bytes read from the controller
 * device) and return nothing.
 * Returns
 * None.
 */
void onReceive(void (*callback)(int)) {
    //we not support slave mode yet
}


/*
 * Description
 * This function registers a function to be called when a controller device requests data from a peripheral device.
 * Syntax
 * Wire.onRequest(handler)
 * Parameters
 * handler: the function to be called, takes no parameters and returns nothing.
 * Returns
 * None.
 */
void onRequest(void (*callback)()) {
    //we not support slave mode yet
}


/*
 * Description
 * Sets the timeout for Wire transmissions in master mode.
 * Syntax
 * Wire.setWireTimeout(timeout, reset_on_timeout)
 * Wire.setWireTimeout()
 * Parameters
 * timeout a timeout: timeout in microseconds, if zero then timeout checking is disabled
 * reset_on_timeout: if true then Wire hardware will be automatically reset on timeout
 * When this function is called without parameters, a default timeout is configured that
 * should be sufficient to prevent lockups in a typical single-master configuration.
 * Returns
 * None.
 */
void setWireTimeout(int timeout, bool reset_on_timeout) {
    wire_timeout = timeout;
    wire_timeout_flag = true;
}


/* Description
 * Clears the timeout flag.
 * Timeouts might not be enabled by default. See the documentation for Wire.setWireTimeout()
 * for more information on how to configure timeouts and how they work.
 * Syntax
 * Wire.clearTimeout()
 * Parameters
 * None.
 * Returns
 * bool: The current value of the flag
 */
bool clearWireTimeoutFlag() {
    wire_timeout_flag = false;
  return true;
}


/*
 * Description
 * Checks whether a timeout has occured since the last time the flag was cleared.
 * This flag is set is set whenever a timeout occurs and cleared when Wire.clearWireTimeoutFlag()
 * is called, or when the timeout is changed using Wire.setWireTimeout().
 * Syntax
 * Wire.getWireTimeoutFlag()
 * Parameters
 * None.
 * Returns
 * bool: The current value of the flag
 */


bool getWireTimeoutFlag() {
  return wire_timeout_flag;
}



這里修改了 I2C 引腳

GLB_GPIO_Type pinlist[] = {
GLB_GPIO_PIN_30,
GLB_GPIO_PIN_31
};

默認(rèn)是 GLB_GPIO_PIN_14、GLB_GPIO_PIN_15.然后封裝.

XFS5152CE 模塊功能代碼

XFS.h

#ifndef __XFS_H
#define __XFS_H


#include 
#include 
#include 
#include 
#include 
#include 
#include         //Added for uint_t
#include 
#include "bflb_mtimer.h"


struct XFS_Protocol_TypeDef
{
    uint8_t DataHead;
    uint8_t Length_HH;
    uint8_t Length_LL;
    uint8_t Commond;
    uint8_t EncodingFormat;
    const char* Text;
};
  
/*
    *| 幀頭(1Byte)| 數(shù)據(jù)區(qū)長(zhǎng)度(2Byte)|           數(shù)據(jù)區(qū)(<4KByte)          |
    *|            |  高字節(jié) | 低字節(jié) | 命令字 | 文本編碼格式 | 待合成文本 |
    *|    0xFD    |  0xHH   |  0xLL  |  0x01  |   0x00~0x03  |  ... ...   |
    */


typedef enum
{
    CMD_StartSynthesis = 0x01,//語(yǔ)音合成命令
    CMD_StopSynthesis = 0x02,//停止合成命令,沒(méi)有參數(shù)
    CMD_PauseSynthesis = 0x03,//暫停合成命令,沒(méi)有參數(shù)
    CMD_RecoverySynthesis = 0x04,//恢復(fù)合成命令,沒(méi)有參數(shù)
    CMD_CheckChipStatus = 0x21,//芯片狀態(tài)查詢(xún)命令
    CMD_PowerSavingMode = 0x88,//芯片進(jìn)入省電模式
    CMD_NormalMode = 0xFF//芯片從省電模式返回正常工作模式
} CMD_Type;//命令字
void StartSynthesis(const char* str);//開(kāi)始合成
// void StartSynthesis(String str);//開(kāi)始合成


bool IIC_WriteByte(uint8_t data);
void IIC_WriteByteSize(uint8_t* buff, uint32_t size);
void SendCommond(CMD_Type cmd);
void StopSynthesis();//停止合成
void PauseSynthesis();//暫停合成
void RecoverySynthesis();//恢復(fù)合成


typedef enum
{
    GB2312 = 0x00,
    GBK = 0x01,
    BIG5 = 0x02,
    UNICODE = 0x03
} EncodingFormat_Type;//文本的編碼格式
void SetEncodingFormat(EncodingFormat_Type encodingFormat);


typedef enum
{
    ChipStatus_InitSuccessful = 0x4A,//初始化成功回傳
    ChipStatus_CorrectCommand = 0x41,//收到正確的命令幀回傳
    ChipStatus_ErrorCommand = 0x45,//收到不能識(shí)別命令幀回傳
    ChipStatus_Busy = 0x4E,//芯片忙碌狀態(tài)回傳
    ChipStatus_Idle = 0x4F//芯片空閑狀態(tài)回傳
} ChipStatus_Type;//芯片回傳


typedef enum
{
    Style_Single,//?為 0,一字一頓的風(fēng)格
    Style_Continue//?為 1,正常合成
} Style_Type; //合成風(fēng)格設(shè)置 [f?]
void SetStyle(Style_Type style);


typedef enum
{
    Language_Auto,//? 為 0,自動(dòng)判斷語(yǔ)種
    Language_Chinese,//? 為 1,阿拉伯?dāng)?shù)字、度量單位、特殊符號(hào)等合成為中文
    Language_English//? 為 2,阿拉伯?dāng)?shù)字、度量單位、特殊符號(hào)等合成為英文
} Language_Type; //合成語(yǔ)種設(shè)置 [g?]
void SetLanguage(Language_Type language);


typedef enum
{
    Articulation_Auto,//? 為 0,自動(dòng)判斷單詞發(fā)音方式
    Articulation_Letter,//? 為 1,字母發(fā)音方式
    Articulation_Word//? 為 2,單詞發(fā)音方式
} Articulation_Type; //設(shè)置單詞的發(fā)音方式 [h?]
void SetArticulation(Articulation_Type articulation);


typedef enum
{
    Spell_Disable,//? 為 0,不識(shí)別漢語(yǔ)拼音
    Spell_Enable//? 為 1,將“拼音+1 位數(shù)字(聲調(diào))”識(shí)別為漢語(yǔ)拼音,例如:hao3
} Spell_Type; //設(shè)置對(duì)漢語(yǔ)拼音的識(shí)別 [i?]
void SetSpell(Spell_Type spell);


typedef enum
{
    Reader_XiaoYan = 3,//? 為 3,設(shè)置發(fā)音人為小燕(女聲, 推薦發(fā)音人)
    Reader_XuJiu = 51,//? 為 51,設(shè)置發(fā)音人為許久(男聲, 推薦發(fā)音人)
    Reader_XuDuo = 52,//? 為 52,設(shè)置發(fā)音人為許多(男聲)
    Reader_XiaoPing = 53,//? 為 53,設(shè)置發(fā)音人為小萍(女聲)
    Reader_DonaldDuck = 54,//? 為 54,設(shè)置發(fā)音人為唐老鴨(效果器)
    Reader_XuXiaoBao = 55//? 為 55,設(shè)置發(fā)音人為許小寶(女童聲)
} Reader_Type;//選擇發(fā)音人 [m?]
void SetReader(Reader_Type reader);


typedef enum
{
    NumberHandle_Auto,//? 為 0,自動(dòng)判斷
    NumberHandle_Number,//? 為 1,數(shù)字作號(hào)碼處理
    NumberHandle_Value//? 為 2,數(shù)字作數(shù)值處理
} NumberHandle_Type; //設(shè)置數(shù)字處理策略 [n?]
void SetNumberHandle(NumberHandle_Type numberHandle);


typedef enum
{
    ZeroPronunciation_Zero,//? 為 0,讀成“zero
    ZeroPronunciation_O//? 為 1,讀成“歐”音
} ZeroPronunciation_Type; //數(shù)字“0”在讀 作英文、號(hào)碼時(shí) 的讀法 [o?]
void SetZeroPronunciation(ZeroPronunciation_Type zeroPronunciation);




typedef enum
{
    NamePronunciation_Auto,//? 為 0,自動(dòng)判斷姓氏讀音
    NamePronunciation_Constraint//? 為 1,強(qiáng)制使用姓氏讀音規(guī)則
} NamePronunciation_Type; //設(shè)置姓名讀音 策略 [r?]
void SetNamePronunciation(NamePronunciation_Type namePronunciation);


void SetSpeed(int speed);//設(shè)置語(yǔ)速 [s?] ? 為語(yǔ)速值,取值:0~10
void SetIntonation(int intonation);//設(shè)置語(yǔ)調(diào) [t?] ? 為語(yǔ)調(diào)值,取值:0~10
void SetVolume(int volume);//設(shè)置音量 [v?] ? 為音量值,取值:0~10


typedef enum
{
    PromptTone_Disable,//? 為 0,不使用提示音
    PromptTone_Enable//? 為 1,使用提示音
} PromptTone_Type; //設(shè)置提示音處理策略 [x?]
void SetPromptTone(PromptTone_Type promptTone);


typedef enum
{
    OnePronunciation_Yao,//? 為 0,合成號(hào)碼“1”時(shí)讀成“幺
    OnePronunciation_Yi//? 為 1,合成號(hào)碼“1”時(shí)讀成“一”
} OnePronunciation_Type; //設(shè)置號(hào)碼中“1”的讀法 [y?]
void SetOnePronunciation(OnePronunciation_Type onePronunciation);


typedef enum
{
    Rhythm_Diasble,//? 為 0,“ *”和“#”讀出符號(hào)
    Rhythm_Enable//? 為 1,處理成韻律,“*”用于斷詞,“#”用于停頓
} Rhythm_Type; //是否使用韻律 標(biāo)記“*”和“#” [z?]
void SetRhythm(Rhythm_Type rhythm);




void SetRestoreDefault();//恢復(fù)默認(rèn)的合成參數(shù) [d] 所有設(shè)置(除發(fā)音人設(shè)置、語(yǔ)種設(shè)置外)恢復(fù)為默認(rèn)值


void XFS5152CE(uint8_t encodingFormat);
void Begin(uint8_t addr);
uint8_t GetChipStatus();
void TextCtrl(char c, int d);


#endif

XFS.c

#include "XFS.h"
#include 
#define DBG_TAG "MAIN"
#include "log.h"


#define XFS_DataHead (uint8_t)0xFD


uint8_t I2C_Addr;
uint8_t ChipStatus;
struct XFS_Protocol_TypeDef DataPack;


size_t foo( const char* restrict src, uint8_t* restrict dst, size_t dst_maxlen )
{
    size_t idx = 0;
    for( ; src[idx] && dst_maxlen; ++idx )
    {
        if( idx%8 == 0 )
            *dst = 0;
        if( src[idx] != '0' )
            *dst |= 1<<(7-idx%8);
        if( idx%8 == 7 )
            ++dst, --dst_maxlen;
    }
    return (idx+7)/8;
}


void XFS5152CE(uint8_t encodingFormat)
{
  DataPack.DataHead = XFS_DataHead;
  DataPack.Length_HH = 0x00;
  DataPack.Length_LL = 0x00;


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


  ChipStatus = 0x00;
}




void Begin(uint8_t addr)
{
  I2C_Addr = addr;
  XFS5152CE(GB2312);
  begin();
}


uint8_t GetChipStatus()
{
  uint8_t AskState[4] = {0xFD,0x00,0x01,0x21};
  beginTransmission(I2C_Addr);
  write_len(AskState,4);
  endTransmission();
  bflb_mtimer_delay_ms(100);
  requestFrom(I2C_Addr, 1);
  while (available())
  {
    ChipStatus = readI2c();
  }
  
  LOG_F("ChipStatus=%x
", ChipStatus);
  return ChipStatus;
}




bool IIC_WriteByte(uint8_t data)
{
  beginTransmission(I2C_Addr);
  write_char(data);
  endTransmission();
  // if(endTransmission()!=0)            //發(fā)送結(jié)束信號(hào)
  //  {
  //         bflb_mtimer_delay_ms(10);
  //         return false;
  //   }
    bflb_mtimer_delay_ms(10);
    return true;  
}


void IIC_WriteBytes(uint8_t* buff, uint32_t size)
{
  for (uint32_t i = 0; i < size; i++)
  {
    IIC_WriteByte(buff[i]);
  }
}


void StartSynthesis(const char* str)
{
  uint16_t size = strlen(str) + 2;
  DataPack.Length_HH = highByte(size);
  DataPack.Length_LL = lowByte(size);
  DataPack.Commond = CMD_StartSynthesis;
  DataPack.Text = str;


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




// void StartSynthesis(String str)
// {
//   StartSynthesis((const char*)str.c_str());
// }


void SendCommond(CMD_Type cmd)
{
  DataPack.Length_HH = 0x00;
  DataPack.Length_LL = 0x01;
  DataPack.Commond = cmd;
  
  beginTransmission(I2C_Addr);
  write_len((uint8_t*)&DataPack, 4);
  endTransmission();
}


void StopSynthesis()
{
  SendCommond(CMD_StopSynthesis);
}


void PauseSynthesis()
{
  SendCommond(CMD_PauseSynthesis);
}


void RecoverySynthesis()
{
  SendCommond(CMD_RecoverySynthesis);
}


void TextCtrl(char c, int d)
{
  char str[10];
  if (d != -1)
    sprintf(str, "[%c%d]", c, d);
  else
    sprintf(str, "[%c]", c);
  StartSynthesis(str);
}


void SetEncodingFormat(EncodingFormat_Type encodingFormat)
{
  DataPack.EncodingFormat = encodingFormat;
}


void SetStyle(Style_Type style)
{
  TextCtrl('f', style);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetLanguage(Language_Type language)
{
  TextCtrl('g', language);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetArticulation(Articulation_Type articulation)
{
  TextCtrl('h', articulation);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetSpell(Spell_Type spell)
{
  TextCtrl('i', spell);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  } 
}


void SetReader(Reader_Type reader)
{
  TextCtrl('m', reader);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetNumberHandle(NumberHandle_Type numberHandle)
{
  TextCtrl('n', numberHandle);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetZeroPronunciation(ZeroPronunciation_Type zeroPronunciation)
{
  TextCtrl('o', zeroPronunciation);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}




void SetNamePronunciation(NamePronunciation_Type namePronunciation)
{
  TextCtrl('r', namePronunciation);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetSpeed(int speed)
{
  // speed = constrain(speed, 0, 10);
  TextCtrl('s', speed);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetIntonation(int intonation)
{
  // intonation = constrain(intonation, 0, 10);
  TextCtrl('t', intonation);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetVolume(int volume)
{
  // volume = constrain(volume, 0, 10);
  TextCtrl('v', volume);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetPromptTone(PromptTone_Type promptTone)
{
  TextCtrl('x', promptTone);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetOnePronunciation(OnePronunciation_Type onePronunciation)
{
  TextCtrl('y', onePronunciation);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}


void SetRhythm(Rhythm_Type rhythm)
{
  TextCtrl('z', rhythm);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}




void SetRestoreDefault()
{
  TextCtrl('d', -1);
  while(GetChipStatus() != ChipStatus_Idle)
  {
     bflb_mtimer_delay_ms(30);
  }
}

語(yǔ)音播報(bào)內(nèi)容 文件頭 speak.h,該文件是為了方式播報(bào)內(nèi)容亂碼錯(cuò)亂。文件需要保存為 ANSI

char* hello[] = {"主人", "出門(mén)記得帶手機(jī)和鑰匙"};

程序代碼 :main.c

#include "bflb_mtimer.h"
#include "board.h"
#include "bflb_gpio.h"
#include "Wire.h"
#include "XFS.h"
#include "speak.h"
#define DBG_TAG "MAIN"
#include "log.h"


/*超時(shí)設(shè)置,示例為30S*/
static uint32_t LastSpeakTime = 0;
#define SpeakTimeOut 10000




/**
    @brief  初始化語(yǔ)音合成
    @param  無(wú)
    @retval 無(wú)
*/


uint8_t n = 1;
static void XFS_Init()
{
    Begin(0x30);//設(shè)備i2c地址,地址為0x50
    bflb_mtimer_delay_ms(n);
    SetReader(Reader_XuXiaoBao);        //設(shè)置發(fā)音人
    bflb_mtimer_delay_ms(n);
    SetEncodingFormat(GB2312);           //文本的編碼格式
    bflb_mtimer_delay_ms(n);
    SetLanguage(Language_Auto);                 //語(yǔ)種判斷
    bflb_mtimer_delay_ms(n);
    SetStyle(Style_Continue);            //合成風(fēng)格設(shè)置
    bflb_mtimer_delay_ms(n);
    SetArticulation(Articulation_Letter);  //設(shè)置單詞的發(fā)音方式
    bflb_mtimer_delay_ms(n);
    SetSpeed(6);                         //設(shè)置語(yǔ)速1~10
    bflb_mtimer_delay_ms(n);
    SetIntonation(5);                    //設(shè)置語(yǔ)調(diào)1~10
    bflb_mtimer_delay_ms(n);
    SetVolume(10);                        //設(shè)置音量1~10
    bflb_mtimer_delay_ms(n);
}


unsigned char result = 0xFF;


struct bflb_device_s *gpio;


void gpio_isr() {
    bool isH = bflb_gpio_read(gpio, GPIO_PIN_13);
    if(isH){
        bflb_gpio_set(gpio, GPIO_PIN_12);
        if(GetChipStatus() == ChipStatus_Idle){
            StartSynthesis(hello[1]);
        }
        bflb_mtimer_delay_ms(3000);
    }else{
        bflb_gpio_reset(gpio, GPIO_PIN_12);
    }
}


int main(void)
{
    board_init();


    gpio = bflb_device_get_by_name("gpio");


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


    bflb_gpio_int_init(gpio, GPIO_PIN_13, GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL);
    bflb_gpio_int_mask(gpio, GPIO_PIN_0, false);
    bflb_irq_attach(gpio->irq_num, gpio_isr, gpio);
    bflb_irq_enable(gpio->irq_num);
  
    XFS_Init();
    StartSynthesis(hello[0]);
    while(GetChipStatus() != ChipStatus_Idle)
    {
        bflb_mtimer_delay_ms(30);
    }


  
    // SetReader(Reader_XuJiu);        //設(shè)置發(fā)音人;   
    StartSynthesis(hello[1]);
    while(GetChipStatus() != ChipStatus_Idle)
    {
        bflb_mtimer_delay_ms(30);
    }
  
    while (1) {
        bflb_mtimer_delay_ms(500);
    }
}

修改 CMakeLists.txt

cmake_minimum_required(VERSION 3.15)


include(proj.conf)


find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE})
# User
sdk_add_compile_definitions(-DCONFIG_CLI_CMD_ENABLE)
#sdk_add_compile_definitions(-DBL616_DHCP_DEBUG)


target_sources(app PRIVATE
                   Wire.c
                   XFS.c)


sdk_add_include_directories(.)


sdk_set_main_file(main.c)


project(helloworld)

開(kāi)發(fā)板:Ai-M61-32S

相關(guān)功能模塊封裝完成,下一步硬件連線(xiàn)。

15d57280-d718-11ef-9310-92fbcf53809c.png

Ai-M61-32S GPIO 接口定義。

Ai-M61-32S XFS5152CE
3.3v VCC
GLB_GPIO_PIN_30 SCL
GLB_GPIO_PIN_31 SDA
GND GND

實(shí)物圖:

15f52e86-d718-11ef-9310-92fbcf53809c.jpg

連接部分:

160bacf6-d718-11ef-9310-92fbcf53809c.jpg

紅外感應(yīng):

161ad032-d718-11ef-9310-92fbcf53809c.jpg

完整 組件結(jié)構(gòu):

162efb16-d718-11ef-9310-92fbcf53809c.jpg

1647e95a-d718-11ef-9310-92fbcf53809c.jpg

到這里基于 Ai-M61-32S “出門(mén)提醒設(shè)備 ”軟硬件已完成。下一步就是外殼了。

04

外殼

外殼選材小插曲

刷 B 站的時(shí)候曾經(jīng)看過(guò)一個(gè)防水盒做音箱的視頻,就跟著做了一個(gè)感覺(jué)很有趣。就買(mǎi)了一些防水盒。

某寶簽到紅包1.5-3塊錢(qián),直接抵下來(lái)幾毛錢(qián)一個(gè)比 3D 打印什么的性?xún)r(jià)比高很多。唯一缺點(diǎn)就是外觀比較固定。

這個(gè)是 DIY 的小音箱。用的是“藍(lán)牙驅(qū)動(dòng)板 m38 藍(lán)牙模塊” 4 快多買(mǎi)的。可以藍(lán)牙連接,也可以當(dāng) USB 聲卡使用還是不錯(cuò)的。側(cè)面改裝成了 Type-C 接口,內(nèi)置了 18650 電池。插著電源開(kāi)關(guān)關(guān)掉就可以了。開(kāi)著開(kāi)關(guān)也沒(méi)關(guān)系。用 mos 管做了隔離。插著線(xiàn)的情況下電池不給設(shè)備供電。

拔掉 USB 線(xiàn),電池供電。基本可以無(wú)縫銜接。

下面言歸正傳,選用的是 835833mm 尺寸的防水盒,用了給的紅包抵扣后價(jià)格 0.17 元。還可以。

1668a21c-d718-11ef-9310-92fbcf53809c.jpg

擺了擺感覺(jué)尺寸剛剛好。

1680d4b8-d718-11ef-9310-92fbcf53809c.jpg

新鉛筆,用小孩兒的卷筆刀削一下。

16968952-d718-11ef-9310-92fbcf53809c.jpg

拿出尺子、圓規(guī)。

16ae01cc-d718-11ef-9310-92fbcf53809c.jpg

畫(huà)上圈圈,定好位置。

16c66f28-d718-11ef-9310-92fbcf53809c.jpg

然后拿把剪刀,搞就完了。

16d4eb66-d718-11ef-9310-92fbcf53809c.jpg

最終效果。下面“ XFS5152CE” 語(yǔ)音合成模塊的那個(gè)孔開(kāi)始想用其他方法開(kāi)孔結(jié)果給弄壞了。

最后用剪刀固定一點(diǎn)一直轉(zhuǎn),圓孔就出來(lái)了,也算是漲經(jīng)驗(yàn)了。

16e3695c-d718-11ef-9310-92fbcf53809c.jpg

開(kāi)孔后接線(xiàn)。

16fafe6e-d718-11ef-9310-92fbcf53809c.jpg

1708ae24-d718-11ef-9310-92fbcf53809c.jpg

最終效果展示,快來(lái)圍觀!

17242690-d718-11ef-9310-92fbcf53809c.png

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 傳感器
    +關(guān)注

    關(guān)注

    2552

    文章

    51353

    瀏覽量

    755562
  • PIR
    PIR
    +關(guān)注

    關(guān)注

    0

    文章

    75

    瀏覽量

    17894
  • HC-SR501
    +關(guān)注

    關(guān)注

    9

    文章

    16

    瀏覽量

    41980

原文標(biāo)題:【DIY電子作品】基于 Ai-M61-32S做一個(gè)出門(mén)提醒設(shè)備(匯總篇)

文章出處:【微信號(hào):安信可科技,微信公眾號(hào):安信可科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何設(shè)計(jì)一個(gè)紅外進(jìn)出門(mén)提醒器?

    如何設(shè)計(jì)一個(gè)紅外進(jìn)出門(mén)提醒器?
    發(fā)表于 02-09 06:01

    Ai-M61-32S(點(diǎn)燈)

    Ai-M61-32S(點(diǎn)燈) 博主環(huán)境:win10 vscode 設(shè)備:usb數(shù)據(jù)線(xiàn)+Ai-M61-32S 工廠配置 首先vscode打開(kāi)文件夾AiPi-Open-Kits,就會(huì)下圖,該文
    發(fā)表于 11-21 09:11

    高性能、低功耗、可驅(qū)屏,Ai-M61系列模組驅(qū)屏能力介紹

    RISC-V CPU,最高主頻可達(dá) 320M,532KB SRAM,128KB ROM,4Kb eFuse;最大發(fā)射功率16-22dBm,靈敏度-98dBm,最高速率229.4 Mbps;該系列包括Ai-M61-01、Ai-M61-3
    的頭像 發(fā)表于 05-22 11:47 ?1598次閱讀
    高性能、低功耗、可驅(qū)屏,<b class='flag-5'>Ai-M61</b>系列模組驅(qū)屏能力介紹

    介紹兩款小安派開(kāi)源硬件:Cam-U和Cam-D

    小安派-Cam-U(AiPi-Cam-U) 是安信可開(kāi)源團(tuán)隊(duì)專(zhuān)門(mén)為Ai-M61-32S設(shè)計(jì)的一款開(kāi)發(fā)板,支持WiFi6、BLE5.3。所搭載的Ai-M61-32S 模組具有豐富的外設(shè)接口,具體包括
    的頭像 發(fā)表于 07-02 11:03 ?692次閱讀
    介紹兩款小安派開(kāi)源硬件:Cam-U和Cam-D

    Ai-M61/62系列的固件燒錄指導(dǎo)

    本文介紹Ai-M61/62系列模組/開(kāi)發(fā)板的固件燒錄。
    的頭像 發(fā)表于 07-02 11:23 ?1682次閱讀
    <b class='flag-5'>Ai-M61</b>/62系列的固件燒錄指導(dǎo)

    小安派開(kāi)源硬件S1和S2有哪些區(qū)別呢?

    答:兩者的主控模組都是Ai-M61-32S。
    的頭像 發(fā)表于 08-11 17:47 ?1197次閱讀

    零基礎(chǔ)開(kāi)發(fā)小安派-Eyes-S1【入門(mén)篇】——初識(shí)小安派-Eyes-S1

    信可開(kāi)源團(tuán)隊(duì)專(zhuān)門(mén)為Ai-M61-32S設(shè)計(jì)的一款開(kāi)發(fā)板,支持WiFi6、BLE5.3。所搭載的Ai-M61-32S 模組具有豐富的外設(shè)接口,具
    的頭像 發(fā)表于 09-18 15:41 ?751次閱讀
    零基礎(chǔ)開(kāi)發(fā)小安派-Eyes-<b class='flag-5'>S</b>1【入門(mén)篇】——初識(shí)小安派-Eyes-<b class='flag-5'>S</b>1

    Ai-M61-32S開(kāi)發(fā)環(huán)境搭建

    Ai-M61-32S開(kāi)發(fā)環(huán)境搭建
    的頭像 發(fā)表于 11-10 12:30 ?999次閱讀
    <b class='flag-5'>Ai-M61-32S</b>開(kāi)發(fā)環(huán)境搭建

    Ai-M61-32S開(kāi)發(fā)板能玩出多少拓展板?

    時(shí)間過(guò)的真快,眨眼間樓主玩M61這個(gè)模組已經(jīng)有一個(gè)多月了,學(xué)習(xí)的同時(shí)結(jié)交了很多不講武德志同道合的朋友,從最開(kāi)始剛接觸的點(diǎn)燈到慢慢嘗試上手用M61驅(qū)動(dòng)各種電子模塊,深感還要學(xué)習(xí)很多。
    的頭像 發(fā)表于 11-13 10:29 ?501次閱讀
    用<b class='flag-5'>Ai-M61-32S</b>開(kāi)發(fā)板能玩出多少拓展板?

    安信可Ai-M61-32S開(kāi)發(fā)板能玩出多少拓展板?

    控制家里的一些設(shè)備~ 實(shí)物展示 這次使用M61開(kāi)發(fā)板只引出了串口,把usb引出到底板上了,順便簡(jiǎn)單的寫(xiě)了一些代碼,可以在讀取ds1302的時(shí)間顯示在屏幕上,讀取溫濕度,光敏電阻讀取光照,還有燈珠~ DS1302時(shí)鐘 板載了一個(gè)ds1302時(shí)鐘ic,以及一個(gè)cr2032備用
    的頭像 發(fā)表于 11-13 14:54 ?614次閱讀
    安信可<b class='flag-5'>Ai-M61-32S</b>開(kāi)發(fā)板能玩出多少拓展板?

    晚上再也不摸黑 ,用Ai-M61-32S&amp;Rd-03制作一盞自動(dòng)感應(yīng)小夜燈

    Ai-M61-32S 開(kāi)發(fā)板,非常開(kāi)心,收到了人生中第一塊板子。也感謝安信可社區(qū)中各種經(jīng)驗(yàn)貼,對(duì)開(kāi)發(fā)板有了一些初步的認(rèn)識(shí)。 起初有這樣一個(gè)想法,晚上起夜要是有個(gè)自動(dòng)感應(yīng)燈就好了,不用太亮,能夠發(fā)出柔和的燈光,照亮房間里大致的樣子就好了。于是網(wǎng)上下單了幾個(gè)USB 小燈、幾個(gè)USB母座。母座不自帶針腳,自己動(dòng)手
    的頭像 發(fā)表于 01-02 10:58 ?576次閱讀
    晚上再也不摸黑 ,用<b class='flag-5'>Ai-M61-32S</b>&amp;Rd-03<b class='flag-5'>制作</b>一盞自動(dòng)感應(yīng)小夜燈

    DIY案例:用Ai-M61-32S做一個(gè)多功能書(shū)桌燈

    這個(gè)書(shū)桌燈可以通過(guò)Ai-M61-32S聯(lián)網(wǎng)實(shí)時(shí)顯示時(shí)間,通過(guò)dht11溫濕度模塊顯示溫濕度,同時(shí)具備抽拉式手機(jī)支架,可以將手機(jī)放在上面,同時(shí)可以通過(guò)手機(jī)遙控開(kāi)燈,當(dāng)開(kāi)燈時(shí),會(huì)控制舵機(jī)將燈升起來(lái)。
    的頭像 發(fā)表于 01-25 15:05 ?671次閱讀
    DIY案例:用<b class='flag-5'>Ai-M61-32S</b>做一個(gè)多功能書(shū)桌燈

    安信可Ai-M61/Ai-M62系列連接AWS亞馬遜云

    本文介紹Ai-M61/Ai-M62系列模組/開(kāi)發(fā)板連接亞馬遜云方法。 Ai-M61 系列模組(下稱(chēng)模組)是由深圳市安信可科技有限公司開(kāi)發(fā)的 Wi-Fi6 藍(lán)牙雙模模組,搭載BL616芯片作為處理器
    的頭像 發(fā)表于 02-04 15:51 ?907次閱讀
    安信可<b class='flag-5'>Ai-M61</b>/<b class='flag-5'>Ai-M</b>62系列連接AWS亞馬遜云

    【外設(shè)移植】Ai-M61-32s 開(kāi)發(fā)板+3.5寸SPI彩屏

    M61-32S3.5寸SPI屏VCCVCCGNDGNDIO12CSIO26RSIO27D/CIO19SDIIO13SCLIO28BLIO18SDO 02、庫(kù)文件介紹 該移植庫(kù)共包含五個(gè)部分,分別
    的頭像 發(fā)表于 03-07 10:02 ?529次閱讀
    【外設(shè)移植】<b class='flag-5'>Ai-M61-32s</b> 開(kāi)發(fā)板+3.5寸SPI彩屏

    不到10塊錢(qián),用Ai-M61-32S如何自制一個(gè)開(kāi)機(jī)棒?

    ?如何自制一個(gè)開(kāi)機(jī)棒? Ai-M61-32S開(kāi)機(jī)棒是一個(gè)僅使用Ai-M61-32S的開(kāi)機(jī)棒,無(wú)需額外的硬件,刷入程序,接上電源,最后結(jié)合一些簡(jiǎn)單的配置即可使用。該項(xiàng)目標(biāo)為用最少的硬件,最少的配置去實(shí)現(xiàn)遠(yuǎn)程開(kāi)機(jī)功能。 Wake-on-LAN 簡(jiǎn)稱(chēng) WoL,指通過(guò)網(wǎng)絡(luò)UDP數(shù)
    的頭像 發(fā)表于 08-27 16:17 ?367次閱讀
    不到10塊錢(qián),用<b class='flag-5'>Ai-M61-32S</b>如何自制一個(gè)開(kāi)機(jī)棒?