資料介紹
描述
概述
無論是因為睡得怪怪的、玩手機太多,還是彎腰坐著盯著電腦看幾個小時,我們大多數人都會時不時地處理脖子上的扭結。緩解頸部疼痛的最佳方法之一是按摩療法。因此,我們改造了傳統的頸部按摩器,讓它變得聰明,輕松消除壓力。
頸部放松按摩器結合了中國傳統理療中的多種按摩手法,采用低頻電脈沖技術模擬真人按摩。能促進局部血液循環,有效緩解頸部疲勞和肌肉緊張。由于我們已經使這款按摩器支持物聯網,因此我們只需一部手機即可控制它。
特征
- 五種模式:智能、放松、主動、敲擊和刮擦。不同的模式讓您體驗不同的按摩樂趣。
- 15級強度由弱到強:您可以自由調節適合自己的強度。
- 三級溫度調節:高、低、關。持續的熱按摩可以放松血管和頸部肌肉。
硬件

腳步
第 1 步:硬件設計
使用涂鴉智能或智能生活應用程序實現遠程控制,我們使用涂鴉的BTU 網絡模塊作為微控制器。
電路由BTU模塊、電池充電、語音播放、按鍵檢測、低頻脈沖電流輸出、加熱、溫度檢測等部分組成。
1.微控制器

?

?
2. 功能模塊
- NTC熱敏電阻(MF52B)
NTC熱敏電阻是環氧樹脂涂層的小尺寸,用于溫度測量。它具有電阻范圍廣、精度穩定性和靈敏度高、響應速度快等特點。對于熱敏電阻的參數,我們使用:B=3950,R=10k。
?

?
- 溫度與電阻的關系
?

- 溫度檢測電路
?

模塊的 ADC 收集電壓并將其轉換為溫度值。然后,模塊相應地調整溫度。
- 加熱絲
白線是發熱絲。
?

- 加熱回路
?

模塊上的P7輸出PWM波來調節電熱絲的溫度。當 P7 輸出低電平時,加熱關閉。當 P7 以某個頻率輸出方波時,發熱處于低水平。當 P7 輸出高電平時,加熱處于高電平。
- 揚聲器
?

- 語音控制電路

在單線串口模式下,BTU模塊可以通過DATA線控制和發送數據到語音芯片,進行語音播放、停止、循環等。
- 電極墊
按摩器上有兩個不銹鋼電極墊。
?

?

低頻脈沖電流輸出
P24 和 P9 輸出的脈沖是對稱的。這兩個引腳不能同時輸出高電平。
- 當P24輸出高電平,P9輸出低電平時,Q2導通,Q5截止。由于人體的阻抗,Q4、Q6、Q8 截止,Q3 處于飽和(導通狀態)。
P17 輸出高電平。它輸出兩個低頻對稱脈沖。
- 當P24輸出低電平,P9輸出高電平時,Q2截止,Q5導通。Q4、Q6 和 Q8 處于導通狀態,Q3 處于截止狀態。
P17 輸出低電平。它輸出兩個低頻對稱脈沖。
?
P24 和 P9 輸出的脈沖是不對稱的。PB5 和 PCO 都輸出高電平。
- 當 Q5、Q2 和 Q6 處于導通狀態時,Q4 和 Q3 處于導通狀態。這樣,三極管可能會燒壞。
- S8050晶體管的開/關取決于二極管D4正端的電壓,該電壓由通過二極管的電流決定。因此,我們可以提供過流保護。一旦通過二極管D4的電流超過10mA,D4的壓降就會超過0.7V,三極管Q2就會導通。
- 模塊上的P24和P9可以輸出不同頻率的脈沖信號(P24和P9輸出的脈沖是對稱的),針對各種模式產生不同的波形。
二極管D4參數
- 電池
我們買了一塊700毫安的鋰聚合物電池,額定電壓為3.7V,充電電壓為4.2V。內置保護電路,防止過充、過放、過流、短路。
?

尺寸:10 毫米(厚)x 23 毫米(寬)x 30 毫米(長)
?

電池充電器電路和升壓電路
- 電池充電器電路:XT2051是單節鋰離子電池的恒流恒壓充電器電路。該組件包括一個內部功率晶體管,不需要外部電流檢測電阻器和阻塞二極管。XT2051 需要最少的外部元件并符合 USB 總線規范。它非常適合現場的便攜式應用。
- 升壓電路原理:當三極管MMBT5551導通時,肖特基二極管D1處于反向偏置狀態。通過電感器 L1 到晶體管 Q1 的電流完成了一個電路。施加到升壓電感器的輸入電壓被轉換成磁能進行存儲。當三極管Q1關斷時,肖特基二極管D1正向偏置,電感中的磁能轉化為電能。該電壓與輸入電壓一起為負載供電并為輸出電容器 C6 充電。需要幾個脈沖來提供足夠的能量來增加輸出電壓。
?
第 2 步:創建產品
本節介紹如何在涂鴉IoT平臺上創建智能頸椎按摩器。有關詳細信息,請參閱創建產品。
1.登錄涂鴉IoT平臺。
2.在標準類別選項卡上,單擊運動與健康>運動與健康。填寫產品信息并選擇藍牙作為協議。

3.點擊創建后,出現添加標準函數對話框。保留三個選定的所需功能。在自定義函數部分中,單擊添加并創建兩個函數。有關要設置的項目,請參見下面的屏幕截圖。

4.在設備面板步驟中,選擇DIY風格面板。然后,進入硬件開發,選擇涂鴉標準模塊 SDK和BT3L 藍牙模塊。單擊屏幕右側的獲取 10 個免費許可證。您將在編碼中獲得 UUID、密鑰和 MAC 地址。
第 3 步:獲取 SDK 并設置 IDE
-
GitHub存儲庫將此存儲庫tuya_ble_sdk_Demo_Project_tlsr8253克隆到您的本地計算機并檢查
README.md
. - 設置IDE模塊上的芯片是TLSR825x,所以我們使用Telink IDE進行開發。轉到適用于 TLSR8 芯片的 IDE 并下載 IDE 并查看項目導入指南。

安裝 IDE 后,導入您的項目。
- 用項目開發1.編輯產品ID。

2.編輯auth_key
、device_id
和mac
。
?

?

3.編譯代碼。
?

- 刷機工具(下載)
?

1.8258
選擇芯片類型和EVK
下載模式。單擊文件并選擇bin
要下載到開發板的文件,該文件位于tuya_ble_sdk_Demo_Project_tlsr8253\telink_kite_ble_sdk_v3.4.0_20190816\ble_sdk_multimode\8258_module\8258_module.bin
.
2.下載后點擊Reset運行。
3.我們使用泰凌的作家。將板上的 SWM 接頭連接到寫入器上的 SWM 接頭。
?

?
注意:日志打印的引腳默認為TL_C2
,波特率為230400。由于我們沒有足夠的I/O,我們將日志打印的引腳改為TL_D3
。您可以在編輯后編譯代碼。配置文件位于tuya_ble_sdk_Demo_Project_tlsr8253\telink_kite_ble_sdk_v3.4.0_20190816\ble_sdk_multimode\vendor\8258_module\app_config.h
. 當 GPIO 讀高時,它返回一個大于 1 的值,可能是 1、2 或 128。
在第 47 行:
#define DEBUG_INFO_TX_PIN GPIO_PC2
變成:
#define DEBUG_INFO_TX_PIN GPIO_PD3
第四步:軟件設計
電脈沖按摩器采用中國傳統物理療法的電脈沖模擬,可促進血液循環,放松局部肌肉,電極墊設計達到雙重按摩效果。
我們實現了五種脈沖模式:智能、放松、主動、敲擊和刮擦。
脈沖模式
模式 時間間隔 放松模式 30 毫秒 主動模式 20 毫秒 輕敲模式 40 毫秒 抓取模式 50 毫秒 智能模式 20 毫秒、30 毫秒、40 毫秒或 50 毫秒隨機生成。
- 原理圖,示意圖
P9 和 P24 控制三極管的開/關以產生電脈沖并啟用不同的脈沖模式。
?

?
- 波形圖
P9 和 P24 輸出 PWM 信號,正占空比為 26.5%,周期為 1 ms。注意這兩個引腳不能同時輸出高電平。否則三極管會燒壞。
以 30 ms 的間隔一次輸出四個 PWM 波,以實現放松模式。

一個脈沖有四個 PWM 波,如上圖所示。以 30 ms 的間隔產生脈沖。

- 模式實現
五種脈沖模式是通過改變脈沖間隔來實現的,如下表所示。

?
實現代碼
引腳初始化
void pattern_pin_init(void)
{
gpio_set_func(PATTERN_PIN_A, AS_PWM1_N);
gpio_set_func(PATTERN_PIN_B, AS_PWM5);
gpio_set_func(HEAT_PIN, AS_GPIO);
gpio_set_output_en(PATTERN_PIN_A, 1);
gpio_set_output_en(PATTERN_PIN_B, 1);
gpio_set_output_en(HEAT_PIN, 1);
gpio_write(PATTERN_PIN_A, 0);
gpio_write(PATTERN_PIN_B, 0);
// gpio_write(HEAT_PIN, 1);
//PWM0 1ms cycle 26.5% duty 1,000 Hz
pwm_set_mode(PWM1_ID, PWM_NORMAL_MODE);
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);
pwm_set_phase(PWM1_ID, 0); // No phase at PWM beginning
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
pwm_polo_enable(PWM1_ID, 1); // Enable the PWM polarity
pwm_start(PWM1_ID);
// PWM5 1 ms cycle, 26.5% duty 1,000 Hz
pwm_set_mode(PWM5_ID, PWM_NORMAL_MODE);
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);
pwm_set_phase(PWM5_ID, 0); // No phase at PWM beginning
pwm_set_cycle_and_duty(PWM5_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
}
GPIO_PC1 (PATTERN_PIN_A)
和電平調整引腳都GPIO_PC2 (BOOST_PIN)
使用 PWM 功能。管腳GPIO_PC1 (PATTERN_PIN_A)
只支持PWM_0
通道,所以GPIO_PC2 (BOOST_PIN)
使用PWM_0
通道。GPIO_PC1 (PATTERN_PIN_A)
使用AS_PWM1_N
通道,因此您只需要編輯pwm_polo_enable(PWM1_ID, 1)
即可更改 PWM 極性。
?

?
由于 PWM 波的數量和脈沖間隔是通過時間延遲來實現的,因此會產生誤差。程序運行在裸機上,而不是 RTOS,所以這個函數必須while(1)
循環運行。
void switching_pattern(unsigned char pat)
{
if (pat > 4) {
TUYA_APP_LOG_ERROR("*********No such model!!!**********");
}
switch (pat) {
case relieve:
pwm_start(PWM5_ID);
sleep_us(450); // Delay 480 μs to prevent the triode from being burned out.
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
sleep_us(5 * TIME_MS);
pwm_stop(PWM5_ID);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
sleep_us(30 * TIME_MS);
break;
case vitality:
pwm_start(PWM5_ID);
sleep_us(450);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
sleep_us(5 * TIME_MS);
pwm_stop(PWM5_ID);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
sleep_us(20 * TIME_MS);
break;
case hammering:
pwm_start(PWM5_ID);
sleep_us(450);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
sleep_us(5 * TIME_MS);
pwm_stop(PWM5_ID);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
sleep_us(40 * TIME_MS);
break;
case scraping_therapy:
pwm_start(PWM5_ID);
sleep_us(450);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
sleep_us(5 * TIME_MS);
pwm_stop(PWM5_ID);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
sleep_us(50 * TIME_MS);
break;
case intelligent:
pwm_start(PWM5_ID);
sleep_us(450);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (265 * CLOCK_SYS_CLOCK_1US) );
sleep_us(5 * TIME_MS);
pwm_stop(PWM5_ID);
pwm_set_cycle_and_duty(PWM1_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
sleep_us(((rand() % 4 + 2) * 10) * TIME_MS); // 20 ms, 30 ms, 40 ms, or 50 ms is generated randomly.
break;
default:
break;
}
return;
}
我們已經實現了五種脈沖模式,接下來是語音提示、加熱和電平調節。
1.語音提示
WTN6是一款多功能單語音芯片,語音合成4位MCU。
?

