好的,非常荣幸能参与到“胡桃摇”这个充满趣味的项目中来。作为一个高级嵌入式软件开发工程师,我将从需求分析开始,逐步深入到系统设计、代码架构、具体实现、测试验证以及未来的维护升级,力求打造一个可靠、高效、可扩展的嵌入式系统平台,让“胡桃摇”项目不仅有趣,而且技术上也经得起推敲。
关注微信公众号,提前获取相关推文

项目背景与需求分析
首先,我们来深入理解“胡桃摇”项目的背景和需求。基于“机智的kason大佬开源了胡桃摇的模型”,我们可以推断这是一个硬件模型,可能是一个小型的机械装置,模拟胡桃摇动的动作。我们的目标是为其设计并实现一套嵌入式系统,赋予这个模型“生命”,使其能够自主或受控地进行摇动,并具备一定的智能和可扩展性。
需求概要:
核心功能:胡桃摇动控制
- 驱动机械模型,实现胡桃的摇动动作。
- 摇动模式可以多样化,例如:匀速摇动、变速摇动、随机摇动等。
- 摇动速度和幅度可调。
交互方式:
- 本地控制: 通过板载按键或传感器(例如触摸、重力感应等)进行本地控制。
- 远程控制(可选但推荐): 考虑通过蓝牙或Wi-Fi等无线通信方式,使用手机APP或其他设备进行远程控制,增加趣味性和可玩性。
状态指示:
- 通过LED指示灯或其他显示方式,反馈系统运行状态,例如:摇动模式、速度、电量等。
电源管理:
- 低功耗设计,延长电池续航时间。
- 电源状态监测,低电量报警。
可扩展性:
- 预留硬件和软件接口,方便未来增加新功能,例如:音乐播放、灯光效果、更复杂的动作模式等。
可靠性和稳定性:
- 系统运行稳定可靠,不易崩溃。
- 具备一定的容错能力,例如:电机过载保护、低电压保护等。
易维护性:
- 代码结构清晰,模块化设计,易于理解和维护。
- 预留调试接口,方便问题排查和软件升级。
系统设计架构
为了满足以上需求,并确保系统的可靠性、高效性和可扩展性,我推荐采用分层架构的设计模式,并结合事件驱动和状态机的思想。这种架构在嵌入式系统开发中被广泛验证,具有良好的结构性和灵活性。
分层架构:
我们将系统软件划分为以下几个层次,由下至上依次为:
硬件抽象层 (HAL - Hardware Abstraction Layer)
- 功能: 直接与硬件交互,封装底层硬件操作细节,向上层提供统一的硬件访问接口。
- 模块:
- GPIO 驱动: 控制通用输入输出引脚,用于LED指示灯、按键输入、电机控制信号等。
- 定时器驱动: 提供定时功能,用于PWM生成、周期性任务调度、时间管理等。
- 电机驱动: 控制电机(例如步进电机或舵机)的转动,实现胡桃的摇动动作。
- 传感器驱动 (可选): 如果使用传感器,例如触摸传感器、重力传感器等,则需要相应的驱动。
- 通信接口驱动 (可选): 如果需要远程控制,例如蓝牙或Wi-Fi,则需要相应的通信接口驱动。
- 电源管理驱动: 监测电压、电流,控制电源模式,实现低功耗管理。
设备驱动层 (Device Driver Layer)
- 功能: 基于HAL层提供的接口,实现对特定设备的控制和管理,向上层提供更高级别的设备操作接口。
- 模块:
- LED 管理驱动: 控制LED的亮灭、闪烁等效果,用于状态指示。
- 按键管理驱动: 检测按键事件,例如单击、双击、长按等,并向上层传递按键事件。
- 电机控制驱动: 实现电机的精确控制,例如角度控制、速度控制、运动模式控制等。
- 传感器管理驱动 (可选): 处理传感器数据,例如触摸事件检测、重力加速度数据读取等。
- 通信协议栈 (可选): 实现蓝牙或Wi-Fi等通信协议,例如蓝牙BLE协议栈、TCP/IP协议栈等。
- 电源管理模块: 实现更高级的电源管理策略,例如休眠模式、唤醒机制等。
系统服务层 (System Service Layer)
- 功能: 提供系统级别的服务,例如任务调度、事件管理、状态管理、配置管理等,为应用层提供基础支撑。
- 模块:
- 任务调度器: 管理系统中的任务,例如周期性任务、事件驱动任务等。
- 事件管理器: 负责事件的接收、分发和处理,实现事件驱动编程模型。
- 状态管理器: 管理系统的各种状态,例如摇动模式、速度、电源状态等,并提供状态切换和查询接口。
- 配置管理器: 管理系统的配置参数,例如摇动速度、模式参数、通信参数等,可以从配置文件或外部存储加载配置。
- 错误处理模块: 处理系统运行过程中出现的错误,例如硬件错误、软件异常等,并进行错误日志记录和恢复。
应用层 (Application Layer)
- 功能: 实现具体的应用逻辑,即“胡桃摇”的核心功能,包括摇动模式控制、用户交互逻辑、状态显示等。
- 模块:
- 摇动控制模块: 实现各种摇动模式,例如匀速摇动、变速摇动、随机摇动等,并根据用户指令控制摇动。
- 用户交互模块: 处理用户输入,例如按键输入、远程控制指令等,并根据用户输入执行相应的操作。
- 状态显示模块: 控制LED指示灯或其他显示设备,显示系统状态信息。
- 电源管理应用: 根据系统状态和用户操作,调用电源管理驱动,实现低功耗运行。
事件驱动与状态机:
事件驱动: 系统以事件为驱动,例如按键事件、定时器事件、传感器事件、远程控制指令事件等。当事件发生时,系统会根据事件类型调用相应的处理函数,执行相应的操作。这种模式能够提高系统的响应性和效率。
状态机: 对于复杂的摇动模式控制和用户交互逻辑,可以使用状态机进行建模。状态机将系统划分为不同的状态,例如“待机状态”、“匀速摇动状态”、“变速摇动状态”等。状态之间可以进行切换,状态切换由事件触发。状态机能够清晰地描述系统的行为,并简化代码逻辑。
代码实现 (C语言)
接下来,我将用C语言逐步实现上述架构的各个层次,并给出关键模块的代码示例。由于篇幅限制,这里只给出核心代码框架和关键功能模块的实现,完整的3000行代码将包含更详细的注释、错误处理、参数配置等。
1. 硬件抽象层 (HAL)
hal_gpio.h
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
| #ifndef HAL_GPIO_H #define HAL_GPIO_H
typedef enum { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_MAX } gpio_pin_t;
typedef enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT } gpio_mode_t;
typedef enum { GPIO_LEVEL_LOW, GPIO_LEVEL_HIGH } gpio_level_t;
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode);
void hal_gpio_write(gpio_pin_t pin, gpio_level_t level);
gpio_level_t hal_gpio_read(gpio_pin_t pin);
#endif
|
hal_gpio.c
(假设基于STM32 HAL库,实际根据具体MCU平台实现)
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
| #include "hal_gpio.h" #include "stm32fxxx_hal.h"
GPIO_TypeDef* gpio_port_map[] = {GPIOA, GPIOB, GPIOC, }; uint16_t gpio_pin_map[] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, };
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_TypeDef* port = gpio_port_map[pin / 16]; uint16_t pin_num = gpio_pin_map[pin % 16];
if (mode == GPIO_MODE_OUTPUT) { GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; } else { GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; } GPIO_InitStruct.Pin = pin_num; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(port, &GPIO_InitStruct); }
void hal_gpio_write(gpio_pin_t pin, gpio_level_t level) { GPIO_TypeDef* port = gpio_port_map[pin / 16]; uint16_t pin_num = gpio_pin_map[pin % 16]; HAL_GPIO_WritePin(port, pin_num, (level == GPIO_LEVEL_HIGH) ? GPIO_PIN_SET : GPIO_PIN_RESET); }
gpio_level_t hal_gpio_read(gpio_pin_t pin) { GPIO_TypeDef* port = gpio_port_map[pin / 16]; uint16_t pin_num = gpio_pin_map[pin % 16]; GPIO_PinState state = HAL_GPIO_ReadPin(port, pin_num); return (state == GPIO_PIN_SET) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW; }
|
hal_timer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #ifndef HAL_TIMER_H #define HAL_TIMER_H
typedef enum { TIMER_1, TIMER_2, TIMER_MAX } timer_id_t;
void hal_timer_init(timer_id_t timer_id, uint32_t period_us);
void hal_timer_start(timer_id_t timer_id);
void hal_timer_stop(timer_id_t timer_id);
void hal_timer_set_callback(timer_id_t timer_id, void (*callback)(void));
#endif
|
hal_timer.c
(假设基于STM32 HAL库)
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
| #include "hal_timer.h" #include "stm32fxxx_hal.h"
TIM_HandleTypeDef htim_map[] = { }; void (*timer_callback_map[TIMER_MAX])(void) = {NULL};
void hal_timer_init(timer_id_t timer_id, uint32_t period_us) { TIM_HandleTypeDef *htim = &htim_map[timer_id]; TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0};
htim->Instance = TIM1 + timer_id; htim->Init.Prescaler = SystemCoreClock / 1000000 - 1; htim->Init.CounterMode = TIM_COUNTERMODE_UP; htim->Init.Period = period_us - 1; htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim->Init.RepetitionCounter = 0; htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(htim, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(htim, &sMasterConfig); HAL_TIM_PeriodElapsedCallback(htim); if (HAL_TIM_Base_Init(htim) != HAL_OK) { } }
void hal_timer_start(timer_id_t timer_id) { HAL_TIM_Base_Start_IT(&htim_map[timer_id]); }
void hal_timer_stop(timer_id_t timer_id) { HAL_TIM_Base_Stop_IT(&htim_map[timer_id]); }
void hal_timer_set_callback(timer_id_t timer_id, void (*callback)(void)) { timer_callback_map[timer_id] = callback; }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { for (int i = 0; i < TIMER_MAX; ++i) { if (htim->Instance == (TIM1 + i)) { if (timer_callback_map[i] != NULL) { timer_callback_map[i](); } break; } } }
|
hal_motor.h
(假设使用步进电机)
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
| #ifndef HAL_MOTOR_H #define HAL_MOTOR_H
typedef enum { MOTOR_1, MOTOR_2, MOTOR_MAX } motor_id_t;
typedef enum { MOTOR_DIRECTION_CW, MOTOR_DIRECTION_CCW } motor_direction_t;
void hal_motor_init(motor_id_t motor_id);
void hal_motor_step(motor_id_t motor_id, int steps, motor_direction_t direction);
void hal_motor_set_speed(motor_id_t motor_id, uint32_t speed);
#endif
|
hal_motor.c
(假设使用步进电机和 GPIO 控制)
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
| #include "hal_motor.h" #include "hal_gpio.h" #include "hal_timer.h"
gpio_pin_t motor_pin_map[MOTOR_MAX][4] = { {GPIO_PIN_X1, GPIO_PIN_X2, GPIO_PIN_X3, GPIO_PIN_X4}, {GPIO_PIN_Y1, GPIO_PIN_Y2, GPIO_PIN_Y3, GPIO_PIN_Y4}, };
const uint8_t step_sequence[4][4] = { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} };
uint32_t motor_speed_map[MOTOR_MAX] = {0}; timer_id_t motor_timer_map[MOTOR_MAX] = {TIMER_MAX};
void hal_motor_init(motor_id_t motor_id) { for (int i = 0; i < 4; ++i) { hal_gpio_init(motor_pin_map[motor_id][i], GPIO_MODE_OUTPUT); } motor_speed_map[motor_id] = 100; motor_timer_map[motor_id] = TIMER_1 + motor_id; }
void hal_motor_step(motor_id_t motor_id, int steps, motor_direction_t direction) { if (steps <= 0) return;
uint32_t step_delay_us = 1000000 / motor_speed_map[motor_id]; static int current_step[MOTOR_MAX] = {0};
for (int step_count = 0; step_count < steps; ++step_count) { if (direction == MOTOR_DIRECTION_CW) { current_step[motor_id] = (current_step[motor_id] + 1) % 4; } else { current_step[motor_id] = (current_step[motor_id] + 3) % 4; }
for (int i = 0; i < 4; ++i) { hal_gpio_write(motor_pin_map[motor_id][i], (step_sequence[current_step[motor_id]][i]) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); } hal_delay_us(step_delay_us); } }
void hal_motor_set_speed(motor_id_t motor_id, uint32_t speed) { motor_speed_map[motor_id] = speed; }
void hal_delay_us(uint32_t us) { volatile uint32_t count = us * (SystemCoreClock / 1000000 / 3); while (count--); }
|
2. 设备驱动层
led_driver.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #ifndef LED_DRIVER_H #define LED_DRIVER_H
typedef enum { LED_RED, LED_GREEN, LED_BLUE, LED_MAX } led_id_t;
void led_driver_init(led_id_t led_id);
void led_driver_set_state(led_id_t led_id, bool on);
void led_driver_blink(led_id_t led_id, uint32_t on_time_ms, uint32_t off_time_ms);
#endif
|
led_driver.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
| #include "led_driver.h" #include "hal_gpio.h" #include "hal_timer.h"
gpio_pin_t led_pin_map[LED_MAX] = { GPIO_PIN_LED_RED, GPIO_PIN_LED_GREEN, GPIO_PIN_LED_BLUE, };
bool led_state_map[LED_MAX] = {false}; timer_id_t led_blink_timer_map[LED_MAX] = {TIMER_MAX}; uint32_t led_on_time_map[LED_MAX] = {0}; uint32_t led_off_time_map[LED_MAX] = {0};
void led_driver_init(led_id_t led_id) { hal_gpio_init(led_pin_map[led_id], GPIO_MODE_OUTPUT); led_driver_set_state(led_id, false); led_blink_timer_map[led_id] = TIMER_2 + led_id; }
void led_driver_set_state(led_id_t led_id, bool on) { led_state_map[led_id] = on; hal_gpio_write(led_pin_map[led_id], on ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); hal_timer_stop(led_blink_timer_map[led_id]); }
void led_driver_blink(led_id_t led_id, uint32_t on_time_ms, uint32_t off_time_ms) { led_on_time_map[led_id] = on_time_ms; led_off_time_map[led_id] = off_time_ms; led_state_map[led_id] = true; hal_timer_init(led_blink_timer_map[led_id], on_time_ms * 1000); hal_timer_set_callback(led_blink_timer_map[led_id], led_blink_callback); hal_timer_start(led_blink_timer_map[led_id]); hal_gpio_write(led_pin_map[led_id], GPIO_LEVEL_HIGH); }
void led_blink_callback(void) { for (int i = 0; i < LED_MAX; ++i) { if (timer_callback_map[led_blink_timer_map[i]] == led_blink_callback) { led_state_map[i] = !led_state_map[i]; hal_gpio_write(led_pin_map[i], led_state_map[i] ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); hal_timer_stop(led_blink_timer_map[i]); hal_timer_init(led_blink_timer_map[i], led_state_map[i] ? led_off_time_map[i] * 1000 : led_on_time_map[i] * 1000); hal_timer_start(led_blink_timer_map[i]); break; } } }
|
button_driver.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #ifndef BUTTON_DRIVER_H #define BUTTON_DRIVER_H
typedef enum { BUTTON_1, BUTTON_2, BUTTON_MAX } button_id_t;
typedef enum { BUTTON_EVENT_CLICK, BUTTON_EVENT_DOUBLE_CLICK, BUTTON_EVENT_LONG_PRESS } button_event_t;
void button_driver_init(button_id_t button_id);
void button_driver_set_event_callback(button_id_t button_id, void (*callback)(button_event_t event));
#endif
|
button_driver.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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| #include "button_driver.h" #include "hal_gpio.h" #include "hal_timer.h"
gpio_pin_t button_pin_map[BUTTON_MAX] = { GPIO_PIN_BUTTON_1, GPIO_PIN_BUTTON_2, };
void (*button_event_callback_map[BUTTON_MAX])(button_event_t event) = {NULL}; timer_id_t button_debounce_timer_map[BUTTON_MAX] = {TIMER_MAX}; bool button_last_state_map[BUTTON_MAX] = {true}; uint32_t button_click_time_map[BUTTON_MAX] = {0};
#define BUTTON_DEBOUNCE_TIME_MS 20 #define BUTTON_LONG_PRESS_TIME_MS 500 #define BUTTON_DOUBLE_CLICK_INTERVAL_MS 300
void button_driver_init(button_id_t button_id) { hal_gpio_init(button_pin_map[button_id], GPIO_MODE_INPUT); button_debounce_timer_map[button_id] = TIMER_3 + button_id; }
void button_driver_set_event_callback(button_id_t button_id, void (*callback)(button_event_t event)) { button_event_callback_map[button_id] = callback; }
void button_scan_task(void) { for (int i = 0; i < BUTTON_MAX; ++i) { gpio_level_t current_level = hal_gpio_read(button_pin_map[i]);
if (current_level != button_last_state_map[i]) { button_last_state_map[i] = current_level;
if (current_level == GPIO_LEVEL_LOW) { hal_timer_init(button_debounce_timer_map[i], BUTTON_DEBOUNCE_TIME_MS * 1000); hal_timer_set_callback(button_debounce_timer_map[i], button_debounce_callback); hal_timer_start(button_debounce_timer_map[i]); } } } }
void button_debounce_callback(void) { for (int i = 0; i < BUTTON_MAX; ++i) { if (timer_callback_map[button_debounce_timer_map[i]] == button_debounce_callback) { hal_timer_stop(button_debounce_timer_map[i]);
if (hal_gpio_read(button_pin_map[i]) == GPIO_LEVEL_LOW) { if (button_event_callback_map[i] != NULL) { if (button_click_time_map[i] == 0) { button_click_time_map[i] = HAL_GetTick(); hal_timer_init(button_debounce_timer_map[i], BUTTON_LONG_PRESS_TIME_MS * 1000); hal_timer_set_callback(button_debounce_timer_map[i], button_long_press_callback); hal_timer_start(button_debounce_timer_map[i]); } else { if (HAL_GetTick() - button_click_time_map[i] < BUTTON_DOUBLE_CLICK_INTERVAL_MS) { button_event_callback_map[i](BUTTON_EVENT_DOUBLE_CLICK); button_click_time_map[i] = 0; } else { button_event_callback_map[i](BUTTON_EVENT_CLICK); button_click_time_map[i] = HAL_GetTick(); hal_timer_init(button_debounce_timer_map[i], BUTTON_DOUBLE_CLICK_INTERVAL_MS * 1000); hal_timer_set_callback(button_debounce_timer_map[i], button_click_timeout_callback); hal_timer_start(button_debounce_timer_map[i]); } } } } break; } } }
void button_long_press_callback(void) { for (int i = 0; i < BUTTON_MAX; ++i) { if (timer_callback_map[button_debounce_timer_map[i]] == button_long_press_callback) { hal_timer_stop(button_debounce_timer_map[i]); if (button_event_callback_map[i] != NULL && hal_gpio_read(button_pin_map[i]) == GPIO_LEVEL_LOW) { button_event_callback_map[i](BUTTON_EVENT_LONG_PRESS); } button_click_time_map[i] = 0; break; } } }
void button_click_timeout_callback(void) { for (int i = 0; i < BUTTON_MAX; ++i) { if (timer_callback_map[button_debounce_timer_map[i]] == button_click_timeout_callback) { hal_timer_stop(button_debounce_timer_map[i]); if (button_event_callback_map[i] != NULL) { button_event_callback_map[i](BUTTON_EVENT_CLICK); } button_click_time_map[i] = 0; break; } } }
|
3. 系统服务层
task_scheduler.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #ifndef TASK_SCHEDULER_H #define TASK_SCHEDULER_H
typedef void (*task_func_t)(void);
typedef struct { task_func_t task_func; uint32_t period_ms; uint32_t last_exec_time; } task_t;
void task_scheduler_init(void);
void task_scheduler_add_task(task_t *task);
void task_scheduler_run(void);
#endif
|
task_scheduler.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
| #include "task_scheduler.h" #include "hal_timer.h"
#define MAX_TASKS 10 task_t task_list[MAX_TASKS]; uint8_t task_count = 0;
void task_scheduler_init(void) { task_count = 0; }
void task_scheduler_add_task(task_t *task) { if (task_count < MAX_TASKS) { task_list[task_count++] = *task; task->last_exec_time = HAL_GetTick(); } else { } }
void task_scheduler_run(void) { uint32_t current_time = HAL_GetTick(); for (int i = 0; i < task_count; ++i) { if (current_time - task_list[i].last_exec_time >= task_list[i].period_ms) { task_list[i].task_func(); task_list[i].last_exec_time = current_time; } } }
|
state_manager.h
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
| #ifndef STATE_MANAGER_H #define STATE_MANAGER_H
typedef enum { SYSTEM_STATE_IDLE, SYSTEM_STATE_ROCKING_SLOW, SYSTEM_STATE_ROCKING_FAST, SYSTEM_STATE_ROCKING_RANDOM, SYSTEM_STATE_PAUSED, SYSTEM_STATE_MAX } system_state_t;
system_state_t state_manager_get_current_state(void);
void state_manager_set_state(system_state_t new_state);
typedef void (*state_change_callback_t)(system_state_t old_state, system_state_t new_state);
void state_manager_register_state_change_callback(state_change_callback_t callback);
#endif
|
state_manager.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include "state_manager.h"
system_state_t current_state = SYSTEM_STATE_IDLE; state_change_callback_t state_change_callback = NULL;
system_state_t state_manager_get_current_state(void) { return current_state; }
void state_manager_set_state(system_state_t new_state) { if (new_state != current_state && new_state < SYSTEM_STATE_MAX) { system_state_t old_state = current_state; current_state = new_state; if (state_change_callback != NULL) { state_change_callback(old_state, new_state); } } }
void state_manager_register_state_change_callback(state_change_callback_t callback) { state_change_callback = callback; }
|
4. 应用层
hu_tao_rocking_app.h
1 2 3 4 5 6 7 8 9 10
| #ifndef HU_TAO_ROCKING_APP_H #define HU_TAO_ROCKING_APP_H
void hu_tao_rocking_app_init(void);
void hu_tao_rocking_app_run(void);
#endif
|
hu_tao_rocking_app.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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| #include "hu_tao_rocking_app.h" #include "led_driver.h" #include "button_driver.h" #include "motor_driver.h" #include "state_manager.h" #include "task_scheduler.h"
#define MOTOR_ROCKING_MOTOR_ID MOTOR_1 #define LED_STATUS_LED_ID LED_RED #define BUTTON_MODE_BUTTON_ID BUTTON_1
#define ROCKING_SPEED_SLOW 50 #define ROCKING_SPEED_FAST 100 #define ROCKING_SPEED_RANDOM_MIN 30 #define ROCKING_SPEED_RANDOM_MAX 120 #define ROCKING_ANGLE 45
#define ROCKING_TIMER_PERIOD_MS 20
#define ROCKING_TIMER_ID TIMER_4
void rocking_task(void);
void system_state_change_handler(system_state_t old_state, system_state_t new_state);
void mode_button_event_handler(button_event_t event);
void rocking_timer_callback(void);
uint32_t simple_rand(void);
void hu_tao_rocking_app_init(void) { led_driver_init(LED_STATUS_LED_ID); button_driver_init(BUTTON_MODE_BUTTON_ID); motor_driver_init(MOTOR_ROCKING_MOTOR_ID);
button_driver_set_event_callback(BUTTON_MODE_BUTTON_ID, mode_button_event_handler); state_manager_register_state_change_callback(system_state_change_handler);
hal_timer_init(ROCKING_TIMER_ID, ROCKING_TIMER_PERIOD_MS * 1000); hal_timer_set_callback(ROCKING_TIMER_ID, rocking_timer_callback);
task_t rocking_task_def = {rocking_task, ROCKING_TIMER_PERIOD_MS, 0}; task_scheduler_add_task(&rocking_task_def);
state_manager_set_state(SYSTEM_STATE_IDLE); }
void hu_tao_rocking_app_run(void) { task_scheduler_run(); button_scan_task(); }
void rocking_task(void) { system_state_t current_state = state_manager_get_current_state(); motor_direction_t direction = MOTOR_DIRECTION_CW; uint32_t speed = 0;
switch (current_state) { case SYSTEM_STATE_ROCKING_SLOW: speed = ROCKING_SPEED_SLOW; break; case SYSTEM_STATE_ROCKING_FAST: speed = ROCKING_SPEED_FAST; break; case SYSTEM_STATE_ROCKING_RANDOM: speed = ROCKING_SPEED_RANDOM_MIN + (simple_rand() % (ROCKING_SPEED_RANDOM_MAX - ROCKING_SPEED_RANDOM_MIN + 1)); direction = (simple_rand() % 2 == 0) ? MOTOR_DIRECTION_CW : MOTOR_DIRECTION_CCW; break; case SYSTEM_STATE_IDLE: case SYSTEM_STATE_PAUSED: default: speed = 0; break; }
if (speed > 0) { motor_driver_set_speed(MOTOR_ROCKING_MOTOR_ID, speed); motor_driver_rock_angle(MOTOR_ROCKING_MOTOR_ID, ROCKING_ANGLE, direction); } else { motor_driver_stop(MOTOR_ROCKING_MOTOR_ID); } }
void system_state_change_handler(system_state_t old_state, system_state_t new_state) { switch (new_state) { case SYSTEM_STATE_IDLE: led_driver_set_state(LED_STATUS_LED_ID, false); break; case SYSTEM_STATE_ROCKING_SLOW: led_driver_blink(LED_STATUS_LED_ID, 500, 500); break; case SYSTEM_STATE_ROCKING_FAST: led_driver_blink(LED_STATUS_LED_ID, 200, 200); break; case SYSTEM_STATE_ROCKING_RANDOM: led_driver_blink(LED_STATUS_LED_ID, 100, 900); break; case SYSTEM_STATE_PAUSED: led_driver_set_state(LED_STATUS_LED_ID, true); break; default: led_driver_set_state(LED_STATUS_LED_ID, false); break; } }
void mode_button_event_handler(button_event_t event) { if (event == BUTTON_EVENT_CLICK) { system_state_t current_state = state_manager_get_current_state(); system_state_t next_state;
switch (current_state) { case SYSTEM_STATE_IDLE: next_state = SYSTEM_STATE_ROCKING_SLOW; break; case SYSTEM_STATE_ROCKING_SLOW: next_state = SYSTEM_STATE_ROCKING_FAST; break; case SYSTEM_STATE_ROCKING_FAST: next_state = SYSTEM_STATE_ROCKING_RANDOM; break; case SYSTEM_STATE_ROCKING_RANDOM: next_state = SYSTEM_STATE_PAUSED; break; case SYSTEM_STATE_PAUSED: default: next_state = SYSTEM_STATE_IDLE; break; } state_manager_set_state(next_state); } else if (event == BUTTON_EVENT_LONG_PRESS) { state_manager_set_state(SYSTEM_STATE_IDLE); } }
void rocking_timer_callback(void) { }
uint32_t simple_rand(void) { static uint32_t seed = 12345; seed = (seed * 1103515245U + 12345U); return seed; }
|
main.c
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include "main.h" #include "hu_tao_rocking_app.h"
int main(void) { HAL_Init(); SystemClock_Config();
task_scheduler_init(); hu_tao_rocking_app_init();
while (1) { hu_tao_rocking_app_run(); } }
|
测试验证与维护升级
测试验证:
单元测试: 针对HAL层、设备驱动层和系统服务层的各个模块进行单元测试,验证其功能的正确性。例如,测试GPIO驱动能否正确控制引脚电平,定时器驱动能否产生准确的定时中断,电机驱动能否按照指令步进等。
集成测试: 将各个模块组合起来进行集成测试,验证模块之间的协同工作是否正常。例如,测试按键驱动和状态管理器能否正确联动,电机驱动和摇动控制模块能否实现预期的摇动模式等。
系统测试: 对整个嵌入式系统进行全面的系统测试,验证其功能、性能、可靠性和稳定性是否满足需求。例如,测试在各种摇动模式下是否运行正常,长时间运行是否稳定,电源管理是否有效等。
用户体验测试: 邀请用户进行实际体验测试,收集用户反馈,进一步完善产品。
维护升级:
预留升级接口: 在硬件设计上预留固件升级接口,例如UART、USB等。在软件设计上,预留固件升级程序入口,方便进行固件升级。
版本控制: 使用版本控制系统(例如Git)管理代码,方便代码的版本管理、bug修复和功能迭代。
模块化设计: 采用模块化设计,方便对系统进行局部修改和升级,降低升级风险。
日志记录: 在系统中加入日志记录功能,方便在运行过程中记录系统状态和错误信息,便于问题排查和维护。
远程升级 (可选): 如果项目包含无线通信功能,可以考虑实现远程固件升级功能,方便用户在线升级。
总结
以上代码示例和架构设计,旨在提供一个可靠、高效、可扩展的“胡桃摇”嵌入式系统平台。这套分层架构结合事件驱动和状态机的设计模式,在嵌入式系统开发中被广泛应用,能够有效地组织代码,提高开发效率,并为未来的功能扩展和维护升级打下坚实的基础。
请注意,这只是一个代码框架和示例,实际项目开发中还需要根据具体的硬件平台、电机类型、传感器选择等进行详细的调整和完善。例如,电机驱动部分需要根据具体的步进电机驱动器型号和控制方式进行调整,定时器的配置需要根据MCU的时钟频率和精度要求进行调整,等等。
希望这份详细的解答能够帮助您完善“胡桃摇”项目,打造出一个有趣又技术含量十足的嵌入式产品! 如果您有任何其他问题或需要更深入的探讨,欢迎随时提出,我会尽力提供帮助。