电子发烧友App

硬声App

0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示
创作
电子发烧友网>电子资料下载>电子资料>智能颈部按摩器原型开源分享

智能颈部按摩器原型开源分享

2023-06-15 | zip | 0.00 MB | 次下载 | 2积分

资料介绍

描述

概述

无论是因为睡得怪怪的、玩手机太多,还是弯腰坐着盯着电脑看几个小时,我们大多数人都会时不时地处理脖子上的扭结。缓解颈部疼痛的最佳方法之一是按摩疗法。因此,我们改造了传统的颈部按摩器,让它变得聪明,轻松消除压力。

颈部放松按摩器结合了中国传统理疗中的多种按摩手法,采用低频电脉冲技术模拟真人按摩。能促进局部血液循环,有效缓解颈部疲劳和肌肉紧张。由于我们已经使这款按摩器支持物联网,因此我们只需一部手机即可控制它。

特征

  • 五种模式:智能、放松、主动、敲击和刮擦。不同的模式让您体验不同的按摩乐趣。
  • 15级强度由弱到强:您可以自由调节适合自己的强度。
  • 三级温度调节:高、低、关。持续的热按摩可以放松血管和颈部肌肉。

硬件

 
pYYBAGNof1-AFuF2AACpjHWAGVE051.png
 

脚步

第 1 步:硬件设计

使用涂鸦智能智能生活应用程序实现远程控制,我们使用涂鸦的BTU 网络模块作为微控制器

电路由BTU模块、电池充电、语音播放、按键检测、低频脉冲电流输出、加热、温度检测等部分组成。

1.微控制器

 
pYYBAGNof2SARPA4AAM9XBe8QyM624.png
 

 

poYBAGNof2eAOt-rAALzh_FfYM0081.png
 

 

2. 功能模块

NTC热敏电阻是环氧树脂涂层的小尺寸,用于温度测量。它具有电阻范围广、精度稳定性和灵敏度高、响应速度快等特点。对于热敏电阻的参数,我们使用:B=3950,R=10k。

 

poYBAGNof2qANsVWAAAZsy4jOv4452.png
 

 

  • 温度与电阻的关系

 

pYYBAGNof3CAc4iBAAUgcjr7q7k403.png
 
  • 温度检测电路

 

pYYBAGNof3KAIMtJAAAduF__51A240.png
 

模块的 ADC 收集电压并将其转换为温度值。然后,模块相应地调整温度。

  • 加热丝

白线是发热丝。

 

pYYBAGNof3WATHL2AAAktQlmfig990.png
 
  • 加热回路

 

poYBAGNof3eAakL5AAApAkKkTOM072.png
 

模块上的P7输出PWM波来调节电热丝的温度。当 P7 输出低电平时,加热关闭。当 P7 以某个频率输出方波时,发热处于低水平。当 P7 输出高电平时,加热处于高电平。

  • 扬声器

 

pYYBAGNof3qALh6DAAAWN6yffdc095.png
 
 
poYBAGNof36AE5KGAABmKRMDbv8316.png
 

在单线串口模式下,BTU模块可以通过DATA线控制和发送数据到语音芯片,进行语音播放、停止、循环等。

  • 电极垫

按摩器上有两个不锈钢电极垫。

 

pYYBAGNof4CAd6JSAAA5n56qYSk792.png
 

 

poYBAGNof4OAZ-rNAABqiHSZCQw393.png
 

低频脉冲电流输出

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。内置保护电路,防止过充、过放、过流、短路。

 

poYBAGNof4aAdr9-AAA0y-5FZCk806.png
 

尺寸:10 毫米(厚)x 23 毫米(宽)x 30 毫米(长)

 

poYBAGNof4iAaxZ_AAC77XtDlxg867.png
 

电池充电器电路和升压电路

  • 电池充电器电路:XT2051是单节锂离子电池的恒流恒压充电器电路。该组件包括一个内部功率晶体管,不需要外部电流检测电阻器和阻塞二极管。XT2051 需要最少的外部元件并符合 USB 总线规范。它非常适合现场的便携式应用。
  • 升压电路原理:当三极管MMBT5551导通时,肖特基二极管D1处于反向偏置状态。通过电感器 L1 到晶体管 Q1 的电流完成了一个电路。施加到升压电感器的输入电压被转换成磁能进行存储。当三极管Q1关断时,肖特基二极管D1正向偏置,电感中的磁能转化为电能。该电压与输入电压一起为负载供电并为输出电容器 C6 充电。需要几个脉冲来提供足够的能量来增加输出电压。

 

第 2 步:创建产品

本节介绍如何在涂鸦IoT平台上创建智能颈椎按摩器有关详细信息,请参阅创建产品

1.登录涂鸦IoT平台

2.在标准类别选项卡上,单击运动与健康>运动与健康填写产品信息并选择蓝牙作为协议。

pYYBAGNof42AEltCAACLqE8oCg0142.png
 

3.点击创建后,出现添加标准函数对话框。保留三个选定的所需功能。自定义函数部分中,单击添加并创建两个函数。有关要设置的项目,请参见下面的屏幕截图。

poYBAGNof5CAaMS9AAEItdIVats167.png
 

4.在设备面板步骤中,选择DIY风格面板然后,进入硬件开发,选择涂鸦标准模块 SDKBT3L 蓝牙模块单击屏幕右侧的获取 10 个免费许可证。您将在编码中获得 UUID、密钥和 MAC 地址。

第 3 步:获取 SDK 并设置 IDE

poYBAGNof5OAA9HUAACuIaGZpsM149.png
 

安装 IDE 后,导入您的项目。

  • 用项目开发1.编辑产品ID。
pYYBAGNof5mAAZ8YAAHRxDIhXos731.png
 

2.编辑auth_keydevice_idmac

 

poYBAGNof5yAIULDAAIkjvXXIVk068.png
 

 

poYBAGNof6CAHfFpAAIXDpWwptw205.png
 

3.编译代码。

 

pYYBAGNof6KARGHYAAHOnK8-eLY039.png
 

 

pYYBAGNof6iAa9TpAAF4JkXG6Qc535.png
 

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 接头。

 

poYBAGNof62AMdKYAAVnWCxL7JU017.png
 

 

注意日志打印的引脚默认为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 控制三极管的开/关以产生电脉冲并启用不同的脉冲模式。

 

poYBAGNof4OAZ-rNAABqiHSZCQw393.png
 

 

  • 波形图

P9 和 P24 输出 PWM 信号,正占空比为 26.5%,周期为 1 ms。注意这两个引脚不能同时输出高电平。否则三极管会烧坏。

以 30 ms 的间隔一次输出四个 PWM 波,以实现放松模式。

pYYBAGNof7KAQ48uAAFga_QesqQ854.png
 

一个脉冲有四个 PWM 波,如上图所示。以 30 ms 的间隔产生脉冲。

pYYBAGNof7aAWQzpAAFBuNsImOg538.png
 
  • 模式实现

五种脉冲模式是通过改变脉冲间隔来实现的,如下表所示。

pYYBAGNof7iAeeRVAAAqy_5ACcI137.png
 

 

实现代码

引脚初始化

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 极性。

 

poYBAGNof7uAKyIHAABzMqUtM2E925.png
 

 

由于 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

 

poYBAGNof76AGhi8AAD9fFd-L4M516.png
 
  • 工作电压:2.8V至5.2V
  • 在待机模式下,静态电流小于 5 μA。
  • 带有内置电阻器 (+/- 1%) 的精确嵌入式振荡器支持低电压复位(LVR=1.8V)和看门狗复位。
  • 高品质 12 位 PWM 直接驱动 8Ω 0.5W 扬声器或蜂鸣器。DAC转换器音频输出可以通过外部音频放大器放大音量。
  • 内置看门狗。
  • 串口控制方式:单线串口和两线串口。最多可加载 224 条语音。
  • 支持忙碌状态下的输出功能。

 

pYYBAGNof8CAVzx8AABXtJVRtrc694.png
 

单线串行通讯

在单线串口模式下,BTU模块可以通过DATA线控制和发送数据到语音芯片,进行语音播放、停止、循环等。

引脚 描述 PA1 DATA PA2 BUSY 数据(十六进制) 功能 00H 不播放音频。01H 第一次音频播放。02H 第二次音频播放。…… …… DFH 第 222 段音频播放。

  • 引脚配置
poYBAGNof8WAD3PcAAAMzeFN34g257.png
 
  • 单行音频地址关联

 

pYYBAGNof8eAQY17AAAnL2Qr5Sk104.png
 

 

单线串口时序图

