单片机实验报告

环境舒适度监测系统应用与设计

概述

众所周知,人们平时的工作环境对工作效率和生产力有很大的影响。如果工作环境不够舒适,温度、湿度不适宜,光照条件不佳(过亮或者过暗),人们工作时的心情和效率都会受到很大影响。正因此,随着人们对工作环境要求的提高以及科技的不断进步,尤其是各类依托于电子技术的环境感知技术的发展,能够监测环境舒适度参数、并在基础上对环境参数进行调控的产品亟需开发。

在上述背景下,本项目利用Arduino开发板、DHT11温湿度传感器、二极管、光敏传感器以及各种相关电子元器件开发了温湿度传感器光控灯两个典型的环境舒适度监测系统。

在本项目中,温湿度传感器适用于一般的工作环境温湿度监测(即湿度5-95%RH,温度 -20-+60℃),可以将当前环境的温湿度数据以2s一次的频率以串口输出的方式显示在上位机显示屏上;光控灯可以将环境光的亮度值输出到上位机显示屏上,同时根据环境光亮度控制所连接二极管的亮度——环境光越亮,则二极管越暗。

温湿度传感器的设计参考了DHT11的文档,在不使用现有库的情况下编写代码,驱动了DHT11与主机的交互和数据传输工作,并将原始数据进行了进制转换,变为了直接可读的数据。而光控灯利用了光敏传感器模块“在环境光亮度不同时会输出大小不同的模拟值”这一特性,依托模拟值的大小对灯的亮度进行控制,实现了光控灯的效果。

相关技术

  • 本项目的开发硬件环境:Windows10 PC、Arduino Uno开发板
  • 本项目用到的电子器件:面包板、各规格杜邦线、USB连接线、DHT11传感器、二极管、光敏传感器
  • 软件环境:Arduino IDE

下面具体介绍Arduino Uno开发板、DHT11、发光二极管、光敏传感器以及Arduino IDE的相关信息。

Arduino Uno开发板

Arduino Uno开发板是Arduino开源硬件开发平台系列中一款基础的开发板。配合外围器件以及其上的各类接口,便可以轻易地开发各种实用的电子电路。

DHT11

DHT11 是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。

DHT11采用单总线数据格式,通过简单的流程就可以实现与主机的数据通讯,将温湿度数据实时传输给主机。

发光二极管

发光二极管,简称为LED,是一种常用的发光器件,通过电子与空穴复合释放能量发光。LED具有单向导电性,当加上正向电压时,从P区注入到N区的空穴和由N区注入到P区的电子,在PN结附近数微米内分别与N区的电子和P区的空穴复合,便会产生自发辐射的荧光。

光敏传感器

光敏传感器主要由一个定值电阻和一个光敏电阻(阻值会随着环境光亮暗而变化)串联构成。当环境光变化时,光敏电阻对应的分压值也会随之变化,模拟引脚点的电压值便会改变。这一引脚点连接到主机上,呈现的便是一个0-1023之间的值。

Arduino IDE

Arduino IDE是专用于Arduino开发板的集成开发环境。它依托于C语言进行代码编写,在连接Arduino之后,可以给所连接的控制板上传程序,还能与控制板相互通信。

项目设计过程

温湿度传感器
设计思路

该系统的硬件组成较为简单,只需要将Arduino开发板连接到上位机,DHT11连接至Arduino开发板即可。其中开发板和DHT11之间进行双向通信(请求数据、接收数据和校验),而Arduino开发板和上位机之间进行单向通信。

此项目的主要难点在于不利用已有库的条件下完成DHT11与开发板之间的通信和数据校验。代码部分使用了三个自定义函数实现了这一功能,具体的介绍在软件部分详细展开。

软件流程

软件部分基于DHT11的固有传输流程编写代码,通过wait_for_dht11()start_signalread_dht11三个主要函数实现了数据的传输、检验和输出。程序的开头部分,首先编写了进制转换函数,用于将原始数据转换为可读的10进制数据。在wait_for_dht11()中,我们等待2s,使DHT11初始化;在start_signal中,先拉低电阻18ms,再拉高,之后将接口模式改为输入,准备接收数据;在read_dht11中,我们根据信号时间长短分别读入0和1作为原始数据、对数据进行校验,并最终输出。具体的代码会在附录中完整给出。

实现效果

光控灯
设计思路

这一系统包含两个子功能:

  • 通过传感器获取到环境光亮度值,进行串口输出
  • 根据获取到的环境光亮度值控制LED亮度

因此Arduino开发板需要与上位机、LED和光敏传感器同时相连。

软件流程

软件流程相对而言比较简单:先进行初始化,之后从传感器处用analogRead读取亮度模拟值并赋给变量val,进行输出;再用val对LED接口进行analogWrite,对亮度进行控制。上述过程每隔0.5s循环一次。具体代码会在附录中完整给出。

实现效果

实验总结

在本次实验中,我们组对单片机的功能和应用有了初步的了解——单片机事实上就相当于一个微型的电脑,可以依托于程序实现收发信号、数据存储以及数据处理。在本课程中,我们通过两个例子对单片机的使用流程有了具体的认识,即先搭建硬件电路、再通过上位机向单片机中注入程序并使其运行,便可以实现我们想要的功能。

在本实验中,我们遇到的主要难点是编写DHT11与MCU的数据传输代码。由于不能使用现有库,我们需要用最基本的C语言及内建函数实现和现有库类似的功能,这一点需要对DHT11的标准数据传输流程有清晰的把握。这一问题的解决是通过查阅现有库文件的注释,以及参考Stack Overflow上的资料完成的。

通过完成这一项目,我们认识到,对于单片机编程的学习,更有效的方法是从底层做起。如果仅仅是把别人已经写好的功能“拿来就用”,最多算是对已有成果的堆砌,并不能真正帮助我们从根本上理解电子器件以及单片机的工作原理。只有由最基础的操作一步一步实现最终的目标,才能使我们真正掌握单片机的使用方法,也能根据实际场景更灵活地进行运用。

附录

DHT11温湿度传感器代码
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
void setup()
{
Serial.begin(9600); //设置波特率
}
void dec2bin(int n)
{
int c, k;
for (c = 15; c >= 0; c--)
{
k = n >> c;
if (k & 1)
Serial.print("1");
else
Serial.print("0");
}
}
void dec2bin8(int n)
{
int c, k;
for (c = 7; c >= 0; c--)
{
k = n >> c;
if (k & 1)
Serial.print("1");
else
Serial.print("0");
}
}
//定义两个进制转换函数,用于最终的输出
void wait_for_dht11()
{
delay(2000); //初始化函数
}

void start_signal(uint8_t dht11_pin){
pinMode(dht11_pin, OUTPUT);
digitalWrite(dht11_pin, LOW);
delay(18);
digitalWrite(dht11_pin, HIGH);
pinMode(dht11_pin, INPUT);
digitalWrite(dht11_pin, HIGH);
}//与传感器握手,请求数据

void read_dht11(uint8_t dht11_pin)
{
uint16_t rawHumidity = 0;
uint16_t rawTemperature = 0;
uint8_t checkSum = 0;
uint16_t data = 0;

uint8_t humi;
uint8_t humd;
uint8_t tempi;
uint8_t tempd;

unsigned long startTime;

for ( int8_t i = -3 ; i < 80; i++ ) {
byte live;
startTime = micros();

do {
live = (unsigned long)(micros() - startTime);
if ( live > 90 ) {
Serial.println("ERROR_TIMEOUT");
return;
}
}
while ( digitalRead(dht11_pin) == (i & 1) ? HIGH : LOW );
//当接口电平在90ms内由高转至低时,do while循环将退出,表示DHT11正确响应;
//若live>90时仍未推出,则报错
if ( i >= 0 && (i & 1) ) {
data <<= 1;
if ( live > 30 ) {
data |= 1; // 持续时长大于30ms则为1
}
}

switch ( i ) {
case 31:
rawHumidity = data;
break;
case 63:
rawTemperature = data;
case 79:
checkSum = data;
data = 0;
break;
}
}
//根据循环次数判断数据属于温度、湿度还是检查和位
Serial.println("Humidity: ");
dec2bin(rawHumidity);
Serial.print("\t");
humi = rawHumidity >> 8;
dec2bin8(humi);
Serial.print("\t");
rawHumidity = rawHumidity << 8;
humd = rawHumidity >> 8;
dec2bin8(humd);
Serial.print("\t");
Serial.print(humi);
Serial.print(".");
Serial.print(humd);
Serial.print("%");
Serial.println("");

Serial.println("Temperature Degree Celcius: ");
dec2bin(rawTemperature);
Serial.print("\t");
tempi = rawTemperature >> 8;
dec2bin8(tempi);
Serial.print("\t");
rawTemperature = rawTemperature << 8;
tempd = rawTemperature >> 8;
//tempd = (byte)rawTemperature;
dec2bin8(tempd);
Serial.print("\t");
Serial.print(tempi);
Serial.print(".");
Serial.print(tempd);
Serial.print("C");
Serial.println("");

Serial.println("Checksum Byte: ");
dec2bin8(checkSum);
Serial.println("");
dec2bin8(tempi + tempd + humi + humd);
Serial.println("");
if((byte)checkSum == (byte)(tempi + tempd + humi + humd)){Serial.print("CHECKSUM_OK");}
else {Serial.print("CHECKSUM_ERROR");}
//检查和
Serial.println("");
Serial.println("");
Serial.println("");
}

void loop()
{
for(unsigned int x = 0; x < 1000; x++)
{
wait_for_dht11();
start_signal(2);
read_dht11(2);
}
Serial.end();
}
//主程序,输出1000次
光控灯代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define PIN_A 0
#define PIN_D 2
#define LED 3
void setup()
{
Serial.begin(9600);
pinMode(LED, OUTPUT);
}

void loop()
{
int val;
val=analogRead(PIN_A);
Serial.print("a:");
Serial.print(val);
analogWrite(LED, val/40);
Serial.print(", d:");
val=digitalRead(PIN_D);
Serial.println(val);
delay(500);
}

单片机实验报告
https://brockshuai.github.io/2023/05/14/单片机实验报告/
作者
神仙魚
发布于
2023年5月14日
许可协议