一、前言
按摩仪主要有物理按摩和电脉冲两种,本项目为电脉冲类型,其原理是通过电极感应金属片,用脉冲技术对颈椎进行刺激,从而缓解颈椎酸痛。
市场上按摩仪的常见功能主要有敲打、锤击、揉捏、针灸、推拿、刮痧、恒温热敷等,本项目中实现了舒缓、活力、锤击拍打、刮痧、智能五个模式。
1、原理图
各种模式的实现是通过P9和P24两个IO口控制三极管的通断从而产生电脉冲来实现。
2、波形图
P9和P24分别产生正占空比为26.5%,周期为1ms的PWM波,但不能同时为高电平,否则会烧毁三级管(需特别注意)。
一次产生四束PWM波后等待30ms再次产生四束波,循环往复即可实现舒缓模式的功能效果。
图中一个脉冲中有四束PWM波,其波形如上图所示。脉冲与脉冲之间的时间为30ms。
3、各模式实现原理
舒缓、活力、锤击拍打、刮痧、智能五个模式是通过脉冲之间的时间间隔来实现的,如下表:
模式 | 脉冲时间间隔 |
---|---|
舒缓模式 | 30ms |
活力模式 | 20ms |
锤击拍打模式 | 40ms |
刮痧模式 | 50ms |
智能模式 | 随机产生20 30 40 50ms |
4、功能代码
相关引脚初始化
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 1000Hz
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); //to enable the pwm polarity
pwm_start(PWM1_ID);
//PWM5 1ms cycle 26.5% duty 1000Hz
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极性改变一下就可以了。
控制PWM个数以及脉冲时间间隔都是通过延时来实现的难免会有误差,大家有更好的实现方式也可以提出来一起交流。由于SDK没有涉及到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); // 延时480us,防止同时置高烧毁三极管
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/30/40/50ms
break;
default:
break;
}
return;
}