一、加湿器介绍
目前市面上加湿器种类各异,有的大几百,有的PDD十元就能入手。大几百那种无外乎多了些大水箱、除菌、适用面积大、加湿量大的特点(真不是我拆不起,手动滑稽,网上看看电器博主他们拆就行),而PDD十来块钱的加湿器仅限于桌面使用,加湿量小、需要频繁加水,办公桌上放一个完全满足使用需求了(这个还是拆的起的)。
上面就是一个自用的桌面加湿器,拆开后包括一个水箱、一个海绵棒、一个雾化片、一块驱动板和若干螺丝。
其中加湿器的核心器件就是雾化片,可以产生超声波震动,利用超声波将液态水击打成水雾,所以其本质属于超声波雾化片。
超声波雾化片有陶瓷雾化片和微孔雾化片两种,二者结构构造不同。
陶瓷雾化片由压电陶瓷片制成,具有压电效应,功率大,驱动往往需要24-48V电压。
微孔雾化片由钢片穿孔而成,中间有细微孔,由海绵棒将水吸上来,经过雾化片细孔喷出,一般适用于小型加湿器中,功率小。本次加湿器里面的雾化片就属于微孔雾化片。
上面优缺点总结可参考链接
https://mp.weixin.qq.com/s/cZOLjkiuTvTekLvInf6NHg
https://mp.weixin.qq.com/s/-QI5WcNj-sg2WMzYbLIPRw
二、雾化片驱动原理介绍
上面文章里也提及了相关的驱动原理,总的来说分为三种。第一种,通过MCU+MOS+升压电感的方式,由MCU输出PWM波,经过MOS进行开关,然后通过升压电感将电压抬升到雾化片的工作电压。第二种,通过专用的雾化片驱动芯片进行驱动,常见的包括SJ303、TTP320、FM8118等,一般不需要MCU参与,驱动芯片上电后自动输出PWM波。第三种,通过NE555生成PWM波。
所以,本质上首先需要一个合适频率(适合雾化片频率)的PWM信号,经过驱动电路后,就可以驱动雾化片震动击打出水雾。
上面是加湿器的驱动板,双面板,上面主要包括USB供电电路、按键、LED、MOS、升压电感、一个8脚SOP封装的芯片(不清楚是MCU还是专用驱动芯片,丝印被打磨掉了)、一个雾化片接口。其中,LED1、LED2用做指示功能;按键SW1用于开关机;U3、C11、C9组成主控电路;R3、R4、Q2组成MOS驱动电路;R6为采样电阻,目的应该是检测电流判断雾化片是否在干烧,但是后面没接到运放和ADC上,应该仅仅是摆设;P1为雾化片接口;T1为升压电感。
由于电路复杂度不高,经过万用表简单测量,大致可以逆向出8脚SOP封装芯片的各个引脚定义。
上面是PWM信号流入MOS后的原理图,仅仅做为原理展示,不代表实际意义。
在U3的PWM引脚处接入飞线,通过示波器观察,可以看到,其输出波形为PWM波,频率为109KHz左右,占空比为46.423%。(理论值为108KHz,占空比50%,由于温度、时钟等原因会存在些许误差,测量到的参数也可以让雾化片正常工作)
三、使用STM32WBA55驱动雾化片
要使用STM32WBA55驱动雾化片,可以借助加湿器驱动板上的驱动电路。将原8脚SOP封装芯片拆掉,转而用STM32WBA55提供一个频率为108KHz,占空比为50%的PWM信号给驱动电路,进而驱动雾化片工作。
通过排针将PWM和GND引出,方便后续接到NUCLEO-WBA55CG开发板上。
配置系统时钟SYSCLK为81MHz,TIM2分频系数为3,计数周期为250。则生成PWM频率为81MHz/3/250=108KHz,占空比为50%。
static void MX_TIM2_Init(void) { /* USER CODE BEGIN TIM2_Init 0 */ /* USER CODE END TIM2_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 2; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 250; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 125; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2); }
int main(void) { /* USER CODE BEGIN 1 */ /* STM32WBAxx HAL library initialization: - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* Configure LD3 */ BSP_LED_Init(LD3); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ICACHE_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ /*## Start PWM signals generation #######################################*/ /* Start channel 1 */ if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1) != HAL_OK) { /* PWM Generation Error */ Error_Handler(); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
四、使用STM32WBA55蓝牙操作雾化片
打开STM32CubeWBA里的BLE_p2pServer例程,按上述步骤配置PWM输出,这里的SYSCLK建议按照例程默认的16MHz使用,然后使用TIM2生成一个近似108KHz的PWM信号。如果更改SYSCLK配置,可能导致BLE协议栈跑不起来(根本原因应该是导致BLE协议栈用到的时钟信号不对),熟悉ST的BLE协议栈可以更改。
上电后,通过ST-LINK的虚拟串口可以打印出BLE协议栈运行信息,根据打印信息可以推断出例程的大致执行顺序,最终发现用户逻辑实现主要在p2p_server_app.c、p2p_server.c文件中。
void P2P_SERVER_Notification(P2P_SERVER_NotificationEvt_t *p_Notification) { /* USER CODE BEGIN Service1_Notification_1 */ /* USER CODE END Service1_Notification_1 */ switch(p_Notification->EvtOpcode) { /* USER CODE BEGIN Service1_Notification_Service1_EvtOpcode */ /* USER CODE END Service1_Notification_Service1_EvtOpcode */ case P2P_SERVER_LED_C_READ_EVT: /* USER CODE BEGIN Service1Char1_READ_EVT */ /* USER CODE END Service1Char1_READ_EVT */ break; case P2P_SERVER_LED_C_WRITE_NO_RESP_EVT: /* USER CODE BEGIN Service1Char1_WRITE_NO_RESP_EVT */ if(p_Notification->DataTransfered.p_Payload[1] == 0x01) { BSP_LED_On(LED_BLUE); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); LOG_INFO_APP("-- P2P APPLICATION SERVER : LED1 ON\n"); P2P_SERVER_APP_Context.LedControl.Led1 = 0x01; /* LED1 ON */ } if(p_Notification->DataTransfered.p_Payload[1] == 0x00) { BSP_LED_Off(LED_BLUE); HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); LOG_INFO_APP("-- P2P APPLICATION SERVER : LED1 OFF\n"); P2P_SERVER_APP_Context.LedControl.Led1 = 0x00; /* LED1 OFF */ } /* USER CODE END Service1Char1_WRITE_NO_RESP_EVT */ break; case P2P_SERVER_SWITCH_C_NOTIFY_ENABLED_EVT: /* USER CODE BEGIN Service1Char2_NOTIFY_ENABLED_EVT */ P2P_SERVER_APP_Context.Switch_c_Notification_Status = Switch_c_NOTIFICATION_ON; LOG_INFO_APP("-- P2P APPLICATION SERVER : NOTIFICATION ENABLED\n"); LOG_INFO_APP(" \n\r"); /* USER CODE END Service1Char2_NOTIFY_ENABLED_EVT */ break; case P2P_SERVER_SWITCH_C_NOTIFY_DISABLED_EVT: /* USER CODE BEGIN Service1Char2_NOTIFY_DISABLED_EVT */ P2P_SERVER_APP_Context.Switch_c_Notification_Status = Switch_c_NOTIFICATION_OFF; LOG_INFO_APP("-- P2P APPLICATION SERVER : NOTIFICATION DISABLED\n"); LOG_INFO_APP(" \n\r"); /* USER CODE END Service1Char2_NOTIFY_DISABLED_EVT */ break; default: /* USER CODE BEGIN Service1_Notification_default */ /* USER CODE END Service1_Notification_default */ break; } /* USER CODE BEGIN Service1_Notification_2 */ /* USER CODE END Service1_Notification_2 */ return; }
由P2P_SERVER_EventHandler调用P2P_SERVER_Notification函数,在上面函数中将开启PWM输出添加到对应点亮LED的逻辑中即可。
五、成果视频
https://www.bilibili.com/video/BV17i9MYfEtB/?vd_source=d04abb16a4fae199fc32e24c366f835d