1. 项目概述
这个基于STM32单片机的水产养殖自动喂食与水环境监测系统,是我最近完成的一个嵌入式开发项目。它能够实时监测鱼塘的水温、湿度、溶氧量等关键参数,并在异常情况下自动启动增氧设备,同时还能按照预设时间自动投喂饲料。对于中小型水产养殖场来说,这套系统可以有效降低人工管理成本,提高养殖效率。
系统硬件部分采用了STM32F103C8T6作为主控芯片,搭配DHT11温湿度传感器、电位器模拟的溶氧传感器、DS1302实时时钟模块、LCD1602显示屏以及电机驱动电路。软件方面使用Keil MDK进行开发,通过Proteus完成了系统仿真验证。
2. 系统硬件设计
2.1 主控芯片选型
我选择了STM32F103C8T6这款Cortex-M3内核的微控制器,主要基于以下几点考虑:
- 性能足够:72MHz主频完全能满足传感器数据采集、处理以及电机控制的需求
- 外设丰富:内置ADC、定时器、GPIO等必要外设,减少外围电路复杂度
- 成本优势:相比同性能的其他MCU,STM32F103系列性价比极高
- 开发便利:有完善的开发工具链和丰富的资料参考
提示:STM32F103C8T6的GPIO分配需要特别注意,部分引脚有复用功能。建议在项目初期就规划好各功能模块的引脚分配,避免后期冲突。
2.2 传感器模块设计
系统使用了三种主要传感器:
-
DHT11温湿度传感器:
- 测量范围:温度0-50℃(±2℃精度),湿度20-90%RH(±5%精度)
- 单总线通信协议,接线简单
- 低功耗,适合长期监测
-
溶氧量检测:
- 使用电位器模拟溶氧传感器输出
- 通过STM32的ADC1通道采集电压值
- 电压-浓度转换公式:nongdu = vol*(3.4/4096)*33
-
DS1302实时时钟:
- 提供精确的时间基准
- 内置电池供电,断电不影响计时
- 通过三线接口与MCU通信
2.3 显示与交互设计
LCD1602显示屏负责展示所有监测数据和时间信息:
- 第一行显示:温度(T)、湿度(H)、溶氧量(N)
- 第二行显示:当前时间(时:分:秒)和预设喂食时间
三个按键用于设置喂食时间:
- 按键1:小时增加
- 按键2:分钟增加
- 按键3:确认设置
3. 系统软件设计
3.1 主程序流程
系统软件采用轮询方式实现,主循环主要完成以下任务:
c复制while (1)
{
i++;
delay_ms(10);
if(i>=100) // 每1秒执行一次
{
i=0;
// 读取ADC值并计算溶氧量
vol = ADC_GetConversionValue(ADC1);
nongdu = vol*(3.4/4096)*33;
// 读取温湿度
DHT11_receive(&shidu,&wendu);
// 读取实时时钟
ReadDS1302Clock(time_data);
shi = time_data[3]%16+time_data[3]/16*10;
fen = time_data[4]%16+time_data[4]/16*10;
miao = time_data[5]%16+time_data[5]/16*10;
// 更新显示
Display();
}
// 按键扫描
anjiansaomiao();
// 溶氧量低于阈值报警并启动增氧
if(nongdu<30) {
PBout(6)=0; // 蜂鸣器报警
}
else {
PBout(6)=1; // 关闭蜂鸣器
}
// 定时喂食控制
if(shi==xiaoshi && fen==fenzhong) {
PBout(14)=0; // 启动喂食电机
}
else {
PBout(14)=1; // 关闭电机
}
}
3.2 关键功能实现
3.2.1 ADC采集与溶氧量计算
溶氧量检测使用了STM32内置的12位ADC:
c复制void ADC_Set(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
// 校准ADC
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
溶氧量计算采用线性转换公式,将ADC值转换为实际浓度:
c复制vol = ADC_GetConversionValue(ADC1);
nongdu = vol*(3.4/4096)*33;
注意:这里的3.4是参考电压(Vref),33是比例系数,实际项目中需要根据具体传感器特性调整这两个参数。
3.2.2 定时喂食功能
喂食时间设置逻辑:
c复制void anjiansaomiao(void)
{
if(KEY1==0) {
delay_ms(10);
if(KEY1==0) {
xiaoshi++;
if(xiaoshi>=24) xiaoshi=0;
while(!KEY1);
}
}
if(KEY2==0) {
delay_ms(10);
if(KEY2==0) {
fenzhong++;
if(fenzhong>=60) fenzhong=0;
while(!KEY2);
}
}
if(KEY3==0) {
delay_ms(10);
if(KEY3==0) {
// 确认设置
while(!KEY3);
}
}
}
4. Proteus仿真实现
4.1 仿真电路设计
Proteus仿真电路包含以下主要元件:
- STM32F103C8控制器
- LCD1602显示屏
- DHT11温湿度传感器
- 电位器(模拟溶氧传感器)
- 电机和蜂鸣器驱动电路
- DS1302实时时钟模块
- 三个设置按键
提示:在Proteus中仿真时,DHT11需要使用DHT11仿真模型,DS1302也需要对应的仿真元件。这些元件库可能需要单独安装。
4.2 仿真调试技巧
-
ADC调试:
- 在Proteus中可以通过改变电位器阻值来模拟不同溶氧量
- 使用虚拟终端观察ADC原始值和计算后的浓度值
-
时间设置验证:
- 在仿真中可以通过修改DS1302的初始时间加速测试
- 观察LCD显示的时间变化是否符合预期
-
喂食触发测试:
- 设置一个接近当前时间的喂食时间
- 观察到达设定时间后电机是否正常启动
5. 实际应用与优化建议
5.1 系统部署注意事项
-
传感器安装:
- DHT11需要避免阳光直射,最好安装在遮阳处
- 溶氧传感器应安装在鱼塘中部深度,避免靠近增氧设备
-
电源管理:
- 建议使用12V蓄电池供电,搭配稳压电路
- 考虑增加太阳能充电模块实现长期户外供电
-
防水处理:
- 所有电路板需要做好防水密封
- 接线处使用防水接头
5.2 功能扩展建议
-
增加无线通信:
- 添加ESP8266模块实现远程监控
- 通过手机APP查看数据和接收报警
-
多参数监测:
- 增加pH值传感器
- 增加氨氮含量检测
-
数据记录:
- 添加SD卡模块存储历史数据
- 实现数据曲线显示和分析
-
智能控制算法:
- 根据历史数据预测最佳喂食时间
- 实现溶氧量的PID控制
6. 常见问题与解决方案
6.1 传感器读数异常
问题现象:DHT11偶尔返回错误数据
解决方案:
- 检查接线是否牢固
- 增加读取失败后的重试机制
- 添加数据校验,丢弃明显不合理的数据
c复制// 改进的DHT11读取函数
uint8_t DHT11_receive(uint8_t *shidu,uint8_t *wendu)
{
uint8_t buf[5];
uint8_t i,checksum;
// 尝试最多3次
for(int retry=0; retry<3; retry++) {
if(DHT11_read_data(buf)==0) {
checksum = buf[0]+buf[1]+buf[2]+buf[3];
if(checksum == buf[4]) { // 校验和正确
*shidu = buf[0];
*wendu = buf[2];
return 0;
}
}
delay_ms(100);
}
return 1; // 读取失败
}
6.2 喂食电机不工作
可能原因:
- 驱动电流不足
- GPIO配置错误
- 定时时间设置不正确
排查步骤:
- 检查电机驱动电路电源电压
- 用万用表测量控制引脚电平
- 在代码中添加调试输出,确认定时判断逻辑
6.3 LCD显示乱码
解决方法:
- 检查初始化序列是否正确
- 确认对比度调节电位器设置
- 检查数据传输时序,必要时增加延时
c复制// 可靠的LCD1602写入函数
void WrByte1602(uint8_t y, uint8_t x, uint8_t dat)
{
while(Busy1602()); // 等待LCD空闲
if(y==0)
WrCom1602(0x80+x); // 第一行
else
WrCom1602(0xC0+x); // 第二行
while(Busy1602());
WrDat1602(dat);
delay_us(50); // 增加适当延时
}
7. 项目总结与心得
在实际开发过程中,有几个关键点值得特别注意:
-
实时时钟的精度问题:DS1302虽然成本低,但长期运行可能会有几秒的误差。对于需要精确计时的应用,可以考虑改用DS3231等高精度模块。
-
传感器抗干扰:水产养殖环境通常湿度大,电磁环境复杂。所有信号线最好使用屏蔽线,并做好防水处理。
-
电源稳定性:系统要长期稳定运行,电源设计至关重要。建议采用宽电压输入的DC-DC模块,并增加必要的滤波电路。
-
异常处理:在实际部署中,各种异常情况比仿真环境复杂得多。代码中需要增加足够的错误检测和恢复机制。
这个项目从原型到实际应用还需要考虑很多工程化问题,但作为学习STM32和嵌入式系统开发的案例,它涵盖了传感器采集、外设控制、人机交互等多个重要知识点,是一个非常实用的练手项目。