[PSOC™] 【英飞凌PSOC 4000T DIY】温奶器DIY原型设计实现

[复制链接]
 楼主| jobszheng 发表于 2025-5-26 02:39 | 显示全部楼层 |阅读模式
<
本帖最后由 jobszheng 于 2025-5-26 02:43 编辑

        在完成了使用英飞凌PSOC 4000T的基础功能实验后,我们进入本次DIY的实现环节——温奶器的DIY。
一、概述
        国家在鼓励生育,做为电子工程师我也利用自身的技术所长做出支持。我申请英飞凌PSoC 4000T Protokit评估板用来DIY一个婴幼儿温奶与消毒器小家电。温奶器一般有恒温水壶和消毒仓组成,通过控制面板设置恒温水温度和控制功能。我家里的温奶器的控制面板人机交互按钮使用的是电容式按键,平时使用时也挺方便的,但是电容式按键一旦滴上水,按键便不再灵敏。温奶器无论在消毒,还是倒水的时候滴上水是很正常的现象。理论上擦干即可,可我家这个不知道为什么擦干要等些时间,而在等待期间按键失灵,温奶器也不能正常工作。虽然我也是电子工程师,但我也没搞懂。这其中的关联不过我知道,如果可以带水操作,则上述问题定不会存在英飞凌PSOC 4000T就可以解决我的问题。还有另外一个问题:我家小宝宝已经3岁,他可以踮着脚伸手触碰到我温奶器的按键。我家的温奶器却没有一个童锁!有时候我们发现温奶器没有正常工作以为系统自己复位了,后来才了解到是小家伙直接给关闭掉了!
二、硬件设计
        英飞凌PSOC 4000T系列是基于ARM公司Cortex-M0+内核设计的一款多传感器用途的MCU,适配英飞凌自家的CapSense第五代专利技术,轻松实现高效、准确、稳定的电感按键采样与识别。
        英飞凌还有一项更加令人兴奋的硬件功能特性——悬停按键,这也实现了隔离触发按键的功能。悬停生效 时,这对小朋友来说仅靠模仿怕是非常困难,也能成功地把小朋友误操作设备导致烫伤的可能性排除了。我们设计了基于英飞凌PSOC 4000T-MS开发板套件的原理设计硬件框图。


2.1 硬件框图
        从上面的硬件框图,我们看到UART外设用于与温奶器的主控MCU通讯,后者需要显示LED屏与控制加热器加热,采集温度传感器获取温度等等。
考虑到本次DIY的时间略紧,以PC机串口为通讯接口。这也满足PSOC 4000T的原型开发的需求。
2.2 硬件配置
        对于硬件外设的配置,我们使用ModusToolBox中的Device Configurator工具软件实现。我们依次配置如下外设:系统时钟,外设分频时钟,串口外设,CapSense外设,GPIO等
系统时钟
        系统时钟使用HSI的48MHz。即英飞凌PSOC 4000T将工作在48MHz的主频下。
外设分频时钟
        我们使用了串口外设,需要我们使用PSOC 4000T的16位,分频时钟,为其提供时钟源输入,具体配置如下:

串口时钟
        SCB串口时钟,在设置了分频时钟后,即可在SCB UART外设界面配置UART时钟,之后将其配置参数设置为115200-8-N-1即可。
CapSense
        本次原型开发使用了4键按键的硬件扩展板。故参照官方示例配置。
GPIO配置
        GPIO主要用于显示设备状态。对于温奶器来说,设备状态使用主控MCU来完成,而PSOC 4000T的LED灯仅使用于我们调试时使用。以上就是我们的硬件配置,接下来我们看看软件设计实现。
三、软件设计
        硬件设计参照英飞凌ModusToolBox来实现,软件外设底层代码也是通过ModusToolBox来实现。其实在device configurator保存一下,代码便自动生成了,自己修改一下主函数的调用即可完成.
3.1 软件流程图

3.2 按键通讯帧
        流程图相对简单,主要是我们将PSOC 4000T的功能点减少,仅作为输入情况处理与主控MCU通讯的数据格式。我们采用类似标准键盘上报键码的形式。以固定长度为一个通讯帧,通过空闲帧和帧头标识来做帧首,帧尾判断,源代码如下:
  1. typedef struct key_frame_s {
  2.         uint8_t id;
  3.         uint8_t func_key;
  4.         uint8_t reserved0;
  5.         uint8_t key[4];
  6.         uint8_t reserved1;
  7. } key_frame_t;

        帧首:第1个字节,固定标识号0x55,用于帧首判断。非此值,则将此帧丢弃。
        功能按键:按位表示功能按键,最多支持8个功能按键。其中按下生效时置位,抬起时清零。
        Key键码域:共4个字节,每次通讯时填充键码值,即按键被按下时依次写入K0、K1、K2、K3。当被按键抬起时,再重新发送此时按下状态的一帧键码。
