一、项目要求描述
通过红外接收模块接收指令,将红外接收的引脚模式设置为输入,通过红外遥控器的按键“1~5”向其输入指令。编写代码,使得Arduino UNO控制板及相关传感器实现“学生寝室”门禁管理。
二、控制电路连接
本电路所包含的电子元件:Arduino UNO板,红外接收传感器、DHT11温湿度传感器、LED灯、舵机、蜂鸣器(无源)、LCD1602显示屏。
红外接收器 | OUT | 2 |
---|---|---|
DHT11温湿度传感器 | OUT | 4 |
LED灯 | I/O | 5 |
舵机 | PWM | 6 |
无源蜂鸣器 | I/O | 12 |
LCD1602 | SDA、SCL | SDA、SCL |
三、功能分析
在硬件通电情况下,LCD屏上显示“This is chamber:113”(这是113寝室)。
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(receivePin,INPUT); //红外VOUT端口模式,输入
pinMode(servoPin,OUTPUT); //舵机端口模式,输出
pinMode(ledPin,OUTPUT);//led灯端口模式,输出
pinMode(fmqPin,OUTPUT);//蜂鸣器端口模式,输出
lcd.init(); //初始化LCD
lcd.backlight(); //打开背光
lcd.print("This is chamber:"); //在LCD上打印信息
lcd.setCursor(0,1); //跳转新的一行
lcd.print("113"); //在LCD上打印信息
sensorIR.enableIRIn();
}
1、功能一:开门
将开门按键设置为“1”,使用1的键值。通过遥控器按下“1”时,舵机旋转120度,灯光闪烁5次,提示有人到来,LCD屏上显示“Door is open.”(门已开启)。
if(results.value==0xFF30CF){ //设置开门按键为1,使用1的键值
servopluse(6,120); //实现开门功能(舵机旋转120°)
lcd.clear(); //LCD屏上打印“门已开启”
lcd.setCursor(0,0);
lcd.print("Door is open.");
for(int i=0;i<5;i++){ //灯光闪烁5次
analogWrite(ledPin,HIGH);
delay(500);
analogWrite(ledPin,LOW);
delay(500);
}
}
2、功能二:关门
将开门按键设置为“2”,使用2的键值。通过遥控器按下“2”时,舵机旋转回原始位置,LCD屏上显示“See you!”(再见)。
if(results.value==0xFF18E7){ //设置关门按键为2,使用2的键值
servopluse(6,0); //实现关门功能(舵机旋转至原始位置)
lcd.clear(); //LCD屏上打印“再见”
lcd.setCursor(0,0);
lcd.print("See you!");
digitalWrite(ledPin,LOW); //灯光熄灭
}
3、功能三:欢迎
将开门按键设置为“3”,使用3的键值。通过遥控器按下“3”时,无源蜂鸣器播放《两只老虎》,LCD屏上显示“Welcome!”(欢迎)。
if(results.value==0xFF7A85){ //设置关门按键为3,使用3的键值
lcd.clear(); //LCD屏上打印“欢迎”,蜂鸣器播放歌曲《两只老虎》
lcd.setCursor(0,0);
lcd.print("Welcome!");
int frequency[] = {262,294,330,262,262,294,330,262,330,349,392,330,349,392,
392,440,392,349,330,262,392,440,392,349,330,262,294,221,262,294,221,262}; // 音频频率数组
float duration[]={0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,1,0.5,0.5,1,
0.25,0.25,0.25,0.25,0.5,0.5,0.25,0.25,0.25,0.25,0.5,0.5,0.5,0.5,1,0.5,0.5,1};//持续时间数组
for (int i = 0; i < 32; i++) { // 循环遍历音符
tone(fmqPin, frequency[i], 500); // 发出声音
delay(600*duration[i]); // 延时 600 毫秒,以便听到声音
}
}
4、功能四:勿扰
将开门按键设置为“4”,使用4的键值。通过遥控器按下“4”时,LCD屏上滚动显示勿扰信息。
if(results.value==0xFF10EF){ //设置关门按键为4,使用4的键值
lcd.clear(); LCD屏上打印字符串(勿扰信息)
f="Sorry,I am busy now!Can you wait a minute?I will open the door for you soon!";
lcdprint();
}
5、功能五:天气
将开门按键设置为“5”,使用5的键值。通过遥控器按下“5”时,LCD屏上显示实时的温湿度。
if(results.value==0xFF38C7){ //设置关门按键为5,使用5的键值
sensor_Dht11.read(Dht11_Pin);
hum=float(sensor_Dht11.humidity),0;
tem=float(sensor_Dht11.temperature),0; //温湿度传感器采集环境温湿度信息
lcd.clear(); //LCD屏上打印温湿度信息
lcd.setCursor(0,0);
lcd.print("Humidity:");
lcd.setCursor(10,0);
lcd.print(hum);
lcd.setCursor(13,0);
lcd.print("^C");
lcd.setCursor(0,1);
lcd.print("Temper:");
lcd.setCursor(10,1);
lcd.print(tem);
lcd.setCursor(13,1);
lcd.print("%");
}
四、定义函数
1、调用各类传感器需要用到的库函数,给出接口及相关函数定义
#include<Wire.h>
#include<LiquidCrystal_I2C.h>
#include <dht11.h>
#include <IRremote.h>
#define receivePin 2
#define fmqPin 12
#define Dht11_Pin 4
#define ledPin 5
#define servoPin 6 //库函数及接口定义
dht11 sensor_Dht11;
int myangle;
int pulsewidth;
int hum,tem;
int e=0;
String f; //函数定义
LiquidCrystal_I2C lcd(0x20,16,2);
IRrecv sensorIR(receivePin);
decode_results results;
2、定义舵机脉冲函数
void servopluse(int servopin,int myangle){ //舵机脉冲函数
pulsewidth=(myangle*11)+500;
digitalWrite(servopin,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servopin,LOW);
delay(20-pulsewidth/1000);
}
3、定义LCD字符串滚动函数
void lcdprint() //LCD屏显示已知字符串
{
char fe[(f.length()+1)];
f.toCharArray(fe,f.length()+1);
int k=0;
int ur=0;
delay(100);
lcd.clear();
lcd.write(fe[ur]);
e=1;
while (fe[ur]){
e++;
ur++;
if (e>16&&e<=31)
{
if(k==0)
{
lcd.setCursor(0,1);
k=1;
}
lcd.write(fe[ur]);
}
else if(e>31)
{
lcd.write(fe[ur]);
k=0;
e=0;
delay(2000);
lcd.clear();
}
else
{
lcd.write(fe[ur]);
}
}
e=0;
lcd.clear();
lcd.print("This is chamber:"); //在LCD上打印信息
lcd.setCursor(0,1); //跳转新的一行
lcd.print("113"); //在LCD上打印信息
}
五、相关问题
1、解决红外遥控与舵机模块均为pwm输出的问题
解决舵机库和pwm输出冲突:直接通过延时函数来给舵机脉冲,达到控制的效果,因为Arduino里延时函数delay()用的是定时器Timer0,所以就不会影响彼此的功能了。
因此,不要调用舵机库,使用不调库的写法。
2、解决IRrecv类库函数(红外遥控)与tone()函数(蜂鸣器音调)共用定时器Timer2的问题
-
UNO板定时器较少,只有三个,可以通过修改库文件使用Timer1
-
此处将tone()函数的默认计时器Timer2修改为Timer1,修改Arduino里Core核心函数里的Tone.c文件(UNO板将118和120行的2改为1),然后再将其添加到项目的文件夹里,点击编译
#else #define AVAILABLE_TONE_PINS 1 #define USE_TIMER1 // Leave timer 0 to last. const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 1 /*, 1, 0 */ }; static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
-
由于舵机模块并没有调用库servo.h,因此Timer1并没有被占用,实现了红外按键同时遥控舵机、蜂鸣器的功能
六、整体代码
#include<Wire.h>
#include<LiquidCrystal_I2C.h>
#include <dht11.h>
#include <IRremote.h>
#define receivePin 2
#define fmqPin 12
#define Dht11_Pin 4
#define ledPin 5
#define servoPin 6 //库函数及接口定义
dht11 sensor_Dht11;
int myangle;
int pulsewidth;
int hum,tem;
int e=0;
String f; //函数定义
LiquidCrystal_I2C lcd(0x20,16,2);
IRrecv sensorIR(receivePin);
decode_results results;
void servopluse(int servopin,int myangle){ //舵机脉冲函数
pulsewidth=(myangle*11)+500;
digitalWrite(servopin,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servopin,LOW);
delay(20-pulsewidth/1000);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(receivePin,INPUT); //红外VOUT端口模式,输入
pinMode(servoPin,OUTPUT); //舵机端口模式,输出
pinMode(ledPin,OUTPUT);//led灯端口模式,输出
pinMode(fmqPin,OUTPUT);//蜂鸣器端口模式,输出
lcd.init(); //初始化LCD
lcd.backlight(); //打开背光
lcd.print("This is chamber:"); //在LCD上打印信息
lcd.setCursor(0,1); //跳转新的一行
lcd.print("113"); //在LCD上打印信息
sensorIR.enableIRIn();
}
void loop() {
// put your main code here, to run repeatedly:
if (sensorIR.decode(&results)){
if(results.value==0xFF30CF){ //设置开门按键为1,使用1的键值
servopluse(6,120); //实现开门功能(舵机旋转120°)
lcd.clear(); //LCD屏上打印“门已开启”
lcd.setCursor(0,0);
lcd.print("Door is open.");
for(int i=0;i<5;i++){ //灯光闪烁5次
analogWrite(ledPin,HIGH);
delay(500);
analogWrite(ledPin,LOW);
delay(500);
}
}
if(results.value==0xFF18E7){ //设置关门按键为2,使用2的键值
servopluse(6,0); //实现关门功能(舵机旋转至原始位置)
lcd.clear(); //LCD屏上打印“再见”
lcd.setCursor(0,0);
lcd.print("See you!");
digitalWrite(ledPin,LOW); //灯光熄灭
}
if(results.value==0xFF7A85){ //设置关门按键为3,使用3的键值
lcd.clear(); //LCD屏上打印“欢迎”,蜂鸣器播放歌曲《两只老虎》
lcd.setCursor(0,0);
lcd.print("Welcome!");
int frequency[] = {262,294,330,262,262,294,330,262,330,349,392,330,349,392,
392,440,392,349,330,262,392,440,392,349,330,262,294,221,262,294,221,262}; // 音频频率数组
float duration[]={0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,1,0.5,0.5,1,
0.25,0.25,0.25,0.25,0.5,0.5,0.25,0.25,0.25,0.25,0.5,0.5,0.5,0.5,1,0.5,0.5,1};//持续时间数组
for (int i = 0; i < 32; i++) { // 循环遍历音符
tone(fmqPin, frequency[i], 500); // 发出声音
delay(600*duration[i]); // 延时 600 毫秒,以便听到声音
}
}
if(results.value==0xFF10EF){ //设置关门按键为4,使用4的键值
lcd.clear(); LCD屏上打印字符串(勿扰信息)
f="Sorry,I am busy now!Can you wait a minute?I will open the door for you soon!";
lcdprint();
}
if(results.value==0xFF38C7){ //设置关门按键为5,使用5的键值
sensor_Dht11.read(Dht11_Pin);
hum=float(sensor_Dht11.humidity),0;
tem=float(sensor_Dht11.temperature),0; //温湿度传感器采集环境温湿度信息
lcd.clear(); //LCD屏上打印温湿度信息
lcd.setCursor(0,0);
lcd.print("Humidity:");
lcd.setCursor(10,0);
lcd.print(hum);
lcd.setCursor(13,0);
lcd.print("^C");
lcd.setCursor(0,1);
lcd.print("Temper:");
lcd.setCursor(10,1);
lcd.print(tem);
lcd.setCursor(13,1);
lcd.print("%");
}
sensorIR.resume(); //等待下一次红外接收指令
}
delay(100);
}
void lcdprint() //LCD屏显示已知字符串
{
char fe[(f.length()+1)];
f.toCharArray(fe,f.length()+1);
int k=0;
int ur=0;
delay(100);
lcd.clear();
lcd.write(fe[ur]);
e=1;
while (fe[ur]){
e++;
ur++;
if (e>16&&e<=31)
{
if(k==0)
{
lcd.setCursor(0,1);
k=1;
}
lcd.write(fe[ur]);
}
else if(e>31)
{
lcd.write(fe[ur]);
k=0;
e=0;
delay(2000);
lcd.clear();
}
else
{
lcd.write(fe[ur]);
}
}
e=0;
lcd.clear();
lcd.print("This is chamber:"); //在LCD上打印信息
lcd.setCursor(0,1); //跳转新的一行
lcd.print("113"); //在LCD上打印信息
}