初始化控制函数#include stdio.h #include sys.h #include uart1.h #include bluetooth.h #include esp01s.h #include led.h #include sg90.h #include systick.h #include key.h int main(void) { HAL_Init(); stm32_clock_init(RCC_PLL_MUL9); uart1_init(115200); led_init(); bt_init(115200); esp01s_init(115200); sg90_init(); KeyDrvInit(); Init_SysTime(); SG90_STATE(); printf(system Run...\r\n); while(1) { // SG90 控制函数 contrl_SG90(); // Key 控制 LED 函数 Key_Status(); // 远程 MQTT 控制函数 ESP_contrl(); // BLE 控制函数 BLE_contrl(); } }SG90控制#include sg90.h #include systick.h TIM_HandleTypeDef tim3_handle {0}; void tim3_init(void) { TIM_OC_InitTypeDef pwm_config {0}; tim3_handle.Instance TIM3; tim3_handle.Init.Prescaler 72 - 1; tim3_handle.Init.Period 20000 - 1; tim3_handle.Init.CounterMode TIM_COUNTERMODE_UP; HAL_TIM_PWM_Init(tim3_handle); pwm_config.OCMode TIM_OCMODE_PWM1; pwm_config.Pulse 1188; // 初始化 62° 由公式 CCRx 500 (angle * 2000) / 180; pwm_config.OCPolarity TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(tim3_handle, pwm_config, TIM_CHANNEL_1); HAL_TIM_PWM_Start(tim3_handle, TIM_CHANNEL_1); } void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { if(htim-Instance TIM3) { GPIO_InitTypeDef gpio_initstruct; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_TIM3_CLK_ENABLE(); gpio_initstruct.Pin GPIO_PIN_6; gpio_initstruct.Mode GPIO_MODE_AF_PP; gpio_initstruct.Pull GPIO_PULLUP; gpio_initstruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, gpio_initstruct); } } //修改CCR值 void tim3_compare_set(uint16_t val) { __HAL_TIM_SET_COMPARE(tim3_handle, TIM_CHANNEL_1, val); } // 计算范围500us-2500us对应0-180度 // CCR 500 (2000 * angle) / 180 static void sg90_angle_set(uint16_t angle) { uint32_t temp (uint32_t)angle * 2000; uint16_t CCRx 500 (temp / 180); tim3_compare_set(CCRx); } void sg90_set_angle(uint16_t angle) { sg90_angle_set(angle); } void sg90_init(void) { tim3_init(); } static ServoState_t servoState SERVO_IDLE; static uint32_t stateStartTime 0; static void controlSG90(void) { uint64_t currentTime get_systick(); switch(servoState) { case SERVO_IDLE: // 空闲状态 break; case OPEN_SERVO_TO_33: { sg90_angle_set(33); servoState OPEN_WAIT_1S; stateStartTime currentTime; } break; case OPEN_WAIT_1S: if(currentTime - stateStartTime 300) { servoState OPEN_SERVO_TO_62; } break; case OPEN_SERVO_TO_62: { sg90_angle_set(62); servoState SERVO_IDLE; stateStartTime currentTime; } break; #if 0 case OPEN_WAIT_500MS: if (currentTime - stateStartTime 500) { servoState OPEN_SERVO_TO_58; } break; case OPEN_SERVO_TO_58: { sg90_angle_set(58); servoState SERVO_IDLE; } break; #endif case CLOSE_SERVO_TO_80: { sg90_angle_set(80); servoState CLOSE_WAIT_500MS_1; stateStartTime currentTime; } break; case CLOSE_WAIT_500MS_1: if (currentTime - stateStartTime 500) { servoState CLOSE_SERVO_TO_62; } break; case CLOSE_SERVO_TO_62: { sg90_angle_set(62); servoState SERVO_IDLE; stateStartTime currentTime; } break; #if 0 case CLOSE_WAIT_500MS_2: if (currentTime - stateStartTime 500) { servoState CLOSE_SERVO_TO_58; } break; case CLOSE_SERVO_TO_58: { sg90_angle_set(58); servoState SERVO_IDLE; } break; #endif default: servoState SERVO_IDLE; break; } } void contrl_SG90(void) { controlSG90(); } static void startOpenSequence(void) { if (servoState SERVO_IDLE) { servoState OPEN_SERVO_TO_33; } else { servoState SERVO_IDLE; } } static void startCloseSequence(void) { if (servoState SERVO_IDLE) { servoState CLOSE_SERVO_TO_80; } else { servoState SERVO_IDLE; } } void ctrl_open_sg90(void) { startOpenSequence(); } void ctrl_close_sg90(void) { startCloseSequence(); }#ifndef __SG90_H__ #define __SG90_H__ #include stdio.h #include stdbool.h #include sys.h typedef enum { SERVO_IDLE 0, OPEN_SERVO_TO_33, OPEN_WAIT_1S, OPEN_SERVO_TO_62, OPEN_WAIT_500MS, OPEN_SERVO_TO_58, CLOSE_SERVO_TO_80, CLOSE_WAIT_500MS_1, CLOSE_SERVO_TO_62, CLOSE_WAIT_500MS_2, CLOSE_SERVO_TO_58 } ServoState_t; void sg90_init(void); void sg90_set_angle(uint16_t angle); void contrl_SG90(void); void ctrl_open_sg90(void); void ctrl_close_sg90(void); #endif-状态机static void controlSG90(void) { uint64_t currentTime get_systick(); switch(servoState) { case SERVO_IDLE: break; case OPEN_SERVO_TO_32: sg90_angle_set(32); servoState OPEN_WAIT_1S; stateStartTime currentTime; break; case OPEN_WAIT_1S: if(currentTime - stateStartTime 1000) { servoState OPEN_SERVO_TO_54; } break; case OPEN_SERVO_TO_54: sg90_angle_set(54); servoState OPEN_WAIT_500MS; stateStartTime currentTime; break; case OPEN_WAIT_500MS: if (currentTime - servoStartTime 500) { servoState OPEN_SERVO_TO_STOP; } break; case OPEN_SERVO_TO_STOP: servoState SERVO_IDLE; currentSequenceIsOpen true; break; case CLOSE_SERVO_TO_70: sg90_angle_set(70); servoState CLOSE_WAIT_500MS_1; servoStartTime currentTime; break; case CLOSE_WAIT_500MS_1: if (currentTime - servoStartTime 500) { servoState CLOSE_SERVO_TO_54; } break; case CLOSE_SERVO_TO_54: sg90_angle_set(54); servoState CLOSE_WAIT_500MS_2; servoStartTime currentTime; break; case CLOSE_WAIT_500MS_2: if (currentTime - servoStartTime 500) { servoState CLOSE_SERVO_TO_STOP; } break; case CLOSE_SERVO_TO_STOP: servoState SERVO_IDLE; currentSequenceIsOpen false; default: servoState SERVO_IDLE; break; } }控制正反转的接口函数void startOpenSequence(void) { if (servoState SERVO_IDLE) { servoState OPEN_SERVO_TO_32; currentSequenceIsOpen true; } else { servoState SERVO_IDLE; } } void startCloseSequence(void) { if (servoState SERVO_IDLE) { servoState CLOSE_SERVO_TO_70; currentSequenceIsOpen false; } else { servoState SERVO_IDLE; } }SG90 供main--主程序中调用的接口函数void sg90_init(void) { tim3_init(); } void SG90_STATE(void) { sg90_initstatus(); } void contrl_SG90(void) { controlSG90(); }角度控制算法接口// 计算范围500us-2500us对应0-180度 // CCR 500 (2000 * angle) / 180 // 先乘后除保留中间结果的精度 static void sg90_angle_set(uint16_t angle) { uint32_t temp (uint32_t)angle * 2000; uint16_t CCRx 500 (temp / 180); tim3_compare_set(CCRx); }Key 控制消抖状态机typedef enum { KEY_RELEASE 0, // 释放松开 KEY_CONFIRM, // 消抖确认 KEY_SHORTPRESS, // 短按 KEY_LONGPRESS // 长按 } KEY_STATE; #define CONFIRM_TIME 10 // 按键消抖时间窗10ms #define DOUBLE_CLICK_INTERVAL_TIME 300 // 两次抬起时间窗300ms用来判断是否双击 #define LONGPRESS_TIME 1000 // 长按时间窗1000ms typedef struct { KEY_STATE keyState; // 表示按键状态 uint8_t singleClickNum; // 保存按键第一次按下后系统运行的时间 uint64_t firstIoChangeSysTime; uint64_t firstReleaseSysTime; } Key_Info_t; static uint8_t KeyScan(uint8_t keyIndex) { uint64_t curSysTime; // 获取系统运行时间变量 uint8_t keyPress; keyPress HAL_GPIO_ReadPin(g_gpioList[keyIndex].gpio, g_gpioList[keyIndex].pin); // 获取GPIO口状态 switch (g_keyInfo[keyIndex].keyState) { case KEY_RELEASE: if (!keyPress) // 判断按键是否按下 { g_keyInfo[keyIndex].keyState KEY_CONFIRM; // 切换消抖确认状态 g_keyInfo[keyIndex].firstIoChangeSysTime get_systick(); // 获取系统运行时间 } break; case KEY_CONFIRM: if (!keyPress) { curSysTime get_systick(); if ((curSysTime - g_keyInfo[keyIndex].firstIoChangeSysTime) CONFIRM_TIME) // 如果按键按下了并且超过时间窗切换到短按 { g_keyInfo[keyIndex].keyState KEY_SHORTPRESS; // 切换为短按状态 } } else { g_keyInfo[keyIndex].keyState KEY_RELEASE; // 如果按键松开了切换到释放状态 } break; case KEY_SHORTPRESS: // 判断按键有没有松开松开则为高电平反之为低 if (keyPress) { g_keyInfo[keyIndex].keyState KEY_RELEASE; // 如果按键松开了切换到释放状态 return (keyIndex 1); // 返回按键码值3个按键短按对应0x01, 0x02, 0x03 } else { curSysTime get_systick(); // 如果没有松开接着获取系统运行时间判断时间窗 if (curSysTime - g_keyInfo[keyIndex].firstIoChangeSysTime LONGPRESS_TIME) { g_keyInfo[keyIndex].keyState KEY_LONGPRESS; // 超过时间窗切换到长按状态 } } break; case KEY_LONGPRESS: if (keyPress) { g_keyInfo[keyIndex].keyState KEY_RELEASE; return (keyIndex 0x81); //返回按键码值三个按键长按对应0x81, 0x82, 0x83 } break; default: g_keyInfo[keyIndex].keyState KEY_RELEASE; break; } return 0; }Key 控制 LED 状态的状态机void Key_Status(void) { uint8_t keyVal; keyVal GetKeyVal(); switch (keyVal) { case KEY0_SHORT_PRESS: led1_on(); startOpenSequence(); break; case KEY0_LONG_PRESS: led1_off(); break; case KEY1_SHORT_PRESS: led2_on(); startCloseSequence(); break; case KEY1_LONG_PRESS: led2_off(); break; default: break; } }滴答定时器实现方法程序#include systick.h #include led.h static uint32_t vSysTick 0; // 系统滴答计数器 // 获取当前系统滴答值 uint32_t get_systick(void) { return vSysTick; // 返回毫秒级计时 } static void SysTick_Init(void) { HAL_SYSTICK_Config(SystemCoreClock / 1000); } void Init_SysTime(void) { SysTick_Init(); } void SysTick_Handler(void) { vSysTick; }