将数据线拉低至 5ms,然后发送 8 位数据,先低位,后高位。用高电平与低电平的比值来表示每个数据位的值。

 

poYBAGNof8mAVuXvAAA2fc97RpA023.png
 

 

pYYBAGNof8yAODXeAAA4ykPlYF8383.png
 

 

实现代码

  • 引脚初始化
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:加热

 

poYBAGNof4OAZ-rNAABqiHSZCQw393.png
 

 

我们向上或向下拉 P7 来控制加热的开/关。颈部按摩器有一个内置传感器来检测温度。当温度超过 40°C 时,将关闭加热以避免过热。

 

poYBAGNof3eAakL5AAApAkKkTOM072.png
 

 

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 级强度。我们使用升压电路实现此功能。

 

poYBAGNof4iAaxZ_AAC77XtDlxg867.png
 

 

我们可以改变 P8 输出的 PWM 波的正占空比来提升电压。下表列出了具体值。

 

pYYBAGNof9iAGPjtAAAlYb2iVuE883.png
 

强度通过按钮调整。单按可增加等级,双按可降低等级。由于 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如下图所示。

 

poYBAGNof9uARR3xAABJoYPGEqA283.png
 

 

0x040000to0x060000是设备可以写入数据的未使用空间。

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传感器,采用先进的精确恒温控制技术,可改善血液循环,缓解疼痛、结节和肌肉紧张。基于这个项目,您可以探索更多很棒的功能!

涂鸦物联网平台提供便捷的物联网开发工具和服务,旨在让您的物联网项目更轻松、更高效。查看并发现更多很棒的想法。

 
 
 

 


下载该资料的人也在下载 下载该资料的人还在阅读
更多 >

评论

查看更多

下载排行

本周

  1. 1山景DSP芯片AP8248A2数据手册
  2. 1.06 MB  |  532次下载  |  免费
  3. 2RK3399完整板原理图(支持平板,盒子VR)
  4. 3.28 MB  |  339次下载  |  免费
  5. 3TC358743XBG评估板参考手册
  6. 1.36 MB  |  330次下载  |  免费
  7. 4DFM软件使用教程
  8. 0.84 MB  |  295次下载  |  免费
  9. 5元宇宙深度解析—未来的未来-风口还是泡沫
  10. 6.40 MB  |  227次下载  |  免费
  11. 6迪文DGUS开发指南
  12. 31.67 MB  |  194次下载  |  免费
  13. 7元宇宙底层硬件系列报告
  14. 13.42 MB  |  182次下载  |  免费
  15. 8FP5207XR-G1中文应用手册
  16. 1.09 MB  |  178次下载  |  免费

本月

  1. 1OrCAD10.5下载OrCAD10.5中文版软件
  2. 0.00 MB  |  234315次下载  |  免费
  3. 2555集成电路应用800例(新编版)
  4. 0.00 MB  |  33566次下载  |  免费
  5. 3接口电路图大全
  6. 未知  |  30323次下载  |  免费
  7. 4开关电源设计实例指南
  8. 未知  |  21549次下载  |  免费
  9. 5电气工程师手册免费下载(新编第二版pdf电子书)
  10. 0.00 MB  |  15349次下载  |  免费
  11. 6数字电路基础pdf(下载)
  12. 未知  |  13750次下载  |  免费
  13. 7电子制作实例集锦 下载
  14. 未知  |  8113次下载  |  免费
  15. 8《LED驱动电路设计》 温德尔著
  16. 0.00 MB  |  6656次下载  |  免费

总榜

  1. 1matlab软件下载入口
  2. 未知  |  935054次下载  |  免费
  3. 2protel99se软件下载(可英文版转中文版)
  4. 78.1 MB  |  537798次下载  |  免费
  5. 3MATLAB 7.1 下载 (含软件介绍)
  6. 未知  |  420027次下载  |  免费
  7. 4OrCAD10.5下载OrCAD10.5中文版软件
  8. 0.00 MB  |  234315次下载  |  免费
  9. 5Altium DXP2002下载入口
  10. 未知  |  233046次下载  |  免费
  11. 6电路仿真软件multisim 10.0免费下载
  12. 340992  |  191187次下载  |  免费
  13. 7十天学会AVR单片机与C语言视频教程 下载
  14. 158M  |  183279次下载  |  免费
  15. 8proe5.0野火版下载(中文版免费下载)
  16. 未知  |  138040次下载  |  免费