3.3 程序关键代码
        按键上报代码:
  1. static void uart_msg_poll(void) {
  2.         int ret = 0;
  3.         if (CAPSENSE_WIDGET_INACTIVE
  4.                         != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON0_WDGT_ID,
  5.                                         &cy_capsense_context)) {
  6.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED1_PORT, CYBSP_KEYPAD_LED1_NUM,
  7.                 CYBSP_LED_ON);
  8.                 key_frame.key[0] = CY_CAPSENSE_BUTTON0_WDGT_ID;
  9.         } else {
  10.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED1_PORT, CYBSP_KEYPAD_LED1_NUM,
  11.                 CYBSP_LED_OFF);
  12.                 key_frame.key[0] = 0;
  13.         }

  14.         if (CAPSENSE_WIDGET_INACTIVE
  15.                         != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON1_WDGT_ID,
  16.                                         &cy_capsense_context)) {
  17.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED2_PORT, CYBSP_KEYPAD_LED2_NUM,
  18.                 CYBSP_LED_ON);
  19.                 key_frame.key[1] = CY_CAPSENSE_BUTTON1_WDGT_ID;
  20.         } else {
  21.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED2_PORT, CYBSP_KEYPAD_LED2_NUM,
  22.                 CYBSP_LED_OFF);
  23.                 key_frame.key[1] = 0;
  24.         }

  25.         if (CAPSENSE_WIDGET_INACTIVE
  26.                         != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON2_WDGT_ID,
  27.                                         &cy_capsense_context)) {
  28.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED3_PORT, CYBSP_KEYPAD_LED3_NUM,
  29.                 CYBSP_LED_ON);
  30.                 key_frame.key[2] = CY_CAPSENSE_BUTTON2_WDGT_ID;
  31.         } else {
  32.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED3_PORT, CYBSP_KEYPAD_LED3_NUM,
  33.                 CYBSP_LED_OFF);
  34.                 key_frame.key[2] = 0;
  35.         }

  36.         if (CAPSENSE_WIDGET_INACTIVE
  37.                         != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON3_WDGT_ID,
  38.                                         &cy_capsense_context)) {
  39.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED4_PORT, CYBSP_KEYPAD_LED4_NUM,
  40.                 CYBSP_LED_ON);
  41.                 key_frame.key[3] = CY_CAPSENSE_BUTTON3_WDGT_ID;
  42.         } else {
  43.                 Cy_GPIO_Write(CYBSP_KEYPAD_LED4_PORT, CYBSP_KEYPAD_LED4_NUM,
  44.                 CYBSP_LED_OFF);
  45.                 key_frame.key[3] = 0;
  46.         }
  47.         ret = key_frame_update_check(&key_frame, &key_frame_shadow);
  48.         if (ret != 0) {
  49.                 Cy_SCB_UART_PutArrayBlocking(UART_HW, &key_frame, sizeof(key_frame_t));
  50.                 key_frame_sync(&key_frame, &key_frame_shadow);
  51.         }
  52. }
       主函数源代码(包含低功耗):
  1. int main(void) {
  2.         cy_rslt_t result;
  3.         uint32_t capsense_state_timeout;
  4.         uint32_t interruptStatus;
  5.         cy_stc_scb_uart_context_t UART_context;

  6. #if ENABLE_RUN_TIME_MEASUREMENT
  7.     static uint32_t active_processing_time;
  8.     static uint32_t alr_processing_time;
  9. #endif

  10.         /* Initialize the device and board peripherals */
  11.         result = cybsp_init();

  12. #if ENABLE_RUN_TIME_MEASUREMENT
  13.     init_sys_tick();
  14. #endif

  15.         /* Board init failed. Stop program execution */
  16.         if (result != CY_RSLT_SUCCESS) {
  17.                 CY_ASSERT(CY_ASSERT_FAILED);
  18.         }

  19.         /* Configure and enable the UART peripheral */
  20.         Cy_SCB_UART_Init(UART_HW, &UART_config, &UART_context);
  21.         Cy_SCB_UART_Enable(UART_HW);

  22.         /* Enable global interrupts */
  23.         __enable_irq();

  24.         /* Register callbacks */
  25.         register_callback();

  26.         /* Define initial state of the device and the corresponding refresh rate*/
  27.         capsense_state = ACTIVE_MODE;
  28.         capsense_state_timeout = ACTIVE_MODE_TIMEOUT;

  29.         /* Initialize MSC CAPSENSE™ */
  30.         initialize_capsense();

  31.         /* Measures the actual ILO frequency and compensate MSCLP wake up timers */
  32.         Cy_CapSense_IloCompensate(&cy_capsense_context);

  33.         /* Configure the MSCLP wake up timer as per the ACTIVE mode refresh rate */
  34.         Cy_CapSense_ConfigureMsclpTimer(ACTIVE_MODE_TIMER, &cy_capsense_context);

  35. //Cy_SCB_UART_PutString(UART_HW, "Hello PSoC 4000T, Hello 21ic.com\r\n");
  36.         Cy_SCB_UART_PutArrayBlocking(UART_HW, uart_tx_buf, 8);

  37.         for (;;) {
  38.                 switch (capsense_state) {
  39.                 case ACTIVE_MODE:

  40.                         Cy_CapSense_ScanAllSlots(&cy_capsense_context);

  41.                         interruptStatus = Cy_SysLib_EnterCriticalSection();

  42.                         while (Cy_CapSense_IsBusy(&cy_capsense_context)) {
  43.                                 Cy_SysPm_CpuEnterDeepSleep();

  44.                                 Cy_SysLib_ExitCriticalSection(interruptStatus);

  45.                                 /* This is a place where all interrupt handlers will be executed */
  46.                                 interruptStatus = Cy_SysLib_EnterCriticalSection();
  47.                         }

  48.                         Cy_SysLib_ExitCriticalSection(interruptStatus);

  49. #if ENABLE_RUN_TIME_MEASUREMENT
  50.                 active_processing_time=0;
  51.                 start_runtime_measurement();
  52. #endif

  53.                         Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

  54.                         /* Scan, process and check the status of the all Active mode sensors */
  55.                         if (Cy_CapSense_IsAnyWidgetActive(&cy_capsense_context)) {
  56.                                 capsense_state_timeout = ACTIVE_MODE_TIMEOUT;
  57.                         } else {
  58.                                 capsense_state_timeout--;

  59.                                 if (TIMEOUT_RESET == capsense_state_timeout) {
  60.                                         capsense_state = ALR_MODE;
  61.                                         capsense_state_timeout = ALR_MODE_TIMEOUT;

  62.                                         /* Configure the MSCLP wake up timer as per the ALR mode refresh rate */
  63.                                         Cy_CapSense_ConfigureMsclpTimer(ALR_MODE_TIMER,
  64.                                                         &cy_capsense_context);
  65.                                 }
  66.                         }

  67. #if ENABLE_RUN_TIME_MEASUREMENT
  68.                 active_processing_time=stop_runtime_measurement();
  69. #endif

  70.                         break;
  71.                         /* End of ACTIVE_MODE */

  72.                         /* Active Low Refresh-rate Mode */
  73.                 case ALR_MODE:

  74.                         Cy_CapSense_ScanAllSlots(&cy_capsense_context);

  75.                         interruptStatus = Cy_SysLib_EnterCriticalSection();

  76.                         while (Cy_CapSense_IsBusy(&cy_capsense_context)) {
  77.                                 Cy_SysPm_CpuEnterDeepSleep();

  78.                                 Cy_SysLib_ExitCriticalSection(interruptStatus);

  79.                                 /* This is a place where all interrupt handlers will be executed */
  80.                                 interruptStatus = Cy_SysLib_EnterCriticalSection();
  81.                         }

  82.                         Cy_SysLib_ExitCriticalSection(interruptStatus);

  83. #if ENABLE_RUN_TIME_MEASUREMENT
  84.                 alr_processing_time=0;
  85.                 start_runtime_measurement();
  86. #endif

  87.                         Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

  88.                         /* Scan, process and check the status of the all Active mode sensors */
  89.                         if (Cy_CapSense_IsAnyWidgetActive(&cy_capsense_context)) {
  90.                                 capsense_state = ACTIVE_MODE;
  91.                                 capsense_state_timeout = ACTIVE_MODE_TIMEOUT;

  92.                                 /* Configure the MSCLP wake up timer as per the ACTIVE mode refresh rate */
  93.                                 Cy_CapSense_ConfigureMsclpTimer(ACTIVE_MODE_TIMER,
  94.                                                 &cy_capsense_context);
  95.                         } else {
  96.                                 capsense_state_timeout--;

  97.                                 if (TIMEOUT_RESET == capsense_state_timeout) {
  98.                                         capsense_state = WOT_MODE;

  99.                                 }
  100.                         }

  101. #if ENABLE_RUN_TIME_MEASUREMENT
  102.                 alr_processing_time=stop_runtime_measurement();
  103. #endif

  104.                         break;
  105.                         /* End of Active-Low Refresh Rate(ALR) mode */

  106.                         /* Wake On Touch Mode */
  107.                 case WOT_MODE:

  108.                         Cy_CapSense_ScanAllLpSlots(&cy_capsense_context);

  109.                         interruptStatus = Cy_SysLib_EnterCriticalSection();

  110.                         while (Cy_CapSense_IsBusy(&cy_capsense_context)) {
  111.                                 Cy_SysPm_CpuEnterDeepSleep();

  112.                                 Cy_SysLib_ExitCriticalSection(interruptStatus);

  113.                                 /* This is a place where all interrupt handlers will be executed */
  114.                                 interruptStatus = Cy_SysLib_EnterCriticalSection();
  115.                         }

  116.                         Cy_SysLib_ExitCriticalSection(interruptStatus);

  117.                         if (Cy_CapSense_IsAnyLpWidgetActive(&cy_capsense_context)) {
  118.                                 capsense_state = ACTIVE_MODE;
  119.                                 capsense_state_timeout = ACTIVE_MODE_TIMEOUT;

  120.                                 /* Configure the MSCLP wake up timer as per the ACTIVE mode refresh rate */
  121.                                 Cy_CapSense_ConfigureMsclpTimer(ACTIVE_MODE_TIMER,
  122.                                                 &cy_capsense_context);
  123.                         } else {
  124.                                 capsense_state = ALR_MODE;
  125.                                 capsense_state_timeout = ALR_MODE_TIMEOUT;

  126.                                 /* Configure the MSCLP wake up timer as per the ALR mode refresh rate */
  127.                                 Cy_CapSense_ConfigureMsclpTimer(ALR_MODE_TIMER,
  128.                                                 &cy_capsense_context);
  129.                         }

  130.                         break;
  131.                         /* End of "WAKE_ON_TOUCH_MODE" */

  132.                 default:
  133.                         /**  Unknown power mode state. Unexpected situation.  **/
  134.                         CY_ASSERT(CY_ASSERT_FAILED);
  135.                         break;
  136.                 }
  137.                 uart_msg_poll();

  138. #if ENABLE_TUNER
  139.                 /* Establishes synchronized communication with the CAPSENSE™ Tuner tool */
  140.                 Cy_CapSense_RunTuner(&cy_capsense_context);
  141. #endif
  142.         }
  143. }

