传送门
【技术分享】初玩树莓派B(二) 实用配置(vnc和串口)&GPIO操作点亮LED灯
人体红外感应报警
前面的LED灯我们操作使用的GPIO的输出功能,这次我们终于需要用到GPIO的输入功能了。由于这个人体红外感应模块的使用比较简单。所以我们实验完毕以后配合前面的蜂鸣器一起,做一个简单的人体感应报警器。
1. HC-SR501 感应模块简介
我们采用 HC-SR501型号的人体红外感应器来探测人体。更加详细的参数参考模块的使用说明书。
对照前面的参数以及电路图,找到下面的左右针脚正负极,中间的PIN为感应输出,感应到人体时,输出3.3V高电平,检测不到信号时输出0。同时还要求工作电压在4.5V-20V之间。恰好树莓派的P1编号中第2,4号PIN都是5V的电压,满足要求,所以这次我们要接5V的电压。
参数调节旋钮是用来扭动控制一些参数的。比如探测的延时时间,灵敏度等等。具体可以参看 HC -SR501的说明书。这里我们都使用默认值。
但是有一个关键的L H模式调节阀门要介绍一下,右上角有三个针脚,按照我实物照片,假定从上到下为123 。还有一个黄色的套接头,图中套接头接通了2 3号,代表了H模式,这个套接头是可以拔下来的,然后插到上面来,接通1 2号,代表了L模式。
L模式是不可重复触发,当探测到一次人体时,输出一次高电平,保持一段时间恢复低电平,在此期间如果还是检测到了人体也不再延长这个高电平的时间。等到低电平的封锁时间(前面默认是2.5S)过了以后才又开始检测。
H模式是可以重复触发,如果一直感应到人体时,会一直输出高电平,直到探测不到人体后保持小段时间然后恢复低电平。
2. GPIO输入的上拉和下拉
对于学习软件的人来说,软件的世界只有0和1,所以我接触硬件之前也是这么认为的。所以我在使用人体红外感应的时候遇到了一个问题,我认为只要设置GPIO的模式为INPUT,后面只需要读取针脚的状态0,1就行了。结果我遇到一个问题。当我在设置比如pin22(wiringpi标号为6)为INPUT模式,接上一根线后,这一条线另一端什么都不接,按理说这时应该输入为0V,但是我尝试读取发现并不是一直保持低电平,而是一会儿高,一会低,用手握住另外一端就会输出高电平。当我接pin3(wiringPi 标号为8)却始终是高电平。不得不查询各种资料,发现还有上拉和下拉这种说法。
当我们给一个针脚接入GND,那么就是低电平,如果我们给一个针脚3.3V,那么就是高电平,状态是很确定的。如果我们什么都不接,那么这个针脚处于悬浮状态,很容易受到外接的干扰,可能是高也可能是低,也可能是处于高和低之间的状态。这时候我们就要明确指定这个针脚应该处于高或者低,不能让他处于悬浮状态。接入一个上拉电阻能够让这个针脚处于明确的高电平状态,接入一个下拉电阻能够让他处于明确的低电平状态。前面我们用作输出的时候都是明确给定了输出的高低状态。关于上拉电阻和下拉电阻,有一篇英文解释写的很不错,我也是参考这篇来看的,里面的测试大家也可以用树莓派测试一下。(http://www.bit-101.com/blog/?p=3813)。
PIN3始终处于高电平状态是因为。这个PIN口是用于树莓派I2C设备的,内部外接了一个物理的上拉电阻。所以他的状态一直是高电平,作为INPUT不能使用这个PIN。
PIN22 时高时低就是由于处于悬浮状态。所以我们要使用这个PIN就比如为他明确指定悬浮的时候是高还是低。wiringpi通过pullUpDnControl来控制这个变量。
3. 接线以及测试
模块左边的针脚1接P1编号的PIN2 为5V的正极,模块右边的针脚3的负极接PIN6,模块中间的针脚2输出线接PIN22(wiringPi就是标号6)。
接线图如下:
图中我连蜂鸣器也接上去了。当我们检测到人体的时候。使用前一节的beep函数发出警告声音。我们先初步检测一下模块有没有工作正常。测试HC-SR501不同的模式。选择的H模式,套接头接下面两个脚。也就是可以重复触发,检测到人体,一直处于高电平。
可以看出中间是连续的检测,也就是高电平的时间随着人的活动延长了。
如果选择的L模式,套接头接上面两个脚。也就是不可以重复触发,检测到人体,输出高电平一段时间,后续一小段时间内检测到也不再延长这个高电平时间,必须等到锁定时间过了才会再次检测。
可以看出中间高电平的时间不是持续的。
检测的代码很简单:
代码:
#include <wiringPi.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#define INFRAREDPIN 6
int main()
{
int AnyBodyHere=0;
wiringPiSetup();
//设置为输入模式
pinMode(INFRAREDPIN,INPUT);
//很重要。控制默认情况下此PIN处于下拉低电平状态
pullUpDnControl(INFRAREDPIN,PUD_DOWN);
while(true)
{
//每一秒检测依次状态
delay(1000);
//读取当前pin的输入状态
AnyBodyHere=digitalRead(INFRAREDPIN);
if(AnyBodyHere)
{
printf("There is somebody heren");
}
else
{
printf("There is no one heren");
}
}
}
我们稍微修改一下。在检测到人体的时候使用第五节的beep函数执行报警的操作,这里我们选择使用H模式,持续感应,感应到以后使用beep发声。这样就简单实现了人体感应后自动报警。
具体代码下载infrared.c参考。
物联网温湿度监控
这一节用温湿度传感器接入中移动物联网上报家中的温湿度。
1. dht11传感器使用简介
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。我购买的dht11只有三个针脚分别是 VCC DATA GND,(有些是四阵脚的,多一个NC空脚)。
常用电路图:
前面我们已经玩了一些常用模块,接线都比较熟悉了。正极接3.3V,负极接GND,DATA(OUT)针脚我接了物理的11号针脚,对应于WiringPi标号是0,同时为DATA针脚接入一个5K欧姆的上拉电阻,使得空闲状态的时候为高电平。
对于之前使用的一些模块,我们只需要知道高低电平就可以了,现在要得到的是温度和湿度的具体数据,那么如何通过DATA针脚得到温度和湿度呢?通过DATA针脚采用单总线格式进行数据通讯。依次完整的数据传输为40bit,先读出来的是高位的数据。40bit数据的格式是:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。如果数据是准确的,那么8bit湿度整 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据的结果的末8位等于8bit校验和。
通讯过程如下,主机首先向传感器发送开始信号,等开始信号发送完毕以后。dht11发送响应信号,依次传回40bit的数据,随后进入空闲状态。
沟通握手过程如下,初始空闲状态DATA为高电平,主机将DATA拉低等待DHT11响应,拉低的时间必须大于18ms保证DHT11可以检测到这个状态。随后dht11等待开始信号结束,主机可以通过拉高电平20-40us表明信号结束。以后就可以准备读取dht11的响应信号了。dht11会发送80us的低电平来响应然后dht11再次将电平拉高持续80us表示后面的数据传输要开始了。
通讯过程如下:dht11每次传输1bit数据的过程是先拉低电平50us。随后拉高电平,高电平的时间长短决定了这1bit的数据是0还是1。当最后一个bit的数据传输完毕以后,dht11拉低电平50ms。随后上拉电阻拉高进入空闲状态。一次数据传输过程完毕。
传输0的过程:
传输1的过程:
关键部分代码如下。
代码:
/*
当检测到的状态不是state的时候就返回。
如果参数state是HIGH,那么需要等到检测到LOW的时候返回。
返回值代表了状态改变所用的时间计数。
返回值如果是-1 表明和设备通讯出现了错误,需要重新开始通讯。
*/
int loopCheckUntilStateChange(int state)
{
//初始时间计数为0
int count=0;
//读取针脚的状态
while(digitalRead(DHT11PIN)==state)
{
//如果状态没变那么计数加1
count++;
//如果计数超过了最大的计数,表明通讯错误,需要重新开始
if(count>MAX_COUNT)
return -1;
//延时1微秒。
delayMicroseconds(1);
}
return count;
}
/*
读取DHT11。如果读取成功,返回true,否则false。将温度放到 ptemp,将湿度放到
phumi
*/
bool readDHT11(float* ptemp,float* phumi)
{
int count=0,ibit=0;
bool bret=false;
//保存电平改变所用的时间计数
int bitsz[40]={0};
//保存读取到的4个温湿度数据和1个校验码
int data[5]={0};
//首先设置为输出模式
pinMode(DHT11PIN,OUTPUT);
//写入低电平
digitalWrite(DHT11PIN,LOW);
//低电平至少持续18ms。保证能够DHT检测到这个初始信号
delay(20);
//随后主机将电平拉高,通知DHT信号结束
digitalWrite(DHT11PIN,HIGH);
//将针脚转为输入模式,等待DHT的响应。
pinMode(DHT11PIN,INPUT);
//经过20-40us,我们需要等待DHT将电平从高电平拉低
if(loopCheckUntilStateChange(HIGH)<0)
{
return bret;
}
//DHT的响应信号低电平持续80us,等待DHT再次由低拉高
if(loopCheckUntilStateChange(LOW)<0)
{
return bret;
}
//高电平将持续80us,等待DHT将高电平拉低。开始传输数据
if(loopCheckUntilStateChange(HIGH)<0)
{
return bret;
}
//数据传输开始。每次传输一个bit。一共40bit。5字节
for(ibit=0;ibit<40;ibit++)
{
//每个bit传输由50us的低电平开始。变为高电平就是开始传输0或者1了。
if(loopCheckUntilStateChange(LOW)<0)
{
return bret;
}
//这次我们要检测高电平到低电平经过了多少个计数的count
//以此来决定这一bit是0还是1
count=loopCheckUntilStateChange(HIGH);
//如果小于0,出错了
if(count<0)
{
return bret;
}
//将高电平持续的count保存在bitsz里面。
bitsz[ibit]=count;
}
/*
定义了区别 0 和1 的count 阈值。这个阈值要根据实际情况和你写的函数调整。
比如 loopCheckUntilStateChange里面如果没有delayMicroseconds(1);完全跑CPU,那么count值会比较大。
如果有delayMicroseconds(1)那么这个值会小一些。
*/
#define THRESHOLD 20
for(ibit=0;ibit<40;ibit++)
{
/*
将data左移1位,因为ibit的传输是从高位到低位
每次填充后就要移动一次。
ibit/8 确定是第几个data
*/
data[ibit/8]<<=1;
/*
根据传输时高电平占用时间的count来确定这个bit是0还是1
THRESHOLD阈值根据不同的情况来确定,1的时间长,count大。0的时间短。count小。确定
一个中间的值即可
*/
if(bitsz[ibit]>THRESHOLD)
{
//如果超过了阈值。说明这一位是1。否则什么都不做。默认就是0了
data[ibit/8]|=1;
}
}
//检查校验码。查看整个数据是否传输准确了
if(data[4]!=(data[3]+data[2]+data[1]+data[0])&0xff)
{
return bret;
}
/*
由于dht11设备默认小数位为0,没有小数位.所以这里小数位就不要了。只有整数位的温度和湿度。
否则就是(%d.%d data[0].data[1])湿度 (%d.%d data[2].data[3])温度
*/
*ptemp=data[2]*1.0;
*phumi=data[0]*1.0;
return true;
}
THRESHOLD和 MAX_COUNT的确定要根据实际的代码来修改。
比如THRESHOLD,如果loopCheckUntilStateChange 没有delayMicroseconds(1)。
count=loopCheckUntilStateChange(HIGH);打印40次
得到的count结果如下。
可以看到count基本分为两类。一类是120-130左右,一类是370-380左右。
因此代表0的26-28us的高电平时间对应的count就是120-130 ,代表1的70us的高电平count就是370-380。所以阈值可以设置为200。超过200就是1。小于200就是0。
如果加上了delayMicroseconds(1)。那么40次count的结果如下,前面指令都是跑CPU,因此count比较大,这里延时了1us,count就变小了。
明显看到一类是 10 左右,代表传输0。一类是30左右,代表传输1。
因此阈值设置为20。大于20是1,小于20是0。
这一部分代码的数据读取准确度不是很高,可能还需要稍作调整使得读取准确率更高,我是按照最好理解的方式写的。
2. 接入中移动的物联网开放平台
http://open.iot.10086.cn/ 是中移动推出的物联网平台,开放一些免费的接口可以开发应用,具体可以去官网查看更多资料,篇幅有限就不多介绍了,http://open.iot.10086.cn/doc/里面有详细文档文档。下面简单介绍一下使用步骤。
主要步骤参考http://open.iot.10086.cn/doc/art190.html#43
1. 注册账号并登陆。
2. 页面中进入开发者中心,并创建一个产品。
创建产品。
填写简单资料。
其他的默认,并且使用http传输协议数据。
3. 添加一个设备
4. 为设备添加数据流
点开设备。
操作栏中点击添加数据流。
注意数据流的id用英文比较好。后续我们post数据需要用这个英文的id,中文容易出各种编码问题。
我们添加两个。一个是humi 湿度。一个是temp温度。
5. 添加一个应用
添加两个仪表盘。设备选择raspberry,数据流一个选择humi,一个选择temp。
保存应用。
web端的设置基本上就完毕了。
参看http://open.iot.10086.cn/doc/art190.html#43的协议文档。
为了上传温度和湿度,我们需要几个关键的数据。
1. 设备id。这个从设备详情页可以拿到。
2. appkey 。这个可以从appkey页面使用默认的
3. 数据的id。也就是之前添加数据流的时候使用的humi和temp。
我们需要post的数据类似于
POST /devices/YOURDEVICEID/datapoints?type=3 HTTP/1.1
Host:api.heclouds.com
api-key:YOURAPIKEY
content-type:application/json
{
“temp”:25,“humi”:60
}
使用libcurl关键部分代码如下(记得替换YOURDEVICEID 以及YOURAPPKEY )。
代码:
#define POST_URL "http://api.heclouds.com/devices/YOURDEVICEID/datapoints?type=3"
void postData(float temp,float humi)
{
CURL *curl;
char jsonData[512];
struct curl_slist* header=NULL;
printf("humi=%.2f temp=%.2fn",humi,temp);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, POST_URL);
header=curl_slist_append(NULL,"api-key:YOURAPPKEY");
curl_slist_append(header,"content-type:application/json");
sprintf(jsonData,"{"temp":"%.2f","humi":"%.2f"}",temp,humi);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, showResponse);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/iotpost.cookie");
curl_easy_perform(curl);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
};
//如果将上传的结果打印出来
size_t showResponse(void *buffer, size_t size, size_t nmemb, void *userp)
{
char* response=NULL;
if(!buffer||!size||!nmemb)
{
printf("no responsen");
return;
}
response=(char*)malloc(size*nmemb+1);
memcpy(response,buffer,size*nmemb);
response[size*nmemb]=0;
printf("response: %snn",response);
free((void*)response);
};
如果成功会输出:
{
"errno": 0,
"error":“succ”,
}
使用libcurl发送post请求。
首先需要安装libcurl
sudo apt-get install libcurl4-gnutls-dev
编译的时候也要加上-lcurl
gcc -o dht11 dht11.c -lwiringPi -lcurl
具体的代码参看dht11.c
如果成功提交post数据。可以在应用的页面看到你家庭的温度和湿度。将发布链接转给别人,人家就能看到你家庭的温度湿度了。
附件
infrared.c:https://yunpan.cn/cvxEVQghJVqZW(提取码:906c)
dht11.c:https://yunpan.cn/cvx5JxcQwdDGm(提取码:63ce)
传送门








































发表评论
您还未登录,请先登录。
登录