川山甲的壳 发表于 2022-1-27 15:39:56

RS485转UART:如何在arduino和microbit 主控上使用风速仪与风向...

本帖最后由 川山甲的壳 于 2022-2-14 11:20 编辑

如何在arduino和microbit 主控上使用风速仪与风向仪?————RS485转UART       这应该是今年的第一贴,首先祝大家新年快乐,虎年大吉。背景:       前一段时间,有位老师想做一个气象站的项目,但是他选的风速仪和风向仪接口不兼容Arduino和micro:bit主控。后面他就找到我,问我有没有什么解决办法?RS485风向变送器-传感器模组-DFRobot创客商城RS485风速变送器-传感器模组-DFRobot创客商城
       当看见他发过来的图片时,方案就已经在脑海里呈现了,对于这个问题,只需要加一个Gravity:RS485转UART有源隔离型信号转换模块 就行了。因为风向变送器和风速变送器是RS485接口,协议是Modbus协议,所以需要使用RS485转UART 模块,其作用就是将RS485接口转换成UART输出。
      下面我就分享一下,如何在arduino和micro:bit主控上使用风向变送器和风速变送器。首先我们根据下图将风向变送器和风速变送器连接在Gravity:RS485转UART有源隔离型信号转换模块上。注:风向变送器和风速变送器的接线方式一样。Arduino uno 上的使用方法

测量风向软硬件准备硬件:

DFRduino UNO R3-Arduino控制器IO 传感器扩展板 V7.1-Arduino扩展板

RS485风向变送器-传感器模组Gravity:RS485转UART有源隔离型信号转换模块

软件:· Arduino IDE 点击下载Arduino IDE· MIND+ 点击下载 mindplus硬件连接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_tAddress = 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 = mySerial.read();
      offset++;
      left--;
    }
    if (millis() - curr > Tineout) {
      break;
    }
}
return offset;
}


/**
@brief计算CRC16_2检验值
@parambuf 需要计算校验值的数据包
@paramlen 需要校验的数据长度。
@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;
    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校验
@parambuf 需要添加校验值的数据包
@paramlen 需要添加校验的数据长度。
@return无
*/
void addedCRC(uint8_t *buf, int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
    crc ^= (uint16_t)buf;
    for (int i = 8; i != 0; i--)
    {
      if ((crc & 0x0001) != 0)
      {
      crc >>= 1;
      crc ^= 0xA001;
      }
      else
      {
      crc >>= 1;
      }
    }
}
buf = crc % 0x100;
buf = crc / 0x100;
}



/**
@brief读取风向
@paramAddress 读取的设备地址。
@return风向单位m/s,读取超时返回—1.
*/

int readWindDirection(uint8_t Address)
{
uint8_t Data = {0};   //储存传感器返回的原始数据包
uint8_t COM = {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 = 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 = ch;
      if (readN(&ch, 1) == 1) {
          if (ch == 0x03) {         //读取并判断包头。
            Data = ch;
            if (readN(&ch, 1) == 1) {
            if (ch == 0x02) {       //读取并判断包头。
                Data = ch;
                if (readN(&Data, 4) == 4) {
                  if (CRC16_2(Data, 5) == (Data * 256 + Data)) {//校验数据包
                  ret = true;
                  WindDirection = Data * 256 + Data;//计算风向
                  }
                }
            }
            }
          }
      }
      }
    }
}
return WindDirection;
}


/**
@brief修改传感器设备地址
@paramAddress1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
@paramAddress2 设备修改后的地址,范围0x00~0xFF,
@return返回true表示修改成功,返回false表示修改失败。
*/

boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
{
uint8_t ModifyAddressCOM = {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 = Address1;
ModifyAddressCOM = 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,可以通过修改设备地址或者重新上电来解决。如下:
测量风速软硬件准备硬件:

DFRduino UNO R3-Arduino控制器IO 传感器扩展板 V7.1-Arduino扩展板

RS485风速变送器-传感器模组Gravity:RS485转UART有源隔离型信号转换模块


软件:· Arduino IDE 点击下载Arduino IDE· MIND+ 点击下载 mindplus硬件连接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_tAddress = 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 = mySerial.read();
      offset++;
      left--;
    }
    if (millis() - curr > Tineout) {
      break;
    }
}
return offset;
}


/**
@brief计算CRC16_2检验值
@parambuf 需要计算校验值的数据包
@paramlen 需要校验的数据长度。
@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;
    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校验
@parambuf 需要添加校验值的数据包
@paramlen 需要添加校验的数据长度。
@return无
*/
void addedCRC(uint8_t *buf, int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
    crc ^= (uint16_t)buf;
    for (int i = 8; i != 0; i--)
    {
      if ((crc & 0x0001) != 0)
      {
      crc >>= 1;
      crc ^= 0xA001;
      }
      else
      {
      crc >>= 1;
      }
    }
}
buf = crc % 0x100;
buf = crc / 0x100;
}



/**
@brief读取风速
@paramAddress 读取的设备地址。
@return风速单位m/s,读取超时返回—1.
*/

float readWindSpeed(uint8_t Address)
{
uint8_t Data = {0};   //储存传感器返回的原始数据包
uint8_t COM = {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 = 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 = ch;
      if (readN(&ch, 1) == 1) {
          if (ch == 0x03) {         //读取并判断包头。
            Data = ch;
            if (readN(&ch, 1) == 1) {
            if (ch == 0x02) {       //读取并判断包头。
                Data = ch;
                if (readN(&Data, 4) == 4) {
                  if (CRC16_2(Data, 5) == (Data * 256 + Data)) {//校验数据包
                  ret = true;
                  WindSpeed = (Data * 256 + Data) / 10.00;//计算风速
                  }
                }
            }
            }
          }
      }
      }
    }
}
return WindSpeed;
}


/**
@brief修改传感器设备地址
@paramAddress1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
@paramAddress2 设备修改后的地址,范围0x00~0xFF,
@return返回true表示修改成功,返回false表示修改失败。
*/

boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
{
uint8_t ModifyAddressCOM = {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 = Address1;
ModifyAddressCOM = 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上的使用方法测量风向软硬件准备硬件:

micro:bit编程入门开发板-micro:bit开发板micro:IO Extend micro:bit 掌控板 IO扩展板

RS485风向变送器-传感器模组Gravity:RS485转UART有源隔离型信号转换模块

软件:· MIND+ 点击下载 mindplus硬件连接Mind+——样例代码1. 打开mind+,添加主控板——micro:bit,;然后再去用户库添加——风向变送器的库。2.将下面的代码上传到micro:bit上。3.打开串口,将波特率调至9600,通过串口观察结果。效果展示:用手轻轻推动风向变送器,观察数据。

测量风速软硬件准备硬件:

micro:bit编程入门开发板-micro:bit开发板micro:IO Extend micro:bit 掌控板 IO扩展板

RS485风速变送器-传感器模组Gravity:RS485转UART有源隔离型信号转换模块


软件:· MIND+ 点击下载 mindplus硬件连接Mind+——样例代码1. 打开mind+,添加主控板——micro:bit,;然后再去用户库添加——风速变送器的库。2.将下面的代码上传到micro:bit上。3.打开串口,将波特率调至9600,通过串口观察结果。效果展示:用手轻轻推动风速变送器,观察数据。

赤星三春牛! 发表于 2022-1-28 15:04:20

厉害厉害

NIKO 发表于 2022-1-29 09:04:27

这个好 正好能用上

KkQ1VrB7W776 发表于 2022-1-30 10:19:29

666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
页: [1]
查看完整版本: RS485转UART:如何在arduino和microbit 主控上使用风速仪与风向...