一、簡介
二、紅外感應篇
三、XFS5152CE語音合成篇
四、外殼篇
01
簡介
本項目設計初衷是為了提醒自己出門不要忘記帶東西——“身”、“手”、“鑰”、“錢” (身份證,手機,鑰匙,錢包)等。不過現在好像都在線支付了,錢包都不帶了。筆者覺得后期可以改造成播報天氣等,提醒帶傘等等。
項目最初設計是使用安信可24G雷達傳感器模塊人體微動感應檢測模組“Rd-03” 來做。由于手上剛好有一個"HC-SR501 紅外感應電子模塊傳感器" 模塊,所以這次先用這個試試。
02
紅外感應篇
硬件相關
紅外感應模塊:HC-SR501
語音合成播報模塊:XFS5152
開發板:Ai-M61-32S
GPIO 全稱 General Purpose Input Output(通用輸入 / 輸出),博流系列芯片的 GPIO 外設主要有以下功能。
普通輸入輸出帶上下拉
復用功能帶上下拉
模擬功能
外部中斷(上升沿、下降沿、高電平、低電平)
硬件消抖
驅動能力控制
GPIO 復用功能通過專門的 pinmux table ,用戶只需要修改 table 中的相關引腳的功能,程序會自動配置這些引腳。pinmux table 位于 bsp/board/xxx_board 目錄下 pinmux_config.h 文件。
通過標準的 GPIO 設備接口配置引腳,缺點是只能配置普通的輸入輸出和中斷功能,復用功能建議還是使用 table 進行配置。
PIR 傳感器如何工作?
**絕對零 (0 開爾文/-273.5 *C) 以上的每個物體都會以紅外輻射的形式發出熱能。物體越熱,它發出的輻射就越多。輻射對人眼是不可見的,PIR傳感器專門設計用于檢測這種輻射水平。
PIR 傳感器由兩個主要部分組成,可以看到的熱釋電傳感器是圓形的,中間有一個矩形晶體。
一種稱為菲涅爾透鏡的特殊透鏡,可將紅外信號聚焦到熱釋電傳感器上。
熱釋電傳感器熱釋電傳感器由一個窗口和兩個由涂層硅制成的矩形槽組成,它允許紅外線通過并阻擋任何其他輻射。傳感器的設計使得一個可以抵消另一個,這樣傳感器就可以抵消環境輻射并檢測輻射模式的變化。
當沒有檢測到運動時,產生的輸出信號為零,因為傳感器正在檢測背景輻射。但是,當傳感器的任何一半截獲運動時,都會導致傳感器兩部分之間的電壓電平發生變化,這就是檢測運動的方式。
菲涅耳透鏡
菲涅耳透鏡由一系列刻在塑料上的同心凹槽組成。這些輪廓充當單獨的折射表面,在焦點處聚集平行光線。因此,菲涅耳透鏡能夠像傳統光學透鏡一樣聚焦光線。
實際上,為了增加 PIR 傳感器的范圍和視野,透鏡被分成幾個面部分,每個部分都是一個單獨的菲涅爾透鏡。
HC-SR501 PIR 運動傳感器模塊引出線
HC-SR501 模塊具有三個引腳。模塊絲印被菲涅耳透鏡遮擋,請參考下面給出的引腳排列。施加 5V – 12V 電源和接地,傳感器輸出在檢測到運動時變為高電平,在空閑時變為低電平(未檢測到運動)。
觸發器選擇跳線
有兩種觸發模式決定傳感器在檢測到運動時如何反應。
單觸發模式:持續運動將導致單觸發。
多重觸發模式:不斷的運動會引起一系列的觸發。
L - 在此設置中,傳感器將處于單觸發模式,在此模式下,當檢測到運動時輸出變高。并在延時電位器設定的一定時間內保持高電平。任何其他類型的檢測都會被阻止,直到輸出變低。
H - 選擇這些設置將設置多重觸發模式。在這種模式下,當檢測到運動時輸出變高,高電平周期由設置的電位器決定。但與單觸發模式不同的是,進一步檢測不會被阻止并且可以連續觸發,當未檢測到移動時,引腳變為低電平。
靈敏度調整
PIR 傳感器背面有一個電位器,用于調節靈敏度。在電位器的幫助下,可以調整設備的靈敏度。順時針旋轉電位器會增加靈敏度,逆時針旋轉電位器會降低靈敏度。
延時調整
傳感器背面的另一個鍋設置輸出將保持高電平的時間以及在檢測到運動后順時針轉動鍋會增加延遲,逆時針轉動鍋會減少延遲。
3.3V 穩壓器
該模塊帶有一個 3.3V 穩壓器,因此它可以由 4.5V 至 12V 電源供電。雖然 5V 是常用的。
保護二極管
該模塊帶有一個保護二極管,用于保護二極管免受反向電壓和電流的影響。
HC-SR501 PIR 傳感器模塊故障排除
PIR 傳感器無法正常工作可能有多種原因。需要通過一些測試來找出問題的根本原因。
傳感器的工作電壓為 4.8V 至 20V,因此無法使用 3.3V 為傳感器供電。
在某些情況下會看到鏡頭頂部積聚了灰塵,因此 PIR 傳感器可能會停止工作。
如果上述方法均無效,請嘗試旋轉電位器。如果將電位計的靈敏度設置為最低,那么這可能是傳感器不工作的原因。
在測試了所有方法后,如果傳感器不工作,那么您可以確定您手中的傳感器有故障。
部分代碼
#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:構建項目并實現 Ai-M61-32S 與 人體紅外感應模塊 HC-SR501 連接,并獲取狀態值。
默認燈光是關閉的:
檢測有人經過時,紅燈亮起。
03
XFS5152CE語音合成篇
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
#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 中的方法,主要是獲取高位和低位數據
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
};
默認是 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)| 數據區長度(2Byte)| 數據區(<4KByte) | *| | 高字節 | 低字節 | 命令字 | 文本編碼格式 | 待合成文本 | *| 0xFD | 0xHH | 0xLL | 0x01 | 0x00~0x03 | ... ... | */ typedef enum { CMD_StartSynthesis = 0x01,//語音合成命令 CMD_StopSynthesis = 0x02,//停止合成命令,沒有參數 CMD_PauseSynthesis = 0x03,//暫停合成命令,沒有參數 CMD_RecoverySynthesis = 0x04,//恢復合成命令,沒有參數 CMD_CheckChipStatus = 0x21,//芯片狀態查詢命令 CMD_PowerSavingMode = 0x88,//芯片進入省電模式 CMD_NormalMode = 0xFF//芯片從省電模式返回正常工作模式 } CMD_Type;//命令字 void StartSynthesis(const char* str);//開始合成 // void StartSynthesis(String str);//開始合成 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();//恢復合成 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,//收到不能識別命令幀回傳 ChipStatus_Busy = 0x4E,//芯片忙碌狀態回傳 ChipStatus_Idle = 0x4F//芯片空閑狀態回傳 } ChipStatus_Type;//芯片回傳 typedef enum { Style_Single,//?為 0,一字一頓的風格 Style_Continue//?為 1,正常合成 } Style_Type; //合成風格設置 [f?] void SetStyle(Style_Type style); typedef enum { Language_Auto,//? 為 0,自動判斷語種 Language_Chinese,//? 為 1,阿拉伯數字、度量單位、特殊符號等合成為中文 Language_English//? 為 2,阿拉伯數字、度量單位、特殊符號等合成為英文 } Language_Type; //合成語種設置 [g?] void SetLanguage(Language_Type language); typedef enum { Articulation_Auto,//? 為 0,自動判斷單詞發音方式 Articulation_Letter,//? 為 1,字母發音方式 Articulation_Word//? 為 2,單詞發音方式 } Articulation_Type; //設置單詞的發音方式 [h?] void SetArticulation(Articulation_Type articulation); typedef enum { Spell_Disable,//? 為 0,不識別漢語拼音 Spell_Enable//? 為 1,將“拼音+1 位數字(聲調)”識別為漢語拼音,例如:hao3 } Spell_Type; //設置對漢語拼音的識別 [i?] void SetSpell(Spell_Type spell); typedef enum { Reader_XiaoYan = 3,//? 為 3,設置發音人為小燕(女聲, 推薦發音人) Reader_XuJiu = 51,//? 為 51,設置發音人為許久(男聲, 推薦發音人) Reader_XuDuo = 52,//? 為 52,設置發音人為許多(男聲) Reader_XiaoPing = 53,//? 為 53,設置發音人為小萍(女聲) Reader_DonaldDuck = 54,//? 為 54,設置發音人為唐老鴨(效果器) Reader_XuXiaoBao = 55//? 為 55,設置發音人為許小寶(女童聲) } Reader_Type;//選擇發音人 [m?] void SetReader(Reader_Type reader); typedef enum { NumberHandle_Auto,//? 為 0,自動判斷 NumberHandle_Number,//? 為 1,數字作號碼處理 NumberHandle_Value//? 為 2,數字作數值處理 } NumberHandle_Type; //設置數字處理策略 [n?] void SetNumberHandle(NumberHandle_Type numberHandle); typedef enum { ZeroPronunciation_Zero,//? 為 0,讀成“zero ZeroPronunciation_O//? 為 1,讀成“歐”音 } ZeroPronunciation_Type; //數字“0”在讀 作英文、號碼時 的讀法 [o?] void SetZeroPronunciation(ZeroPronunciation_Type zeroPronunciation); typedef enum { NamePronunciation_Auto,//? 為 0,自動判斷姓氏讀音 NamePronunciation_Constraint//? 為 1,強制使用姓氏讀音規則 } NamePronunciation_Type; //設置姓名讀音 策略 [r?] void SetNamePronunciation(NamePronunciation_Type namePronunciation); void SetSpeed(int speed);//設置語速 [s?] ? 為語速值,取值:0~10 void SetIntonation(int intonation);//設置語調 [t?] ? 為語調值,取值:0~10 void SetVolume(int volume);//設置音量 [v?] ? 為音量值,取值:0~10 typedef enum { PromptTone_Disable,//? 為 0,不使用提示音 PromptTone_Enable//? 為 1,使用提示音 } PromptTone_Type; //設置提示音處理策略 [x?] void SetPromptTone(PromptTone_Type promptTone); typedef enum { OnePronunciation_Yao,//? 為 0,合成號碼“1”時讀成“幺 OnePronunciation_Yi//? 為 1,合成號碼“1”時讀成“一” } OnePronunciation_Type; //設置號碼中“1”的讀法 [y?] void SetOnePronunciation(OnePronunciation_Type onePronunciation); typedef enum { Rhythm_Diasble,//? 為 0,“ *”和“#”讀出符號 Rhythm_Enable//? 為 1,處理成韻律,“*”用于斷詞,“#”用于停頓 } Rhythm_Type; //是否使用韻律 標記“*”和“#” [z?] void SetRhythm(Rhythm_Type rhythm); void SetRestoreDefault();//恢復默認的合成參數 [d] 所有設置(除發音人設置、語種設置外)恢復為默認值 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) //發送結束信號 // { // 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); } }
語音播報內容 文件頭 speak.h,該文件是為了方式播報內容亂碼錯亂。文件需要保存為 ANSI
char* hello[] = {"主人", "出門記得帶手機和鑰匙"};
主程序代碼 :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" /*超時設置,示例為30S*/ static uint32_t LastSpeakTime = 0; #define SpeakTimeOut 10000 /** @brief 初始化語音合成 @param 無 @retval 無 */ uint8_t n = 1; static void XFS_Init() { Begin(0x30);//設備i2c地址,地址為0x50 bflb_mtimer_delay_ms(n); SetReader(Reader_XuXiaoBao); //設置發音人 bflb_mtimer_delay_ms(n); SetEncodingFormat(GB2312); //文本的編碼格式 bflb_mtimer_delay_ms(n); SetLanguage(Language_Auto); //語種判斷 bflb_mtimer_delay_ms(n); SetStyle(Style_Continue); //合成風格設置 bflb_mtimer_delay_ms(n); SetArticulation(Articulation_Letter); //設置單詞的發音方式 bflb_mtimer_delay_ms(n); SetSpeed(6); //設置語速1~10 bflb_mtimer_delay_ms(n); SetIntonation(5); //設置語調1~10 bflb_mtimer_delay_ms(n); SetVolume(10); //設置音量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); //設置發音人; 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)
開發板:Ai-M61-32S
相關功能模塊封裝完成,下一步硬件連線。
Ai-M61-32S GPIO 接口定義。
Ai-M61-32S | XFS5152CE |
3.3v | VCC |
GLB_GPIO_PIN_30 | SCL |
GLB_GPIO_PIN_31 | SDA |
GND | GND |
實物圖:
連接部分:
紅外感應:
完整 組件結構:
到這里基于 Ai-M61-32S “出門提醒設備 ”軟硬件已完成。下一步就是外殼了。
04
外殼
外殼選材小插曲
刷 B 站的時候曾經看過一個防水盒做音箱的視頻,就跟著做了一個感覺很有趣。就買了一些防水盒。
某寶簽到紅包1.5-3塊錢,直接抵下來幾毛錢一個比 3D 打印什么的性價比高很多。唯一缺點就是外觀比較固定。
這個是 DIY 的小音箱。用的是“藍牙驅動板 m38 藍牙模塊” 4 快多買的。可以藍牙連接,也可以當 USB 聲卡使用還是不錯的。側面改裝成了 Type-C 接口,內置了 18650 電池。插著電源開關關掉就可以了。開著開關也沒關系。用 mos 管做了隔離。插著線的情況下電池不給設備供電。
拔掉 USB 線,電池供電。基本可以無縫銜接。
下面言歸正傳,選用的是 835833mm 尺寸的防水盒,用了給的紅包抵扣后價格 0.17 元。還可以。
擺了擺感覺尺寸剛剛好。
新鉛筆,用小孩兒的卷筆刀削一下。
拿出尺子、圓規。
畫上圈圈,定好位置。
然后拿把剪刀,搞就完了。
最終效果。下面“ XFS5152CE” 語音合成模塊的那個孔開始想用其他方法開孔結果給弄壞了。
最后用剪刀固定一點一直轉,圓孔就出來了,也算是漲經驗了。
開孔后接線。
最終效果展示,快來圍觀!
-
傳感器
+關注
關注
2552文章
51356瀏覽量
755622 -
PIR
+關注
關注
0文章
75瀏覽量
17894 -
HC-SR501
+關注
關注
9文章
16瀏覽量
41981
原文標題:【DIY電子作品】基于 Ai-M61-32S做一個出門提醒設備(匯總篇)
文章出處:【微信號:安信可科技,微信公眾號:安信可科技】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論