简介:智能鱼缸DIY模块主控板
这款智能鱼缸DIY模块主控板旨在为鱼缸爱好者提供一个灵活、可定制的智能控制解决方案。它具备以下主要特点:
关注微信公众号,提前获取相关推文
- 多传感器数据采集: 支持温度传感器、pH传感器、水位传感器、光照传感器等多种传感器,实时监测鱼缸环境参数。
- 智能设备控制: 可控制水泵、加热棒、照明灯、喂食器、氧气泵等设备,实现自动化管理。
- 可编程定时任务: 用户可以自定义定时任务,例如定时开关灯、定时喂食、定时换水等。
- 本地/远程控制: 支持本地按键、触摸屏控制,并预留网络接口,可扩展远程APP或Web控制。
- 数据记录与分析: 记录传感器数据和设备状态,方便用户查看历史数据和进行分析。
- 模块化设计: 采用模块化设计,方便用户根据需求自由组合和扩展功能模块。
- 低功耗设计: 考虑嵌入式系统的功耗限制,采用低功耗MCU和优化软件设计,降低系统功耗。
- 易于DIY和维护: 硬件接口标准化,软件设计清晰易懂,方便用户DIY和后期维护升级。
一、 需求分析
在项目启动阶段,需求分析至关重要。我们需要明确智能鱼缸主控板的具体功能和性能指标,以便为后续的设计和开发奠定基础。
1. 功能需求:
- 传感器数据采集:
- 温度传感器:实时采集水温,精度±0.5℃,范围0-50℃。
- pH传感器:实时采集pH值,精度±0.1pH,范围0-14pH。
- 水位传感器:监测水位高低,精度±1cm,范围0-30cm。
- 光照传感器:监测环境光照强度,范围0-1000Lux。
- (可扩展)溶解氧传感器、TDS传感器等。
- 设备控制:
- 水泵:控制水泵启停,可PWM调速(可选)。
- 加热棒:控制加热棒启停,PID温度控制。
- 照明灯:控制照明灯开关,PWM调光(可选),模拟日出日落。
- 喂食器:控制喂食器定量投喂,定时喂食。
- 氧气泵:控制氧气泵启停,定时充氧。
- (可扩展)CO2发生器、UV杀菌灯等。
- 用户界面:
- 本地显示:LCD或OLED显示屏,显示实时数据、状态信息、菜单操作。
- 本地按键/触摸:用于本地参数设置和设备控制。
- 远程接口:预留WiFi/以太网接口,支持远程APP或Web控制(后期扩展)。
- 定时任务:
- 可配置多个定时任务,例如每天定时开关灯、定时喂食、定时换水等。
- 定时任务可重复执行,可设置执行周期(每天、每周、自定义日期)。
- 数据记录:
- 周期性记录传感器数据和设备状态,存储在本地存储器(Flash/SD卡)。
- 可查询历史数据,方便用户分析鱼缸环境变化趋势。
- 报警功能:
- 可配置报警阈值,例如水温过高/过低、pH值异常、水位过低等。
- 报警方式:本地蜂鸣器报警、显示屏报警提示、远程APP推送报警(后期扩展)。
- 系统配置:
- 系统时间设置(RTC)。
- 传感器校准参数配置。
- 设备控制参数配置(PID参数、PWM占空比等)。
- 网络配置(WiFi/以太网配置,后期扩展)。
2. 性能指标:
- 实时性: 传感器数据采集周期:1秒,设备控制响应时间:<100ms。
- 可靠性: 系统稳定运行时间:>7*24小时,平均无故障时间(MTBF):>1年。
- 功耗: 正常工作功耗:<500mW,待机功耗:<100mW。
- 存储容量: 数据记录存储容量:>1个月的数据(假设每分钟记录一次所有传感器数据)。
- 扩展性: 预留足够的硬件接口和软件接口,方便用户扩展传感器、设备和通信方式。
3. 约束条件:
- 成本: 硬件成本控制在合理范围内,满足DIY用户的需求。
- 体积: 主控板尺寸紧凑,易于安装在鱼缸附近或集成到鱼缸设备中。
- 开发周期: 项目开发周期控制在3-6个月。
二、 代码设计架构
为了构建一个可靠、高效、可扩展的智能鱼缸系统平台,我们采用分层架构的代码设计方法。分层架构将系统划分为若干个独立的层次,每个层次负责特定的功能,层与层之间通过清晰的接口进行交互。这种架构具有良好的模块化、可维护性和可扩展性。
1. 分层架构模型:
我们的代码设计架构主要分为以下几个层次:
-
硬件抽象层 (HAL, Hardware Abstraction Layer):
- 最底层,直接与硬件交互。
- 封装硬件驱动,向上层提供统一的硬件接口。
- 包括GPIO驱动、ADC驱动、I2C驱动、SPI驱动、定时器驱动、UART驱动、RTC驱动、Flash驱动等。
- 硬件抽象层屏蔽了底层硬件的差异,使得上层应用可以独立于具体的硬件平台。
-
板级支持包 (BSP, Board Support Package):
- 位于HAL之上,为特定的硬件平台提供支持。
- 包括系统初始化、时钟配置、中断管理、内存管理、外设初始化等。
- BSP层将HAL层提供的通用硬件接口适配到具体的硬件平台上。
-
操作系统层 (OSAL, Operating System Abstraction Layer):
- 可选层,如果使用RTOS(Real-Time Operating System),则需要操作系统抽象层。
- 封装RTOS的API,向上层提供统一的操作系统接口。
- 如果不使用RTOS,则可以简化为一个简单的任务调度器或裸机系统。
- 操作系统层提供任务管理、线程同步、消息队列、定时器等服务,提高系统的并发性和实时性。
-
服务层 (Service Layer):
- 核心层,实现智能鱼缸系统的各种核心功能。
- 基于HAL和BSP层提供的硬件接口,实现传感器数据采集、设备控制、数据记录、定时任务、报警管理等服务。
- 服务层将底层的硬件操作抽象成高层次的功能接口,方便应用层调用。
-
应用层 (Application Layer):
- 最上层,实现用户界面的逻辑和系统控制逻辑。
- 基于服务层提供的功能接口,实现本地UI交互、远程控制逻辑、自动化控制策略、数据分析显示等应用功能。
- 应用层直接面向用户,提供友好的用户界面和丰富的功能。
2. 模块化设计:
在每个层次内部,我们进一步采用模块化设计,将功能分解为独立的模块。例如,在服务层,可以划分为传感器管理模块、设备控制模块、定时任务模块、数据记录模块、报警管理模块等。模块之间通过定义清晰的接口进行通信,降低模块之间的耦合度,提高代码的可维护性和可复用性。
3. 代码组织结构:
├── Core // 核心代码
│ ├── Inc // 头文件
│ │ ├── app.h // 应用层头文件
│ │ ├── service.h // 服务层头文件
│ │ ├── osal.h // 操作系统抽象层头文件
│ │ ├── bsp.h // 板级支持包头文件
│ │ └── hal.h // 硬件抽象层头文件
│ └── Src // 源文件
│ ├── app.c // 应用层源文件
│ ├── service.c // 服务层源文件
│ ├── osal.c // 操作系统抽象层源文件
│ ├── bsp.c // 板级支持包源文件
│ └── hal.c // 硬件抽象层源文件
├── Drivers // 驱动代码
│ ├── HAL // HAL驱动 (硬件无关)
│ │ ├── inc // HAL头文件
│ │ │ ├── hal_gpio.h
│ │ │ ├── hal_adc.h
│ │ │ ├── hal_i2c.h
│ │ │ ├── hal_spi.h
│ │ │ ├── hal_timer.h
│ │ │ ├── hal_uart.h
│ │ │ ├── hal_rtc.h
│ │ │ └── hal_flash.h
│ │ └── src // HAL源文件
│ │ ├── hal_gpio.c
│ │ ├── hal_adc.c
│ │ ├── hal_i2c.c
│ │ ├── hal_spi.c
│ │ ├── hal_timer.c
│ │ ├── hal_uart.c
│ │ ├── hal_rtc.c
│ │ └── hal_flash.c
│ └── BSP // BSP驱动 (硬件相关)
│ ├── inc // BSP头文件
│ │ ├── bsp_config.h // BSP配置头文件
│ │ ├── bsp_gpio.h
│ │ ├── bsp_adc.h
│ │ ├── bsp_i2c.h
│ │ ├── bsp_spi.h
│ │ ├── bsp_timer.h
│ │ ├── bsp_uart.h
│ │ ├── bsp_rtc.h
│ │ └── bsp_flash.h
│ └── src // BSP源文件
│ │ ├── bsp_init.c // 系统初始化
│ │ ├── bsp_gpio.c
│ │ ├── bsp_adc.c
│ │ ├── bsp_i2c.c
│ │ ├── bsp_spi.c
│ │ ├── bsp_timer.c
│ │ ├── bsp_uart.c
│ │ ├── bsp_rtc.c
│ │ └── bsp_flash.c
├── Middlewares // 中间件 (可选)
│ ├── RTOS // RTOS (例如 FreeRTOS, RT-Thread)
│ └── ... // 其他中间件 (例如 文件系统, 图形库)
├── Config // 配置文件夹
│ ├── app_config.h // 应用层配置
│ ├── service_config.h// 服务层配置
│ ├── bsp_config.h // BSP配置
│ └── hal_config.h // HAL配置
├── Doc // 文档
│ ├── README.md // 项目说明
│ └── ... // 其他文档
└── Project // 工程文件 (例如 Keil, IAR, GCC)
├── ... // 工程配置文件
└── ... // 编译输出文件
三、 具体C代码实现
接下来,我们将逐步实现各个层次和模块的代码。为了演示方便,我们将使用伪代码和简化代码,重点突出架构和核心逻辑。在实际项目中,需要根据具体的硬件平台和RTOS进行详细的实现。
1. 硬件抽象层 (HAL)
- hal_gpio.h:
#ifndef HAL_GPIO_H
#define HAL_GPIO_H
#include <stdint.h>
#include <stdbool.h>
typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_AF, // Alternate Function
GPIO_MODE_ANALOG
} GPIO_ModeTypeDef;
typedef enum {
GPIO_PULL_NONE,
GPIO_PULLUP,
GPIO_PULLDOWN
} GPIO_PullTypeDef;
typedef enum {
GPIO_SPEED_LOW,
GPIO_SPEED_MEDIUM,
GPIO_SPEED_HIGH,
GPIO_SPEED_VERY_HIGH
} GPIO_SpeedTypeDef;
typedef struct {
uint32_t Pin; // GPIO Pin number
GPIO_ModeTypeDef Mode; // GPIO Mode
GPIO_PullTypeDef Pull; // Pull-up/Pull-down
GPIO_SpeedTypeDef Speed; // GPIO Speed
} GPIO_InitTypeDef;
typedef struct {
uint32_t GPIOx_BASE; // GPIO Port Base Address (硬件相关)
} GPIO_TypeDef;
#define GPIOA_BASE (0x40020000UL) // 示例地址
#define GPIOB_BASE (0x40020400UL) // 示例地址
// ... 其他GPIO端口
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
// ... 其他GPIO端口
// 初始化GPIO
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
// 设置GPIO输出高电平
void HAL_GPIO_SetBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
// 设置GPIO输出低电平
void HAL_GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
// 读取GPIO输入电平
uint32_t HAL_GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
// 切换GPIO输出电平
void HAL_GPIO_ToggleBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
#endif /* HAL_GPIO_H */
- hal_gpio.c:
#include "hal_gpio.h"
#include "bsp_config.h" // 引入BSP配置
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) {
// 硬件相关的GPIO初始化代码,例如配置寄存器
// 这里需要根据具体的MCU平台进行实现
// 例如:使能GPIO时钟,配置GPIO模式、速度、上下拉等
// 使用BSP层提供的宏或函数来访问硬件寄存器
// 例如:BSP_GPIO_EnableClock(GPIOx);
// BSP_GPIO_SetMode(GPIOx, GPIO_Init->Pin, GPIO_Init->Mode);
// ...
// 示例代码 (伪代码)
if (GPIOx == GPIOA) {
// 使能GPIOA时钟
BSP_GPIOA_ClockEnable();
} else if (GPIOx == GPIOB) {
// 使能GPIOB时钟
BSP_GPIOB_ClockEnable();
}
// ... 其他GPIO端口时钟使能
// 配置GPIO模式
if (GPIO_Init->Mode == GPIO_MODE_OUTPUT) {
BSP_GPIO_SetModeOutput(GPIOx, GPIO_Init->Pin);
} else if (GPIO_Init->Mode == GPIO_MODE_INPUT) {
BSP_GPIO_SetModeInput(GPIOx, GPIO_Init->Pin);
} // ... 其他模式配置
// 配置GPIO上下拉
if (GPIO_Init->Pull == GPIO_PULLUP) {
BSP_GPIO_SetPullUp(GPIOx, GPIO_Init->Pin);
} else if (GPIO_Init->Pull == GPIO_PULLDOWN) {
BSP_GPIO_SetPullDown(GPIOx, GPIO_Init->Pin);
} // ... 其他下拉配置
// 配置GPIO速度
BSP_GPIO_SetSpeed(GPIOx, GPIO_Init->Pin, GPIO_Init->Speed);
}
void HAL_GPIO_SetBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) {
// 设置GPIO输出高电平的硬件相关代码
BSP_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET); // 使用BSP层函数
}
void HAL_GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) {
// 设置GPIO输出低电平的硬件相关代码
BSP_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET); // 使用BSP层函数
}
uint32_t HAL_GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) {
// 读取GPIO输入电平的硬件相关代码
return BSP_GPIO_ReadPin(GPIOx, GPIO_Pin); // 使用BSP层函数
}
void HAL_GPIO_ToggleBits(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) {
// 切换GPIO输出电平的硬件相关代码
BSP_GPIO_TogglePin(GPIOx, GPIO_Pin); // 使用BSP层函数
}
- 其他HAL驱动 (hal_adc.h, hal_i2c.h, …): 类似HAL_GPIO,定义各种硬件外设的抽象接口,例如 ADC 初始化、读取数据,I2C 初始化、读写数据等。 这些驱动的实现都需要调用BSP层提供的硬件操作函数。
2. 板级支持包 (BSP)
- bsp_config.h: 定义硬件平台相关的配置信息,例如 GPIO 端口地址、寄存器位定义、时钟频率等。
#ifndef BSP_CONFIG_H
#define BSP_CONFIG_H
// MCU 选择 (示例)
#define STM32F407xx
// 时钟配置 (示例)
#define SYS_CLK_FREQ_HZ 168000000UL // 168MHz
// GPIO 端口定义 (示例)
#define BSP_GPIOA_CLK_ENABLE() // 使能GPIOA时钟的宏定义 (硬件相关)
#define BSP_GPIOB_CLK_ENABLE() // 使能GPIOB时钟的宏定义 (硬件相关)
// ... 其他GPIO端口时钟使能宏
#define BSP_GPIO_SET_MODE_OUTPUT(GPIOx, Pin) // 设置GPIO为输出模式的宏定义 (硬件相关)
#define BSP_GPIO_SET_MODE_INPUT(GPIOx, Pin) // 设置GPIO为输入模式的宏定义 (硬件相关)
// ... 其他GPIO模式设置宏
#define BSP_GPIO_SET_PULLUP(GPIOx, Pin) // 设置GPIO上拉的宏定义 (硬件相关)
#define BSP_GPIO_SET_PULLDOWN(GPIOx, Pin) // 设置GPIO下拉的宏定义 (硬件相关)
// ... 其他GPIO上下拉设置宏
#define BSP_GPIO_SET_SPEED(GPIOx, Pin, Speed) // 设置GPIO速度的宏定义 (硬件相关)
#define BSP_GPIO_WRITE_PIN(GPIOx, Pin, State) // GPIO写引脚的宏定义 (硬件相关)
#define BSP_GPIO_READ_PIN(GPIOx, Pin) // GPIO读引脚的宏定义 (硬件相关)
#define BSP_GPIO_TOGGLE_PIN(GPIOx, Pin) // GPIO翻转引脚的宏定义 (硬件相关)
// ADC 外设定义 (示例)
#define ADC1_BASE (0x40012000UL) // ADC1 基地址
#define ADC1 ((ADC_TypeDef *)ADC1_BASE)
typedef struct {
uint32_t CR1;