资料介绍
描述
概述
无论是因为睡得怪怪的、玩手机太多,还是弯腰坐着盯着电脑看几个小时,我们大多数人都会时不时地处理脖子上的扭结。缓解颈部疼痛的最佳方法之一是按摩疗法。因此,我们改造了传统的颈部按摩器,让它变得聪明,轻松消除压力。
颈部放松按摩器结合了中国传统理疗中的多种按摩手法,采用低频电脉冲技术模拟真人按摩。能促进局部血液循环,有效缓解颈部疲劳和肌肉紧张。由于我们已经使这款按摩器支持物联网,因此我们只需一部手机即可控制它。
特征
- 五种模式:智能、放松、主动、敲击和刮擦。不同的模式让您体验不同的按摩乐趣。
- 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智能开源电热水器的原理图和源代码免费下载 46次下载
- 电子按摩器电路及制作
- fpga原型验证平台与硬件仿真器的区别 828次阅读
- 【AWTK开源智能串口屏方案】方案介绍和工作原理 744次阅读
- 按摩器按键与LED控制电路拆解分析 879次阅读
- 按摩椅显示屏的EMC问题整改方案 1330次阅读
- 开源激光雷达原型平台 2235次阅读
- 基于语音芯片的共享按摩椅设计 1311次阅读
- 典型的按摩器数码管显示电路 4039次阅读
- digilent开源微控制器介绍 1492次阅读
- firefly智能音乐按摩器 1684次阅读
- 电动按摩椅的使用好处及常见电路故障分析 9172次阅读
- 电子按摩器的电路原理及常见故障和维修方法 3.7w次阅读
- 适用于30V1A的按摩器电源方案芯片 5365次阅读
- NASA的开源软件是什么?NASA的开源软件的详细分析 7188次阅读
- 在按摩椅中模拟人体手指的压力传感器 4955次阅读
- 教您打造小型、控制精确的超舒适智能按摩椅 3150次阅读
下载排行
本周
- 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次下载 | 免费
评论
查看更多