项目简介
用Arduino开发板在Proteus仿真软件中搭建DHT22温湿度计,实现用ws2812灯带颜色区分温度计工作状态。所用软件版本为Arduino IDE1.8.19,Proteus8.11。
一、设计方案
1.1功能介绍
1.1.1 DHT22温湿度传感器(A0引脚)
DHT22温湿度计测量范围(0——100°),用于读取环境中的实际温度和实际湿度,第一行显示实际湿度(%),第二行显示实际温度(°C)。
1.1.2 WS2812灯带(8位)(13号引脚)
用于区分环境实际温度相对于设置的阈值温度的大小,当实际温度高于阈值温度,WS2812灯带显示红色;当实际温度等于阈值温度,WS2812灯带显示绿色;当实际温度低于阈值温度,WS2812灯带显示蓝色。
1.1.3 工作状态区分灯带(12号引脚)
正常工作时灯带颜色是彩虹色,表示温度计处于正常工作状态。
1.1.4 超过阈值温度报警器(11号引脚)
当实际温度超过设置的阈值温度时,报警器响铃。
实际温度未超过阈值温度(报警器未响起) 实际温度超过阈值温度(报警器响起)
1.1.5 LCD显示屏(A4、A5引脚)
第一行Temp代表实际温度(℃),第二行THR代表设置的阈值温度(℃)(阈值温度默认为27°C),第三行humidity代表环境的湿度值(%),第四行前五列作为阈值温度输入模式时的输入温度显示。
1.1.6 串口模块(0、1号引脚)
温度/湿度值通过虚拟串口发送,串口将一些数据通过串口发送。波特率设置为9600。
1.1.7 阈值温度输入模式开关(9号引脚)
接高电平打开阈值输入模式,程序进入中断;输入完成阈值温度后,将阈值温度输入模式开关接地,关闭阈值输入模式。
阈值输入模式打开 阈值输入模式关闭
1.1.8 阈值温度输入模式指示灯(10号引脚)
打开阈值输入模式开关时亮起,指示灯亮的时候表示可以进行阈值温度的设置,关闭阈值输入模式时熄灭。
阈值输入模式关闭 阈值输入模式打开
1.1.9 4*3矩阵输入键盘(2、3、4、5、6、7、8引脚)
用于打开阈值温度输入模式后进行阈值温度的设置输入,阈值温度默认设置为27°C,阈值温度输入格式"xx.xx + Enter"。
实现功能:
温度测量模式:用DHT22温湿度传感器采集环境的实际温度和实际湿度,当实际温度高于阈值温度(默认27°C)时,ws2812显示红色,报警器报警响铃;当实际温度等于阈值温度时,ws2812显示绿色;当实际温度低于阈值温度时,ws2812显示蓝色。
阈值温度输入模式:打开阈值温度输入模式可以进行阈值温度的输入,输入格式为xx.xx+Enter。输入完成之后要关闭阈值温度输入模式开关,可以实现阈值温度的更改。
1.2所用库名
1.2.1 Adafruit_NeoPixel.h库
Adafruit_NeoPixel是一个开源的Arduino库,用于控制基WS2812等LED驱动芯片的RGB LED像素串。
1.2.2 LiquidCrystal_I2C.h库
LCD1604是一种16列4行的字符液晶显示模块,常用于Arduino等嵌入式系统的用户接口。为了简化连接和编程,我们将使用I2C接口,这只需要Arduino的两个模拟输入引脚,需要安装用于I2C通信的arduino库LiquidCrystal_I2C。
1.2.3 Keypad.h库
Keypad.h库是一个用于Arduino的库,用于处理键盘输入。它可以用于连接和读取矩阵式键盘或按钮阵列。通过使用Keypad.h库,可以轻松地检测按下的按钮,并执行相应的操作。
二、电路图
2.1 设计proteus仿真电路图如下图所示
三、程序流程图
3.1 arduino程序中的loop循环运行逻辑流程图如下图所示:
四、设计实现结果
当实际温度为27°C等于阈值温度(默认27°C)时,ws2812灯带显示绿色。
当实际温度为27.1°C大于阈值温度(默认27°C)时,ws2812灯带显示红色,超过阈值温度报警器响起。
当实际温度为26.9°C小于阈值温度(默认27°C)时,ws2812灯带显示蓝色。
同时,串口发送环境的实际温度和环境的实际湿度。
打开阈值温度输入模式开关,进行阈值温度重新设定输入,可以看到阈值温度输入模式指示灯亮起。
重新设置阈值温度为15.04°C,可以看到LCD屏幕第四行前五列显示输入的阈值温度,输入完成后点击Enter键确定,然后关闭阈值温度输入模式开关。
等待2s后可以在LCD显示屏上看到阈值温度THR变成了15.04°C,实际温度26.9°C大于重新设置的阈值温度,ws2812灯带显示红色,超过阈值温度报警器响起。
五、Arduino代码
#include<Adafruit_NeoPixel.h> //ws2812灯带
#include<LiquidCrystal_I2C.h> //LCD显示屏
#include<Keypad.h> //导入矩阵键盘模块
#define WS2812_Pin1 13 //ws2812灯带1接引脚13
#define WS2812_Pin2 12 //ws2812灯带2接引脚12
#define NUM_LEDS1 8 //灯带一有8个灯
#define NUM_LEDS2 16 //灯带二有16个灯
#define switch_key 9 //阈值温度输入模式开关接引脚9
#define LED 10 //阈值温度输入模式指示灯接引脚10
#define sounder 11 //温度阈值报警器接引脚11
#define data A0 //DHT22的Data引脚接到Arduino开发板的A0引脚
Adafruit_NeoPixel strip1(NUM_LEDS1, WS2812_Pin1, NEO_GRB + NEO_KHZ800);//ws2812灯带1
Adafruit_NeoPixel strip2(NUM_LEDS2, WS2812_Pin2, NEO_GRB + NEO_KHZ800);//ws2812灯带2
LiquidCrystal_I2C lcd(0x27, 16, 4); //16*4 LCD显示屏
unsigned char i; //无符号8位整型变量
float RH,T; //单精度浮点数(32位长度)
byte RH_H,RH_L,T_H,T_L,sum,check; //字节变量,二进制数
float Threshold_temperature = 27.0; //阈值温度(默认27.00°C)
int j = 0; //对输入显示位置计数
const byte ROWS = 4; //矩阵键盘行数
const byte COLS = 3; //矩阵键盘列数
char keys[ROWS][COLS] = { // 定义键盘矩阵数组
{'1','2','3'}, // 1 2 3
{'4','5','6'}, // 4 5 6
{'7','8','9'}, // 7 8 9
{'.','0','A'}, // . 0 A
};
byte rowPins[ROWS] = {2, 3, 4, 5};//行的针脚连接的接口,第一行连2脚,第二行连3脚,第三行连4脚,第四行连5脚
byte colPins[COLS] = {6, 7, 8}; //列的针脚连接的接口,第一列连6脚,第二列连7脚,第三列连8脚
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); //4*3键盘
String inputString = ""; // 保存输入数据的字符串
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); //设置串口通信波特率9600
lcd.init(); //LCD初始化
lcd.backlight();
lcd.setCursor(0,0); //lcd第1行显示温度
lcd.print("Temp: C");
lcd.setCursor(12,0);
lcd.print((char)223); //显示o符号
lcd.setCursor(0,1); //lcd第2行显示阈值温度
lcd.print("THR: C");
lcd.setCursor(12,1);
lcd.print((char)223); //显示o符号
lcd.setCursor(7,1);
lcd.print(Threshold_temperature); //LCD阈值温度显示
lcd.setCursor(-4,2); //lcd第三行显示湿度
lcd.print("humidity: %");
strip1.begin(); //设置灯带开始
strip1.setBrightness(250); //设置灯带亮度(0,255)
strip1.show(); // 初始化
strip2.begin(); //设置灯带开始
strip2.setBrightness(250); //设置灯带亮度(0,255)
strip2.show(); // 初始化
pinMode(LED,OUTPUT); // LED引脚输出模式
digitalWrite(LED,LOW); // 低电平输出
pinMode(sounder,OUTPUT); // 报警器引脚输出模式
digitalWrite(sounder,LOW); // 低电平输出
pinMode(switch_key, INPUT); // 设置引脚10为输入模式
}
void loop() {
// put your main code here, to run repeatedly:
if(digitalRead(switch_key) == HIGH){ // 如果开关被按下,进入阈值温度输入模式
digitalWrite(LED,HIGH); // 点亮led表示可以进行阈值温度输入
char key = keypad.waitForKey(); // 存贮输入的字符
delay(200); // 延迟 200ms
if(key != 'A'){
lcd.setCursor(-4+j,3);
lcd.print(key);
j++;
}
inputString += key;
Serial.print(key);
Serial.print("\n");
Serial.print("Current inputString:");
Serial.print(inputString);
theaterChaseRainbow(0); // 彩虹灯带亮
}
else{
digitalWrite(LED,LOW); //led低电平
theaterChaseRainbow(3);
}
if (inputString.endsWith("A")) {
inputString = inputString.substring(0, inputString.length() - 1); // 移除结束标志‘A’
float temperature = inputString.toFloat(); // 将字符串转换成浮点数xx.xx
if(temperature >= 0 && temperature <= 100){ //判读输入温度是否合理
Threshold_temperature = temperature; //设置阈值温度大小
}
inputString = ""; //清空字符串
Serial.print("\n");
Serial.print(Threshold_temperature); //串口发送显示阈值温度大小
lcd.setCursor(7,1);
lcd.print(Threshold_temperature); //LCD阈值温度显示
digitalWrite(LED,LOW); //led低电平关闭
i = 0;
delay(3000); //延长3秒,用于灯带用户取消阈值输入模式
}
digitalWrite(LED,LOW);
DHT22(); //获取温湿度数据
Serial.print("Humidity:"); //向串口打印 Humidity:
Serial.print(RH); //向串口打印湿度数据
Serial.print("%");
Serial.print(" Temperature:");
Serial.print(T); //向串口打印温度数据
Serial.println("C");
lcd.setCursor(7,0);
lcd.print(T); //LCD温度显示
lcd.setCursor(5,2);
lcd.print(RH); //LCD湿度显示
lcd.setCursor(7,1);
lcd.print(Threshold_temperature); //LCD阈值温度显示
if(T < Threshold_temperature){
colorWipe(strip1.Color( 0, 0, 255), 30); // 蓝
digitalWrite(sounder,LOW);
}
else if(T > Threshold_temperature){
colorWipe(strip1.Color(255, 0, 0), 30); // 红
digitalWrite(sounder,HIGH);
}
else{
colorWipe(strip1.Color( 0, 255, 0), 30); // 绿
digitalWrite(sounder,LOW);
}
}
//用一种颜色一个接一个地填充条形像素。带材未先清除;原有像素都将被逐个覆盖。
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip1.numPixels(); i++) { //每次循环处理一个像素
strip1.setPixelColor(i, color); // 设置像素值 (在RAM里)
strip1.show();
delay(wait);
}
}
// 彩虹函数,在帧之间传递延迟时间(毫秒)
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // 第一个像素以红色开始(色调0)
for(int a=0; a<30; a++) { // 重复30次...
for(int b=0; b<3; b++) { // 'b'从0到2…
strip2.clear(); // 将RAM中的所有像素设置为0(关闭)
// “c”从“b”开始计数,以3为增量到条带的末尾…
for(int c=b; c<strip2.numPixels(); c += 3) {
// 像素“c”的色相被偏移了一定的量,使其饱满
// 色轮(范围65536)沿长度的转数
// (strip. numpixels()步骤):
int hue = firstPixelHue + c * 65536L / strip2.numPixels();
uint32_t color = strip2.gamma32(strip2.ColorHSV(hue)); // hue -> RGB
strip2.setPixelColor(c, color); // 设置像素c的值为color
}
strip2.show(); // 用新内容更新条带
delay(wait); // 等待
firstPixelHue += 65536 / 90; // 一个周期的色轮超过90帧
}
}
}
void DHT22(void)
{
RH_H=0,RH_L=0,T_H=0,T_L=0,sum=0,check=0;
pinMode(data,OUTPUT); //设置IO口为输出模式
digitalWrite(data,1); //设置IO口输出高电平
delay(10); //延时10毫秒
digitalWrite(data,0); //设置IO口输出低电平
delay(25); //延时25毫秒
digitalWrite(data,1); //设置IO口输出高电平
pinMode(data,INPUT); //设置IO口为输入模式
delayMicroseconds(30); //延时30微秒
if(!digitalRead(data)) //判断IO口输入电平是否低电平
{
while(!digitalRead(data)); //一直循环至输入为高电平
while(digitalRead(data)); //一直循环至输入为低电平
for(i=0;i<8;i++) //循环执行8次
{
while(!digitalRead(data));//一直循环至输入为高电平
delayMicroseconds(28); //延时28微秒
if(digitalRead(data)){ //判断IO口输入电平是否高电平
bitWrite(RH_H, 7-i, 1); //在二进制变量RH_H的第7-i位(从右数起)写入1
while(digitalRead(data));
}
}
for(i=0;i<8;i++)
{
while(!digitalRead(data));
delayMicroseconds(28);
if(digitalRead(data)){
bitWrite(RH_L, 7-i, 1);
while(digitalRead(data));
}
}
for(i=0;i<8;i++)
{
while(!digitalRead(data));
delayMicroseconds(28);
if(digitalRead(data)){
bitWrite(T_H, 7-i, 1);
while(digitalRead(data));
}
}
for(i=0;i<8;i++)
{
while(!digitalRead(data));
delayMicroseconds(28);
if(digitalRead(data)){
bitWrite(T_L, 7-i, 1);
while(digitalRead(data));
}
}
for(i=0;i<8;i++)
{
while(!digitalRead(data));
delayMicroseconds(28);
if(digitalRead(data)){
bitWrite(check, 7-i, 1);
while(digitalRead(data));
}
}
}
sum=RH_H + RH_L + T_H + T_L;
byte sum_temp=0;
//读取sum的末8位写入sum_temp
for(i=0;i<8;i++){
bitWrite(sum_temp,i,bitRead(sum,i));
}
if(check==sum_temp){
if(bitRead(RH_H,7)==1){ //判断温度是否零下
T=-(float(T_H<<8)+float(T_L))/10;
}else{
T=(float(T_H<<8)+float(T_L))/10;
}
RH=(float(RH_H<<8)+float(RH_L))/10;
}
}