2017年11月6日 星期一

super169/hkweather

之前既天文台資料 project, 整左個 docker image, 有興趣可以自己裝黎玩下.

主要目的係比部 MCU 顯示出黎, 做下簡單既天氣資料站.

家陣仲諗緊要乜野資料需要, 同埋每個資料既來源, 睇下點樣可以簡化佢.

初步諗只會有兩個頁面顯示天氣資料:

1) 主頁, 地區天氣資料 (可輸入地區碼)
2) 九天天氣預測 - 來源
  • 天氣圖示
  • 最高/低氣溫
  • 最高/低濕度

另外, 會插上 其他 sensor (例如溫度, 濕度, 光照, 人體, 距離, ....)

資源來源:

  1. http://rss.weather.gov.hk/rss/CurrentWeather.xml
  2. http://www.weather.gov.hk/wxinfo/ts/text_readings_e.htm
  3. http://rss.weather.gov.hk/rss/WeatherWarningSummaryv2.xml
  4. http://rss.weather.gov.hk/rss/SeveralDaysWeatherForecast.xml


各項資料分析 (盡量拆英文網站, 避免中文字撞碼):

即時本港天氣圖示 - 主(1)

src="http://rss.weather.gov.hk/img/pic60.png"

該區現時氣溫 - 主(2)  後備(1)

(1)  HK Observatory 25.1
(2)  Hong Kong Observatory 25 degrees 

該區現時濕度 - 主(2) 

HK Observatory                 25.1       66

紫外線指數/強度 - 主(1)

During the past hour the mean UV Index recorded at King's Park : 2
Intensity of UV radiation : low

今日最高/低氣溫 - 主(2) 

(1) HK Observatory                 25.1       66        25.2 / 21.8

天氣警告(只要颱風及暴雨) - 主(3)

hard code 認呢度既字眼: http://www.weather.gov.hk/m/warndef.htm

九天天氣預測 - 主(4) 圖示補充 準備轉用 

天氣圖示
成篇文咁, 拆到想死, 例如呢幾句野, 大家會點理解, 點決定用邊個圖:
  1. Mainly cloudy with one or two rain patches.
  2. Mainly cloudy. One or two rain patches at first. 
  3. Mainly cloudy with a few rain patches.

最高/低氣溫

Temp range: 23 - 27 C


最高/低濕度

R.H. range: 65 - 85 per Cent

香港天文台資訊

做乜鬼玩玩下 arduino 走去講 香港天文台資訊?

因為  pat pat 痕, 想整個 internet clock, 整好左之後, 見既然上左網, 不如攞埋天氣睇下.
搵左D sample, 可以用 http://wunderground.com, 不過, 唔知個 source 係邊.

既然講香港天氣, 更係搵下香港天文台喇, 年年花香港咁多錢, 點都有D野睇下掛.
而且, 唔知外國既, 有無香港D天氣警號 (例如 8 號風球).
點知, 上網搵下至知, 香港天文台既天氣 資料, 仲停留十幾年前既科技...只係得 RSS.

真係粗口都黎埋, 今時今日, 仲只係預人地用電腦睇, 仲有無落後D呀. 唉, 算喇, 香港....

再去搵下, 原來幾年前已經有人開左個 開放源碼香港天氣計劃 hk0weather.
不過, 佢係用 python,  小弟真係唔識.
而且, 個 OpenData 既 project, 好似重點唔係天氣.
加上自己用 mcu, 就算佢比 JSON 比我, 要拆都仲係煩.

求人不如求己, pat pat 痕多野, 決定自已做算了.


首天, 資料既來原好重要, 既然想睇香港天氣, 就算幾唔準都係, 都係睇番香港天文台先.
暫時睇, 主要會用呢幾個 source 既資料:



PDA Data source:




不過, 之前都講左, 香港天文台比番日既野, 十九幾年前既 RSS, 仲要 data 係夾左做 html 出.
所以, 唔好諗住有好靚既料, 例如: Temperature=29 咁比你, 只可以認位拆舍 html/xml.


本港地區天氣報告 (中文English) - 更新: 每小時的 02 分, 或有特別需要
有香港整體數據, 包括:

  • 氣溫
  • 相對濕度
  • 過 去 一 小 時 平 均 紫 外 線 指 數
  • 紫 外 線 強 度 
  • 各區氣溫
  • 颱 風 消息


香港分區天氣 (中文English) - 更新:

有各區氣象站錄得既數據, 包括:

  • 即時氣溫
  • 即時相對濕度
  • 今日最高/低溫度
  • 即時草溫
  • 今日最低草溫
  • 十分鐘平均風向,風速及最高陣風風速 (多個氣象站)
  • 平均海平面氣壓 (赤鱲角,長洲,天文台,流浮山,坪洲,沙田,石崗,上水,打鼓嶺,大埔,橫瀾島,濕地公園)
  • 十分鐘平均能見度 (中環,赤鱲角,西灣河,橫瀾島)
  • 太陽總輻射量/直接輻射量/漫射輻射量  (滘西洲,京士柏)

九 天 天 氣 預 報 (中文English) - 更新: 11:30, 16:30, 或有特別需要

未來九天天氣預測, 包括: 
  • 風向及風力
  • 天氣情況
  • 氣溫
  • 相對濕 度


只係知道個 url, 但佢會點出, 好多野唔係時時有既, 只可以估估下, 到時執生.


玩玩下都幾火, RSS 真係唔多合用黎拆 data, 好多野都唔知.
比如 Weather 既 condition 會有幾多種唔知, 就唔知要做幾多個 icon 比佢.
天文台就當然唔會有 spec 提供, 估都有排估, 試下拆佢成版 HTML 話者仲易.
暫時用 regular express 拆左兩個 page, 整埋個 service  可以用下:


https://hkweather-tester01-rbhcwiqj1ojo.runkit.sh/c?location=hko

即時天氣, 有氣溫, 濕度, 同埋 UV 指數.  如果有 location 比埋你果區既氣溫.
Location code 係我自己定既, 其實好懶咁將天文台果 26 區既 initial 起既.
比如: TM=屯門, ST=沙田, TMT=大美篤, ....
唔比或者唔存在, 就會出番天文台 HKO.
幾個 data 分別係:

  • pic# : 用黎顯示家陣既天氣既公仔
  • 氣溫
  • 相對濕度
  • 過去一小時紫外線指數
  • 紫外線強度
  • 地區英文區
  • 地區氣溫


遲D可能會去埋 香港分區天氣 攞多D地區資料, 不過, 果版野...真係拆到火都黎埋.


https://hkweather-tester01-rbhcwiqj1ojo.runkit.sh/f

九天天氣預報.



2017年8月30日 星期三

Arduino 之間的 I2C 通訊 (9) 實例(一) 簡單傳感數據收集

完成以上 8 章之後, 要進行 arduino 之間的 i2c 通訊, 應該沒有難度吧.

但有個問題, 為什麼要以 i2c 通訊呢?

因為有很多原因, 單一片 arduino 不足以滿足要求, 比如 I/O 不足, 又或有些程式太煩覆, 希望可以拆開, 以多片 arduino 合成一個大的系統.

比如你想建立一個超多傳感的測量系統, arduino 的 I/O 絕對不能滿足.  而且, 要安裝不同的庫, arduino 的記憶體也是一個限制.

如果可以把工作分開, 由多個 arduino 板子組成一個更大的系統, 當中由一個 master 板子, 執行主程式, 其他 slave 去配合讀取不同的資料.

當然, 現在的 arduino, 一般只有一組 i2c, 所以整個系統就只可以有一組 i2c bus.
而在  i2c bus 上只可以有一個 master, 所以 i2c 有關的設備, 都只可以靠 master 去處理.
另外, 相同 i2c 地址的設備, 不會因為加入多塊 arduino 板子, 而可以同時使用.
這個缺憾, 需要有另一個系統去配合.
比如在  i2c 之外, 再加上SPI 的通訊, 就可以把 i2c 都分開了.
這個複雜的系統, 之後再去探討吧.  現在以一個 i2c bus 為基礎去開始.

首先, 嘗試做一個簡單系統.  假設你的板子 I/0 都用盡了, 你還想加入一個 DHT11 的溫濕度測量.  你可以簡單加入一片 mini 或 nano 的板子, 以 i2c  跟主板連上, 去擴充你的 I/O.

最簡單是修改 "由 master 向 slave 要求資料回傳" 的例子.
當 master 向 slave 發出請求時, 配合 "(8) 浮點的傳送" 的例子, 就可以把 溫濕度 數據以直接回傳.

由於某些 設備的庫, 不一定可以在 interrupt 內執行的, 可以嘗試在 slave 的 loop 內不斷更新, 當收到 master 的請求時, 就把最後的資料發過去.

詳情大家可以在相關程式中看到, 執行後, 在 master 隨意發送一些資料, slave 就會回傳.



而 slave 的 serial monitor 亦會同時顯示出已發送的資料供對比:



用類似的方法, 就可以把 非 i2c 的傳感, 放到另一片 arduino 中去讀取數據, 甚至先進行簡單分析.  例如 濾波.
一片 arduino slave 板子, 可以同時接上多個 非 i2c device 呢.  其主力工作, 就是為主程式準備所需的資料.

當 主程式需要時, 就可以向 slave 直接讀取了.  主程式亦不需要加入有關的庫, 會變得簡單一點.

當然, 這不是沒有付出的, 系統上, 就要增加了 arduion 板子.  是否值得, 還是看需要吧.


相關程式下載:




Arduino 之間的 I2C 通訊 (8) 浮點的傳送

之前有點忙, 在準備 "Arduino 之間的 I2C 通訊 (7) 單片機有效傳送數據的選擇" 中, 突然停了一下, 沒想到一停就停了一年多.

當中留下了一個問題給看官思考的, 就是有關 浮點的傳送.

網上經常會看到, 有人問用 串口通訊時, 如何把 浮點 的數據送出去?
一般的答案, 都會是轉成字串發送吧, 例如 "123.45".
如果需要的浮點, 有固定的大小, 精確度有限, 這個有可能失真的方法還不錯吧.
為什麼說"失真'呢?  因為原本的數值, 小點後可能是連續很長的, 要轉成字串, 就要把長度限制了, 自然會有失真.

但大家有否考慮過, 可以簡單又完全不失真的傳送呢?
注意, 這裡的"不失真", 只是跟原來儲存的數值比較, 並非所有數值都可以.
如果原來儲存的數值已經是有"失真"的話, 傳送時也只會原原本本的發過去.
這是什麼意思呢?
簡單說, 要記錄 pi, 用 float 本身就有精確度的限制, 發送出去的 float, 絕不可能突然變成 double 的精度吧.  可以做到的, 就是你給我一個 float, 我就把這個 float 原整的發出去.  詳細情況, 可以在最後的例子中看到.

如果要轉成字串, 要用多少個字符才足夠呢? 100? 1000? 就是一萬也不一定是完全一樣.

但如果有考慮過電腦內的記憶體的運作,  無論發送什麼數值的 float, 也只需 4 個 byte 就可以了.
為什麼? 發送 123.45 有 5 個數字, 還要記下小數位, 也只需 4 bytes?

沒錯, 就是 4 bytes, 這沒有什特別, 因為原本用來儲存 float 的記憶體, 就只需要 4 bytes.
只要我們把這 4 個 bytes 發出去, 就可以原原本本的把那個數值傳過去了.

但怎樣可以把這 4 個 bytes 發出去, 在 接收端得到一個 float 呢?

看看 wire 或 serial 有關的 function, 都沒有以 float 作為參數或結果的, 那可以怎樣做到.

學習 c 的人, 應該不會有問題吧.  c 的 pointer 可是超好用的東西.

大家可以看看 wire 的庫, write 的方法之中, 其中一個就是:
virtual size_t write(const uint8_t *, size_t);
只要把 const uint8_t * 指到要發出的 float 去, size_t 設定為 4, 不就可以把 float 的 4 個 byte 發出去了嗎?

比如 你的資料儲存在   float data = 123.45678, 當中 data 是一個 float.
只要用  wire.write((uint8_t *) &data, 4)  就可以把它的值, 原原本本的發出去.

注意:  由於 data 是 float, &data 是 (float *), c 是不會主動把 (float *) 轉成 (uint8_t *) 的, 所以需要自己指定轉換.


之後, 在接收端收到 4 個 byte, 用相反的方法, 把 4 個 byte 用 pointer 放進 float 對應的記憶體, 就可以還原了.

文字很難清楚說明, 還是直接看程式碼吧.


slave 回傳 float

以下是一個收到任何請求, 都回傳一個 float 數值的例子,

#include 
 
#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 115200 
 
#define I2C_BUFFER_SIZE 32  
uint8_t i2cBuffer[I2C_BUFFER_SIZE];
uint8_t i2cBufferCnt = 0;

float data = 123.45678;
 
void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  Wire.onRequest(requestEvent); // register event
  
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Slave.08 started\n");
}
 
void loop() {
}
 
void requestEvent()
{
  Wire.write((uint8_t *) &data,4);
}



master 接收 float

下面是對應的 master 程式例子:

#include 
 
#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 115200 
#define DATA_SIZE 4
 
void setup()
{
  Wire.begin();
  
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Master.08 started");
  Serial.println();
}

float data = 0;
  