四、DIY成果与创新点
        先来上一段视频转换的gif动图。
        通过上面的视频,可以看到我们的英飞凌PSOC 4000T成功识别出来我的按键操作。也可以看到在按键按下后,英飞凌PSOC 4000T快速的通过串口上报了键码。当按键抬起时,我们英飞凌PSOC 4000T也迅速的发送空值的键码。通过串口的实时键码上报,可以让主控MCU及时获取到按键的状态,从而做出正确的控制执行操作。
        本次DIY利用了英飞凌PSOC 4000 T MS套件的电感触摸按键和悬浮按键的优秀性能。在根本上解决了温奶器面板在滴水时,遇到电容按键失灵的严重用户体验问题。悬浮按键技术又解决了小朋友爱模仿,多动手操作的天性下“误按”按键带来的烫伤的风险。我个人觉得英飞凌PSOC 4000T为下一代按键面板的理想选择。我们又体验了英飞凌PSOC  4000T的平衡成本与性能,虽然仅预留了一个Uart外设接口,仍轻松通过协议帧完成按键操作的实时响应与数据上报操作。
五、致谢
        感谢英飞凌中国提供这么高大上的开发套件,让我充分感受到英飞凌中国对国内工程师的热情,践行了英飞凌“在中国,服务中国”的口号。
        感谢21ic论坛,感谢21ic小跑堂的大力支持。
        感谢一直关注我DIY活动的网友们!
        谢谢你们!我们英飞凌论坛天天见!











本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
星辰大海不退缩 发表于 2025-5-26 16:21 | 显示全部楼层
非常不错的案例分享
小夏天的大西瓜 发表于 2025-5-27 10:19 | 显示全部楼层
非常不错的DIY设计
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:嵌入式技术专家
简介:热爱开源,乐于分享。在嵌入式技术领域里面,主攻通讯协议,Modbus,TCP/IP以及虚拟化和RTOS

30

主题

740

帖子

23

粉丝
认证:嵌入式技术专家
简介:热爱开源,乐于分享。在嵌入式技术领域里面,主攻通讯协议,Modbus,TCP/IP以及虚拟化和RTOS

30

主题

740

帖子

23

粉丝
快速回复 在线客服 返回列表 返回顶部