- 工作電壓:2.8V至5.2V
- 在待機模式下,靜態電流小于 5 μA。
- 帶有內置電阻器 (+/- 1%) 的精確嵌入式振蕩器。支持低電壓復位(LVR=1.8V)和看門狗復位。
- 高品質 12 位 PWM 直接驅動 8Ω 0.5W 揚聲器或蜂鳴器。DAC轉換器的音頻輸出可以通過外部音頻放大器放大音量。
- 內置看門狗。
- 串口控制方式:單線串口和兩線串口。最多可加載 224 條語音。
- 支持忙碌狀態下的輸出功能。
?

單線串行通訊
在單線串口模式下,BTU模塊可以通過DATA線控制和發送數據到語音芯片,進行語音播放、停止、循環等。
引腳 描述 PA1 DATA PA2 BUSY 數據(十六進制) 功能 00H 不播放音頻。01H 第一次音頻播放。02H 第二次音頻播放。…… …… DFH 第 222 段音頻播放。
- 引腳配置

- 單行音頻地址關聯
?

?
單線串口時序圖
將數據線拉低至 5ms,然后發送 8 位數據,先低位,后高位。用高電平與低電平的比值來表示每個數據位的值。
?

?

?
實現代碼
- 引腳初始化
void voice_prompt_init(void)
{
gpio_set_func(WTN6_DATA_PIN | WTN6_BUSY_PIN, AS_GPIO);
gpio_set_input_en(WTN6_BUSY_PIN, 1);
gpio_set_output_en(WTN6_DATA_PIN, 1);
gpio_write(WTN6_BUSY_PIN, 0);
}
?
- 音頻播放
void voice_playing(uint8_t sb_data)
{
uint8_t s_data, j;
bool b_data;
s_data = sb_data;
gpio_write(WTN6_DATA_PIN, 0);
sleep_us(5000); // Delay 5 ms
b_data = s_data & 0X01;
for (j=0; j<8; j++) {
if (b_data == 1) {
gpio_write(WTN6_DATA_PIN, 1);
sleep_us(600); // Delay 600 μs
gpio_write(WTN6_DATA_PIN, 0);
sleep_us(200); // Delay 200 μs
} else {
gpio_write(WTN6_DATA_PIN, 1);
sleep_us(200); // Delay 200 μs
gpio_write(WTN6_DATA_PIN, 0);
sleep_us(600); // Delay 600 μs
}
s_data = s_data >> 1;
b_data = s_data & 0X01;
}
gpio_write(WTN6_DATA_PIN, 1);
}
指定參數voice_playing(0x01)
以播放離線音頻。
2:加熱
?

?
我們向上或向下拉 P7 來控制加熱的開/關。頸部按摩器有一個內置傳感器來檢測溫度。當溫度超過 40°C 時,將關閉加熱以避免過熱。
?

?
int switching_heat(unsigned char warm)
{
if (warm > 1) {
TUYA_APP_LOG_ERROR("*********No such model!!!**********");
}
// printf("wram%d massage_state.heat%d\r\n", warm, massage_state.heat);
switch (warm) {
case strong_heat:
TUYA_APP_LOG_INFO("**********strong_heat************");
gpio_write(HEAT_PIN, 1);
temperature_detection();
break;
case off_heat:
TUYA_APP_LOG_INFO("**********off_heat************");
gpio_write(HEAT_PIN, 0);
break;
default:
break;
}
return 0;
}
?
/*Temperature detection, which is called when heating feature is in high or low level.*/
int temperature_detection(void)
{
int Rntc = 0, Vcc = 0;
adc_channel_checkout(channel_x1);
Vcc = adc_sample_and_get_result(); // Unit: mV
Rntc = Vcc*R25 / (3300-Vcc);
TUYA_APP_LOG_INFO("Rntc_val=%dΩ", Rntc);
if (Rntc >= 5311) { // NTC resistance value is 5311Ω at 40°C.
TUYA_APP_LOG_WARNING("********High Temperature Warning!!!********");
gpio_write(HEAT_PIN, 0); // When the temperature exceeds 40°C, heating will be turned off.
}
return 0;
}
有關 NTC 溫度如何與電阻相關的更多信息,請參閱溫度和電阻之間的關系。
3:強度調整
按摩器提供從弱到強的 15 級強度。我們使用升壓電路實現此功能。
?

