【物聯網開發系列】氣象物聯網:使用微控器讀取風向感測器下篇 - vMaker 台灣自造者vMaker 台灣自造者
中文 | English

【物聯網開發系列】氣象物聯網:使用微控器讀取風向感測器下篇

文/曹永忠、許智誠、蔡英德

環境監控是物聯網開發中非常重要的一環,上篇文章「【物聯網開發系列】氣象物聯網:使用微控器讀取風向感測器上篇」(曹永忠,許智誠 & 蔡英德,2017f),我們談到了如何讓 Ameba RTL 8195 AM 開發板透過 TTL 轉 RS485 模組,透過 Modbus RTU 通訊協定來讀取風向感測器的風向資料,然而我們透過透過 Modbus RTU 通訊協定讀取的資料是否正確,是否有誤或是傳送過程有差異,這是一個非常關鍵的議題。

本文將進一步針對風向感測器中,其使用 Modbus RTU 通訊協定時,有訂立容錯的機制,作為本文的主體。

硬體組立

如下表所示,我們將 Ameba RTL 8195 AM 開發板與 TTL 轉 RS485 模組之電路連接起來後,連同 Modbus RTU 繼電器模組與電源供應器等,進行最後的電路組立,完成後如下圖所示,我們可以完成 Ameba RTL 8195 AM 開發板連接風向感測器模組之完整電路。

表 1:電路組立接腳表

TTL 轉 RS485 風向感測器
A+ 風向感測器黃線 (A)
B- 風向感測器藍線 (B)

TTL 轉 RS485 Ameba RTL 8195 AM開發板
GND GND
RXD D0
TXD D1
5V +5V
 
TTL 轉 RS485 風向感測器

圖 1:Ameba RTL 8195 AM 開發板連接風向感測器之完整電路圖

使用 CRC16 確認資料正確性

我們在【氣象物聯網】風力偵測開發感測器篇(曹永忠,許智誠 & 蔡英德,2017c)一文中,得到 CRC16 的檢測值,更可以確認資料的正確性,所以我們必須修改程式來達到檢測資料正確性:

由於風向感測器採用 Modbus-RTU 通訊規格,如下表所示,我們可以了解其使用 Modbus-RTU 回傳資料格式如下表:

表 2:風向感測器回傳資料格式

地址碼 功能碼 返回有效位元組數 風向

(0-7 檔)

風向

(0-360°)

CRC16
1 位元組 1 位元組 1 位元組 2 位元組 2 位元組 2 位元組

我們將 Ameba RTL 8195 AM 開發板的驅動程式安裝好之後,我們打開 Ameba RTL 8195 AM 開發板的開發工具:Sketch IDE 整合開發軟體(軟體下載),撰寫一段程式,如下表所示之具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式,使用控制命令讀取風向感測器的風向資料。

表 3:具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式

具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式(wind_Modbus03)
#include "crc16.h"

#include <SoftwareSerial.h>

uint8_t outdata[] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x38 } ;

uint8_t incomingdata[9] ;



SoftwareSerial mySerial(0, 1); // RX, TX

//modbusDevice dev = new modbusDevice() ;

void setup() {

// put your setup code here, to run once:

Serial.begin(9600)  ;

Serial.println("Program Start Here");

mySerial.begin(9600) ;

// Modbus(&mySerial,9600)

}



void loop() {



sendQuery() ;

if (receiveQuery())

{

Serial.println("Get Data OK");

Serial.print("Wind Direction  is :(");

Serial.print(incomingdata[3],HEX) ;

Serial.print("/");

Serial.print(incomingdata[4],HEX) ;

Serial.print("/");

Serial.print((double)incomingdata[3]*256+(double)incomingdata[4]) ;

Serial.print("  m/s ) \n");

Serial.print("Wind Direction  is :(");

Serial.print(incomingdata[5],HEX) ;

Serial.print("/");

Serial.print(incomingdata[6],HEX) ;

Serial.print("/");

Serial.print((double)incomingdata[5]*256+(double)incomingdata[6]) ;

Serial.print("  angle ) \n");

if (CompareCRC16(ModbusCRC16(incomingdata,7),incomingdata[8],incomingdata[7]))

{

Serial.println("The Data is Correct") ;

}

else

{

Serial.println("The Data is not Correct") ;

}



}

else

{

Serial.println("Fail to Get Data");



}



delay(2000) ;



}



