这是一个极其简单的东西,仅利用一个普通小电机作为”传感器“。我们知道当转动电机时,将产生一定的电压,往往转动的越快电压越高(并非完全的线性关系)。利用这一特性,使用Arduino的模拟引脚读取电压值就可以换算得到“风速”。
当然,这只是一个“玩具”,如果你手头有一些二极管、电阻之类的还可以做得更好一些。风速测试的方法有很多是基于小风车转速的,如果你手头有一些红外计数器,可以在风车适当位置增加挡片来获得较为准确的转速,也可以用成品的多线的圆片(多用于电机测速);除此之外,还有很多方法,例如用一些压力传感器测试后换算、用一些高灵敏度的超声波类传感器等等,看手头有什么东西就用什么吧^ ^
以使用一个小电机为例,结合一些显示屏来进行显示(手头有几块闲置的触摸屏,所以还是用触摸屏)或者直接输出到串口进行观察都可以。
一、硬件
1、Arduino随便一款
2、一个废弃的小电机——轴越灵活越好
3、一个小风车(有很多3D打印资源,找一个打出来,如果没有搓一个纸壳的都行)
4、电阻、二极管、电容、电感(没有问题也不大,最好是有,万一小电机加速度太高害烧了Arduino就赔上了)。我做的这个小玩具确实没有用也还挺抗造的,如果你想用可以搜索一下相关知识,然后选择合适的型号制作一个简单的电路来过滤尖峰、平稳电压、限制输入电压大小等。
5、显示屏(有就用,没有就算了)
二、编码
1、首先,定义一个引脚来读电压,并把它们保存到一个数组里:
void setup() {
Serial.begin(115200);
pinMode(A0, INPUT);
mySerial.begin(9600);
// 初始化数组为0
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
}
代码中使用了A0引脚,D开头那些不可以,这个工程非常简单没有引脚冲突需要解决,所以查看引脚图随意选一个能读模拟电压的即可。
2、在循环中进行读取
void loop() {
// 1. 读取当前电压值
int sensorValue = analogRead(voltagePin);
float voltage = sensorValue * (5.0 / 1023.0); // 转换为电压 (0-5V)
// 2. 更新均值计算
voltageSum -= readings[readIndex]; // 减去旧值
readings[readIndex] = voltage; // 存储新值
voltageSum += voltage; // 加上新值
readIndex = (readIndex + 1) % numReadings; // 循环索引
// 3. 计算5秒均值
voltageAvg = voltageSum / numReadings;
float windSpeed = voltageAvg * 86; // 使用均值计算风速
3、风力等级的换算
一般,我们直接使用下表就可以了:
int getBeaufortScale(float windSpeed_mps) {
if (windSpeed_mps < 0.3) return 0;
else if (windSpeed_mps <= 1.5) return 1;
else if (windSpeed_mps <= 3.3) return 2;
else if (windSpeed_mps <= 5.4) return 3;
else if (windSpeed_mps <= 7.9) return 4;
else if (windSpeed_mps <= 10.7) return 5;
else if (windSpeed_mps <= 13.8) return 6;
else if (windSpeed_mps <= 17.1) return 7;
else if (windSpeed_mps <= 20.7) return 8;
else if (windSpeed_mps <= 24.4) return 9;
else if (windSpeed_mps <= 28.4) return 10;
else if (windSpeed_mps <= 32.6) return 11;
else return 12;
}
至于液晶屏的使用,前面有多篇介绍中有,用几次就熟悉了。一般我们封装几个函数来完成指令发送,而接收部分通常使用一个缓冲区来处理。以下是几个封装范例:
/**
@brief 发送浮点数指令(格式:page0.t4.txt="23.5" + FF FF FF)
@param value 浮点数值(如23.5)
@param objName 目标对象名(如"page0.t4")
*/
void sendFloatAsHex(float value, const char* objName) {
// 1. 将浮点数转换为保留1位小数的字符串
char floatStr[8];
dtostrf(value, 0, 1, floatStr); // 格式: "23.5"
// 2. 拼接完整指令字符串
String command = String(objName) + "=\"" + floatStr + "\"";
// 3. 转换为16进制字节流并发送
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i)); // 逐个字符发送(ASCII即16进制字节)
}
// 4. 发送结束符 FF FF FF
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
/**
@brief 发送整数指令(格式:dim=50 + FF FF FF)
@param value 整数值(如50)
@param objName 目标对象名(如"dim")
*/
void sendIntAsHex(int value, const char* objName) {
// 1. 将整数转换为字符串
char intStr[8];
itoa(value, intStr, 10); // 转换为十进制字符串
// 2. 拼接完整指令字符串
String command = String(objName) + "=\"" + intStr + "\"";
// 3. 转换为16进制字节流并发送
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i)); // 逐个字符发送(ASCII即16进制字节)
}
// 4. 发送结束符 FF FF FF
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
/**
@brief 发送字符串指令(格式:Setting.twifiname.txt="winfiname" + FF FF FF)
@param text 要发送的字符串内容(如"winfiname")
@param objName 目标对象名(如"Setting.twifiname")
*/
void sendTextCommand(String text, const char* objName) {
String command = String(objName) + "=\"" + text + "\"";
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i));
}
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
4、完整代码:
#include <SoftwareSerial.h>
const int voltagePin = A0;
SoftwareSerial mySerial(A2, A3); // RX, TX
// 新增变量用于存储历史数据和均值计算
const int numReadings = 10; // 5秒内10次记录(每次间隔500ms)
float readings[numReadings]; // 存储历史电压值
int readIndex = 0; // 当前写入的数组索引
float voltageSum = 0; // 累加值
float voltageAvg = 0; // 平均值
void setup() {
Serial.begin(115200);
pinMode(A0, INPUT);
mySerial.begin(9600);
// 初始化数组为0
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
}
void loop() {
// 1. 读取当前电压值
int sensorValue = analogRead(voltagePin);
float voltage = sensorValue * (5.0 / 1023.0); // 转换为电压 (0-5V)
// 2. 更新均值计算
voltageSum -= readings[readIndex]; // 减去旧值
readings[readIndex] = voltage; // 存储新值
voltageSum += voltage; // 加上新值
readIndex = (readIndex + 1) % numReadings; // 循环索引
// 3. 计算5秒均值
voltageAvg = voltageSum / numReadings;
// 4. 输出结果(与原代码一致)
Serial.print("电压(均值): ");
Serial.print(voltageAvg);
Serial.print(" V");
float windSpeed = voltageAvg * 86; // 使用均值计算风速
Serial.print("\t风速: ");
Serial.print(windSpeed);
Serial.print(" m/s");
int windLevel = getBeaufortScale(windSpeed);
Serial.print("\t等级: ");
Serial.print(windLevel);
Serial.println("");
// 5. 发送数据到串口(使用均值)
sendFloatAsHex(voltageAvg * 10, "page0.t1.txt");
sendFloatAsHex(windSpeed, "page0.t4.txt");
sendIntAsHex(windLevel, "page0.t7.txt");
delay(500); // 每 0.5 秒读取一次
}
int getBeaufortScale(float windSpeed_mps) {
if (windSpeed_mps < 0.3) return 0;
else if (windSpeed_mps <= 1.5) return 1;
else if (windSpeed_mps <= 3.3) return 2;
else if (windSpeed_mps <= 5.4) return 3;
else if (windSpeed_mps <= 7.9) return 4;
else if (windSpeed_mps <= 10.7) return 5;
else if (windSpeed_mps <= 13.8) return 6;
else if (windSpeed_mps <= 17.1) return 7;
else if (windSpeed_mps <= 20.7) return 8;
else if (windSpeed_mps <= 24.4) return 9;
else if (windSpeed_mps <= 28.4) return 10;
else if (windSpeed_mps <= 32.6) return 11;
else return 12;
}
/**
@brief 发送浮点数指令(格式:page0.t4.txt="23.5" + FF FF FF)
@param value 浮点数值(如23.5)
@param objName 目标对象名(如"page0.t4")
*/
void sendFloatAsHex(float value, const char* objName) {
// 1. 将浮点数转换为保留1位小数的字符串
char floatStr[8];
dtostrf(value, 0, 1, floatStr); // 格式: "23.5"
// 2. 拼接完整指令字符串
String command = String(objName) + "=\"" + floatStr + "\"";
// 3. 转换为16进制字节流并发送
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i)); // 逐个字符发送(ASCII即16进制字节)
}
// 4. 发送结束符 FF FF FF
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
/**
@brief 发送整数指令(格式:dim=50 + FF FF FF)
@param value 整数值(如50)
@param objName 目标对象名(如"dim")
*/
void sendIntAsHex(int value, const char* objName) {
// 1. 将整数转换为字符串
char intStr[8];
itoa(value, intStr, 10); // 转换为十进制字符串
// 2. 拼接完整指令字符串
String command = String(objName) + "=\"" + intStr + "\"";
// 3. 转换为16进制字节流并发送
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i)); // 逐个字符发送(ASCII即16进制字节)
}
// 4. 发送结束符 FF FF FF
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
/**
@brief 发送字符串指令(格式:Setting.twifiname.txt="winfiname" + FF FF FF)
@param text 要发送的字符串内容(如"winfiname")
@param objName 目标对象名(如"Setting.twifiname")
*/
void sendTextCommand(String text, const char* objName) {
String command = String(objName) + "=\"" + text + "\"";
for (size_t i = 0; i < command.length(); i++) {
mySerial.write(command.charAt(i));
}
mySerial.write(0xFF);
mySerial.write(0xFF);
mySerial.write(0xFF);
}
441

被折叠的 条评论
为什么被折叠?