?
我們可以改變 P8 輸出的 PWM 波的正占空比來提升電壓。下表列出了具體值。
?

強度通過按鈕調整。單按可增加等級,雙按可降低等級。由于 SDK 配置,P8 在固件刷新后模塊復位時被拉高。因此,我們需要下拉P8。
void boost_init(void)
{
gpio_set_func(BOOST_PIN, AS_PWM0);
gpio_set_output_en(BOOST_PIN, 1);
// PWM0 1ms cycle
pwm_set_mode(PWM0_ID, PWM_NORMAL_MODE);
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, BOOST_PWM_CLOCK_HZ); // When voltage is stepped up, the frequency of PWM is 16M / (968-1) ≈ 16.55 kHz.
pwm_set_phase(PWM0_ID, 0); // No phase at PWM beginning
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (0 * CLOCK_SYS_CLOCK_1US) );
pwm_start(PWM0_ID);
}
初始化后,您可以指定占空比的值來升壓。
void switching_gear(unsigned char gears)
{
if (gears > 15) {
TUYA_APP_LOG_ERROR("*********There is no such gear!!!**********");
}
switch (gears) {
case first_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (10 * CLOCK_SYS_CLOCK_1US) );
break;
case second_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (20 * CLOCK_SYS_CLOCK_1US) );
break;
case third_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (40 * CLOCK_SYS_CLOCK_1US) );
break;
case fourth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (60 * CLOCK_SYS_CLOCK_1US) );
break;
case fifth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (70 * CLOCK_SYS_CLOCK_1US) );
break;
case sixth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (90 * CLOCK_SYS_CLOCK_1US) );
break;
case seventh_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (120 * CLOCK_SYS_CLOCK_1US) );
break;
case eighth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (160 * CLOCK_SYS_CLOCK_1US) );
break;
case ninth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (180 * CLOCK_SYS_CLOCK_1US) );
break;
case tenth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (220 * CLOCK_SYS_CLOCK_1US) );
break;
case eleventh_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (240 * CLOCK_SYS_CLOCK_1US) );
break;
case twelfth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (260 * CLOCK_SYS_CLOCK_1US) );
break;
case thirteenth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (300 * CLOCK_SYS_CLOCK_1US) );
break;
case fourteenth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (340 * CLOCK_SYS_CLOCK_1US) );
break;
case fifteenth_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (360 * CLOCK_SYS_CLOCK_1US) );
break;
case max_gear:
pwm_set_cycle_and_duty(PWM0_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US), (u16) (360 * CLOCK_SYS_CLOCK_1US) );
break;
default:
break;
}
}
4:斷電記憶
將設備掉電前的狀態數據寫入可用的閃存中。當設備再次上電時從閃存中讀取數據。這樣,設備上電后可以恢復到之前的狀態。
TLSR8253芯片的flash如下圖所示。
?

