前言
板子上的外设有限,加上想法也很局限,就用几个传感器实现了非常简单的监测,显示和效应也没用太复杂的效果。虽说很简单,但传感器驱动还是琢磨了不久,加上串口线坏了,调试了半天才发现不是代码错了而是线有问题,总而言之,课设不复杂,难度不高,凑合看吧。
电路图
系统的需求描述
温室环境监测系统的功能性需求描述如下:
1.光照监测与响应
系统对光敏电阻进行 AD 采样获取环境光照强度。当环境光照减弱至预设阈值以下时, 系统会自动点亮绿灯以提供照明。同时,LED 灯闪烁报警,蜂鸣器需发出报警声。
2.温度监测与响应
系统通过 DS18B20 数字温度传感器和 DHT11 数字湿温度传感器获取温室环境温度, 以两者平均值作为测量的温度。当温度低于预设的下限阈值时,系统自动启动加热装置进行 加热(开发板并无加热设备,这里使用点亮红灯来模拟),直到温度上升至正常水平。当温 度高于预设的上限阈值时,系统需驱动电机旋转(风扇)以进行散热。并且,温度异常(过 高或过低)时,LED 灯闪烁报警,蜂鸣器需发出报警声。
3.湿度监测与响应
系统通过 DHT11 数字湿温度传感器获取环境湿度。当湿度超出预设的正常范围时, LED 灯闪烁报警,蜂鸣器需发出报警声。湿度太高时,还会亮起蓝灯。湿度太低时,会驱动 电机模拟启动灌溉设备。
4.数据显示
LCD 屏幕会实时显示光照、温度和湿度的数据信息。显示要做到清楚、直观,更新频率 适中。
5.串口通信
上位机和系统能通过串口进行通信,系统能够将光照、温度和湿度的采样数据实时发送 给上位机,上位机可以将数据存储到本地文件或上传到云服务器,实现了环境数据的采集、 传输、存储,可以为后续大数据处理提供数据支持。数据传输需稳定可靠,数据格式要遵守 通信协议。
6.按键控制
管理员可以通过按键开关报警功能和手动开关全彩灯。按键操作简单直观,响应时间快, 如果系统自动化调整功能失效,还可以通过手动方式调整设备。
结构图
详细设计
只说明传感器的部分
DS18B20 模块:
用于环境温度的数据采集。
DS18B20 是常用的数字温度传感器,单总线结构。该传感器体积小、硬件开销低、抗干扰能力强、误差小。一般在启动传感器并与之通信前,需要先经过 ROM 检测,但是开发板上只挂载了一个 DS18B20 设备,可以在初始化总线之后直接发送 0xcc 跳过 ROM 检查。使用 Convert T 开始温度转化命令(0x44)开始温度转化之后,经过一定时间,DS18B20 会将温度转化之后的数据存储到暂存器内。通过 Read Scratchpad 读取命令(0xBE) 可以从暂存器读数据。只采集温度数据所以只用接受前两个字节,高八位的高五位是符号位,高八位的低三位和低八位的高四位表示温度的整数位,低八位的低四位表示小数位。在本系统中温度数据保留一位小数。该模块对应文件为"ds18b20.h"和"ds18b20.c"。
相关的讲解可看(这两篇文章并不是使用的stm32,主要看模块的时序):
蓝桥杯电子类单片机学习二——DS18B20温度传感器(onewire驱动)_蓝桥杯板子用ds18b20-CSDN博客
51单片机-18B20温度传感器-CSDN博客
参考代码:
适配stm32板子 、hal库
#include "ds18b20.h"
#include "tim.h"
void DS18B20_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);
}
void DS18B20_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);
}
void DS18B20_Rst(void)
{
DS18B20_IO_OUT();
DS18B20_DQ_OUT_LOW;
delay_us_by_Tim(750);
DS18B20_DQ_OUT_HIGH;
delay_us_by_Tim(15);
}
uint8_t DS18B20_Check(void)
{
uint8_t retry = 0;
DS18B20_IO_IN();
while(DS18B20_DQ_IN && retry < 200)
{
retry++;
delay_us_by_Tim(1);
}
if(retry >= 200)
return 1;
else
retry = 0;
while(!DS18B20_DQ_IN && retry < 240)
{
retry++;
delay_us_by_Tim(1);
}
if(retry >= 240)
return 1;
return 0;
}
uint8_t DS18B20_Read_Bit(void)
{
uint8_t data;
DS18B20_IO_OUT();
DS18B20_DQ_OUT_LOW;
delay_us_by_Tim(2);
DS18B20_DQ_OUT_HIGH;
DS18B20_IO_IN();
delay_us_by_Tim(12);
if(DS18B20_DQ_IN)
data = 1;
else
data = 0;
delay_us_by_Tim(50);
return data;
}
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i,j,data;
data = 0;
for(i=1;i<=8;i++)
{
j = DS18B20_Read_Bit();
data = (j<<7)|(data>>1);
}
return data;
}
void DS18B20_Write_Byte(uint8_t data)
{
uint8_t j;
uint8_t testb;
DS18B20_IO_OUT();
for(j=1;j<=8;j++)
{
testb=data&0x01;
data=data>>1;
if(testb)
{
DS18B20_DQ_OUT_LOW;
delay_us_by_Tim(2);
DS18B20_DQ_OUT_HIGH;
delay_us_by_Tim(60);
}
else
{
DS18B20_DQ_OUT_LOW;
delay_us_by_Tim(60);
DS18B20_DQ_OUT_HIGH;
delay_us_by_Tim(2);
}
}
}
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
}
uint8_t DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);
DS18B20_Rst();
return DS18B20_Check();
}
short DS18B20_Get_Temperature(void)
{
//uint8_t temp;
uint8_t TL,TH;
short temperature;
DS18B20_Start();
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0xbe);
TL = DS18B20_Read_Byte();
TH = DS18B20_Read_Byte();
if(TH>7)
{
TH = ~TH;
TL = ~TL;
// temp = 0;
}
// else
// temp = 1;
temperature = TH;
temperature <<= 8;
temperature += TL;
temperature = (float)temperature*0.625;//0.0625*10,保留小数一位,后面处理的时候要除以10
if(temperature)
return temperature;
else
return -temperature;
}
DHT11 模块:
用于环境温度和湿度的数据采集。
DHT11 数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。一次完整的数据传输为 40bit,高位先出,数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,校验和数据为前四个字节相加。
DHT11 传输时序为:总线空闲状态为高电平,主机把总线拉低等待 DHT11 响应(总线拉低必须大于 18 毫秒,保证 DHT11 能检测到起始信号),主机发送开始信号结束后,延时等待 20-40us,DHT11 接收到主机的开始信号后,等待主机开始信号结束,然后发送 80us(一般存在误差,20-100us 都可以认为是正常响应时间)低电平响应信号。如果读取总线为低电平,说明 DHT11 发送响应信号,如果读取总线为高电平,则 DHT11 没有响应。DHT11 发送响应信号后,再把总线拉高,准备发送数据,每 1bit 数据都以 50us 低电平时隙开始,告诉主机开始传输一位数据了。当 50us 低电平时隙过后拉高总线,高电平持续 26~28us 表示数据“0”;持续 70us 表示数据“1”。由于存在误差,程序中在延时 40us 后检测总线状态,为高说明该位数据为“1”,为低说明该位数据为“0”。当最后 1bit 数据传送完毕后,
DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。该模块对应文件为"dht11.h"和"dht11.c"。
该模块可从下面博客移植:
HAL库:
STM32F103ZET6——DHT11温湿度传感器(hal库)_dht11stm32f103-CSDN博客
标准库(主要参考其的时序讲解):
DHT11详细介绍(内含51和STM32代码)-CSDN博客
基于STM32的温湿度传感器(DHT11)+OLED屏显示(超详细)_stm32控制dht11-CSDN博客
参考代码
(注意这里的延时函数命名成了delay_us_by_Tim()):
#include "dht11.h"
#include "tim.h"
void DHT11_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);
}
void DHT11_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);
}
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //设置为输出
DHT11_DQ_OUT_LOW; //拉低DQ
HAL_Delay(20); //拉低至少18ms
DHT11_DQ_OUT_HIGH; //DQ=1
delay_us_by_Tim(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void)
{
uint8_t retry=0;
DHT11_IO_IN(); //设置为输出
while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us_by_Tim(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us_by_Tim(1);
};
if(retry>=100)return 1;
return 0;
}
//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void)
{
uint8_t retry=0;
while(DHT11_DQ_IN&&retry<100)//等待变为低电平
{
retry++;
delay_us_by_Tim(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待变高电平
{
retry++;
delay_us_by_Tim(1);
}
delay_us_by_Tim(40);//等待40us
if(DHT11_DQ_IN)return 1;
else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte(void)
{
uint8_t i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)
{
uint8_t buf[5];
uint8_t i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=(buf[0]<<8) + buf[1];
*temp=(buf[2]<<8) + buf[3];
}
}else return 1;
return 0;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
uint8_t DHT11_Init(void)
{
DHT11_Rst();
return DHT11_Check();
}