void sendQuery()

{

mySerial.write(outdata,8) ;



}



boolean receiveQuery()

{

boolean ret = false ;

unsigned strtime = millis() ;

while(true)

{

if ( (millis() - strtime) > 2000)

{

ret = false ;

return  ret ;

}



if (mySerial.available() >= 9)

{

mySerial.readBytes(incomingdata, 9) ;

ret = true ;

return  ret ;

}

}

}

程式碼

表 4:具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式(CRC16)

具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式(crc16.h)
    static const unsigned int wCRCTable[] = {

0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,

0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,

0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,

0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,

0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,

0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,

0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,

0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,

0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,

0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,

0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,

0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,

0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,

0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,

0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,

0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,

0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,

0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,

0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,

0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,

0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,

0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,

0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,

0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,

0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,

0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,

0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,

0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,

0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,

0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,

0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,

0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };



unsigned int  ModbusCRC16 (byte *nData, int wLength)

{





byte nTemp;

unsigned int wCRCWord = 0xFFFF;



while (wLength--)

{

nTemp = *nData++ ^ wCRCWord;

wCRCWord >>= 8;

wCRCWord  ^= wCRCTable[nTemp];

}

return wCRCWord;

} // End: CRC16





boolean CompareCRC16(unsigned int stdvalue, uint8_t Li, uint8_t Lo)

{

if (stdvalue == Li*256+Lo)

{

return true ;

}

else

{

return false ;

}

}

 

 

程式碼

如下圖所示,我們可以在:透過串列埠傳輸命令,讀取 Modbus RTU 風向感測器組測試程式結果畫面看到風向,如果完成編譯檔燒錄動作,我們可以見到完成之畫面。

圖 2:具檢測 CRC16 功能之讀取 Modbus RTU 風向感測器組測試程式結果畫面

 

將讀取風向感測器模組的風向值送到網頁

首先,如下表所示,我們參考風向感測器資料格式對照表,瞭解風向(0-7 檔)與風向(0-360°)兩個值的意義:

  • 風向(0-7 檔)表東、南、西、北、東北、東南、西北、西南八方向
  • 風向(0-360°)表以北方為零度,順時鐘方向的角度

表 5:風向感測器資料格式對照表

採集值(0-7 檔) 採集值(0-360°) 對應方向
0 北風
1 45° 東北風
2 90° 東風
3 135° 東南風
4 180° 南風
5 225° 西南風
6 270° 西風
7 315° 西北風

所以我們必先將表 5 之格式,取出「【物聯網開發系列】氣象物聯網:風向偵測開發感測器下篇」(曹永忠,許智誠 & 蔡英德,2017d, 2017e)之表 6 的第 4 欄的資料,為風向高位元與風向低位元,根據高位元組與低位元組進行運算,風向高位元 *256+ 風向低位元 = 風向值,再根據表 5之格式,參照之後算出風向。

最後我們根據表 5 之格式,取出「【物聯網開發系列】氣象物聯網:風向偵測開發感測器下篇」(曹永忠 et al.,2017d,2017e)之表 6 的第 5 欄的資料,為風向角度高位元與風向角度低位元,根據高位元組與低位元組進行運算,風向角度高位元 *256+ 風向角度低位元 = 風向角度值,我們再根據表 5 之格式,參照之後算出風向角度。

我們將 Ameba RTL 8195 AM 開發板的驅動程式安裝好之後,我們打開 Ameba RTL 8195 AM 開發板的開發工具:Sketch IDE 整合開發軟體(軟體下載),寫一段程式,如下表所示之顯示風向感測器模組之風向於網頁測試程式,透過 Ameba RTL 8195 AM 開發板,將讀取風向感測器的風向資料,使用網站方式,透過網頁顯示在網頁上。

表 6:風向感測器模組之風向於網頁測試程式

風向感測器模組之風向於網頁測試程式(wind_Modbus16)
#include "crc16.h"

#include <String.h>

#include <SoftwareSerial.h>

#include <WiFi.h>

uint8_t outdata[] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x38 } ;

uint8_t incomingdata[9] ;

String WindWay[] = {"北風","東北風","東風","東南風","南風","西南風","西風","西北風" } ;



// --------WIFI USE

uint8_t MacData[6];

char ssid[] = "IOT";      // your network SSID (name)

char pass[] = "0123456789";     // your network password

int keyIndex = 0;                 // your network key Index number (needed only for WEP)

IPAddress  Meip ,Megateway ,Mesubnet ;

String MacAddress ;

int status = WL_IDLE_STATUS;



WiFiServer server(80);



#define RXPin  0

#define TXPin  1



SoftwareSerial mySerial(RXPin, TXPin); // RX, TX

//modbusDevice dev = new modbusDevice() ;

void setup() {

// put your setup code here, to run once:

Serial.begin(9600)  ;

Serial.println("Program Start Here");

mySerial.begin(9600) ;

if (WiFi.status() == WL_NO_SHIELD)

{

Serial.println("WiFi shield not present");

// don't continue:

while (true);

}

String fv = WiFi.firmwareVersion();

if (fv != "1.1.0")

{

Serial.println("Please upgrade the firmware");

}

MacAddress = GetWifiMac() ; // get MacAddress

ShowMac() ;       //Show Mac Address



// attempt to connect to Wifi network:

initializeWiFi();

server.begin();

// you're connected now, so print out the status:

ShowInternetStatus();

}



void loop() {









// listen for incoming clients

WiFiClient client = server.available();

if (client) {

Serial.println("new client");

// an http request ends with a blank line

boolean currentLineIsBlank = true;

while (client.connected()) {

if (client.available()) {

char c = client.read();

Serial.write(c);

// if you've gotten to the end of the line (received a newline

// character) and the line is blank, the http request has ended,

// so you can send a reply

if (c == '\n' && currentLineIsBlank) {

// send a standard http response header

client.println("HTTP/1.1 200 OK");

client.println("Content-Type: text/html");

client.println("Connection: close");  // the connection will be closed after completion of the response

client.println("Refresh: 5");  // refresh the page automatically every 5 sec

client.println();

client.println("<!DOCTYPE HTML>");

client.println("<html>");

if (GetWindCheck())

{

// output the value of each analog input pin

client.print("Wind Direction :(");

client.print(WindWay[CalcWind(incomingdata[3],incomingdata[4])]);

client.print(" and  ");

client.print(CalcWind(incomingdata[5],incomingdata[6]));

client.print(" 度)");

}



client.println("</html>");

break;

}

if (c == '\n') {

// you're starting a new line

currentLineIsBlank = true;

} else if (c != '\r') {

// you've gotten a character on the current line

currentLineIsBlank = false;

}

}

}

// give the web browser time to receive the data

delay(1);



// close the connection:

client.stop();

Serial.println("client disonnected");

}

}

int CalcWind(uint8_t Hi, uint8_t Lo)

{

return (  Hi *  256+ Lo  ) ;

}

boolean GetWindCheck()

{

sendQuery() ;

if (receiveQuery())

{

//    Serial.println(incomingdata[3],HEX) ;

//    Serial.println(incomingdata[4],HEX) ;

//   Serial.println(( ( (double)incomingdata[3]*256+(double)incomingdata[4] )/10) ) ;



if ( CompareCRC16(ModbusCRC16(incomingdata,7),incomingdata[8],incomingdata[7]) )

{

return (true)  ;

}

else

{

return (false)  ;

}



}

else

{

return (false) ;



}



}



void sendQuery()

{

mySerial.write(outdata,8) ;



}



boolean receiveQuery()

{

boolean ret = false ;

unsigned strtime = millis() ;

while(true)

{

if ( (millis() - strtime) > 2000)

{

ret = false ;

return  ret ;

}



if (mySerial.available() >= 9)

{

mySerial.readBytes(incomingdata, 9) ;

ret = true ;

return  ret ;

}

}

}





void ShowMac()

{



Serial.print("MAC:");

Serial.print(MacAddress);

Serial.print("\n");



}









String GetWifiMac()

{

String tt ;

String t1,t2,t3,t4,t5,t6 ;

WiFi.status();    //this method must be used for get MAC

WiFi.macAddress(MacData);



Serial.print("Mac:");

Serial.print(MacData[0],HEX) ;

Serial.print("/");

Serial.print(MacData[1],HEX) ;

Serial.print("/");

Serial.print(MacData[2],HEX) ;

Serial.print("/");

Serial.print(MacData[3],HEX) ;

Serial.print("/");

Serial.print(MacData[4],HEX) ;

Serial.print("/");

Serial.print(MacData[5],HEX) ;

Serial.print("~");



t1 = print2HEX((int)MacData[0]);

t2 = print2HEX((int)MacData[1]);

t3 = print2HEX((int)MacData[2]);

t4 = print2HEX((int)MacData[3]);

t5 = print2HEX((int)MacData[4]);

t6 = print2HEX((int)MacData[5]);

tt = (t1+t2+t3+t4+t5+t6) ;

Serial.print(tt);

Serial.print("\n");



return tt ;

}

String  print2HEX(int number) {

String ttt ;

if (number >= 0 && number < 16)

{

ttt = String("0") + String(number,HEX);

}

else

{

ttt = String(number,HEX);

}

return ttt ;

}











void printWifiData()

{

// print your WiFi shield's IP address:

Meip = WiFi.localIP();

Serial.print("IP Address: ");

Serial.println(Meip);

Serial.print("\n");



// print your MAC address:

byte mac[6];

WiFi.macAddress(mac);

Serial.print("MAC address: ");

Serial.print(mac[5], HEX);

Serial.print(":");

Serial.print(mac[4], HEX);

Serial.print(":");

Serial.print(mac[3], HEX);

Serial.print(":");

Serial.print(mac[2], HEX);

Serial.print(":");

Serial.print(mac[1], HEX);

Serial.print(":");

Serial.println(mac[0], HEX);



// print your subnet mask:

Mesubnet = WiFi.subnetMask();

Serial.print("NetMask: ");

Serial.println(Mesubnet);



// print your gateway address:

Megateway = WiFi.gatewayIP();

Serial.print("Gateway: ");

Serial.println(Megateway);

}



void ShowInternetStatus()

{



if (WiFi.status())

{

Meip = WiFi.localIP();

Serial.print("Get IP is:");

Serial.print(Meip);

Serial.print("\n");



}

else

{

Serial.print("DisConnected:");

Serial.print("\n");

}



}



void initializeWiFi() {

while (status != WL_CONNECTED) {

Serial.print("Attempting to connect to SSID: ");

Serial.println(ssid);

// Connect to WPA/WPA2 network. Change this line if using open or WEP network:

status = WiFi.begin(ssid, pass);

//   status = WiFi.begin(ssid);



// wait 10 seconds for connection:

delay(10000);

}

Serial.print("\n Success to connect AP:") ;

Serial.print(ssid) ;

Serial.print("\n") ;



}

程式碼

表 7:風向感測器模組之風向於網頁測試程式

風向感測器模組之風向於網頁測試程式(crc16.h)
    static const unsigned int wCRCTable[] = {

0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,

0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,

0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,

0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,

0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,

0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,

0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,

0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,

0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,

0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,

0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,

0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,

0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,

0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,

0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,

0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,

0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,

0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,

0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,

0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,

0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,

0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,

0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,

0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,

0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,

0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,

0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,

0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,

0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,

0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,

0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,

0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };



unsigned int  ModbusCRC16 (byte *nData, int wLength)

{





byte nTemp;

unsigned int wCRCWord = 0xFFFF;



while (wLength--)

{

nTemp = *nData++ ^ wCRCWord;

wCRCWord >>= 8;

wCRCWord  ^= wCRCTable[nTemp];

}

return wCRCWord;

} // End: CRC16





boolean CompareCRC16(unsigned int stdvalue, uint8_t Li, uint8_t Lo)

{



if (stdvalue == Li*256+Lo)

{

return true ;

}

else

{

return false ;

}

}

 

程式碼

如下圖(a)所示,我們先用監控畫面取得網頁的網址,在使用瀏覽器,如下圖(b)所示,在網址列輸入網址 :192.168.88.103,讀者的網址請注意,因環境不同,不一定和筆者一樣網址,請勿輸錯(曹永忠,許智誠 & 蔡英德,2017a, 2017b)。

如下圖(b)所示,在瀏覽器中我們可以看到風向值,接上來我們如下圖(c)所示,可以在用監控畫面來監看傳輸過程的傳輸資訊,是否有問題。

(a)取得網頁網址

(b)使用瀏覽器觀看風向值

(c)監控畫面觀看連線資訊

圖 3:風向感測器模組之風向於網頁測試程式結果畫面

後續

本篇是「氣象物聯網」系列中「使用微控器讀取風向感測器下篇」,主要告訴讀者,如何讓 Ameba RTL 8195 AM 開發板透過 TTL 轉 RS485 模組,透過 Modbus RTU 通訊協定來讀取風向感測器的風向資料,並透過風向感測器的容錯機制,進行稽核,並將結果顯示在網頁上。

後續筆者還會繼續發表「氣象物聯網」系列的文章,在未來我們可以創造出更優質,更具未來性的物聯網(Internet of Thing:IOT)產品開發相關技術。

敬請期待更多的文章。

作者介紹:

曹永忠(Yung-Chung Tsao) ,目前為自由作家暨專業 Maker,專研於軟體工程、軟體開發與設計、物件導向程式設計,商品攝影及人像攝影。長期投入創客運動、資訊系統設計與開發、企業應用系統開發、軟體工程、新產品開發管理、商品及人像攝影等領域,並持續發表作品及相關專業著作。
Email:prgbruce@gmail.com
Line ID:dr.brucetsao
作者網頁臉書社群 (Arduino.Taiwan)Github網站Youtube

許智誠(Chih-Cheng Hsu),美國加州大學洛杉磯分校(UCLA) 資訊工程系博士,曾任職於美國 IBM 等軟體公司多年,現任教於中央大學資訊管理學系專任副教授,主要研究為軟體工程、設計流程與自動化、數位教學、雲端裝置、多層式網頁系統、系統整合。
Email: khsu@mgt.ncu.edu.tw

蔡英德(Yin-Te Tsai),國立清華大學資訊科學系博士,目前是靜宜大學資訊傳播工程學系教授、靜宜大學計算機及通訊中心主任,主要研究為演算法設計與分析、生物資訊、軟體開發、視障輔具設計與開發。
Email: yttsai@pu.edu.tw

參考文獻:

曹永忠, 許智誠, & 蔡英德. (2017a). Ameba风力监控系统开发(气象物联网) (Using Ameba to Develop a Wind Monitoring System (IOT for Weather)) (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.

曹永忠, 許智誠, & 蔡英德. (2017b). Ameba風力監控系統開發(氣象物聯網) (Using Ameba to Develop a Wind Monitoring System (IOT for Weather)) (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.

曹永忠, 許智誠, & 蔡英德. (2017c). 【物聯網開發系列】氣象物聯網 :風力偵測開發感測器篇. 物聯網開發系列.  Retrieved from https://vmaker.tw/archives/19431

曹永忠, 許智誠, & 蔡英德. (2017d). 【物聯網開發系列】氣象物聯網 :風向偵測開發感測器上篇. 物聯網開發系列.  Retrieved from https://vmaker.tw/

曹永忠, 許智誠, & 蔡英德. (2017e). 【物聯網開發系列】氣象物聯網 :風向偵測開發感測器下篇. 物聯網開發系列.  Retrieved from https://vmaker.tw/

曹永忠, 許智誠, & 蔡英德. (2017f). 【物聯網開發系列】氣象物聯網:使用微控器讀取風向感測器上篇. 物聯網開發系列.  Retrieved from https://vmaker.tw/

分享到社群

曹永忠

曹永忠 (Yung-Chung Tsao) ,目前為自由作家暨專業Maker,專研於軟體工程、軟體開發與設計、物件導向程式設計,商品攝影及人像攝影。長期投入創客運動、資訊系統設計與開發、企業應用系統開發、軟體工程、新產品開發管理、商品及人像攝影等領域,並持續發表作品及相關專業著作。 Email:prgbruce@gmail.com Line ID:dr.brucetsao 作者網站:https://www.cs.pu.edu.tw/~yctsao/ 臉書社群(Arduino.Taiwan):https://www.facebook.com/groups/Arduino.Taiwan/ Github網站:https://github.com/brucetsao/ Youtube:https://www.youtube.com/channel/UCcYG2yY_u0m1aotcA4hrRgQ