?
0x040000
to0x060000
是設備可以寫入數據的未使用空間。
1.將狀態寫入閃存。
/***********************************************************
* Function: write_massage_status_to_flash
* Input: none
* Output: none
* Return: none
* Notice: Write massager status to the flash memory.
***********************************************************/
void write_massage_status_to_flash(void)
{
Flash_Write_Buff[0] = massage_state.on_off;
Flash_Write_Buff[1] = massage_state.pattern;
Flash_Write_Buff[2] = massage_state.gear;
Flash_Write_Buff[3] = massage_state.heat;
flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
return;
}
2.從閃存中讀取狀態。
/***********************************************************
* Function: write_massage_status_to_flash
* Input: none
* Output: none
* Return: none
* Notice: Write massager status to the flash memory.
***********************************************************/
void write_massage_status_to_flash(void)
{
Flash_Write_Buff[0] = massage_state.on_off;
Flash_Write_Buff[1] = massage_state.pattern;
Flash_Write_Buff[2] = massage_state.gear;
Flash_Write_Buff[3] = massage_state.heat;
flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
return;
}/**********************************************************************
* Function: read_massage_status_to_flash
* Input: none
* Output: none
* Return: none
* Notice: Read the massager status data before power-off from the flash memory, and save it to the status struct.
**********************************************************************/
void read_massage_status_to_flash(void)
{
flash_read_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Read_Buff);
// Store the data read from the flash memory into the struct.
massage_state.on_off = Flash_Read_Buff[0];
massage_state.pattern = Flash_Read_Buff[1];
massage_state.gear = Flash_Read_Buff[2];
massage_state.heat = Flash_Read_Buff[3];
return;
}
/***********************************************************
* Function: erase_massage_flash
* Input: none
* Output: none
* Return: none
* Notice: Restore defaults
***********************************************************/
void erase_massage_flash(void)
{
massage_state.on_off = OFF;
massage_state.pattern = relieve;
massage_state.gear = first_gear;
massage_state.heat = off_heat;
Flash_Write_Buff[0] = OFF;
Flash_Write_Buff[1] = relieve;
Flash_Write_Buff[2] = first_gear;
Flash_Write_Buff[3] = off_heat;
flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
return;
}
- 恢復默認值。
/***********************************************************
* Function: erase_massage_flash
* Input: none
* Output: none
* Return: none
* Notice: Restore defaults
***********************************************************/
void erase_massage_flash(void)
{
massage_state.on_off = OFF;
massage_state.pattern = relieve;
massage_state.gear = first_gear;
massage_state.heat = off_heat;
Flash_Write_Buff[0] = OFF;
Flash_Write_Buff[1] = relieve;
Flash_Write_Buff[2] = first_gear;
Flash_Write_Buff[3] = off_heat;
flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
return;
}
5:云端控制
對于低功耗藍牙模塊,單個數據點 (DP) 的所有數據都存儲在一個數組中。以 DP ID 104 為例。它的數組如下。
unsigned char mode_buf[] = {0x68, 0x04, 0x01, 0x00}; //{DP_ID, DP_type, DP_len, DP_data}
tuya_ble_dp_data_report(mode_buf, 4); // Data reporting function.
調用tuya_ble_dp_data_report(uint8_t *p_data,uint32_t len)
將單個DP的狀態數據上報到云端。
來自移動應用程序的控制命令存儲在數組中dp_data_array[255+3]
。您可以編寫一個DP數據發送處理函數,并dp_data_array[255+3]
作為參數傳遞給該函數tuya_cb_handler(tuya_ble_cb_evt_param_t* event)
,tuya_ble_demo.c
以實現從移動應用程序發送命令。
void app_dp_handle(uint8_t *dp_data)
{
printf("dp_data:%d %d %d %d\r\n", dp_data[0], dp_data[1], dp_data[2], dp_data[3]);
switch (dp_data[0]) {
case 0x66:
if (dp_data[3] == strong_heat) {
massage_state.heat = strong_heat;
} else {
massage_state.heat = off_heat;
}
printf("dp_data[3]:%d massage_state.heat:%d\r\n", dp_data[3], massage_state.heat);
if (!app_flag) {
switching_heat(massage_state.heat);
}
break;
case 0x67:
printf("dp_data[3]:%d \r\n", dp_data[3]);
switch (dp_data[3]) {
case first_gear:
massage_state.gear = first_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case second_gear:
massage_state.gear = second_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case third_gear:
massage_state.gear = third_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case fourth_gear:
massage_state.gear = fourth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case fifth_gear:
massage_state.gear = fifth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case sixth_gear:
massage_state.gear = sixth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case seventh_gear:
massage_state.gear = seventh_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case eighth_gear:
massage_state.gear = eighth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case ninth_gear:
massage_state.gear = ninth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case tenth_gear:
massage_state.gear = tenth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case eleventh_gear:
massage_state.gear = eleventh_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case twelfth_gear:
massage_state.gear = twelfth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case thirteenth_gear:
massage_state.gear = thirteenth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case fourteenth_gear:
massage_state.gear = fourteenth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case fifteenth_gear:
massage_state.gear = fifteenth_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
case max_gear:
massage_state.gear = max_gear;
if (!app_flag) {
switching_gear(massage_state.gear);
}
break;
default:
break;
}
break;
case 0x68:
if (dp_data[3] == relieve) {
massage_state.pattern = relieve;
} else if (dp_data[3] == vitality) {
massage_state.pattern = vitality;
} else if (dp_data[3] == hammering) {
massage_state.pattern = hammering;
} else if (dp_data[3] == scraping_therapy) {
massage_state.pattern = scraping_therapy;
} else {
massage_state.pattern = intelligent;
}
break;
case 0x69:
if (dp_data[3] == ON) {
massage_state.on_off = ON;
rs2255_init();
voice_prompt_init();
pattern_pin_init();
app_flag = 0;
} else {
massage_state.on_off = OFF;
power_off_init();
app_flag = 1;
}
break;
default:
break;
}
}
第 5 步:設備控制
在手機上安裝涂鴉智能應用或智能生活應用。它們在移動應用市場上可用。打開應用程序并單擊右上角的+圖標以配對設備。設備連接后,您可以通過應用程序對其進行控制。
概括
恭喜!您已成功設計出智能頸部按摩器的原型。
這款多功能物聯網按摩器與 TENS 技術相結合,有助于緩解頸部酸痛和疼痛。內置NTC傳感器,采用先進的精確恒溫控制技術,可改善血液循環,緩解疼痛、結節和肌肉緊張。基于這個項目,您可以探索更多很棒的功能!
涂鴉物聯網平臺提供便捷的物聯網開發工具和服務,旨在讓您的物聯網項目更輕松、更高效。查看并發現更多很棒的想法。
?
- 原型板電源連接器開源分享
- 搖臂轉向架輪椅原型開源硬件
- bm1387b原型v1開源分享
- 原型板28針PIC開源分享
- Arduino UNO的原型板開源分享
- 智能家居控制系統方案開源資料
- SBC 85 Pad per hole原型板開源
- STM32原型機開源
- 頭部按摩器電路 15次下載
- 原型板開源項目
- 通用PCB原型板開源項目
- zw7-40.5高原型35kv高壓真空斷路器廠家
- 開源網絡協議分析器WireShark軟件下載 15次下載
- WIFI智能開源電熱水器的原理圖和源代碼免費下載 47次下載
- 電子按摩器電路及制作
- 智能頸部按摩儀拆解 392次閱讀
- fpga原型驗證平臺與硬件仿真器的區別 1184次閱讀
- 按摩器按鍵與LED控制電路拆解分析 1457次閱讀
- 按摩椅顯示屏的EMC問題整改方案 1637次閱讀
- 開源激光雷達原型平臺 2624次閱讀
- 基于語音芯片的共享按摩椅設計 1532次閱讀
- 典型的按摩器數碼管顯示電路 4212次閱讀
- digilent開源微控制器介紹 1653次閱讀
- firefly智能音樂按摩器 1816次閱讀
- 電動按摩椅的使用好處及常見電路故障分析 9462次閱讀
- 電子按摩器的電路原理及常見故障和維修方法 3.9w次閱讀
- 適用于30V1A的按摩器電源方案芯片 5707次閱讀
- NASA的開源軟件是什么?NASA的開源軟件的詳細分析 7444次閱讀
- 在按摩椅中模擬人體手指的壓力傳感器 5158次閱讀
- 教您打造小型、控制精確的超舒適智能按摩椅 3366次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數據手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅動電路設計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論