本帖最后由 川山甲的壳 于 2022-2-14 11:20 编辑
如何在Arduino和microbit 主控上使用风速仪与风向仪? 这应该是今年的第一贴,首先祝大家新年快乐,虎年大吉。 背景: 前一段时间,有位老师想做一个气象站的项目,但是他选的风速仪和风向仪接口不兼容Arduino和micro:bit主控。后面他就找到我,问我有没有什么解决办法? 当看见他发过来的图片时,方案就已经在脑海里呈现了,对于这个问题,只需要加一个Gravity:RS485转UART有源隔离型信号转换模块 就行了。因为风向变送器和风速变送器是RS485接口,协议是Modbus协议,所以需要使用RS485转UART 模块,其作用就是将RS485接口转换成UART输出。
注:风向变送器和风速变送器的接线方式一样。 Arduino uno 上的使用方法
测量风向软硬件准备 硬件:
软件: 硬件连接 ArduinoIDE——样例代码 1. 将风向变送器,RS485转UART模块,uno R3按照上面的方式连接在一起。 2. 打开Arduino IDE,将下面的代码上传到DFRduino uno R3上。 3. 打开串口,将波特率调至115200,通过串口观察结果。 4. 数值对应的方向。
- #include <SoftwareSerial.h>
- SoftwareSerial mySerial(2, 3); //定义软串口,3号端口为TX,2号端口为RX,
-
- uint8_t Address = 0x03;
-
- void setup()
- {
- Serial.begin(115200);
- mySerial.begin(9600);
- ModifyAddress(0x00, Address); //设备地址修改,修改地址后请注释掉这句重新上电。
- }
-
- void loop()
- {
- Serial.println(readWindDirection(Address)); //读取风向
- delay(1000);
- }
-
-
- size_t readN(uint8_t *buf, size_t len)
- {
- size_t offset = 0, left = len;
- int16_t Tineout = 1500;
- uint8_t *buffer = buf;
- long curr = millis();
- while (left) {
- if (mySerial.available()) {
- buffer[offset] = mySerial.read();
- offset++;
- left--;
- }
- if (millis() - curr > Tineout) {
- break;
- }
- }
- return offset;
- }
-
-
- /**
- @brief 计算CRC16_2检验值
- @param buf 需要计算校验值的数据包
- @param len 需要校验的数据长度。
- @return 返回一个16位的校验结果。
- */
- uint16_t CRC16_2(uint8_t *buf, int16_t len)
- {
- uint16_t crc = 0xFFFF;
- for (int pos = 0; pos < len; pos++)
- {
- crc ^= (uint16_t)buf[pos];
- for (int i = 8; i != 0; i--)
- {
- if ((crc & 0x0001) != 0)
- {
- crc >>= 1;
- crc ^= 0xA001;
- }
- else
- {
- crc >>= 1;
- }
- }
- }
-
- crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
- return crc;
- }
-
-
- /**
- @brief 为数据包末尾添加CRC_16校验
- @param buf 需要添加校验值的数据包
- @param len 需要添加校验的数据长度。
- @return 无
- */
- void addedCRC(uint8_t *buf, int len)
- {
- uint16_t crc = 0xFFFF;
- for (int pos = 0; pos < len; pos++)
- {
- crc ^= (uint16_t)buf[pos];
- for (int i = 8; i != 0; i--)
- {
- if ((crc & 0x0001) != 0)
- {
- crc >>= 1;
- crc ^= 0xA001;
- }
- else
- {
- crc >>= 1;
- }
- }
- }
- buf[len] = crc % 0x100;
- buf[len + 1] = crc / 0x100;
- }
-
-
-
- /**
- @brief 读取风向
- @param Address 读取的设备地址。
- @return 风向单位m/s,读取超时返回—1.
- */
-
- int readWindDirection(uint8_t Address)
- {
- uint8_t Data[7] = {0}; //储存传感器返回的原始数据包
- uint8_t COM[8] = {0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; //读取风向的指令
- boolean ret = false; //风向获取成功标志位
- int WindDirection = 0;
- long curr = millis();
- long curr1 = curr;
- uint8_t ch = 0;
- COM[0] = Address; //参考通讯协议将指令包添加完整。
- addedCRC(COM , 6); //为读取风向指令包添加CRC_16校验
- mySerial.write(COM, 8); //发送读取风向的指令
-
- while (!ret) {
- if (millis() - curr > 1000) {
- WindDirection = -1; //如果整个超过1000毫秒还未读取到风向将视为超时,并返回—1.
- break;
- }
-
- if (millis() - curr1 > 100) {
- mySerial.write(COM, 8); //如果上一条读取风向的指令发出超过100毫秒还未收到返回指令将从新发送读取风向的指令
- curr1 = millis();
- }
-
- if (readN(&ch, 1) == 1) {
- if (ch == Address) { //读取并判断包头。
- Data[0] = ch;
- if (readN(&ch, 1) == 1) {
- if (ch == 0x03) { //读取并判断包头。
- Data[1] = ch;
- if (readN(&ch, 1) == 1) {
- if (ch == 0x02) { //读取并判断包头。
- Data[2] = ch;
- if (readN(&Data[3], 4) == 4) {
- if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) { //校验数据包
- ret = true;
- WindDirection = Data[3] * 256 + Data[4]; //计算风向
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return WindDirection;
- }
-
-
- /**
- @brief 修改传感器设备地址
- @param Address1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
- @param Address2 设备修改后的地址,范围0x00~0xFF,
- @return 返回true表示修改成功,返回false表示修改失败。
- */
-
- boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
- {
- uint8_t ModifyAddressCOM[11] = {0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
- boolean ret = false;
- long curr = millis();
- long curr1 = curr;
- uint8_t ch = 0;
- ModifyAddressCOM[0] = Address1;
- ModifyAddressCOM[8] = Address2;
- addedCRC(ModifyAddressCOM , 9);
- mySerial.write(ModifyAddressCOM, 11);
- while (!ret) {
- if (millis() - curr > 1000) {
- break;
- }
-
- if (millis() - curr1 > 100) {
- mySerial.write(ModifyAddressCOM, 11);
- curr1 = millis();
- }
-
- if (readN(&ch, 1) == 1) {
- if (ch == Address1) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x10 ) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x10) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x00) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x00) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x01) {
- while (1) {
- Serial.println("请给传感器重新上电。");
- delay(1000);
- }
- ret = true ;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return ret;
- }
复制代码
效果展示: 注意:安装时传感器上白点必须朝向正北。如下图: 串口打印的结果为13(西北偏西)
手机对应的方向为西北偏西,几乎一致。
注意:如果最终结果返回的是-1,需要将这句代码“ModifyAddress(0x00, Address); //设备地址修改,修改地址后请注释掉这句重新上电。”注释掉,再重新上传与上电。 Mind+——样例代码 1.打开mind+,添加主控板——arduino uno,;然后再去用户库添加——风向变送器库。
注:如果mind+的用户库没有找到风速变送器和风向变送器的库,可以在用户库中的搜索栏搜索“RS485风速变送器”与“RS485风向变送器”。 2.将下面的代码上传到DFRduino uno R3上。 3.打开串口,将波特率调至9600,通过串口观察结果。 效果展示: 串口打印出来的结果显示北方。
手机对应的方向为北方,一致。
注意:如果最终结果返回的是-1,可以通过修改设备地址或者重新上电来解决。如下:
测量风速软硬件准备 硬件:
软件: 硬件连接 ArduinoIDE——样例代码 1. 将风速变送器,RS485转UART模块,uno R3按照上面的方式连接在一起。 2. 打开Arduino IDE,将下面的代码上传到DFRduino uno R3上。 3. 打开串口,将波特率调至115200,通过串口观察结果。 - #include <SoftwareSerial.h>
- SoftwareSerial mySerial(2, 3); //定义软串口,3号端口为TX,2号端口为RX,
-
- uint8_t Address = 0x10;
-
-
- void setup()
- {
- Serial.begin(115200);
- mySerial.begin(9600);
- ModifyAddress(0x00, Address); //设备地址修改,修改地址后请注释掉这句重新上电。
- }
-
- void loop()
- {
- Serial.print(readWindSpeed(Address)); //读取风速
- Serial.println("m/s");
- delay(1000);
- }
-
-
- size_t readN(uint8_t *buf, size_t len)
- {
- size_t offset = 0, left = len;
- int16_t Tineout = 1500;
- uint8_t *buffer = buf;
- long curr = millis();
- while (left) {
- if (mySerial.available()) {
- buffer[offset] = mySerial.read();
- offset++;
- left--;
- }
- if (millis() - curr > Tineout) {
- break;
- }
- }
- return offset;
- }
-
-
- /**
- @brief 计算CRC16_2检验值
- @param buf 需要计算校验值的数据包
- @param len 需要校验的数据长度。
- @return 返回一个16位的校验结果。
- */
- uint16_t CRC16_2(uint8_t *buf, int16_t len)
- {
- uint16_t crc = 0xFFFF;
- for (int pos = 0; pos < len; pos++)
- {
- crc ^= (uint16_t)buf[pos];
- for (int i = 8; i != 0; i--)
- {
- if ((crc & 0x0001) != 0)
- {
- crc >>= 1;
- crc ^= 0xA001;
- }
- else
- {
- crc >>= 1;
- }
- }
- }
-
- crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
- return crc;
- }
-
-
- /**
- @brief 为数据包末尾添加CRC_16校验
- @param buf 需要添加校验值的数据包
- @param len 需要添加校验的数据长度。
- @return 无
- */
- void addedCRC(uint8_t *buf, int len)
- {
- uint16_t crc = 0xFFFF;
- for (int pos = 0; pos < len; pos++)
- {
- crc ^= (uint16_t)buf[pos];
- for (int i = 8; i != 0; i--)
- {
- if ((crc & 0x0001) != 0)
- {
- crc >>= 1;
- crc ^= 0xA001;
- }
- else
- {
- crc >>= 1;
- }
- }
- }
- buf[len] = crc % 0x100;
- buf[len + 1] = crc / 0x100;
- }
-
-
-
- /**
- @brief 读取风速
- @param Address 读取的设备地址。
- @return 风速单位m/s,读取超时返回—1.
- */
-
- float readWindSpeed(uint8_t Address)
- {
- uint8_t Data[7] = {0}; //储存传感器返回的原始数据包
- uint8_t COM[8] = {0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}; //读取风速的指令
- boolean ret = false; //风速获取成功标志位
- float WindSpeed = 0;
- long curr = millis();
- long curr1 = curr;
- uint8_t ch = 0;
- COM[0] = Address; //参考通讯协议将指令包添加完整。
- addedCRC(COM , 6); //为读取风速指令包添加CRC_16校验
- mySerial.write(COM, 8); //发送读取风速的指令
-
- while (!ret) {
- if (millis() - curr > 1000) {
- WindSpeed = -1; //如果整个超过1000毫秒还未读取到风速将视为超时,并返回—1.
- break;
- }
-
- if (millis() - curr1 > 100) {
- mySerial.write(COM, 8); //如果上一条读取风速的指令发出超过100毫秒还未收到返回指令将从新发送读取风速的指令
- curr1 = millis();
- }
-
- if (readN(&ch, 1) == 1) {
- if (ch == Address) { //读取并判断包头。
- Data[0] = ch;
- if (readN(&ch, 1) == 1) {
- if (ch == 0x03) { //读取并判断包头。
- Data[1] = ch;
- if (readN(&ch, 1) == 1) {
- if (ch == 0x02) { //读取并判断包头。
- Data[2] = ch;
- if (readN(&Data[3], 4) == 4) {
- if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) { //校验数据包
- ret = true;
- WindSpeed = (Data[3] * 256 + Data[4]) / 10.00; //计算风速
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return WindSpeed;
- }
-
-
- /**
- @brief 修改传感器设备地址
- @param Address1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
- @param Address2 设备修改后的地址,范围0x00~0xFF,
- @return 返回true表示修改成功,返回false表示修改失败。
- */
-
- boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
- {
- uint8_t ModifyAddressCOM[11] = {0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
- boolean ret = false;
- long curr = millis();
- long curr1 = curr;
- uint8_t ch = 0;
- ModifyAddressCOM[0] = Address1;
- ModifyAddressCOM[8] = Address2;
- addedCRC(ModifyAddressCOM , 9);
- mySerial.write(ModifyAddressCOM, 11);
- while (!ret) {
- if (millis() - curr > 1000) {
- break;
- }
-
- if (millis() - curr1 > 100) {
- mySerial.write(ModifyAddressCOM, 11);
- curr1 = millis();
- }
-
- if (readN(&ch, 1) == 1) {
- if (ch == Address1) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x10 ) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x10) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x00) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x00) {
- if (readN(&ch, 1) == 1) {
- if (ch == 0x01) {
- // while (1) {
- Serial.println("请给传感器重新上电。");
- // delay(1000);
- // }
- ret = true ;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return ret;
- }
复制代码
效果展示: 用手轻轻推动风速变送器,观察数据。 Mind+——样例代码 1.打开mind+,添加主控板——arduino uno,;然后再去用户库添加——风速变送器的库。 2.将下面的代码上传到DFRduino uno R3上。 3.打开串口,将波特率调至9600,通过串口观察结果。 效果展示: 用手轻轻推动风速变送器,观察数据。
micro:bit上的使用方法测量风向软硬件准备 硬件:
软件: 硬件连接 Mind+——样例代码 1. 打开mind+,添加主控板——micro:bit,;然后再去用户库添加——风向变送器的库。 2.将下面的代码上传到micro:bit上。 3.打开串口,将波特率调至9600,通过串口观察结果。 效果展示: 用手轻轻推动风向变送器,观察数据。
测量风速软硬件准备 硬件:
软件: 硬件连接 Mind+——样例代码 1. 打开mind+,添加主控板——micro:bit,;然后再去用户库添加——风速变送器的库。 2.将下面的代码上传到micro:bit上。 3.打开串口,将波特率调至9600,通过串口观察结果。 效果展示: 用手轻轻推动风速变送器,观察数据。
|