15396| 9
|
[项目] 用arduino做的包包防盗器 |
本帖最后由 marcusme 于 2015-9-14 17:30 编辑 Arduino包包防盗器 【简介】利用光敏电阻和蜂鸣器制作的一个防止包被拉开的东东用mini遥控器来控制其开关; 【器材】Arduino UNO,光敏电阻,红外遥控器,红外接收器,蜂鸣器,LED小灯,电阻,面包板,导线若干。 【接线】接线示意图如下 【硬件实现】 1. 光敏电阻 这个器件是依赖光作用的,在黑暗的环境中,光敏电阻是具有非常高阻值的电阻。光线越强,电阻值反而越低。通过读取这个电阻值,就可以检查光线的亮暗了。 上式中,R1代表的就是10k电阻,R2代表的就是光敏电阻。本来R2在黑暗中,阻值非常大,所以Vout也就很大,接近5V。当有光线照射的时候,R2的阻值就会迅速减小,所以Vout也就随之减小了,读取的电压值就会变小。通过上面这个公式我们可以看出,R1选取不能太小,最好在1k~10k,以便让比值变化更明显。 2. 蜂鸣器 蜂鸣器其实就是一种会发声的电子元件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。 压电式蜂鸣器是以压电陶瓷的压电效应,来带动金属片的振动而发声。当受到外力导致压电材料发生形变时压电材料会产生电荷。电磁式的蜂鸣器,则是利用通电导体会产生磁场的特性,通电时将金属振动膜吸下,不通电时依振动膜的弹力弹回。不太明白也没太大关系,不影响我们使用。压电式蜂鸣器需要比较高的电压才能有足够的音压,一般建议为9V以上。电磁式蜂鸣器用1.5V就可以发出85dB以上的音压了,唯消耗电流会大大的高于压电式蜂鸣器。所以还是建议初学者使用电磁式蜂鸣器。 无论是压电式蜂鸣器还是电磁式蜂鸣器,都有有源蜂鸣器和无源蜂鸣器两种区分。有源蜂鸣器和无源蜂鸣器的根本区别是输入信号的要求不一样。这里的“源”不是指电源,而是指振荡源,有源蜂鸣器内部带振荡源,说白了就是只要一通电就会响。而无源内部不带震荡源,所以如果仅用直流信号无法使其响,必须用2K-5K的方波去驱动它。从外观上看,有源无源的区别在于,有源蜂鸣器有长短脚,也就是所谓正负极,长脚为正极,短脚为负极。而无源蜂鸣器则没有正负极,两个引脚长度相同。在这里,我们使用的是无源蜂鸣器。 3. 红外接收 所谓的红外接收管,也就是接收红外光的电子器件。在我们的电视机、空调等家电,遥控小车、遥控飞机等玩具里,它们都需要用到红外接收管。遥控器发射出来的都是红外光,电视机上势必要有红外接收管,才能接收到遥控器发过来的红外信号。其连线图大致如下: 红外遥控器和接收器的使用跟很多元器件是有所不同的,它有着自己的库——IRromote多协议红外遥控库。利用这个库我们可以轻松实现多协议红外遥控编码的发送和接收。本红外远程库由两部分组成:负责发射红外遥控器数据包的IRsend,负责接收和解码红外消息的IRrecv。此红外远程库由两部分组成:负责发射红外遥控器数据包的IRsend,负责接收和解码红外消息的IRrecv。在这里,我们只用到了IRrecv。 IRrecv红外接收类函数 公共类 私有类
IRsend() 红外发射类 公共类 私有类 IDE中也有着对于红外的例子,我们可以直接下载到板子上自己感受: 例子
在运用中如果我们将IRrecvDemo这个例子下载到板子进行测试,通过串口监视器可以观察到,串口中如果正确接收的话,会出现以FD开头的六位数,并且对于红外遥控器上的每一个按键都有一个专属的红外码值。 【设计思路】 1. 就如同一开始所介绍的功能一样,我们先定义一个标志位并且其初值为零,当红外接收管接收到红外码的时候判断其是否为开关键对应的红外码,如果是,就将标志位取反,如果不是就继续允许接收下一个红外码再做判断。接着,判断标志位是否为0,不管是或者不是都给标志位取反,然后再判断标志位是否为1,如果不为1那么就关闭蜂鸣器和LED然后回到程序初始的地方接收判断红外码。如果为1,则开始读取光敏电阻的分压值,并将其作为参数放入防盗功能的函数中进行工作。 到了防盗函数中一开始就判断光敏电阻的分压值是否小于临界值,如果没有就继续接收判断模拟口0传来的新值。如果该值已经小于了临界值,此时就开让蜂鸣器按照正弦的方式鸣叫,LED小灯也按照这样的方式进行闪烁。之后,程序会回到红外接收的地方继续开始执行。 2.流程图: 【程序代码】代码程序如下: #include <IRremote.h> int RECV_PIN = 11; //定义RECV_PIN变量为11 IRrecv irrecv(RECV_PIN);// 设置RECV_PIN(也就是11引脚)为红外接收端 decode_results results;// 定义results变量为红外结果存放位置 int buzzer = 8; //设置蜂鸣器为数字引脚8 int led=10;//设置LED灯为数字引脚10 float sinVal; //定义浮点型的数据以便更精确的描述正弦值 int toneVal;//将弧度值转换为声音的频率 int state=0; void setup(){ Serial.begin(9600); //设置波特率为9600 bps irrecv.enableIRIn(); //启动红外解码 pinMode(buzzer, OUTPUT); // 蜂鸣器引脚设置 pinMode(led,OUTPUT);//led引脚设置 } void loop(){ if(irrecv.decode(&results) ) { Serial.println(results.value, HEX);//串口监视器查看红外码 if (state == 0 && results.value == 0xFD00FF) { state = 1; Serial.println(state); } else if(state == 1 && results.value == 0xFD00FF) { state = 0; Serial.println(state); } irrecv.enableIRIn(); // Start the receiver } if(state == 1) { int val; val = analogRead(0); function(val); } else { digitalWrite(buzzer, LOW); digitalWrite(led, LOW); } } void newtone(byte tonePin, int frequency,int duration) { int period = 1000000L / frequency; int pulse = period / 2; for (long i = 0; i < duration * 1000L; i+= period) { digitalWrite(tonePin, HIGH); delayMicroseconds(pulse); digitalWrite(tonePin, LOW); delayMicroseconds(pulse); } } void function(int val){ if(val<1021){ //如果小于设定值,蜂鸣器响 for(int x=0; x<180; x++){ //将sin函数角度转化为弧度 sinVal = (sin(x*(3.1412/180))); //用sin函数值产生声音的频率 toneVal = 2000+(int(sinVal*1000)); newtone(buzzer,toneVal,10); analogWrite(led,x); delay(2); } } else{ // 如果小于设定值,关闭蜂鸣器 digitalWrite(buzzer,LOW); //关闭蜂鸣器 analogWrite(led,LOW);} } 【代码回顾】 #include <IRremote.h>是调用红外库接着设置数字11脚为红外接收端。IRrecv irrecv(RECV_PIN); decode_results results; 这两句代码分别是定义接收器的输入管脚和接收红外编码,如果编码接收成功则返回True,如果没有接收则返回False。当编码被成功接收后,有关信息会保存在“results”中。这两个函数就为我们奠定了后面使用其功能的基础。 接下来分别设置蜂鸣器、LED小灯对应的引脚,然后定义两个变量:floatsinVal;int toneVal; 浮点型变量sinVal用来存储正弦值,正弦波呈现一个波浪形的变化,变化比较均匀,所以我们选用正弦波的变化来作为我们声音频率的变换,toneVal从sinVal变量中获得数值,并把它转换为所需要的频率。这里用的是sin()函数,一个数学函数,可以算出一个角度的正弦值,这个函数采用弧度单位。因为我们不想让函数值出现负数,所以设置for循环在0~179之间,也就是0~180度之间:for(intx=0; x<180; x++){},函数sin()用的弧度单位,不是角度单位。要通过公式(3.1412/180)将角度转为弧度:sinVal=(sin(x*(3.1412/180))); 之后,将这个值转变成相应的报警声音的频率: toneVal = 2000+(int(sinVal*1000)); sinVal是个浮点型变量,也就是含小数点的值,而我们不希望频率出现小数点的,所以需要有一个浮点值转换为整型值得过程,也就是下面这句语句就完成了这件事:int(sinVal*1000) 把sinVal乘以1000,转换为整型后再加上2000赋值给变量toneVal,现在toneVal就是一个适合声音频率了。之后,我们用newtone()函数把生成的这个频率给我们的蜂鸣器。newtone(buzzer,toneVal);但是,一般情况下让蜂鸣器按照一定频率发声tone函数就行了,我这里为什么要用另一个自己编写的newtone函数呢? 原因在于:因为要使用红外的功能,所以要调用IRremote.h库函数,而该库函数跟tone函数是有冲突的,当调用IRremote.h再使用tone函数,就出现这个错误提示: core.a(Tone.cpp.o): In function `__vector_7': E:\arduino-1.0.1\hardware\arduino\cores\arduino/Tone.cpp:523: multipledefinition of `__vector_7' IRremote\IRremote.cpp.o:E:\arduino-1.0.1\libraries\IRremote/IRremote.cpp:311:first defined here 这个错误提示表面上是说在红外库里定义过的函数在Tone里又重复定义了,实际原因是红外库和Tone都使用了相同的内部计时器TIMER2(在各自的 ISR函数里),所以考虑下面的Tone的替代办法: 我们知道arduino的几个延时函数都是用的timer 0。这里有个不用timer2而用延时函数的发声函数,用它替代Tone是可以避开与红外库的计时器冲突的: void newtone(byte tonePin, int frequency, int duration) { int period = 1000000L / frequency; int pulse = period / 2; for (long i = 0; i < duration * 1000L; i += period) { digitalWrite(tonePin, HIGH); delayMicroseconds(pulse); digitalWrite(tonePin, LOW); delayMicroseconds(pulse); } } 以上的L把整数常数强制转换成长整数类型long,因为int装不下这么大的数。 Loop函数中的一大段if函数的主要目的就是一旦接受到开关键所对应的红外码就给标志位取反,一旦标志位的值等于一就开始读取光敏电阻的分压值并调用放到函数。如果标志位的值等于零就继续接收新的红外码。Function函数中的anologWrite(led,x);就是为了让LED的闪烁的频率也跟蜂鸣器的趋势大致相同。 【效果】视频展示如下: |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed