1001浏览
查看: 1001|回复: 3

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

[复制链接]
本帖最后由 川山甲的壳 于 2022-2-14 11:20 编辑

如何在Arduino和microbit 主控上使用风速仪与风向仪
————RS485转UART
       这应该是今年的第一贴,首先祝大家新年快乐,虎年大吉。
背景:
       前一段时间,有位老师想做一个气象站的项目,但是他选的风速仪和风向仪接口不兼容Arduino和micro:bit主控。后面他就找到我,问我有没有什么解决办法?

风向仪

风向仪
ThuJanuary-202201275427..png
       当看见他发过来的图片时,方案就已经在脑海里呈现了,对于这个问题,只需要加一个Gravity:RS485转UART有源隔离型信号转换模块 就行了。因为风向变送器和风速变送器是RS485接口,协议是Modbus协议,所以需要使用RS485转UART 模块,其作用就是将RS485接口转换成UART输出。
ThuJanuary-202201277747..png

      下面我就分享一下,如何在arduino和micro:bit主控上使用风向变送器风速变送器。首先我们根据下图将风向变送器风速变送器连接在Gravity:RS485转UART有源隔离型信号转换模块上。
ThuJanuary-202201278821..png
注:风向变送器和风速变送器的接线方式一样。
Arduino uno 上的使用方法

测量风向
软硬件准备
硬件:
ThuJanuary-202201271453..png
ThuJanuary-202201276387..png
ThuJanuary-202201273482..png
ThuJanuary-202201271335..png

