制作一款可以尝尽百味的勺子

更新时间Invalid date

概况

2013年,新加坡国立大学实验室的研究人员公开了一款合成味觉的交互设备原型,它可以通过电流和温度来模拟人类几种原始味觉。

原来,人类在进食的时候,舌头味蕾会产生相应的生物电,并传到大脑,让大家食而知其味。这款设备的原理也有几分相似:通过不同的电流和温度刺激,来产生一些原始的味道,比如说酸甜苦咸。

对于不同的人类原始味觉,它们需要什么样“参数”来“欺骗”大脑呢?大致如下:

  • 酸味:60-180uA 的电流、舌头温度从20℃上升到30℃

  • 甜味:反向电流、舌头温度先升到35℃,再缓慢降低至20℃

  • 苦味:60-140uA 的反向电流

  • 咸味:20-50uA 的低频率电流

涂鸦智能开发者团队开发出了一款智能设备—百味勺子,从电流,温度等方面刺激舌头,让大脑模拟出对应的味觉。

百味勺子可以用来改善食物的口味。比如,通过电流刺激模拟咸味使原本低盐度食物吃起来像是正常盐度,通过模拟甜味来使糖尿病患者在进食时可以品尝到更接近正常饮食的甜度,提供了健康保障的同时提高了的生活质量。