void loop()
{
  if (Serial.available()) {
 
    Wire.requestFrom(SLAVE_ADDRESS, DATA_SIZE);
    Wire.beginTransmission(SLAVE_ADDRESS);
    data = 0;
    uint8_t *ptr = (uint8_t *) &data;
    if (Wire.available()) {
      Serial.print("Data returned: ");
      while (Wire.available()) {
        uint8_t b = Wire.read();
        *ptr++ = b;
        Serial.print(b, HEX);
        Serial.print(" ");
      }
      Serial.println();
      Serial.print("Data value: ");
      Serial.println(data, 6);
    }
    Wire.endTransmission();
    while(Serial.available()) Serial.read();  // Clear the serial buffer, in this example, just request data from slave
  }
 
}


以上範例, 只在於說明如何發送參數給 slave 使用, 當中並沒有加入錯誤的檢測.

執行之後, 你會得到以下結果:

Data returned: DF E9 F6 42
Data value: 123.456779


DF E9 F6 42 就是記憶體中, 用來儲存 123.45678 的 4 個 bytes 了.

但...為什麼 Data value 是 123.456779, 而不是 123.456780 呢?  不是說不會"失真"嗎?

這裡那 0.000001 的差別, 並非傳送時的失真, 而是 float 本身的失真的.
在 arduino 的 float, 是不能準確記下 123.456780 的, 其精確度所限, 會記錄成 123.456779.
正如上面說過, 傳送過程是會原原本本的發過去, 結果就是 123.456779 了.

不信的話, 你可以試試在 slave 的程式中, 把 data 以 6 位小數印出來看看吧.




相關程式下載:


2017年8月22日 星期二

顯示器(一) Nokia 5110 (84x48 LCD)

Nokia 5110 既 LCD 都有好多唔同款既, 而 pin 位都有少少分別.
小弟買左既就係呢款, 接線亦會以呢款為跟據:




基本資料:



相關資料下載:



    接線方法:

    除特定連接 (例 D3-D7) 外, 一般例子都以 SPI 接法, 轉化如下:

    5110MappedUNO
    RSTRSTD11
    CECSD12
    DCDCD10
    DinMOSID9
    ClkSCKD8
    VccVcc3.3V/5V
    BLBL3,3V
    GndGndGND

    (以上連接, 同一般 SPI 庫用 D10-D13 有D唔同, 但搵唔番出處了, 有待再驗證.)


    好可惜...我塊 5110 唔知乜事死左, 要買過塊再試.

    2017年3月17日 星期五

    Arduino 溫度濕度 DHT11

    測量溫度, 濕度 基本上係大路野, 而比較便宜既傳感, 應該可以話係 DHT11 了.
    一般平既可以買到有燈同無燈既版本, 多盞燈大約會貴 1 蚊左右, 但唔會話準左既.


    有樣特別, 唔知係咪我買到既有問題, 有燈同無燈, 安裝係相反既.
    至於邊隻準D, 真係唔知喇.  但係 DHT11 既模塊, 讀數都幾參差.
    我買左三隻, 其中一隻有燈, 用  Adafruit 既 庫, 三隻既讀數都有差別.
    溫度係 22-25 度, 濕度係 44-48%, 比較特別係 溫度高左既濕度就比較低.
    由於我都唔知正確既溫度同濕度係幾多, 無辦法比較.
    遲下買隻號稱準好多既 DHT22 番黎, 再比較一下.


    基本資料:


    電壓:3.3-5V
    溫度測量範圍:20%-95%(0度-50度范围)误差:+-5%
    濕度測量範圍:0度-50度 温度测量误差:+-2度
    输出形式:数字输出

    相關資料下載:
    DHT11  (AOSONG 版本, D-Robotics 版本, 中文版本)

    DHT11 既庫太多了, 暫時用個大路既, Adafruit 出品.



    接線方法:

    得三隻腳, {+,Out,-} 或 {VCC, DATA, GND} , 由於係 數字輸出, 接 D? 腳, 測試用 D2.

    UNODHT11
    D2Out/Data
    3.3V / 5V+/VCC
    GND-/GND


    測試程式:

    在 Adafruit 庫中, 已有 DHTtester 的程式.

    2017年3月13日 星期一

    Arduino 時間系列 (二) DS1307

    除左 DS3231 外, 比較常用既時鐘模塊應該算係  DS1307


    基本資料:

    電壓:3.3V


    相關資料下載:
    DS1307 既庫又係超多, 以下只係我用開既, 唔代表係最好既


    DS1307 Datasheet

    接線方法:

    I2C 的標準接法.

    UNOHS-SR04

    SQ

    DS
    A5SCL
    A4SDA
    3.3VVCC
    GNDGND

    BAT


    測試程式:

    在相關庫的 examples 中.
    
    

    Arduino 時間系列 (一) DS3231

    今次要講既係時鐘模塊  DS3231


    基本資料:

    電壓:3.3V


    相關資料下載:
    DS3231 既庫真係超多, 以下只係我用開既, 唔代表係最好既
    DS3231 (來源: https://github.com/NorthernWidget/DS3231 )
    RTClib  (來源: https://github.com/adafruit/RTClib )
    DS3231 Datasheet

    接線方法:

    I2C 的標準接法.

    UNOHS-SR04

    32K

    SQW
    A5SCL
    A4SDA
    3.3V / 5VVCC
    GNDGND


    測試程式:

    在相關庫的 examples 中.

    
    

    2017年3月5日 星期日

    旋轉編碼器 KY-040

    呢隻野, 真係比佢玩死.  之前做 CNC 手控時, 買左黎玩.

    但係寫完程式測試, 一直都唔可以成功量度到轉動既訊號, 經常無故自動亂跳.

    最近手痕再攞出黎玩, 見 Youtube 有幾清楚既教學 (https://www.youtube.com/watch?v=J9cDEef0IbQ), 就跟住做一次.
    點知, 結果都係一樣.  其實個程式同我之前既做法差唔多.

    心諗無理由我買幾人個都係壞既, 而且後尾發現, 原來只要我隻手放迎近佢就會亂跳, 好奇怪.  開始懷疑係線路上有問題.

    用另一部機試, 完全正常...omg, 比佢玩左我好耐, 原來係部機既 USB 有問題.
    只係知有問題, 唔知乜野問題.
    再試, 改下個程式用 TFT 輸出, 外部比電, 完全正常.
    之前買左個 USB 数字隔离器 諗住比部 CNC 用, 但最後都唔關事.  手痕就攞出黎試下, 果然係掂.  似係 arduion 受電腦經 USB 干擾....

    "肺話"講完, 入正題, 講番點用, 唔係第日又唔記得.

    測試程式可以用番上面條 Youtube 片果個, 又或者用我改左經 UsartGPU TFT 輸出既.

    接線方法:

    UNOKY-040
    D3CLK
    D4DT
    D8SW
    5V+
    GNDGND

    注意, 呢度既 CLK 同 DT, 其實個名有點亂, 應該即係兩個感應器既輸出, pinA 同 pinB.
    佢既原理在 Youtube 片講得好清楚了, 主要係靠兩個差 90度既感應, 從而量度出旋轉既步數, 及推算方向 (順時針/逆時針).  所以, 就算 CLK 同 DT 交換插都唔會有問題, 只係可能順/逆既方向調轉左.

    程式中以 CLK 去觸發 Interrupt, 所以如果 D3 有其他野用左, 只可以轉用其他有 interrupt 既 pin.
    有關 Interrupt pin 既選擇, 可以去 呢度 睇.

    測試程式:
    KY040.ino   (原網址, 私人收藏)

    2017年2月27日 星期一

    ILI9341 3.2 TFT

    Using Rinky-Dink's UTFT Library:  UTFT myGLCD(ILI9341_16, 38, 39, 40, 41);


    From TFT to Due:

    TFT-Pin Lable Due
    1 CS 40
    2 RS 38
    3 WR 39
    4 RD 3.3V
    5 RST 41
    6 DB0 37
    7 DB1 36
    8 DB2 35
    9 DB3 34
    10 DB4 33
    11 DB5 32
    12 DB6 31
    13 DB7 30
    14 DB8 22
    15 DB9 23
    16 DB10 24
    17 DB11 25
    18 DB12 26
    19 DB13 27
    20 DB14 28
    21 DB15 29
    22 SDCS --
    23 BL 3.3V
    24 VDD 3.3V
    25 VDD 3.3V
    26 GND GND
    27 GND GND
    28 NC --
    29 MISO 3
    30 MOSI 4
    31 PEN 2
    32 F_CS --
    33 T_CS 5
    34 CLK 6


    From Due to TFT:

    Due Lable
    2 PEN
    3 MISO
    4 MOSI
    5 T_CS
    6 CLK
    22 DB8
    23 DB9
    24 DB10
    25 DB11
    26 DB12
    27 DB13
    28 DB14
    29 DB15
    30 DB7
    31 DB6
    32 DB5
    33 DB4
    34 DB3
    35 DB2
    36 DB1
    37 DB0
    38 RS
    39 WR
    40 CS
    41 RST
    -- SDCS
    -- NC
    -- F_CS
    3.3V RD
    3.3V BL
    3.3V VDD
    3.3V VDD
    GND GND
    GND GND


    References: