电子说
第1步:电路
组件:
1 x Arduino Uno
3 x 220欧姆电阻器
1 x绿色LED
1 x黄色LED
1 x红色LED
1 x TMP36温度传感器
1 x JY-MCU蓝牙从模块(请参阅介绍)
1 x面包板
电线
连接:
步骤1):将Arduino的地线和5V连接到面包板。
步骤2):将LED放在面包板上,并将其阴极接地。将它们的阳极分别通过220欧姆电阻连接到数字引脚:黄色到引脚3,绿色到引脚4,红色到引脚5。
步骤3):将TMP36传感器放在面包板上,将其引脚连接到5V,接地和A0 Arduino引脚。
步骤4):将提供的电缆的一侧连接到JY-MCU蓝牙模块,另一侧连接到面包板;连接如下:
VCC 《-》 5V
GND 《-》 GND TXD 《-》引脚0(Rx)
RXD 《-》引脚1(Tx)
该草图还将使用数字引脚13上的Arduino内置LED。
由于TXD转到Rx,而RXD转到,蓝牙模块的连接可能会有些混乱。 Tx:这是一个解释。发送和接收是针对每个设备的,因此,蓝牙模块的TXD引脚发出的传输必须由Arduino在Rx引脚0上接收;同样,从Arduino Tx引脚1发出的传输也必须到达其RXD引脚上的JY-MCU蓝牙模块。
警告:蓝牙模块可能会干扰PC与Arduino的通信:对电路板进行编程时,请断开VCC。 (在我的测试中,情况并非如此,但请确保它不会造成任何伤害)。
步骤2:Arduino代码-简介
Arduino监听命令以点亮某些LED或显示其状态。另外,定时器中断使它可以通过TMP36传感器检查温度:如果温度大于阈值,则LED点亮;否则,指示灯熄灭。每n秒(其中n是通过应用设置的参数)会向该应用发送状态报告。简单的命令结构使应用程序可以将参数和值发送到Arduino,反之亦然。
程序中定义的命令结构为:
CMD RED | GREEN | YELLOW =开|关
CMD TMAX | SECONDS =值
CMD SECONDS =值
CMD状态
状态消息结构为:
状态红色|绿色|黄色| TMAX | SECONDS | TEMP | THIGH = value
Arduino将以完整状态回答STATUS命令,而在中断时它将报告较短的版本。
示例:
CMD RED = ON将红色LED点亮
CMD GREEN = OFF将绿色LED熄灭
您可以通过在Arduino IDE的串行监视器中发出命令并查看响应来测试草图:确保在底部的下拉选项中选择“回车”。
您可以从附件中下载草图代码。下一步将对此进行详细说明。
步骤3:Arduino代码-详细信息
上一步中所述的命令和消息结构
//串行参数:COM11 9600 8 N 1
// r或 n结束命令行
//蓝牙处于针脚0和1,速度为9600
//命令结构//CMD RED | GREEN | YELLOW = ON | OFF
//CMD TMAX | SECONDS = value
//CMD SECONDS = value
//CMD STATUS
//状态消息结构
//STATUS RED | GREEN | YELLOW | TMIN | TMAX | SECONDS | TEMP | THIGH = value
温度控制所需变量的初始化
float maxTemp = 30.0;//当温度》 maxTemp
int maxTempSensor =(int)((maxTemp/100 + .5)* 204.8);
浮点温度= 0.0;
以后可以更改maxTemp,但是程序需要使用默认值开始。 maxTempSensor是将maxTemp转换为Arduino ADC转换器提供的0-1023范围;温度比较将通过我们希望尽快执行的中断例程执行:直接比较整数Pin输出值而不是浮点温度更为有效。我们仍然要报告温度,程序会将其以相同的名称存储在变量中。
如果您不熟悉温度转换公式,可以在这里查看。
maxSeconds也可以使用命令进行更改,但再次需要默认值
int maxSeconds = 10;//每maxSeconds
Pin常量声明发送状态消息
const int ledPin = 13;//温度指示灯
const int tempPin = A0;//T36温度传感器模拟输入引脚
const int led1Pin = 3;//黄色
const int led2Pin = 4;//Green
const int led3Pin = 5;//红色
中断例程中使用并从其外部访问的变量
volatile int tempVal;
volatile int seconds = 0;
volatile boolean tempHigh = false;
volatile boolean statusReport = false;
Volatile是一个特殊的关键字,可防止编译器执行某些优化:在中断内修改的所有变量例程,并且必须在例程之外进行访问,必须将其声明为volatile,以表明其值可以随时更改,并确保在需要时从内存中读取最新的正确值。
命令字符串变量(稍后将对此进行说明)
字符串inputString =“”;
String command =“”;
字符串值=“”;
布尔stringComplete = false;
setup()函数
void setup(){
//开始串行连接
Serial.begin(9600);
Serial.print(“ Max T:”);
Serial.print(maxTemp);
Serial.print(“ Sensor:”);
Serial.println(maxTempSensor);
inputString.reserve(50);
command.reserve(50) ;
value.reserve(50);
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin,LOW);
pinMode(led1Pin,OUTPUT);
pinMode(led2Pin,OUTPUT) ;
pinMode(led3Pin,OUTPUT);
digitalWrite(led1Pin,LOW);
digitalWrite(led2Pin,LOW);
digitalWrite(led3Pin,LOW);
字符串的reserve方法分配作为参数提供的字节数。
需要以下代码来初始化计时器中断并将其设置为每秒触发一次,这是Arduino可以完成的最慢的时间。有关详细信息,请参见此处。
cli();//禁用全局中断
//初始化Timer1以中断@ 1000毫秒
TCCR1A = 0;//将整个TCCR1A寄存器设置为0
TCCR1B = 0;//与TCCR1B
相同//将比较匹配寄存器设置为所需的计时器计数:
OCR1A = 15624;//打开CTC模式:
TCCR1B | =(1 《//为1024个预分频器设置CS10和CS12位:
TCCR1B | =(1 《 TCCR1B | =(1 《//启用计时器比较中断:
TIMSK1 | =(1 《 sei();//启用全局中断
}
定时器中断例程:我们无法更改其名称,但内容是完全可定制的。/p》
ISR(TIMER1_COMPA_vect)
{
tempVal = AnalogRead(tempPin);
if(tempVal》 maxTempSensor){
digitalWrite(ledPin,HIGH);
tempHigh = true;
}
else {
digitalWrite(ledPin,LOW);
tempHigh = false;
}
温度值-或如上文所述,从传感器读取其0-1023整数表示形式,并将其与阈值进行比较:当上面的内置LED点亮并且tempHigh设置为true时,否则关闭LED并 tempHigh设置为false。
如果(秒++》 = maxSeconds){
statusReport = true;
秒= 0;
}
}
请记住,每秒触发一次中断,但是我们希望报告系统状态的频率降低:秒变量在每次迭代时递增,直到达到s报告到期时的值;稍后将在主循环中通过检查statusReport标志来完成此操作。通常,永远不要执行太慢的操作,例如从中断例程中将数据写入串行。
loop()函数在接收到指令后便会解释并执行命令,然后如果计时器发出标志,则会报告状态打断。为了从串行缓冲区读取字符串,loop()依赖于将在最后定义的serialEvent()函数:该例程在每次loop()运行之间运行。它没有得到广泛的记录,并且可能不适用于所有的Arduino模型。无论如何,将其内容嵌套在主循环中并不难(请参见本步骤的结尾)。
void loop(){
int intValue = 0;
if(stringComplete){ boolean stringOK = false;
if(inputString.startsWith(“ CMD”)){
inputString = inputString.substring(4);
首先,我们检查接收到的字符串是否以“ CMD”开头:如果是这样,我们可以丢弃前四个字符,否则稍后会出现错误。
int pos = inputString.indexOf(‘=’);
if(pos》 -1){
command = inputString.substring(0,pos);
value = inputString。 substring(pos + 1,inputString.length()-1);//提取最多 n个被排除的命令
有两种类型的命令:设置值的命令,在其中找到分隔空格的“ =”值对,以及该命令是单个指令(STATUS)。如果pos处出现“ =”,则字符串将分为命令(左部分)和值(右部分),并将“ =”插入中间,并在行尾添加末尾字符。
如果(command.equals(“ RED”)){//RED = ON | OFF
value.equals(“ ON”)? digitalWrite(led3Pin,HIGH):digitalWrite(led3Pin,LOW);
stringOK = true;
}
否则if(command.equals(“ GREEN”)){//GREEN = ON | OFF
value.equals(“ ON”)吗? digitalWrite(led2Pin,HIGH):digitalWrite(led2Pin,LOW);
stringOK = true;
}
否则if(command.equals(“ YELLOW”)){//YELLOW = ON | OFF
value.equals(“ ON”)吗? digitalWrite(led1Pin,HIGH):digitalWrite(led1Pin,LOW);
stringOK = true;
}
我们检查并执行LED命令;请注意,代码仅检查值ON:如果您写入GREEN = ASD,它将被解释为GREEN = OFF。它不是完美的,但是它使事情变得简单得多。每次识别并执行命令时都会设置stringOK = true,以便以后标记错误的命令。
否则,如果(command.equals(“ TMAX”)){//TMAX =值
intValue = value.toInt();
如果(intValue》 0){
maxTemp = (float)intValue;
maxTempSensor =(int)((maxTemp/100 + .5)* 204.8);
stringOK = true;
}
}
否则,如果(command.equals(“ SECONDS”)){//SECONDS = value
intValue = value.toInt();
如果(intValue》 0){
maxSeconds = intValue;
stringOK = true;
}
}
当值应为数字时,我们需要将其转换并测试它确实是一个数字。对于MaxTemp,我们还按照变量定义部分中的说明计算传感器值
}//pos》 -1
else if(inputString.startsWith(“ STATUS”)){
Serial.print(“ STATUS RED =”);
Serial.println(digitalRead(led3Pin ));
Serial.print(“ STATUS GREEN =”);
Serial.println(digitalRead(led2Pin));
Serial.print(“ STATUS YELLOW =”);
Serial.println(digitalRead(led1Pin));
Serial.print(“ STATUS TMAX =“);
Serial.println(maxTemp);
Serial.print(” STATUS SECONDS =“);
Serial.println(maxSeconds);
Serial.print(“ STATUS TEMP =”);
Serial.println(temperature);
Serial.print(“ STATUS THIGH =”);
Serial.println(tempHigh);
stringOK = true ;
}//inputString.starts With(“ STATUS”)
如果命令是STATUS,则程序仅将所有信息输出到串行。
}//inputString.startsWith (“ CMD”)
stringOK吗? Serial.println(“ Command Executed”):Serial.println(“ Invalid Command”);
指示是否已收到有效或无效命令。
//清除字符串以进行下一次迭代
inputString =“”;
stringComplete = false;
}//stringComplete
下一次命令迭代的变量内务处理。
if(statusReport){
temperature =(tempVal * 0.0048828125-.5)* 100;
Serial.print(“ STATUS TEMP =”);
Serial.println(temperature);
Serial.print(“ STATUS THIGH =”);
Serial.println(tempHigh);
statusReport = false;
}
}
如果中断例程已引发statusReport标志,则将打印一些信息请注意,此时要计算当前温度值:因此,如果在statusReport时间间隔之间发出STATUS命令,则会得到旧的温度值。
如前所述,只要新数据进入硬件串行RX,就会发生serialEvent()。该例程在每次loop()运行之间运行,因此在循环内部使用delay可以延迟响应。可能有多个字节的数据。
无效的serialEvent(){
而(Serial.available()){
//获得新的字节:
char inChar =(char)Serial.read();
//将其添加到inputString:
inputString + = inChar;
//如果传入字符是换行符或回车符,则设置标志
//,因此主循环可以对此做一些事情:
if(inChar ==‘ n’|| inChar ==‘ r’){
stringComplete = true;
}
}
}
从串行读取每个字节并将其添加到输入字符串,直到遇到“ n”或“ r”表示字符串结尾:在这种情况下,设置由loop()检查的stringComplete标志。同时使用回车符 r和换行符 n确保代码能够从各种输入(包括Arduino IDE串行监视器以外的其他串行终端)检测字符串结尾。
关于蓝牙和串行的注意事项
在许多示例中,包括JY-MCU卖方的示例,您可以找到连接在不同Arduino数字引脚(例如10和11)上的蓝牙模块,以及通过SoftwareSerial库访问。根据我的测试结果,当该模块仅用于发送信息时,SoftwareSerial可以完美运行,但是在接收命令时Arduino Uno不够快。我没有尝试降低SoftwareSerial连接的速度(在示例中通常设置为2400bps),因为MIT AppInventor应用似乎不支持蓝牙连接速度设置。
使用SoftwareSerial,serialEvent()不会工作:需要重命名它(例如mySerialEvent())并在loop()的开头显式调用它。
步骤4:App Inventor代码-简介
在使用Android应用之前,您需要将Bluetooth模块与智能手机配对。
给Arduino开发板通电,打开在Android手机上的蓝牙上并搜索附近的蓝牙设备:JY-MCU模块将显示为HC-06,配对密码为1234。
蓝牙Arduino连接的关键组件应用程序是蓝牙客户端,而Arduino板将充当服务器:这意味着应用程序将始终启动连接。给Arduino开发板供电时,蓝牙模块红色LED开始闪烁;按下应用程序的“连接到设备”按钮,然后从列表中选择模块:红色LED指示灯将变为稳定,连接状态将变为“已连接”。
同样,这与蓝牙无关Master/Slave,但仍可能令人困惑:您的Bluetooth模块需要为Slave,但它(或Arduino草图)在客户端中将充当Server-与Android应用程序进行服务器通信。
您可以直接从Android Play商店安装Bluetooth Arduino Connection App,或者您可以通过下载附件将完整的应用程序代码导入到MIT App Inventor项目中。
蓝牙Arduino连接应用程序是使用MIT App Inventor 2开发的;以下步骤将提供详细说明。
步骤5:App Inventor代码-详细信息
Arduino蓝牙连接应用程序的关键组件是:
用于蓝牙配对设备的ListPicker(ListPicker1)
3个按钮,每个按钮控制相应的配色板LED(RedLedBtn,GreenLedBtn,YellowLedBtn)
发送状态命令(GetStatusBtn)的按钮
带有关联按钮的按钮文本框以设置状态报告间隔(SecondsBtn和SecondsTxBx)
巨大的多行状态标签,显示从Arduino板(状态)接收的信息
上一步(BluetoothClient1)
一个时钟组件,该时钟组件在客户端连接时每秒触发一次中断(Clock1)
以下是基于以下内容的应用代码说明:上面的图片。
图1
Variabl当打开应用程序屏幕时,将设置并初始化LED的状态和间隔。
图2
连接ListPicker对象ListPicker1使用两种方法:
已准备好可用(配对)的蓝牙设备的列表,并显示给用户
当用户选择设备时,将调用Bluetooth Client对象的Connect方法为了开始连接:如果成功,它将显示在适当的标签中,并激活Clock中断,以便可以接收来自设备的消息。
图3
在这里,我们演示如何向Arduino板发送命令。
按下GetStatusBtn时,将调用Bluetooth Client对象的SendText方法并执行文本命令发出:注意,在“ CMD STATUS”字符串的末尾添加了“ n”,以便Arduino草图中的serialEvent()函数能够知道消息何时结束。
代码打开或关闭LED稍微复杂一点:
我们使用相应的变量来跟踪其当前状态:如果打开,我们想将其关闭,反之亦然;因此,首先,我们将变量更改为布尔值
,然后使用新状态更新按钮标签
最后,调用BluetoothClient1.SendText来传输命令。
其他命令的代码非常相似,因此未显示。
图4
每次Clock1计时器触发,该例程被执行:它等效于Arduino的serialEvent();。如果BluetoothClient1接收到字节,则将它们复制到状态标签中。请注意,Bluetooth客户端对象具有一种返回所接收消息长度的方法。
步骤6:结论
在此指导中,我演示了一个通过蓝牙连接Arduino开发板和Android智能手机的有用方法。通信是双向的,因此开发板不仅向应用程序报告其状态,而且还从应用程序接收命令。
此外,一个简单的扩展程序允许将Arduino的命令发送给应用程序。电话:例如:按下板上的按钮即可拍照或发送短信。
Arduino草图可以作为远程命令处理的基础,它使用中断来执行一些操作-检查温度并打开LED警报-并发送状态心跳信号:该技术不仅可以通过蓝牙通信应用,还可以通过以太网等其他方式应用。
MIT App Inventor应用程序使用中断同样:它等效于Arduino的loop()+ serialEvent()函数的重复,并且类似地用于接收消息。
全部0条评论
快来发表一下你的评论吧 !