步骤

  • 第 1 步:硬件设计

    sys

    主控单元

    主控芯片选择涂鸦智能开发的嵌入式蓝牙模组。

    电源管理系统

    百味勺子为了做到整体小巧精致且方便携带,因此电源需要选择能量比高、自放电率低的锂电池。

    为了安全管理锂电池充放电,以及延长其工作寿命,需要设计一套电源管理电路。

    芯片方面,可以选用业内常用的 TP4056 芯片。这是一款恒流恒压线性充电芯片,采用了内部 PMOSFET 架构,内置防倒充电路。芯片具有热反馈功能,可对充电电流进行自动调节,以便在大功率操作或高环境温度条件下对芯片温度加以限制。其充电电压固定在 4.2V,而充电电流可通过一个电阻器进行外部设置。当充电电流在达到最终浮充电压之后降至设定值的 1/10 时,TP4056 将自动终止充电循环。

    电源管理电路原理图

    charge

    V_IN 为 USB 输入的 5V 电压,V_BAT 连接锂电池的正极(锂电池的负极记得连 GND),CE 脚是芯片使能端,只有 CE 脚高电平的时候,TP4056 才会正常工作。

    • STDBY 脚是电池充电完成指示端。当电池充电完成时,该脚被内部开关拉到低电平,表示充电完成。除此之外,该管脚都将处于高阻态。

    • CHRG 脚是漏极开路输出的充电状态指示端。当充电器向电池充电时, 该管脚被内部开关拉到低电平,表示充电正在进行;否则该管脚处于高阻态。

      说明:开发者可以在 STDBY 和 CHRG 脚分别添加绿色和红色两个 LED。这样,当锂电池正在充电时,红灯点亮,当充电完成,绿灯点亮。

    • PROG 脚是恒流充电电流设置和充电电流监测端。从 PROG 管脚连接一个外部电阻到地端可以对充电电流进行编程。在预充电阶段,此管脚的电压被调制在 0.1V;在恒流充电阶段,此管脚的电压被固定在 1V。在充电状态的所有模式,测量该管脚的电压都可以根据下面的公式来估算充电电流 Ibat=1200*Vprog/Rprog。

      注意

      • 为了防止大电流充电,造成芯片和电池温度上升,开发者把充电最大电流设置为 0.8A。根据公式可知,Rprog=1200*Vprog/Ibat。
      • 其中 Ibat 取 0.8A,Vprog 取 1V,计算得 Rprog=1.5K 欧姆。如果开发者想加大电流,在此基础上适当减小 Rprog 电阻即可。

    • TEMP脚是电池温度检测输入端。将 TEMP 管脚接到电池的 NTC 传感器的输出端。如果 TEMP 管脚的电压小于输入电压的 45% 或者大于输入电压的 80%,意味着电池温度过低或过高,则充电被暂停。如果 TEMP 直接接 GND,电池温度检测功能取消,其他充电功能正常

      说明:为了减少开发周期,开发者可以将 R16 或者 R14 焊 0 欧姆电阻,以取消该功能。如果开发者希望启用,可以联系涂鸦智能获取专业技术支持。

    关于该芯片的其他详情,请查看 TP4056数据手册

    电流调制系统

    百味勺子的核心功能就是产生一定大小和频率的电流以刺激人体舌头模拟产生味觉,因此可靠稳定的电流调制系统非常重要。

    电流调制主要有两部分组成:电流频率的调制和电流大小的调制。我们经过反复测试验证,设计出了下面这款电路:

    current

    由于锂电池一般只有 3.6V 左右,而后面要用到的数字电位器的推荐工作电压为 5V,还需要负载条件下满足恒流输出。3.6V 锂电池的裕量预计不够,因此,我们需要先进行升压操作。

    选择升压芯片

    可以采用德州仪器的 LM2733X 系列芯片。该芯片内置40V DMOS FET,开关频率高达 1.6MHz,输出电流可达1A。它的输入电压范围很宽,2.7V~14V 均可,锂电 3.6V 电平完全满足它的要求。更多详情,请参考 LM2733X 数据手册

    我们需要调制 R1 和 R5 的阻值,使得输出在 5V 附近。根据手册可知,LM2733X 输出电压 Vout=Vfb*(1+R5/R1),其中 Vfb 的典型值为 1.23V。本案例中 R1 选择 10K,R5 选择 33K,这样计算出 Vout 大约为 5.3V 左右。开发者也可以根据自己的需要,升压至别的电压点,但是不建议超过7V,因为数字电位器工作耐压为 7V,超过 7V 会损坏器件。

    电流频率调制

    接下来是频率调制电路,开发者可以通过两个不同沟道的 MOS 管,组合成一个控制电路。

    • 当 S_tongue 信号为高电平时,Q5 MOS 管导通,电流允许通过 Q5,给后面的电路供电;
    • 当 S_tongue 信号为低电平时,Q5 MOS 管截止,Q5 后面的器件停止工作,没有输出。

    通过控制 S_tongue 信号的周期和占空比,开发者可以实现后端负载电压的频率控制,从而实现负载电流的频率调制。

    电流大小调制

    可以采用一颗 LDO 和一颗数字电位器。

    本案例中,

    • U2(LDO)采用比较常用的 AMS1117-33。它是一个正向低压降稳压器,内部集成过热保护和限流电路,最大可以输出 1A 电流,输入电压最高允许 12V,输出稳压到 3.3V,输出精度误差仅在 1% 以内。更多详情,请参考 AMS1117数据手册

    • U7(数字电位器)采用 X9C104SIZT1。它是一种数控可编程的电阻器,可以采用数控方式调节电阻值,具有调节精度高、低噪声、抗干扰、无机械磨损等显著优点,是电流调节电路中的关键器件。

      数字电位器一般由输入控制,计数控制和译码,非易失性存贮器及电阻阵列三部分组成。输入控制部分的工作就像一个升/降计数器。这个计数器的输出被译码而接通一个单接点的电子开关,以便把电阻阵列上的一个点接到滑动输出端。在适当的条件下, 计数器的内容可以贮存在非易失性存贮器中并保持以便今后使用。电阻阵列包含99 个单独的电阻,他们以串联的形式连接。在二个终端端点以及每个电阻之间都有一个电子开关,可将该点的电位传输到滑动端。其中,

      • RH 和 RL 等效于一个机械电位器的固定端。

      • RW 是滑动端,等效于一个机械电位器的可移动端。滑动端在电阻阵列中的位置由控制输入脚决定。

      • U/D 是升/降输入脚,用于控制滑动端移动的方向。

      • INC 是增加输入脚,由负边沿触发。触发 INC 将使滑动端向计数器增加或减少的方向移动,移动的方向由 U/D 端输入的逻辑电平决定。

        更多详情,请参考 X9C104SIZT1 数据手册

    电流大小调制的原理如下:

    当电流调制电路工作时,LDO 的 R+ 和 R- 两端的电压大小为 Vref(3.3V),R+ 和 R- 两端的电阻大小为 U7(数字电位器)接入电阻的大小 Rs。

    可以计算出

    • LDO 的 R+ 和 R- 两端流经的电流大小 Is=Vref/Rs。
    • 流经负载端的总电流 I=Is+Iss。

    其中 Iss 为 LDO 的静态漏电流,方向由 LDO 的公共端流向 GND。不同型号的 LDO,Iss 也存在差异,但是由于 Iss 比较小,与 Is 相比可以忽略不急。

    因此,流经负载端的总电流可以简化为 I≈Is=Vref/Rs

    由公式可知,当 LDO 选型确定后,因 Vref 为定值,开发者只需通过程序改变 Rs 的阻值,即可调节系统的输出电流大小。

    电路通过 J5 放电,可以使舌头感受到电流刺激。

    温度控制系统

    温度控制系统主要分为加热部分和温度检测控制部分。原理图如下:

    heat

    加热器件

    选择市面上常用的 PI 聚酰亚胺电热膜。它是一种三明治结构的半透明金属柔性电热膜,以金属箔﹑金属丝为内导电发热体,经高温高压热合而成。聚酰亚胺薄膜电热膜具有优异的绝缘强度,抗电强度,热传导效率,电阻稳定性,这使得它能够广泛地适用于加热领域并能够获得相当高的温度控制精度。开发者可以选择将带胶的 PI 电热膜直接贴在 PCB 板上,如上图中把电热膜的引脚焊接在 J3 位置。

    温度检测控制

    Q2 为 P 沟道 MOS 管,Q3 为 N 沟道 MOS 管,工作原理如下:

    • 当 S_Heat 信号为高电平时,Q2 MOS 管导通,J3 处的电热膜开始加热;
    • 当 S_Heat 信号为低电平时,Q2 MOS 管截止,J3 处的电热膜停止加热。

    想做到温度控制,除了加热之外,当然还需要温度检测。这部分,开发者可以采用德州仪器的 TIMP75 数字温度传感器。

    它是负温度系数 (NTC) 和正温度系数 (PTC) 热敏电阻的理想替代产品,支持 SMBus™、两线制和 I2C 三种接口,在-40°C 至 125°C 范围内精度为 ±1°C。 TMP75 静态电流只有 50μA, 待机电流只有 0.1μA。该器件无需校准或外部组件信号调节即可提供典型值为 ±1°C 的精度。器件温度传感器为高度线性化产品,无需复杂计算或查表即可得知温度。片上 12 位模数转换器 (ADC) 提供低至 0.0625°C 的分辨率。更多详情请参考 TMP75数据手册

    至此,百味勺子核心电路已经设计完毕,完整原理图和示例 PCB 可从以下链接中获取。开发者还可以根据自身的需求和创意,增加一些小功能,比如 LED、按键、USB通信等。

  • 第 2 步:外观结构设计

    电路设计完成后,您还需要发挥创意,给勺子设计一个好看的外形结构。

    这边我们给大家起个头,抛砖引玉,非常欢迎大家来交流自己的奇思妙想。

    spoon

    设计图如下所示:

  • 第 3 步:创建产品

    1. 登录 涂鸦 IoT 平台

    2. 选择 创建产品

    3. 在页面左下角,选择 其他

    4. 自定义创建 区域内,填写参数后单击 创建产品

      • 产品名称、产品描述、产品型号:用户自定义填写。
      • 通讯协议:选择 蓝牙

    5. 功能定义 页签中,添加自定义功能。功能点可以根据需求自行增减,功能点名称以及属性也可根据需求自行修改。

      本方案中需要添加以下自定义功能点:低电量报警、味觉、电流、频率、温度。数据类型和参数值参考下图。

    6. 设备面板 页签中,按照界面提示选择 App 面板。调试阶段推荐选择开发调试面板便于测试。

    7. 硬件开发 页签中,选择 涂鸦标准模组 SDK开发

    8. 选择一款模组后,单击 免费领取10个激活码

    9. 选择 授权码清单 后,将清单表格下载到本地以备后续软件开发使用。

      至此,产品创建阶段已经基本完成。

  • 第 4 步:软件开发

    功能需求

    功能名称 说明 备注
    复位配网 快速上下电三次 总电源按键实现
    电量提示 电量不足提示用户充电 App 提示是否需要充电
    基本味觉 酸、甜、苦、咸 控制电流、频率、温度三个参数
    用户自定义 用户可自由调整电流、频率、温度三个参数 App 上可调节这三个参数

    获取 SDK

    下载 单点 BLE SDK。请仔细阅读 readme 文件,以了解 Flash 布局划分、调试输出引脚和波特率。

    环境搭建

    本案例开发使用泰凌微官方 IDE,下载和使用请参考 泰凌微 TLSR8 芯片官方文档

    工程开发

    1. 将 PID 修改为前文创建产品过程中产生的 PID。

    2. 修改 auth_keydevice_idmac 为前文下载的授权码清单中的参数。

    3. 修改 void tuya_ble_app_init(void) 函数。

    4. 编译。

    功能实现

    复位配网

    百味勺子只有一个物理按键,同时复用为电源键和配网按键。电源按键直接将模组断电而非进入低功耗休眠模式。当用作配网按键时,通过快速上下电三次模组会解除与当前已绑定设备的信息,重新进入配网模式新设备可以正常连接。如果为同一台设备须在APP上解除与当前产品的绑定即可重新配网。

    复位配网原理

    设立一个配网标志位,在第一次断电重新上电后将标志位的值写入 Flash,第二次上电时标志位的值加 1,以此类推。同时开启一个定时器,当时间到某一个设定值(判定设备已进入正常工作状态)后清除当前 Flash 中的标志位。第三次上电时会调用函数 tuya_ble_device_factory_reset()进行设备重置,同时添加一个配网指示灯显示当前联网状态。快闪表示进入配网模式等待设备连接,常亮表示设备已配网。功能实现代码如下:

    // 清除flash中断电配网标志位
    static int clear_ble_flag(void)
    {
    	Flash_Write_Buff[0] = 0;
    	flash_erase_sector(FLASH_ADDR);
    	flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
    	blt_soft_timer_delete(&clear_ble_flag);
    	return 0;
    }
    
    //通断电三次配网
    uint8_t switch_setup_network(void)
    {
    	blt_soft_timer_add(&clear_ble_flag, 5000*TIME_MS);	// 设备正常使用5s后清除flash中断电配网标志位
    	flash_read_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Read_Buff);
    	Flash_Write_Buff[0] = Flash_Read_Buff[0];
    	TUYA_APP_LOG_INFO("Flash_Read_Buff[1] = %d", Flash_Read_Buff[0]);
    
    	// 上下电三次重新配网
    	if (Flash_Read_Buff[0] < POWER_COUNT) {
    		Flash_Write_Buff[0]++;
    		flash_erase_sector(FLASH_ADDR);
    		flash_write_page(FLASH_ADDR, FLASH_BUFF_LEN, (unsigned char *)Flash_Write_Buff);
    	} else {
    		TUYA_APP_LOG_INFO("start connect new device");
    		tuya_ble_device_factory_reset();	// 断开与当前设备的连接(会清除已绑定设备的信息),进入配网模式
    	}
    
    	return Flash_Write_Buff[0];
    }
    
    void led_connect_status(void)		//配网指示灯状态判断 loop中调用
    {
    	if (BONDING_CONN == status_flag) {
    		gpio_write(BLE_LED_PIN, 0);
    	} else {
    		if (clock_time_exceed(time_tick, TIME_MS * 400)) {
    			time_tick = clock_time();
    
    			gpio_toggle(BLE_LED_PIN);
    		}
    	}
    }
    

    其中,switch_setup_network()会在初始化函数中调用,led_connect_status()在loop中调用。

    电量提示

    通过 ADC 采集到电池电压,当电压值低于总电压的 10%(电池电压为3.5V)时会在 App 上报警提示用户对设备充电。get_battery_value()在 loop 中调用,每 10 秒采集一次电池电压。

    / ADC采样频率14位,参考电压1.2V
    static unsigned int get_adc_value(void)
    {
    	adc_init();
    	adc_base_init(BATTERY_ADC_PORT);
    	adc_power_on_sar_adc(1);
    	return adc_sample_and_get_result();
    }
    
    // 电池电压采集
    unsigned short get_battery_value(void)
    {
    	if (!clock_time_exceed(battery_time_tick, TIME_MS*10000)) {
    			return 0;
    	}
    	battery_time_tick = clock_time();
    
    	unsigned int battery_adc_value = 0;
    
    	battery_adc_value = get_adc_value() * 2;	// 电路分压,实际电池电压 = 2*battery_adc_value
    	if (battery_adc_value <= BATTERY_ADC_LOWER_LIMIT) {	//电量剩余10%APP报警
    		power_alarm_buf[3] = ALARM;
    		tuya_ble_dp_data_report(power_alarm_buf, DP_BUF_LEN); //上报报警状态
    	} else {
    		power_alarm_buf[3] = NORMAL;
    		tuya_ble_dp_data_report(power_alarm_buf, DP_BUF_LEN);
    	}
    	TUYA_APP_LOG_INFO("battery_val = %dmv", battery_adc_value);
    
        return battery_adc_value;
    }
    

    味觉

    味觉主要有基本味觉和用户自定义。基本味觉主要有酸、甜、苦、咸四个口味。App 端下发味觉的相应命令,通过控制模组的几个引脚外加加热电路,控制输出微电流刺激舌头产生这几种味觉。微电流的产生是通过 X9C104 电位器调节阻值大小实现的。

    用户自定义功能中的开放电流、频率、温度三个参数,可以让用户自行调节出其他的味道。

    void app_dp_handle(uint8_t *dp_data)
    {
    	TUYA_APP_LOG_INFO("dp_data:%d  %d  %d  %d", dp_data[0], dp_data[1], dp_data[2], dp_data[3]);
    
    	switch (dp_data[0]) {
    	// 味觉 酸、甜、苦、咸
    	case 0x66:
    		switch (dp_data[3]) {
    		case sour:
    			spoon_state.temp = sour_temp;
    			blt_soft_timer_delete(&sweet_temp_contorl);
    			blt_soft_timer_delete(&bitter_temp_contorl);
    			gpio_write(TONGUE_PIN, 1);
    			x9c104s_set(_140uA);
    //			blt_soft_timer_add(&sour_temp_contorl, 200*TIME_MS);
    			break;
    		case sweet:
    			spoon_state.temp = heat_off;
    //			blt_soft_timer_delete(&sour_temp_contorl);
    			blt_soft_timer_delete(&bitter_temp_contorl);
    			gpio_write(TONGUE_PIN, 1);
    			x9c104s_set(_80uA);
    			blt_soft_timer_add(&sweet_temp_contorl, 200*TIME_MS);
    			break;
    		case bitter:
    			spoon_state.temp = heat_off;
    //			blt_soft_timer_delete(&sour_temp_contorl);
    			blt_soft_timer_delete(&sweet_temp_contorl);
    			gpio_write(TONGUE_PIN, 1);
    			x9c104s_set(_100uA);
    			blt_soft_timer_add(&bitter_temp_contorl, 200*TIME_MS);
    			break;
    		case salty:
    			spoon_state.temp = heat_off;
    //			blt_soft_timer_delete(&sour_temp_contorl);
    			blt_soft_timer_delete(&sweet_temp_contorl);
    			blt_soft_timer_delete(&bitter_temp_contorl);
    			x9c104s_set(_60uA);
    			blt_soft_timer_add(&set_tongue_Hz, _hz100);
    			break;
    		case user_defined:
    //			blt_soft_timer_sour_tempdelete(&sour_temp_contorl);
    			blt_soft_timer_delete(&sweet_temp_contorl);
    			blt_soft_timer_delete(&bitter_temp_contorl);
    			x9c104s_set(_60uA);
    			blt_soft_timer_add(&set_tongue_Hz, _hz100);
    			break;
    		default:
    			break;
    		}
    		break;
    
    	// 电流调节 自定义模式下使用
    	case 0x67:
    		switch (dp_data[3]) {
    		case uA_20:
    			x9c104s_set(_20uA);
    			break;
    		case uA_40:
    			x9c104s_set(_40uA);
    			break;
    		case uA_60:
    			x9c104s_set(_60uA);
    			break;
    		case uA_80:
    			x9c104s_set(_80uA);
    			break;
    		case uA_100:
    			x9c104s_set(_100uA);
    			break;
    		case uA_120:
    			x9c104s_set(_120uA);
    			break;
    		case uA_140:
    			x9c104s_set(_140uA);
    			break;
    		case uA_180:
    			x9c104s_set(_180uA);
    			break;
    		case uA_200:
    			x9c104s_set(_200uA);
    			break;
    		default:
    			break;
    		}
    		break;
    
    	// 频率调节 自定义模式下使用
    	case 0x68:
    		switch  (dp_data[3]) {
    		case hz_50:
    			blt_soft_timer_add(&set_tongue_Hz, _hz50);
    			break;
    		case hz_100:
    			blt_soft_timer_add(&set_tongue_Hz, _hz100);
    			break;
    		case hz_200:
    			blt_soft_timer_add(&set_tongue_Hz, _hz200);
    			break;
    		case hz_400:
    			blt_soft_timer_add(&set_tongue_Hz, _hz400);
    			break;
    		case hz_600:
    			blt_soft_timer_add(&set_tongue_Hz, _hz600);
    			break;
    		case hz_800:
    			blt_soft_timer_add(&set_tongue_Hz, _hz800);
    			break;
    		case hz_1000:
    			blt_soft_timer_add(&set_tongue_Hz, _hz1000);
    			break;
    		case hz_0:
    			blt_soft_timer_delete(&set_tongue_Hz);
    			gpio_write(TONGUE_PIN, 1);
    			break;
    		default:
    			break;
    		}
    		break;
    
    	// 温度调节 自定义模式下使用
    	case 0x69:
    		switch (dp_data[3]) {
    		case T_30:
    			break;
    		case T_31:
    			spoon_state.temp = temp_31;
    			break;
    		case T_32:
    			spoon_state.temp = temp_32;
    			break;
    		case T_33:
    			spoon_state.temp = temp_33;
    			break;
    		case T_34:
    			spoon_state.temp = temp_34;
    			break;
    		case T_35:
    			spoon_state.temp = temp_35;
    			break;
    		case T_36:
    			spoon_state.temp = temp_36;
    			break;
    		case T_37:
    			spoon_state.temp = temp_37;
    			break;
    		case T_38:
    			spoon_state.temp = temp_38;
    			break;
    		case T_39:
    			spoon_state.temp = temp_39;
    			break;
    		case T_40:
    			spoon_state.temp = temp_40;
    			break;
    		default:
    			break;
    		}
    		break;
    	default:
    		break;
    	}
    }
    
  • 第 5 步:烧录授权

    请参考 涂鸦 BLE 模组烧录授权 进行烧录授权。

小结

好吧,大家带着手中的百味勺子,结合涂鸦智能APP,一起去探索那些未知的美味吧。

涂鸦物联网开发平台为开发者提供了便捷的 IoT 开发工具与服务,助力开发者更高效的完成设备接入,并为开发者提供物联网应用开发及场景服务能力。

更进一步