HomeKit ESP32 Control Light III

快把你家的灯接入HomeKit吧其三(整合篇)

我的回合,抽卡。发动魔法卡–融合!

第一篇文章中介绍了如何控制LED的亮灭,而第二篇文章中介绍了如何控制舵机旋转到指定的角度,那么现在让它们融合起来了吧!

融合前的检测

在LED的Demo中,每次开灯关灯操作都会调用**led_write(bool status)**函数,所以我们只需要根据传进来的status值,旋转舵机到对应的角度即可。

先让我们从mcpwm_servo_control_example.c中提取出需要的方法, 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 引入的头文件

#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"
#include "esp_attr.h"

// 舵机参数的宏定义
#define SERVO_MIN_PULSEWIDTH 500 // 最小脉冲时间ms
#define SERVO_MAX_PULSEWIDTH 2500 // 最大脉冲时间ms
#define SERVO_MAX_DEGREE 180 // 舵机最大可旋转角度

// 初始化2号端口为PWM
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm servo control gpio......\n");
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 2 as PWM0A, to which servo is connected
}

// 该方法输入目标角度,输出对应高电平脉冲宽度单位us
static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
{
uint32_t cal_pulsewidth = 0;
cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
return cal_pulsewidth;
}

// 开灯函数
void turn_on(void *arg)
{
uint32_t angle;
//1. mcpwm gpio 初始化
mcpwm_example_gpio_initialize();
//2. 初始化 mcpwm 配置
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; // 舵机信号频率为50Hz,每个周期时长20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //应用上面配置到 PWM0A & PWM0B
// 旋转角度
printf("Angle of rotation: %d\n", 0);
// 计算60度对应的脉冲宽度
angle = servo_per_degree_init(60);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation at 5V
vTaskDelete(NULL);
}

// 关灯函数
void turn_off(void *arg)
{
uint32_t angle;
//1. mcpwm gpio 初始化
mcpwm_example_gpio_initialize();
//2. 初始化 mcpwm 配置
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //ConfigurePWM0A & PWM0B with above settings
printf("Angle of rotation: %d\n", 0);
// 计算120度对应的脉冲宽度
angle = servo_per_degree_init(120);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate,generally 100ms/60degree rotation at 5V
vTaskDelete(NULL);
}

// 最后修改led_write函数为
void led_write(bool on)
{
if (on)
{
// 接收到开灯命令,执行开灯任务
xTaskCreate(turn_on, "turn_on", 4096, NULL, 5, NULL);
}
else
{
// 接收到关灯命令,执行关灯任务
xTaskCreate(turn_off, "turn_off", 4096, NULL, 5, NULL);
}
}

完整的文件位于
HomeKitServoLight.c

来瞅一瞅效果吧。

现在舵机就听我们的指令了哦!

再配合上一个简陋的结构,就可以控制开关了。
servo_on_light

别担心,最终的成品可不会这样寒酸。
本系列还没有结束,还有第四部分的结构设计,尽请期待吧!

下期预告:快把你家的灯接入HomeKit吧其四(结构设计篇)

参考资料:
ESP-IDF 编程指南

Espressif IoT Development Framework