Compare commits

...

1 Commits

Author SHA1 Message Date
64adab9238 feat: 增加sg90电机文件和服务 2025-08-28 09:54:04 +08:00
10 changed files with 516 additions and 11 deletions

View File

@ -38,6 +38,7 @@
#include "ext_trans_service.h"
#include "display_service.h"
#include "audio_service.h"
#include "switch_control_service.h"
#include <string.h>
#include "imp_out_port.h"
@ -107,12 +108,15 @@ uint8_t _main_task_wake_up_services()
xTaskCreate(imp_ext_trans_service_task,
imp_main_task_table[IMP_TASK_ID_EXT_TRANS_SERVICE_TASK], 2048,
NULL, 10, NULL);
xTaskCreate(imp_display_service_task,
imp_main_task_table[IMP_TASK_ID_DISP_SERVICE_TASK], 8192, NULL,
11, NULL);
xTaskCreate(imp_audio_service_task,
imp_main_task_table[IMP_TASK_ID_AUDIO_SERVICE_TASK], 2048, NULL,
12, NULL);
// xTaskCreate(imp_display_service_task,
// imp_main_task_table[IMP_TASK_ID_DISP_SERVICE_TASK], 8192, NULL,
// 11, NULL);
// xTaskCreate(imp_audio_service_task,
// imp_main_task_table[IMP_TASK_ID_AUDIO_SERVICE_TASK], 2048, NULL,
// 12, NULL);
xTaskCreate(imp_switch_control_service_task,
imp_main_task_table[IMP_TASK_ID_SWITCH_CONTROL_TASK], 2048,
NULL, 12, NULL);
return 0;
}

View File

@ -11,12 +11,14 @@ idf_component_register(
"components/msq_queue"
"components/imp_out_port"
"services/ext_trans_service"
"services/audio_service"
"services/display_service"
"services/switch_control_service"
"utilities/u8g2/src"
"utilities/u8g2/port"
"services/display_service"
"components/screen_pages/test_page"
"components/imp_esp_i2c_master_dev_op"
"services/audio_service"
"components/sg90_servo"
"components/Codec/ES8388"
EXCLUDE_SRCS
@ -33,16 +35,18 @@ idf_component_register(
"utilities/imp_types/"
"components/msq_queue"
"components/imp_out_port"
"services/ext_trans_service"
"utilities/imp_util_tlv_trans_protocol/"
"utilities/u8g2/src"
"utilities/u8g2/port"
"services/ext_trans_service"
"services/display_service"
"services/switch_control_service"
"services/audio_service"
"components/screen_pages/test_page"
"components/imp_esp_i2c_master_dev_op"
"services/audio_service"
"components/Codec/ES8388"
"components/Codec"
"components/sg90_servo"
LDFRAGMENTS
"utilities/letter_shell/port/esp-idf/shell.lf"

View File

@ -0,0 +1,73 @@
/**
* @file imp_comp_sg90.c
* @author Alvin Young (impressionyang@outlook.com)
* @brief
* @version 0.1
* @date 2025-04-14
*
* _ _
* (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
* / / ' \/ _ \/ __/ -_|_-<(_-</ / _ \/ _ \/ // / _ `/ _ \/ _ `/
* /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
* /_/ /___/ /___/
* @copyright Copyright (c) 2025 impressionyang
*
* @par :
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2025-04-14 <td>v1.0 <td>Alvin Young <td>
* </table>
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include "imp_comp_sg90.h"
/* define --------------------------------------------------------------------*/
/* typedef -------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/
/* Private function(only *.c) -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
uint8_t imp_comp_sg90_init(imp_comp_sg90_t* handle, uint8_t gpio,
uint8_t pwm_ch)
{
handle->is_init = 1;
handle->servo_pin = gpio;
handle->servo_pwm_channel = pwm_ch;
handle->speed_mode = LEDC_LOW_SPEED_MODE;
handle->servo_config.channel_number = 1;
handle->servo_config.channels.servo_pin[0] = handle->servo_pin;
handle->servo_config.channels.ch[0] =
pwm_ch > LEDC_CHANNEL_MAX ? LEDC_CHANNEL_MAX : pwm_ch;
handle->servo_config.max_angle = 180;
handle->servo_config.min_width_us = 500;
handle->servo_config.max_width_us = 2500;
handle->servo_config.freq = 50;
handle->servo_config.timer_number = LEDC_TIMER_0;
iot_servo_init(handle->speed_mode, &handle->servo_config);
return 0;
}
uint8_t imp_comp_sg90_set_angle(imp_comp_sg90_t* handle, float angle)
{
iot_servo_write_angle(handle->speed_mode, handle->servo_pwm_channel, angle);
return 0;
}
uint8_t imp_comp_sg90_get_angle(imp_comp_sg90_t* handle, float* angle)
{
iot_servo_read_angle(handle->speed_mode, handle->servo_pwm_channel, angle);
return 0;
}
uint8_t imp_comp_sg90_deinit(imp_comp_sg90_t* handle)
{
iot_servo_deinit(handle->speed_mode);
return 0;
}
/*
* EOF
*/

View File

@ -0,0 +1,60 @@
/**
* @file imp_comp_sg90.h
* @author Alvin Young (impressionyang@outlook.com)
* @brief
* @version 0.1
* @date 2025-04-14
*
* _ _
* (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
* / / ' \/ _ \/ __/ -_|_-<(_-</ / _ \/ _ \/ // / _ `/ _ \/ _ `/
* /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
* /_/ /___/ /___/
* @copyright Copyright (c) 2025 impressionyang
*
* @par :
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2025-04-14 <td>v1.0 <td>Alvin Young <td>
* </table>
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __IMP_COMP_SG90_H__
#define __IMP_COMP_SG90_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "iot_servo.h"
/* define --------------------------------------------------------------------*/
/* typedef -------------------------------------------------------------------*/
typedef struct __imp_comp_sg90_t__
{
uint8_t is_init;
uint8_t speed_mode;
uint8_t servo_pin;
uint8_t servo_pwm_channel;
servo_config_t servo_config;
} imp_comp_sg90_t;
/* variables -----------------------------------------------------------------*/
/* Private function(only *.c) -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
uint8_t imp_comp_sg90_init(imp_comp_sg90_t* handle, uint8_t gpio, uint8_t pwm_ch);
uint8_t imp_comp_sg90_set_angle(imp_comp_sg90_t* handle, float angle);
uint8_t imp_comp_sg90_get_angle(imp_comp_sg90_t* handle, float* angle);
uint8_t imp_comp_sg90_deinit(imp_comp_sg90_t* handle);
#ifdef __cplusplus
}
#endif
#endif //__IMP_COMP_SG90_H__
/*
* EOF
*/

View File

@ -0,0 +1,130 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "esp_err.h"
#include "driver/ledc.h"
#include "iot_servo.h"
static const char *TAG = "servo";
#define SERVO_CHECK(a, str, ret_val) \
if (!(a)) { \
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define SERVO_LEDC_INIT_BITS LEDC_TIMER_10_BIT
#define SERVO_FREQ_MIN 50
#define SERVO_FREQ_MAX 400
static uint32_t g_full_duty = 0;
static servo_config_t g_cfg[LEDC_SPEED_MODE_MAX] = {0};
static uint32_t calculate_duty(ledc_mode_t speed_mode, float angle)
{
float angle_us = angle / g_cfg[speed_mode].max_angle * (g_cfg[speed_mode].max_width_us - g_cfg[speed_mode].min_width_us) + g_cfg[speed_mode].min_width_us;
ESP_LOGD(TAG, "angle us: %f", angle_us);
uint32_t duty = (uint32_t)((float)g_full_duty * (angle_us) * g_cfg[speed_mode].freq / (1000000.0f));
return duty;
}
static float calculate_angle(ledc_mode_t speed_mode, uint32_t duty)
{
float angle_us = (float)duty * 1000000.0f / (float)g_full_duty / (float)g_cfg[speed_mode].freq;
angle_us -= g_cfg[speed_mode].min_width_us;
angle_us = angle_us < 0.0f ? 0.0f : angle_us;
float angle = angle_us * g_cfg[speed_mode].max_angle / (g_cfg[speed_mode].max_width_us - g_cfg[speed_mode].min_width_us);
return angle;
}
esp_err_t iot_servo_init(ledc_mode_t speed_mode, const servo_config_t *config)
{
esp_err_t ret;
SERVO_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG);
SERVO_CHECK(config->channel_number > 0 && config->channel_number <= LEDC_CHANNEL_MAX, "Servo channel number out the range", ESP_ERR_INVALID_ARG);
SERVO_CHECK(config->freq <= SERVO_FREQ_MAX && config->freq >= SERVO_FREQ_MIN, "Servo pwm frequency out the range", ESP_ERR_INVALID_ARG);
uint64_t pin_mask = 0;
uint32_t ch_mask = 0;
for (size_t i = 0; i < config->channel_number; i++) {
uint64_t _pin_mask = 1ULL << config->channels.servo_pin[i];
uint32_t _ch_mask = 1UL << config->channels.ch[i];
SERVO_CHECK(!(pin_mask & _pin_mask), "servo gpio has a duplicate", ESP_ERR_INVALID_ARG);
SERVO_CHECK(!(ch_mask & _ch_mask), "servo channel has a duplicate", ESP_ERR_INVALID_ARG);
SERVO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(config->channels.servo_pin[i]), "servo gpio invalid", ESP_ERR_INVALID_ARG);
pin_mask |= _pin_mask;
ch_mask |= _ch_mask;
}
ledc_timer_config_t ledc_timer = {
.clk_cfg = LEDC_AUTO_CLK,
.duty_resolution = SERVO_LEDC_INIT_BITS, // resolution of PWM duty
.freq_hz = config->freq, // frequency of PWM signal
.speed_mode = speed_mode, // timer mode
.timer_num = config->timer_number // timer index
};
ret = ledc_timer_config(&ledc_timer);
SERVO_CHECK(ESP_OK == ret, "ledc timer configuration failed", ESP_FAIL);
for (size_t i = 0; i < config->channel_number; i++) {
ledc_channel_config_t ledc_ch = {
.intr_type = LEDC_INTR_DISABLE,
.channel = config->channels.ch[i],
.duty = calculate_duty(speed_mode, 0),
.gpio_num = config->channels.servo_pin[i],
.speed_mode = speed_mode,
.timer_sel = config->timer_number,
.hpoint = 0
};
ret = ledc_channel_config(&ledc_ch);
SERVO_CHECK(ESP_OK == ret, "ledc channel configuration failed", ESP_FAIL);
}
g_full_duty = (1 << SERVO_LEDC_INIT_BITS) - 1;
g_cfg[speed_mode] = *config;
return ESP_OK;
}
esp_err_t iot_servo_deinit(ledc_mode_t speed_mode)
{
SERVO_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "LEDC speed mode invalid", ESP_ERR_INVALID_ARG);
for (size_t i = 0; i < g_cfg[speed_mode].channel_number; i++) {
ledc_stop(speed_mode, g_cfg[speed_mode].channels.ch[i], 0);
}
ledc_timer_rst(speed_mode, g_cfg[speed_mode].timer_number);
g_full_duty = 0;
return ESP_OK;
}
esp_err_t iot_servo_write_angle(ledc_mode_t speed_mode, uint8_t channel, float angle)
{
SERVO_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "LEDC speed mode invalid", ESP_ERR_INVALID_ARG);
SERVO_CHECK(channel < LEDC_CHANNEL_MAX, "LEDC channel number too large", ESP_ERR_INVALID_ARG);
SERVO_CHECK(angle >= 0.0f, "Angle can't to be negative", ESP_ERR_INVALID_ARG);
esp_err_t ret;
uint32_t duty = calculate_duty(speed_mode, angle);
ret = ledc_set_duty(speed_mode, (ledc_channel_t)channel, duty);
ret |= ledc_update_duty(speed_mode, (ledc_channel_t)channel);
SERVO_CHECK(ESP_OK == ret, "write servo angle failed", ESP_FAIL);
return ESP_OK;
}
esp_err_t iot_servo_read_angle(ledc_mode_t speed_mode, uint8_t channel, float *angle)
{
SERVO_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "LEDC speed mode invalid", ESP_ERR_INVALID_ARG);
SERVO_CHECK(channel < LEDC_CHANNEL_MAX, "LEDC channel number too large", ESP_ERR_INVALID_ARG);
uint32_t duty = ledc_get_duty(speed_mode, channel);
float a = calculate_angle(speed_mode, duty);
*angle = a;
return ESP_OK;
}

