1. Overall System Design Scheme
This intelligent massager control system is centered around the STM32F103C8T6 microcontroller, integrating motor drive modules, pressure sensor modules, temperature sensor modules, Bluetooth communication modules, power management modules, and human-computer interaction modules. It achieves various functions such as mode switching, intensity adjustment, timing control, and user status monitoring. The overall system architecture is shown in Figure 1, consisting mainly of five parts: the main control unit, sensor unit, execution unit, power unit, and interaction unit.
2. Hardware Design
2.1 Core Control Module
The main control chip selected is the STM32F103C8T6, which is based on the ARM Cortex-M3 core, with a main frequency of 72MHz, 64KB Flash, and 20KB SRAM. It has a rich set of peripheral interfaces, including 3 USARTs, 2 SPIs, 2 I2Cs, 1 CAN, and 16 ADC channels, fully meeting the system control requirements. The minimum system circuit includes a reset circuit, crystal oscillator circuit, and download circuit, where the reset circuit uses a button reset method, and the crystal oscillator circuit uses an 8MHz external crystal, which is multiplied to 72MHz via PLL.
2.2 Motor Drive Module
The system uses the MX1616 dual-channel motor driver chip, which supports a voltage input of 2.5V-10V, with a maximum continuous output current of 1.5A per channel and a peak current of 3A. Motor speed and direction control can be achieved through PWM signals. A 12V vibration motor is used to implement three massage modes: kneading, tapping, and vibrating. The driving circuit is shown in Figure 2, where the TIM2 and TIM3 timers of the STM32 generate PWM signals to control the IN1/IN2 pins of the MX1616, achieving motor speed adjustment; the OUT1/OUT2 pins connect to the vibration motor, allowing intensity adjustment from 0 to 5 levels by changing the PWM duty cycle (0-100%).
2.3 Sensor Module
2.3.1 Pressure Sensor
The thin-film pressure sensor FSR402 is used to detect whether the user is in contact with the massage head, with its output resistance decreasing as pressure increases. The sensor signal is conditioned by a voltage follower formed by the LM358 operational amplifier and connected to the ADC1 channel of the STM32, obtaining the pressure value through AD conversion. When the pressure value exceeds a threshold (which can be set via a button), the system automatically starts the massage function; otherwise, it enters standby mode to reduce power consumption.
2.3.2 Temperature Sensor
The DS18B20 digital temperature sensor is selected, connected to the GPIO pin of the STM32 via a single bus, to monitor the temperature of the massage head in real-time. When the temperature exceeds 45℃, the system automatically stops heating and alarms to prevent burns to the user. The sensor interface circuit is shown in Figure 3, using an external pull-up resistor (4.7KΩ) to ensure signal stability.
2.4 Power Management Module
The power module is powered by a lithium battery (3.7V/2000mAh), converted to 12V for motor power using the FP6293 boost chip, while providing a 3.3V power supply for the STM32 and other peripherals through the AMS1117-3.3V voltage regulator chip. The FP6293 is a high-efficiency synchronous boost converter with an input voltage range of 2.6V-5.5V, adjustable output voltage (up to 13V), and an output current of up to 1.4A, meeting the motor drive requirements. The power circuit is shown in Figure 4, including a battery protection circuit (to prevent overcharging and over-discharging) and a power indication circuit.
2.5 Human-Computer Interaction Module
2.5.1 Buttons and Display
The system is equipped with 5 independent buttons: mode switch button, intensity increase/decrease button, timer button, and start/stop button, each connected to the GPIO pins of the STM32 (configured as pull-up input mode). The display module uses an OLED12864 screen (I2C interface) to display the current massage mode, intensity level, remaining time, and temperature value in real-time.
2.5.2 Bluetooth Module
The JDY-31 Bluetooth module (UART interface) is used, connected to the USART1 of the STM32, to achieve wireless communication with a mobile app. Users can set massage parameters (mode, intensity, time) through the app and check the device status.
2.6 Circuit Schematic
The overall circuit schematic of the system can be obtained by following my public account. Please contact me via private message to receive it. The schematic mainly includes the minimum system of the STM32, motor drive circuit, sensor interface circuit, power management circuit, and human-computer interaction circuit. Each module is connected through standard interfaces for easy debugging and maintenance.
3. Software Design
3.1 Main Program Flow
The main program adopts a modular design, mainly including system initialization, sensor data acquisition, button scanning, Bluetooth communication, motor control, and display updating modules. After powering on the system, peripheral initialization (GPIO, USART, TIM, ADC, I2C, etc.) is performed first, then it enters the main loop, continuously detecting user input (button or Bluetooth commands), controlling motor operation based on the current mode, and adjusting massage parameters through sensor data. The main program flowchart is shown in Figure 6.
3.2 Key Module Code
3.2.1 System Initialization
C
#include “stm32f10x.h”
#include “delay.h”
#include “oled.h”
#include “motor.h”
#include “key.h”
#include “bluetooth.h”
#include “sensor.h”
void System_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
delay_init(); // Delay function initialization
OLED_Init(); // OLED initialization
Motor_Init(); // Motor driver initialization
Key_Init(); // Button initialization
Bluetooth_Init(); // Bluetooth module initialization
Sensor_Init(); // Sensor initialization (pressure, temperature)
OLED_Clear();
OLED_ShowString(0, 0, “Massage Device”);
OLED_ShowString(0, 2, “Initializing…”);
delay_ms(1000);
}
3.2.2 Motor Control Module
C
// Massage mode definition
typedef enum {
KNEADING = 0, // Kneading mode
TAPPING, // Tapping mode
VIBRATING // Vibrating mode
} MassageMode;
// Motor PWM initialization (TIM2_CH2 and TIM3_CH1)
void Motor_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// Configure PA1 (TIM2_CH2) and PB0 (TIM3_CH1) as alternate push-pull output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Initialize TIM2 (for kneading/tapping motor)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 999; // Period 1000us (frequency 1kHz)
TIM_TimeBaseStructure.TIM_Prescaler = 71; // Prescaler 72, counting frequency 1MHz
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// Initialize TIM3 (for vibrating motor)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// Configure PWM mode
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; // Initial duty cycle 0%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure); // TIM2_CH2
TIM_OC1Init(TIM3, &TIM_OCInitStructure); // TIM3_CH1
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
// Set motor speed (duty cycle 0-1000 corresponds to 0-100%)
void Motor_SetSpeed(uint8_t motor, uint16_t duty)
{
if (duty > 1000) duty = 1000;
if (motor == 0)
{
// Kneading/tapping motor
TIM_SetCompare2(TIM2, duty);
} else {
// Vibrating motor
TIM_SetCompare1(TIM3, duty);
}
}
// Massage mode control
void Massage_Control(MassageMode mode, uint8_t intensity) {
uint16_t duty = intensity * 20; // Intensity 0-5 corresponds to duty cycle 0-1000
switch(mode)
{
case KNEADING:
Motor_SetSpeed(0, duty); // Kneading motor runs
Motor_SetSpeed(1, 0); // Vibrating motor stops
break;
case TAPPING:
// Tapping mode (PWM duty cycle changes periodically)
for (uint8_t i = 0; i < 5; i++)
{
Motor_SetSpeed(0, duty);
delay_ms(200);
Motor_SetSpeed(0, 0);
delay_ms(100);
}
break;
case VIBRATING:
Motor_SetSpeed(0, 0); // Kneading motor stops
Motor_SetSpeed(1, duty); // Vibrating motor runs
break;
default:
break;
}
}
3.2.3 Sensor Data Acquisition
#include “stm32f10x_adc.h”
#include “ds18b20.h”
// Pressure sensor (ADC acquisition)
uint16_t Pressure_Read(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// Configure PC0 as analog input
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// ADC initialization
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
// Temperature sensor (DS18B20)
float Temperature_Read(void)
{
return DS18B20_GetTemp(); // Call DS18B20 driver function
}
// Sensor data processing
void Sensor_Process(void)
{
uint16_t pressure = Pressure_Read();
float temp = Temperature_Read();
// Pressure threshold judgment (start/stop massage)
if (pressure > 2000 && !g_MassageStatus)
{
g_MassageStatus = 1; // Start massage
} else if (pressure < 1000 && g_MassageStatus)
{
g_MassageStatus = 0; // Stop massage
Motor_SetSpeed(0, 0);
Motor_SetSpeed(1, 0);
}
// Temperature protection (stop heating if over 45℃)
if (temp > 45.0)
{
Heating_Stop();
OLED_ShowString(0, 6, “Overheat!”);
}
}
3.2.4 Bluetooth Communication Module
C
#include “usart.h”
// Bluetooth data reception processing
void Bluetooth_Process(uint8_t *data, uint8_t len) {
switch (data[0])
{
case ‘M’: // Set mode (M0: kneading M1: tapping M2: vibrating)
g_Mode = data[1] – ‘0’;
break;
case ‘I’: // Set intensity (I0-I5)
g_Intensity = data[1] – ‘0’;
break;
case ‘T’: // Set time (T5-T30, in minutes)
g_Time = (data[1] – ‘0’) * 10 + (data[2] – ‘0’);
g_RemainTime = g_Time * 60; // Convert to seconds
break;
case ‘S’: // Start/stop control (S1: start S0: stop)
g_MassageStatus = data[1] – ‘0’;
break;
default:
break;
}
// Reply to APP (confirm command received)
uint8_t reply[10] = “ACK:”;
memcpy(reply + 4, data, len);
USART_SendData(USART1, reply, 4 + len);
}
3.2.5 Main Function
int main(void)
{
System_Init(); // System initialization
uint8_t key_val;
g_Mode = KNEADING; // Default mode: kneading
g_Intensity = 3; // Default intensity: level 3
g_Time = 15; // Default time: 15 minutes
g_RemainTime = g_Time * 60;
g_MassageStatus = 0; // Default stop status
while (1)
{
// Sensor data acquisition and processing
Sensor_Process(); // Button scanning
key_val = Key_Scan(0);
switch (key_val)
{
case KEY_MODE_PRESSED: // Mode switch
g_Mode = (g_Mode + 1) % 3;
break;
case KEY_INTENSITY_UP: // Increase intensity
if (g_Intensity < 5) g_Intensity++;
break;
case KEY_INTENSITY_DOWN: // Decrease intensity
if (g_Intensity > 0) g_Intensity–;
break;
case KEY_TIME_PRESSED: // Time setting (5/10/15/20/25/30 minutes)
g_Time = (g_Time % 30) + 5;
g_RemainTime = g_Time * 60;
break;
case KEY_START_STOP: // Start/stop control
g_MassageStatus = !g_MassageStatus;
break;
default:
break;
}
// Bluetooth data reception
if (Bluetooth_GetData())
{
Bluetooth_Process(g_BluetoothData, g_BluetoothLen);
}
// Massage control
if (g_MassageStatus && g_RemainTime > 0)
{
Massage_Control(g_Mode, g_Intensity);
g_RemainTime–;
}
else if (g_RemainTime == 0)
{
g_MassageStatus = 0;
Motor_SetSpeed(0, 0);
Motor_SetSpeed(1, 0);
}
// OLED display update
OLED_Clear();
OLED_ShowString(0, 0, “Mode: “);
switch (g_Mode)
{
case KNEADING: OLED_ShowString(48, 0, “Kneading”); break;
case TAPPING: OLED_ShowString(48, 0, “Tapping “); break;
case VIBRATING:OLED_ShowString(48, 0, “Vibrating”); break;
}
OLED_ShowString(0, 2, “Intensity: “);
OLED_ShowNum(80, 2, g_Intensity, 1);
OLED_ShowString(0, 4, “Time: “);
OLED_ShowNum(48, 4, g_RemainTime / 60, 2);
OLED_ShowString(64, 4, “:”);
OLED_ShowNum(72, 4, g_RemainTime % 60, 2);
OLED_ShowString(0, 6, “Temp: “);
OLED_ShowNum(48, 6, (int)Temperature_Read(), 2);
OLED_ShowString(64, 6, “C”);
delay_ms(100); // Delay 100ms
}}
4. System Testing and Optimization
4.1 Functional Testing
The functional testing of the system mainly includes the following items:
- Massage mode switching: Switching between kneading, tapping, and vibrating modes through buttons or the app, with normal motor operation.
- Intensity adjustment: 0-5 levels of intensity corresponding to different PWM duty cycles (0%, 20%, 40%, 60%, 80%, 100%), with significant changes in vibration amplitude.
- Timing function: 5-30 minutes timing, automatically stopping after the countdown ends.
- Temperature protection: When the temperature exceeds 45℃, the system stops heating and displays an alarm message.
- Bluetooth communication: Normal communication between the mobile app and the device, with command response time < 100ms.
4.2 Performance Optimization
- Power consumption optimization: In standby mode, the motor drive and sensor acquisition are turned off, leaving only the Bluetooth module and button detection, reducing current consumption from 150mA in working state to 30mA.
- Anti-interference design: The sensor signal lines use shielded cables, and the power circuit adds a π-type filter (C=10μF+0.1μF) to reduce electromagnetic interference.
- User experience optimization: Added voice prompt function (using JR6001 voice module) to play prompt sounds during mode switching and when timing ends.
5. Conclusion and Outlook
This design implements an intelligent massager control system based on the STM32F103C8T6 microcontroller. Through modular hardware design and layered software programming, it achieves various functions such as multiple massage modes, intensity adjustment, timing control, and wireless communication. The system has advantages such as small size, low power consumption, and ease of operation, meeting the massage needs of different users. Future optimizations may include:
- Adding a heart rate sensor to implement intelligent massage scheme recommendations based on user physiological status.
- Introducing machine learning algorithms to automatically adjust massage parameters based on user habits.
- Developing a multi-platform app (Android/iOS) to expand remote control and data statistics functions.