软件:
硬件连接
ThuJanuary-202201274268..png
ArduinoIDE——样例代码
1. 将风向变送器,RS485转UART模块,uno R3按照上面的方式连接在一起。
2. 打开Arduino IDE,将下面的代码上传到DFRduino uno R3上。
3. 打开串口,将波特率调至115200,通过串口观察结果。
4. 数值对应的方向。
ThuJanuary-202201275681..png
  1. #include <SoftwareSerial.h>
  2. SoftwareSerial mySerial(2, 3); //定义软串口,3号端口为TX,2号端口为RX,
  3. uint8_t  Address = 0x03;
  4. void setup()
  5. {
  6.   Serial.begin(115200);
  7.   mySerial.begin(9600);
  8.   ModifyAddress(0x00, Address);  //设备地址修改,修改地址后请注释掉这句重新上电。
  9. }
  10. void loop()
  11. {
  12.   Serial.println(readWindDirection(Address)); //读取风向
  13.   delay(1000);
  14. }
  15. size_t readN(uint8_t *buf, size_t len)
  16. {
  17.   size_t offset = 0, left = len;
  18.   int16_t Tineout = 1500;
  19.   uint8_t  *buffer = buf;
  20.   long curr = millis();
  21.   while (left) {
  22.     if (mySerial.available()) {
  23.       buffer[offset] = mySerial.read();
  24.       offset++;
  25.       left--;
  26.     }
  27.     if (millis() - curr > Tineout) {
  28.       break;
  29.     }
  30.   }
  31.   return offset;
  32. }
  33. /**
  34.   @brief  计算CRC16_2检验值
  35.   @param  buf 需要计算校验值的数据包
  36.   @param  len 需要校验的数据长度。
  37.   @return  返回一个16位的校验结果。
  38. */
  39. uint16_t CRC16_2(uint8_t *buf, int16_t len)
  40. {
  41.   uint16_t crc = 0xFFFF;
  42.   for (int pos = 0; pos < len; pos++)
  43.   {
  44.     crc ^= (uint16_t)buf[pos];
  45.     for (int i = 8; i != 0; i--)
  46.     {
  47.       if ((crc & 0x0001) != 0)
  48.       {
  49.         crc >>= 1;
  50.         crc ^= 0xA001;
  51.       }
  52.       else
  53.       {
  54.         crc >>= 1;
  55.       }
  56.     }
  57.   }
  58.   crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
  59.   return crc;
  60. }
  61. /**
  62.   @brief  为数据包末尾添加CRC_16校验
  63.   @param  buf 需要添加校验值的数据包
  64.   @param  len 需要添加校验的数据长度。
  65.   @return  无
  66. */
  67. void addedCRC(uint8_t *buf, int len)
  68. {
  69.   uint16_t crc = 0xFFFF;
  70.   for (int pos = 0; pos < len; pos++)
  71.   {
  72.     crc ^= (uint16_t)buf[pos];
  73.     for (int i = 8; i != 0; i--)
  74.     {
  75.       if ((crc & 0x0001) != 0)
  76.       {
  77.         crc >>= 1;
  78.         crc ^= 0xA001;
  79.       }
  80.       else
  81.       {
  82.         crc >>= 1;
  83.       }
  84.     }
  85.   }
  86.   buf[len] = crc % 0x100;
  87.   buf[len + 1] = crc / 0x100;
  88. }
  89. /**
  90.   @brief  读取风向
  91.   @param  Address 读取的设备地址。
  92.   @return  风向单位m/s,读取超时返回—1.
  93. */
  94. int readWindDirection(uint8_t Address)
  95. {
  96.   uint8_t Data[7] = {0};   //储存传感器返回的原始数据包
  97.   uint8_t COM[8] = {0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};   //读取风向的指令
  98.   boolean ret = false;   //风向获取成功标志位
  99.   int WindDirection = 0;
  100.   long curr = millis();
  101.   long curr1 = curr;
  102.   uint8_t ch = 0;
  103.   COM[0] = Address;    //参考通讯协议将指令包添加完整。
  104.   addedCRC(COM , 6);   //为读取风向指令包添加CRC_16校验
  105.   mySerial.write(COM, 8);  //发送读取风向的指令
  106.   while (!ret) {
  107.     if (millis() - curr > 1000) {
  108.       WindDirection = -1;    //如果整个超过1000毫秒还未读取到风向将视为超时,并返回—1.
  109.       break;
  110.     }
  111.     if (millis() - curr1 > 100) {
  112.       mySerial.write(COM, 8);  //如果上一条读取风向的指令发出超过100毫秒还未收到返回指令将从新发送读取风向的指令
  113.       curr1 = millis();
  114.     }
  115.     if (readN(&ch, 1) == 1) {
  116.       if (ch == Address) {          //读取并判断包头。
  117.         Data[0] = ch;
  118.         if (readN(&ch, 1) == 1) {
  119.           if (ch == 0x03) {         //读取并判断包头。
  120.             Data[1] = ch;
  121.             if (readN(&ch, 1) == 1) {
  122.               if (ch == 0x02) {       //读取并判断包头。
  123.                 Data[2] = ch;
  124.                 if (readN(&Data[3], 4) == 4) {
  125.                   if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {  //校验数据包
  126.                     ret = true;
  127.                     WindDirection = Data[3] * 256 + Data[4];  //计算风向
  128.                   }
  129.                 }
  130.               }
  131.             }
  132.           }
  133.         }
  134.       }
  135.     }
  136.   }
  137.   return WindDirection;
  138. }
  139. /**
  140.   @brief  修改传感器设备地址
  141.   @param  Address1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
  142.   @param  Address2 设备修改后的地址,范围0x00~0xFF,
  143.   @return  返回true表示修改成功,返回false表示修改失败。
  144. */
  145. boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
  146. {
  147.   uint8_t ModifyAddressCOM[11] = {0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
  148.   boolean ret = false;
  149.   long curr = millis();
  150.   long curr1 = curr;
  151.   uint8_t ch = 0;
  152.   ModifyAddressCOM[0] = Address1;
  153.   ModifyAddressCOM[8] = Address2;
  154.   addedCRC(ModifyAddressCOM , 9);
  155.   mySerial.write(ModifyAddressCOM, 11);
  156.   while (!ret) {
  157.     if (millis() - curr > 1000) {
  158.       break;
  159.     }
  160.     if (millis() - curr1 > 100) {
  161.       mySerial.write(ModifyAddressCOM, 11);
  162.       curr1 = millis();
  163.     }
  164.     if (readN(&ch, 1) == 1) {
  165.       if (ch == Address1) {
  166.         if (readN(&ch, 1) == 1) {
  167.           if (ch == 0x10 ) {
  168.             if (readN(&ch, 1) == 1) {
  169.               if (ch == 0x10) {
  170.                 if (readN(&ch, 1) == 1) {
  171.                   if (ch == 0x00) {
  172.                     if (readN(&ch, 1) == 1) {
  173.                       if (ch == 0x00) {
  174.                         if (readN(&ch, 1) == 1) {
  175.                           if (ch == 0x01) {
  176.                             while (1) {
  177.                               Serial.println("请给传感器重新上电。");
  178.                               delay(1000);
  179.                             }
  180.                             ret = true ;
  181.                           }
  182.                         }
  183.                       }
  184.                     }
  185.                   }
  186.                 }
  187.               }
  188.             }
  189.           }
  190.         }
  191.       }
  192.     }
  193.   }
  194.   return ret;
  195. }
复制代码

效果展示:
注意:安装时传感器上白点必须朝向正北。如下图:
ThuJanuary-202201278487..png
串口打印的结果为13(西北偏西)
ThuJanuary-202201276330..png

手机对应的方向为西北偏西,几乎一致。
ThuJanuary-202201275545..png

注意:如果最终结果返回的是-1,需要将这句代码“ModifyAddress(0x00, Address);  //设备地址修改,修改地址后请注释掉这句重新上电。”注释掉,再重新上传与上电。

Mind+——样例代码
1.打开mind+,添加主控板——arduino uno,;然后再去用户库添加——风向变送器库。
ThuJanuary-202201275412..png
ThuJanuary-202201276235..png

注:如果mind+的用户库没有找到风速变送器和风向变送器的库,可以在用户库中的搜索栏搜索“RS485风速变送器”与“RS485风向变送器”。

2.将下面的代码上传到DFRduino uno R3上。
3.打开串口,将波特率调至9600,通过串口观察结果。
ThuJanuary-202201272358..png
效果展示:
串口打印出来的结果显示北方。
ThuJanuary-202201274793..png

手机对应的方向为北方,一致。
ThuJanuary-202201271833..png

注意:如果最终结果返回的是-1,可以通过修改设备地址或者重新上电来解决。如下:
MonFebruary-202202149033..png

测量风速
软硬件准备
硬件:
ThuJanuary-202201276283..png
ThuJanuary-202201275108..png
ThuJanuary-202201273187..png
ThuJanuary-202201277821..png


软件:
硬件连接
ArduinoIDE——样例代码
1. 将风速变送器,RS485转UART模块,uno R3按照上面的方式连接在一起。
2. 打开Arduino IDE,将下面的代码上传到DFRduino uno R3上。
3. 打开串口,将波特率调至115200,通过串口观察结果。
  1. #include <SoftwareSerial.h>
  2. SoftwareSerial mySerial(2, 3); //定义软串口,3号端口为TX,2号端口为RX,
  3. uint8_t  Address = 0x10;
  4. void setup()
  5. {
  6.   Serial.begin(115200);
  7.   mySerial.begin(9600);
  8. ModifyAddress(0x00, Address);  //设备地址修改,修改地址后请注释掉这句重新上电。
  9. }
  10. void loop()
  11. {
  12.   Serial.print(readWindSpeed(Address)); //读取风速
  13.   Serial.println("m/s");
  14.   delay(1000);
  15. }
  16. size_t readN(uint8_t *buf, size_t len)
  17. {
  18.   size_t offset = 0, left = len;
  19.   int16_t Tineout = 1500;
  20.   uint8_t  *buffer = buf;
  21.   long curr = millis();
  22.   while (left) {
  23.     if (mySerial.available()) {
  24.       buffer[offset] = mySerial.read();
  25.       offset++;
  26.       left--;
  27.     }
  28.     if (millis() - curr > Tineout) {
  29.       break;
  30.     }
  31.   }
  32.   return offset;
  33. }
  34. /**
  35.   @brief  计算CRC16_2检验值
  36.   @param  buf 需要计算校验值的数据包
  37.   @param  len 需要校验的数据长度。
  38.   @return  返回一个16位的校验结果。
  39. */
  40. uint16_t CRC16_2(uint8_t *buf, int16_t len)
  41. {
  42.   uint16_t crc = 0xFFFF;
  43.   for (int pos = 0; pos < len; pos++)
  44.   {
  45.     crc ^= (uint16_t)buf[pos];
  46.     for (int i = 8; i != 0; i--)
  47.     {
  48.       if ((crc & 0x0001) != 0)
  49.       {
  50.         crc >>= 1;
  51.         crc ^= 0xA001;
  52.       }
  53.       else
  54.       {
  55.         crc >>= 1;
  56.       }
  57.     }
  58.   }
  59.   crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
  60.   return crc;
  61. }
  62. /**
  63.   @brief  为数据包末尾添加CRC_16校验
  64.   @param  buf 需要添加校验值的数据包
  65.   @param  len 需要添加校验的数据长度。
  66.   @return  无
  67. */
  68. void addedCRC(uint8_t *buf, int len)
  69. {
  70.   uint16_t crc = 0xFFFF;
  71.   for (int pos = 0; pos < len; pos++)
  72.   {
  73.     crc ^= (uint16_t)buf[pos];
  74.     for (int i = 8; i != 0; i--)
  75.     {
  76.       if ((crc & 0x0001) != 0)
  77.       {
  78.         crc >>= 1;
  79.         crc ^= 0xA001;
  80.       }
  81.       else
  82.       {
  83.         crc >>= 1;
  84.       }
  85.     }
  86.   }
  87.   buf[len] = crc % 0x100;
  88.   buf[len + 1] = crc / 0x100;
  89. }
  90. /**
  91.   @brief  读取风速
  92.   @param  Address 读取的设备地址。
  93.   @return  风速单位m/s,读取超时返回—1.
  94. */
  95. float readWindSpeed(uint8_t Address)
  96. {
  97.   uint8_t Data[7] = {0};   //储存传感器返回的原始数据包
  98.   uint8_t COM[8] = {0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};   //读取风速的指令
  99.   boolean ret = false;   //风速获取成功标志位
  100.   float WindSpeed = 0;
  101.   long curr = millis();
  102.   long curr1 = curr;
  103.   uint8_t ch = 0;
  104.   COM[0] = Address;    //参考通讯协议将指令包添加完整。
  105.   addedCRC(COM , 6);   //为读取风速指令包添加CRC_16校验
  106.   mySerial.write(COM, 8);  //发送读取风速的指令
  107.   while (!ret) {
  108.     if (millis() - curr > 1000) {
  109.       WindSpeed = -1;    //如果整个超过1000毫秒还未读取到风速将视为超时,并返回—1.
  110.       break;
  111.     }
  112.     if (millis() - curr1 > 100) {
  113.       mySerial.write(COM, 8);  //如果上一条读取风速的指令发出超过100毫秒还未收到返回指令将从新发送读取风速的指令
  114.       curr1 = millis();
  115.     }
  116.     if (readN(&ch, 1) == 1) {
  117.       if (ch == Address) {          //读取并判断包头。
  118.         Data[0] = ch;
  119.         if (readN(&ch, 1) == 1) {
  120.           if (ch == 0x03) {         //读取并判断包头。
  121.             Data[1] = ch;
  122.             if (readN(&ch, 1) == 1) {
  123.               if (ch == 0x02) {       //读取并判断包头。
  124.                 Data[2] = ch;
  125.                 if (readN(&Data[3], 4) == 4) {
  126.                   if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {  //校验数据包
  127.                     ret = true;
  128.                     WindSpeed = (Data[3] * 256 + Data[4]) / 10.00;  //计算风速
  129.                   }
  130.                 }
  131.               }
  132.             }
  133.           }
  134.         }
  135.       }
  136.     }
  137.   }
  138.   return WindSpeed;
  139. }
  140. /**
  141.   @brief  修改传感器设备地址
  142.   @param  Address1 设备修改前的地址。使用0x00地址可以设置任何地址,设置后需要重新上电重新启动模块.
  143.   @param  Address2 设备修改后的地址,范围0x00~0xFF,
  144.   @return  返回true表示修改成功,返回false表示修改失败。
  145. */
  146. boolean ModifyAddress(uint8_t Address1, uint8_t Address2)
  147. {
  148.   uint8_t ModifyAddressCOM[11] = {0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
  149.   boolean ret = false;
  150.   long curr = millis();
  151.   long curr1 = curr;
  152.   uint8_t ch = 0;
  153.   ModifyAddressCOM[0] = Address1;
  154.   ModifyAddressCOM[8] = Address2;
  155.   addedCRC(ModifyAddressCOM , 9);
  156.   mySerial.write(ModifyAddressCOM, 11);
  157.   while (!ret) {
  158.     if (millis() - curr > 1000) {
  159.       break;
  160.     }
  161.     if (millis() - curr1 > 100) {
  162.       mySerial.write(ModifyAddressCOM, 11);
  163.       curr1 = millis();
  164.     }
  165.     if (readN(&ch, 1) == 1) {
  166.       if (ch == Address1) {
  167.         if (readN(&ch, 1) == 1) {
  168.           if (ch == 0x10 ) {
  169.             if (readN(&ch, 1) == 1) {
  170.               if (ch == 0x10) {
  171.                 if (readN(&ch, 1) == 1) {
  172.                   if (ch == 0x00) {
  173.                     if (readN(&ch, 1) == 1) {
  174.                       if (ch == 0x00) {
  175.                         if (readN(&ch, 1) == 1) {
  176.                           if (ch == 0x01) {
  177.                             //                            while (1) {
  178.                             Serial.println("请给传感器重新上电。");
  179.                             //                              delay(1000);
  180.                             //                            }
  181.                             ret = true ;
  182.                           }
  183.                         }
  184.                       }
  185.                     }
  186.                   }
  187.                 }
  188.               }
  189.             }
  190.           }
  191.         }
  192.       }
  193.     }
  194.   }
  195.   return ret;
  196. }
复制代码
效果展示:
用手轻轻推动风速变送器,观察数据。
ThuJanuary-202201275522..png
Mind+——样例代码
1.打开mind+,添加主控板——arduino uno,;然后再去用户库添加——风速变送器的库。
ThuJanuary-202201273209..png
ThuJanuary-202201278350..png
2.将下面的代码上传到DFRduino uno R3上。
3.打开串口,将波特率调至9600,通过串口观察结果。
ThuJanuary-202201277768..png
效果展示:
用手轻轻推动风速变送器,观察数据。

ThuJanuary-202201276336..png

micro:bit上的使用方法测量风向
软硬件准备
硬件:
ThuJanuary-202201275036..png
ThuJanuary-202201274582..png
ThuJanuary-202201277519..png
ThuJanuary-202201277040..png

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


测量风速
软硬件准备
硬件:
ThuJanuary-202201278870..png
ThuJanuary-202201277024..png
ThuJanuary-202201271006..png
ThuJanuary-202201278850..png


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


MonFebruary-202202147563..png

赤星三春牛!  中级技匠

发表于 2022-1-28 15:04:20

厉害厉害
回复

使用道具 举报

NIKO  见习技师

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

这个好 正好能用上
回复

使用道具 举报

KkQ1VrB7W776  初级技师

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

666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail