[HC04-Arduino]——光电探测器
写在最开始是我想要做个什么?简单来说,我要用蓝牙实现光电探测器的数据传输,并在手机端实现波形展示。
一、电路搭建
电路很简单,一个光敏电阻一个10k的电阻。然后没找的蓝牙模块,就用四路开关代替了,引脚名称从左往右对应RXD,TXD,GND和VCC。按理来说光敏电阻那我直接接5V电压就行了,但是我非接数字引脚多此一举一下哈哈哈哈哈哈哈。
二、光敏电阻部分代码
#include <SoftwareSerial.h> SoftwareSerial BTSerial(8, 9); //8:rx | 9:tx int lightValue = 0; void setup() { pinMode(13, OUTPUT); pinMode(A0, INPUT); Serial.begin(9600); BTSerial.begin(9600); digitalWrite(13, LOW); } void loop() { digitalWrite(13, HIGH); lightValue = analogRead(A0); //为光敏电阻两端分压 float lightV = (lightValue * (5.0 / 1023.0)); //将模拟端接受的0-1023电压值转为0-5V Serial.print("Raw: "); //【串口】输出,返回给串口监视器 Serial.print(lightValue); Serial.print(" | Voltage"); Serial.println(lightV,4); //Serial.print() 对于 float / double 类型,默认只打印两位小数。后面加隔,为4位 BTSerial.print("Raw: "); //【蓝牙】输出,返回给手机蓝牙串口助手 BTSerial.print(lightValue); BTSerial.print(" | Voltage"); BTSerial.println(lightV,4); delay(10); // Delay a little bit to improve simulation performance }注意的是浮点类型了,因为我用 Serial.print()打印浮点类型默认小数点后2位,但是我要4位,所以在后面加了个4。同理 BTSerial.print()也是如此。
这部分代码主要就是实现蓝牙数据的发送。但是我不是要把数据弄成波形展示吗?
三、波形实现
我比较捡懒,用的江协自研的蓝牙串口小程序,功能很强大,有显示屏,波形和遥感功能。他这个主要就是向蓝牙串口发送特定格式的数据包,然后就自动显示出波形来了,哈哈哈哈哈很省事。但有一个缺点就是横纵坐标名称写不了,希望有一天有能力自己写一个波形展示APP出来。
这个特定格式数据包是[plot,数据1,数据2...]。我们知道 Serial.print("[plot,数据1,数据2...]")里这个“数据”是文本模式,但是我希望这里是变量,所以需要用到字符串拼接。
方法一:使用string类(最直观,适合新手)
这种方法就是把不同的部分用+连接起来。这里用到了类型转换,把 float 类型的lightV变量转为能和处理文本一样的string类。把这行代码加在上面代码后后面,蓝牙串口接收区就能成功接受指定格式的数据包了,然后点击波形,就能实现展示。
但,我有点不满意,就是波形不够细致。因为上面也说了 Serial.print()打印浮点类型默认小数点后2位,所以这里接受到的电压数据是小数点后两位。那我想要后四位,这里没法在后面直接加个,4了。由此D老师教了我方法二。
BTSerial.println("[plot," + String(lightV) + "]"); //此为字符串拼接方式,可打印多个文本内容。String(lightV)同样对于浮点数默认保留两位方法二:使用 dtostrf() 将浮点数转为指定小数位数的字符串(依然用于字符串拼接)
/*char *dtostrf(double val, int width, unsigned int prec, char *buf); val:要转换的浮点数 width:整个字符串的最小宽度(包括小数点),通常填0表示自动 prec:小数位数 buf:存放结果的字符数组*/ char buffer[30]; // 足够大的缓冲区 dtostrf(lightV, 0, 4, buffer); // buffer 现在内容是类似 "2.4532" BTSerial.println("[plot," + String(buffer) + "]");String 在拼接时可能会产生临时副本,造成内存碎片,所以还有一个方法三,用sprintf直接在数组里操作,对UNO板更友好。
方法三:用 sprintf + dtostrf 构建字符数组(内存友好)
/*int sprintf(char *buffer, const char *format, ...); buffer:字符数组,用来存放生成的结果字符串 format:格式控制字符串,包含普通文本和格式说明符(如 %d, %s) ...:可变参数,要与格式说明符一一对应*/ char buffer[40]; char buffer0[10]; dtostrf(lightV, 0, 4, buffer0); // 格式化电压为4位小数字符串,此时buffer0 现在内容是类似 "2.4532" sprintf(buffer, "[plot,%s]", buffer0); // 此时buffer里内容为[plot,2.4532] BTSerial.println(buffer);最后一个脑洞。我记得可以用%.4f来指定浮点类型的小数点位数。那我直接
char buffer[20]; sprintf(buffer, "[plot,%.4f]", lightV); BTSerial.println(buffer);问了D老师,它说不行,因为Arduino的标准库为了节省代码空间,默认禁用了sprintf的浮点数格式化功能。所以还是规规矩矩用 dtostrf 操作字符数组吧。
四、完整代码
#include <SoftwareSerial.h> SoftwareSerial BTSerial(8, 9); //8:rx | 9:tx int lightValue = 0; void setup() { pinMode(13, OUTPUT); pinMode(A0, INPUT); Serial.begin(9600); BTSerial.begin(9600); digitalWrite(13, LOW); } void loop() { digitalWrite(13, HIGH); lightValue = analogRead(A0); //为光敏电阻两端分压 float lightV = (lightValue * (5.0 / 1023.0)); //将模拟端接受的0-1023电压值转为0-5V Serial.print("Raw: "); //【串口】输出,返回给串口监视器 Serial.print(lightValue); Serial.print(" | Voltage"); Serial.println(lightV,4); //Serial.print() 对于 float / double 类型,默认只打印两位小数。后面加隔,为4位 BTSerial.print("Raw: "); //【蓝牙】输出,返回给手机蓝牙串口助手 BTSerial.print(lightValue); BTSerial.print(" | Voltage"); BTSerial.println(lightV,4); //将数据做成数据包返回给蓝牙串口,方便画图[plot,数据1,数据2....]。 //方法一:字符串拼接方式 // BTSerial.println("[plot," + String(lightV) + "]"); //此为字符串拼接方式,可打印多个文本内容。String(lightV)同样对于浮点数默认保留两位 //方法二:使用 dtostrf() 将浮点数转为指定小数位数的字符串 /*char *dtostrf(double val, int width, unsigned int prec, char *buf); val:要转换的浮点数 width:整个字符串的最小宽度(包括小数点),通常填0表示自动 prec:小数位数 buf:存放结果的字符数组*/ /*char buffer[30]; // 足够大的缓冲区 dtostrf(lightV, 0, 4, buffer); // buffer 现在内容是类似 "2.4532" BTSerial.println("[plot," + String(buffer) + "]"); */ //方法三:使用 sprintf() 函数+ dtostrf 构建字符数组(内存友好) /*int sprintf(char *buffer, const char *format, ...); buffer:字符数组,用来存放生成的结果字符串 format:格式控制字符串,包含普通文本和格式说明符(如 %d, %s) ...:可变参数,要与格式说明符一一对应*/ char buffer[40]; char buffer0[10]; dtostrf(lightV, 0, 4, buffer0); // 格式化电压为4位小数字符串,此时buffer0 现在内容是类似 "2.4532" sprintf(buffer, "[plot,%s]", buffer0); // 此时buffer里内容为[plot,2.4532,512] BTSerial.println(buffer); delay(10); // Delay a little bit to improve simulation performance }