View File

@ -0,0 +1,104 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _IOT_SERVO_H_
#define _IOT_SERVO_H_
#include "esp_err.h"
#include "driver/ledc.h"
#include "driver/gpio.h"
/**
* @brief Configuration of servo motor channel
*
*/
typedef struct {
gpio_num_t servo_pin[LEDC_CHANNEL_MAX]; /**< Pin number of pwm output */
ledc_channel_t ch[LEDC_CHANNEL_MAX]; /**< The ledc channel which used */
} servo_channel_t;
/**
* @brief Configuration of servo motor
*
*/
typedef struct {
uint16_t max_angle; /**< Servo max angle */
uint16_t min_width_us; /**< Pulse width corresponding to minimum angle, which is usually 500us */
uint16_t max_width_us; /**< Pulse width corresponding to maximum angle, which is usually 2500us */
uint32_t freq; /**< PWM frequency */
ledc_timer_t timer_number; /**< Timer number of ledc */
servo_channel_t channels; /**< Channels to use */
uint8_t channel_number; /**< Total channel number */
} servo_config_t;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize ledc to control the servo
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param config Pointer of servo configure struct
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Configure ledc failed
*/
esp_err_t iot_servo_init(ledc_mode_t speed_mode, const servo_config_t *config);
/**
* @brief Deinitialize ledc for servo
*
* @param speed_mode Select the LEDC channel group with specified speed mode.
*
* @return
* - ESP_OK Success
*/
esp_err_t iot_servo_deinit(ledc_mode_t speed_mode);
/**
* @brief Set the servo motor to a certain angle
*
* @note This API is not thread-safe
*
* @param speed_mode Select the LEDC channel group with specified speed mode.
* @param channel LEDC channel, select from ledc_channel_t
* @param angle The angle to go
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t iot_servo_write_angle(ledc_mode_t speed_mode, uint8_t channel, float angle);
/**
* @brief Read current angle of one channel
*
* @param speed_mode Select the LEDC channel group with specified speed mode.
* @param channel LEDC channel, select from ledc_channel_t
* @param angle Current angle of the channel
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t iot_servo_read_angle(ledc_mode_t speed_mode, uint8_t channel, float *angle);
#ifdef __cplusplus
}
#endif
#endif /* _IOT_SERVO_H_ */

View File

@ -37,7 +37,7 @@
/// @brief 所有Task的命名集合名字长度不能超过configMAX_TASK_NAME_LEN = 16
char* imp_main_task_table[] = {
"idle", "main_task", "ext_trans_task", "display", "audio",
"idle", "main_task", "ext_trans_task", "display", "audio", "switch_key",
};
/* Private function(only *.c) -----------------------------------------------*/

View File

@ -37,6 +37,7 @@ extern "C" {
#define IMP_TASK_ID_EXT_TRANS_SERVICE_TASK (2)
#define IMP_TASK_ID_DISP_SERVICE_TASK (3)
#define IMP_TASK_ID_AUDIO_SERVICE_TASK (4)
#define IMP_TASK_ID_SWITCH_CONTROL_TASK (5)
/* typedef -------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/

View File

@ -0,0 +1,82 @@
/**
* @file switch_control_service.c
* @author Alvin Young (impressionyang@outlook.com)
* @brief
* @version 0.1
* @date 2025-04-14
*
* _ _
* (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
* / / ' \/ _ \/ __/ -_|_-<(_-</ / _ \/ _ \/ // / _ `/ _ \/ _ `/
* /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
* /_/ /___/ /___/
* @copyright Copyright (c) 2025 impressionyang
*
* @par :
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2025-04-14 <td>v1.0 <td>Alvin Young <td>
* </table>
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include "switch_control_service.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "imp_msg_queue.h"
#include "imp_comp_sg90.h"
#include "main_common.h"
#include "esp_log.h"
/* define --------------------------------------------------------------------*/
/* typedef -------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/
static imp_msg_queue_t* msg_q_handle = NULL;
/* Private function(only *.c) -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
void imp_switch_control_service_task(void*)
{
msg_q_handle = imp_msg_queue_create_handle(IMP_TASK_ID_SWITCH_CONTROL_TASK);
imp_msg_item_t msg_item = { 0 };
uint8_t msg_read_ret = 0;
uint8_t direction = 0;
int i = 0;
float angle_ls = 0;
imp_comp_sg90_t sg90_01_hanle = { 0 };
uint16_t max_degree = 45;
imp_comp_sg90_init(&sg90_01_hanle, 12, 0);
vTaskDelay( 5000 / portTICK_PERIOD_MS);
while (1) {
if (!direction) {
for (i = 0; i <= max_degree; i++) {
// _set_angle(LEDC_LOW_SPEED_MODE, i);
imp_comp_sg90_set_angle(&sg90_01_hanle, i);
vTaskDelay(10 / portTICK_PERIOD_MS);
imp_comp_sg90_get_angle(&sg90_01_hanle, &angle_ls);
ESP_LOGI("servo", "[%d|%.2f]", i, angle_ls);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
direction = !direction;
} else {
for (i = max_degree; i >= 0; i--) {
imp_comp_sg90_set_angle(&sg90_01_hanle, i);
vTaskDelay(10 / portTICK_PERIOD_MS);
imp_comp_sg90_get_angle(&sg90_01_hanle, &angle_ls);
ESP_LOGI("servo", "[%d|%.2f]", i, angle_ls);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
direction = !direction;
}
}
imp_comp_sg90_deinit(&sg90_01_hanle);
}
/*
* EOF
*/

View File

@ -0,0 +1,47 @@
/**
* @file switch_control_service.h
* @author Alvin Young (impressionyang@outlook.com)
* @brief
* @version 0.1
* @date 2025-04-14
*
* _ _
* (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
* / / ' \/ _ \/ __/ -_|_-<(_-</ / _ \/ _ \/ // / _ `/ _ \/ _ `/
* /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
* /_/ /___/ /___/
* @copyright Copyright (c) 2025 impressionyang
*
* @par :
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2025-04-14 <td>v1.0 <td>Alvin Young <td>
* </table>
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SWITCH_CONTROL_SERVICE_H__
#define __SWITCH_CONTROL_SERVICE_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
/* define --------------------------------------------------------------------*/
/* typedef -------------------------------------------------------------------*/
/* variables -----------------------------------------------------------------*/
/* Private function(only *.c) -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
void imp_switch_control_service_task(void *);
#ifdef __cplusplus
}
#endif
#endif //__SWITCH_CONTROL_SERVICE_H__
/*
* EOF
*/