2013/01/17

Arduino撰寫自己的程式庫

不論是哪套軟體開發平台,一定會有程式庫(也可能以元件庫、類別庫、軟體開發框架的形式出現)的概念,其功用就是把某功能寫好包裝起來,隱藏細節,方便大家運用。

Arduino軟體開發環境內建了一些常用程式庫,諸如LiquidCrystal、Servo、SoftwareSerial、SPI、等等,有了它們,便只需在較抽象較上層的階級對該功能有所了解即可,不必完全知曉底層複雜的技術。

另外也有很多人將開發出來的Arduino程式包裝成程式庫開放給大家使用,譬如Dr. Monk的Timer、存取1-Wire匯流排協定的OneWire、讀取Dallas溫度感測器的DallasTemperature、解決按鈕訊號在高低電位之間彈跳Bounce、等等,

這篇的主題是撰寫自己的Arduino程式庫,將功能包裝後變成程式庫,隱藏底層細節、提供較簡易的介面,供別的專案使用,甚至供其他人使用。

首先以底下這份草稿碼,以PWM讓LED漸亮、漸暗、不斷循環,我稱之為呼吸燈。

詳情就不解說了,請參考我寫的Arduino練習:呼吸燈

int brightness = 0;
int fadeAmount = 5;
int delayDuration = 30;

void setup()  {
  pinMode(9, OUTPUT);
}

void loop()  {
  analogWrite(9, brightness);
  brightness = brightness + fadeAmount;
  if (brightness <= 0 || brightness >= 255) {
    fadeAmount = -fadeAmount ;
  }  

  delay(delayDuration);                          
}

好,那如果想要有三個呼吸燈呢,程式會變得很複雜吧。當然啦,其實可使用計時器的程式庫,譬如Dr. Monk的Timer,就能寫出簡單易懂的程式碼,不過這篇要介紹的是自行撰寫Arduino程式庫,所以讓我寫個程式庫,將以上的程式碼包起來,方便使用。

Arduino程式庫有兩個地方,一個是內建的,我們不動它,另一個是自己安裝的,這個程式庫的目錄在sketchbook底下的libraries(若無請自行建立)。

在libraries底下新增目錄,命名為PwmLed,這就是我將撰寫的程式庫的位置,裡面放進PwmLed.cpp與PwmLed.h,這是程式庫的主體,內容如下。

(咳咳,我就不解釋C++程式語言了。)

首先是PwmLed.h:

#ifndef PwmLed_h
#define PwmLed_h

#include <inttypes.h>

class PwmLed
{

public:
  unsigned long m_lastTime;
  uint8_t m_pin;
  int m_brightness;
  int m_fadeAmount;
  unsigned long m_delayDuration;
 
  PwmLed(void);
  void set(uint8_t pin, int initBrightness, int fadeAmount, unsigned long delayDuration);
  void update(void);
};

#endif

內容很普通,就是一般的C++標頭檔。接下來是PwmLed.cpp:

// For Arduino 1.0 and earlier
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "PwmLed.h"

PwmLed::PwmLed(void)
{
}

void PwmLed::set(uint8_t pin, int initBrightness, int fadeAmount, unsigned long delayDuration)
{
    m_pin = pin;
    m_brightness = initBrightness;
    m_fadeAmount = fadeAmount;
    m_delayDuration = delayDuration;
   
    pinMode(m_pin, OUTPUT);
    analogWrite(m_pin, m_brightness);
    m_lastTime = millis();
}


void PwmLed::update(void)
{
    unsigned long t = millis();
    if(t > m_lastTime + m_delayDuration){
        m_lastTime += m_delayDuration;
       
        analogWrite(m_pin, m_brightness);
        m_brightness = m_brightness + m_fadeAmount;
   
        if (m_brightness <= 0 || m_brightness >= 255) {
            m_fadeAmount = -m_fadeAmount;
        }
    }
}

還可以再加入keywords.txt,指定程式庫的關鍵字,這麼一來,Arduino軟體開發環境的編輯器就能以不同顏色顯示。如下:

#######################################
# Syntax Coloring Map For Timer Library
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

PwmLed    KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

set    KEYWORD2
update    KEYWORD2

#######################################
# Instances (KEYWORD2)
#######################################

#######################################
# Constants (LITERAL1)
#######################################

libraries/PwmLed底下還可以放個examples目錄,存放範例,我就不管了。

程式庫至此已經準備完畢,請重新開啟Arduino軟體開發環境,應該就能在Sketch-Import Library...下看到PwmLed。

接下來就是使用了。

電路圖如下:

Arduino腳位9、10、11(具有PWM功能),各自接到220 ohm電阻、再接到LED長腳,LED短腳接地。


然後,使用PwmLed程式庫,讓三個LED變成呼吸燈的草稿碼如下:

#include <PwmLed.h>

#define LED0 9
#define LED1 10
#define LED2 11

PwmLed led0;
PwmLed led1;
PwmLed led2;

void setup()  {
  led0.set(LED0, 0, 5, 30);
  led1.set(LED1, 0, 10, 60);
  led2.set(LED2, 0, 30, 300);
}

void loop()  {
  led0.update();  
  led1.update();  
  led2.update();
}

先以set設定,參數第一個是PWM腳位,第二個是初始亮度,0不亮、255全亮,第三個是每次更新亮度時的更新幅度,越小代表變化會越平順,第四個代表更新頻率,單位是千分之一秒,越小代表越快更新。聽起來很複雜,但換換數字看看結果就清楚了。

然後在loop()裡以update更新亮度。

很簡單吧!

原始碼可到這裡下載。


參考資料:


57 comments:

  1. 葉大,
    想請問一個問題,
    我將 include 的檔案修改了部份,
    但在重新 compile 的時候卻還是跑舊的 include 檔案
    請問我要如何修改?

    目前的改法是在 .h 和.cpp 檔案中,加入 #if WITH_AAA ... #endif
    照理說 compile 時應該會略過,
    第一次修改時有成功,於是我就想說改一下 WITH_AAA 的值讓它跑看看
    所以我就多加了 #define WITH_AAA true
    結果從此以後 compile 都會進入#if WITH_AAA ... #endif
    就算我把 #define 的部份拿掉都一樣,
    甚至我把 #if 區段裡的 Code 全刪了,結果還是一樣可以compile ...

    請問是否 Arduio 會把 #define 的值做記錄?
    還是會另外將 compile 的檔案做暫存並重覆使用??

    ReplyDelete
    Replies
    1. Arduino開發環境應該沒有預先編譯.h檔(precompiled header)的功能。所以不會把#define的值做記錄。

      當你多加了#define WITH_AAA true後,WITH_AAA就是有定義了(就算改成false也算是有定義),自然從此以後都會進入#if WITH_AAA ... #endif。
      但是為什麼你拿掉#define後還是一樣,從你給的資訊,我看不出來原因。

      還是請你再多給些資訊吧,檔案的內容?

      Delete
  2. 葉大
    不好意思,我找到原因了!

    原因是我在改 .h .cpp 檔之前,
    有先將arduino-1.0.5\libraries\下的要修改資料夾備份,
    所以第一次會成功是因為我將 Arduino 的 IDE 程式開啟後並沒有關閉,
    然後直接改arduino-1.0.5\libraries\下的資料夾檔案
    第一次 compile 成功,
    再來加入 #define XXXX 後也可以正常將 #if XXXX 的區段進行 Compile
    但後來 IDE 程式關閉後再重新 Compile 都無法跳過 #if 區段,
    因為我的arduino-1.0.5\libraries\資料夾下一直存在原來的資料夾,(雖然資料夾的命名不同,但還是會抓到舊的內容。)
    我將舊內容的資料夾刪除後,
    重新 Compile 後就又可以跳過 #if XXXX 區段了。
    目前測試都正常。

    不好意思,浪費了葉大的保貴時間。

    ReplyDelete
    Replies
    1. 不會,不用客氣。

      Arduino IDE會在背地裡作一些動作,它應該會去掃描arduino-1.0.5\libraries\裡的各個子資料夾。

      Delete
  3. 想請問葉大
    程式中的自行安裝的程式碼
    是要去哪裡下載安裝
    因為我參考葉大的程式碼
    有些標頭檔我沒有
    如果下載好了那要放在哪一個資料夾
    還有.cpp檔需要用visual studio跑過一次還是直接放在資料夾裡就好

    ReplyDelete
    Replies
    1. 哪個標頭檔?哪個程式庫?

      > 要放在哪一個資料夾
      Arduino程式庫的資料夾,通常是sketchbook資料夾的子目錄libraries。

      > .cpp, visual stduio
      不用,放進去即可。

      Delete
    2. 跟WProgram.h相關的標頭檔我都沒有

      Delete
    3. Arduino 1.0版以前有WProgram.h,後來改名為Arduino.h。
      我不是用#if #else #endif處理了嗎?

      Delete
  4. Anonymous17/9/15 11:16

    葉大您好:
    我想請問您有使用過DFPlayer_Mini_Mp3這個模組嗎?
    因為我想使用ARDUINO去控制兩塊DFPlayer_Mini_Mp3
    單一塊控制可,但卻無法同時使用兩塊,該如何撰寫程式解決這個問題呢?

    ReplyDelete
    Replies
    1. 沒有。

      但是看起來似乎可以。

      Delete
    2. Anonymous17/9/15 11:28

      http://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299
      那應該如何解決呢?

      Delete
    3. 可能電源不足?可能程式裡關於SoftwareSerial的部份沒寫對?可能因為delay而導致與模組間的通訊出錯?等等...

      我沒有該模組,建議你或許直接向原廠索要範例。

      Delete
    4. Anonymous17/9/15 13:45

      好,謝謝!!
      另外我想請問!!如何使用MEGA板控制兩組TX、RX??

      Delete
    5. mega版不是有很多硬體序列埠(RX與TX)?有什麼問題嗎?

      Delete
  5. 葉大你好~
    小弟有問題想請教大大
    我使用Arduino UNO版,配合L298n控制馬的達正反轉
    想把此功能像內文所說的一樣,把功能包裝起來,並在執行C++的程式中使用
    但很多東西並不知道在哪裡,我該如何創建一個這樣的功能,能讓C++把library掛進來,然後執行程式

    ReplyDelete
    Replies
    1. 我這篇有點舊了,雖然內容還是對的,但已經不算完整。
      建議參考官方文件https://www.arduino.cc/en/Hacking/LibraryTutorial

      > 但很多東西並不知道在哪裡
      什麼東西?

      > 我該如何創建一個這樣的功能,能讓C++把library掛進來,然後執行程式
      聽不太懂。

      Delete
    2. 比如說像大大所說的sketchbook及怎麼會跑出一個CPP檔
      內容很普通,就是一般的C++標頭檔。接下來是PwmLed.cpp:

      // For Arduino 1.0 and earlier
      #if defined(ARDUINO) && ARDUINO >= 100
      #include "Arduino.h"
      #else
      #include "WProgram.h"
      #endif

      #include "PwmLed.h"

      PwmLed::PwmLed(void)
      {
      }

      void PwmLed::set(uint8_t pin, int initBrightness, int fadeAmount, unsigned long delayDuration)
      {
      m_pin = pin;
      m_brightness = initBrightness;
      m_fadeAmount = fadeAmount;
      m_delayDuration = delayDuration;

      pinMode(m_pin, OUTPUT);
      analogWrite(m_pin, m_brightness);
      m_lastTime = millis();
      }

      大大所說的這個Cpp檔是怎麼出現的?
      .h檔還知道在哪邊,但Cpp檔要去哪找我就不清楚了
      因為我洗忘我能把驅動馬達的功能包裝起來visual C++可使用
      比如給他某些指令,那麼他就能相對給我在Arduino上包裝好的馬達正反轉的功能

      Delete
    3. > 這個Cpp檔是怎麼出現的?
      我寫的啊。

      > 包裝起來visual C++可使用...
      還是不懂你的問題。

      Arduino為什麼提到visual C++?
      你是要「撰寫C++程式在Windows上跑」,而且能夠跟「Arduino」溝通嗎?

      Delete
    4. 是的,誠如大大所說想撰寫C++程式在Windows上跑,而且能夠跟Arduino溝通,想讓C++去控制Arduino的功能

      Delete
    5. 你說的跟這篇文章(Arduino撰寫自己的程式庫)沒什麼關係吧。

      那麼你的Windows電腦跟Arduino之間,採取什麼連接方式呢?乙太網路、Wi-Fi、序列埠?

      若是序列埠的話,一般Arduino開發板使用USB線連接電腦。
      在Windows電腦上撰寫C++程式,需要能夠存取序列埠的程式庫,便能寫入、讀取資料。
      而Arduino端就跟平常一樣,使用Serial存取序列埠。

      能夠收發資料後,也就是能夠溝通了。

      Delete
    6. 是用序列埠,我分別兩有個程式,一個用C++開啟攝影機的,一個是用Arduino控制馬達的,想要把這兩者結合在一起,只需要執行C++那個開啟攝影機的程式碼,也能同時執行控制馬達的功能,想請問葉大,我是需要用什麼樣的方式,能夠達到此效果

      Delete
    7. 你需要一套Windows上的、C++語言的序列埠程式庫,
      譬如http://playground.arduino.cc/Interfacing/CPPWindows,

      讓C++程式與Arduino程式雙方能夠溝通。大概如下:

      你在Windows上的C++程式 - 該程式庫 - 存取Windows的序列埠 - 連接到Arduino的序列埠 - Arduino程式

      Delete
  6. 感謝葉大,您推薦的方法我已經嘗試且成功了,但是感覺跟我自己當初想的不太一樣,再請教大大,如果我想將arduino的功能,完全用c++程式編譯,像是把程式寫進去或掛進去,一旦編譯完成後可開啟鏡頭及控制馬達,且還能不需要透過serial port去連接,這想法是可行的嗎? 我要用什麼樣的方式可以完成這個想法

    ReplyDelete
  7. 感謝葉大,您推薦的方法我已經嘗試且成功了,但是感覺跟我自己當初想的不太一樣,再請教大大,如果我想將arduino的功能,完全用c++程式編譯,像是把程式寫進去或掛進去,一旦編譯完成後可開啟鏡頭及控制馬達,且還能不需要透過serial port去連接,這想法是可行的嗎? 我要用什麼樣的方式可以完成這個想法

    ReplyDelete
    Replies
    1. > 不需要透過serial port去連接
      那你要透過什麼連接?
      你的電腦跟Arduino板子,兩個裝置,要怎麼連接?

      Delete
    2. 了解~也就是說要使用arduino功能,依舊需要互相連接才能辦得到,還是說我們能將arduino的程式碼轉換成c++的,讓c++讀得懂? 那如果說我們一樣透過serial sport做連接,但是能一執行c++程式後,arduino控制馬達的功能能不透過手動方式開啟及控制,可以一旦程式執行後就自行啟動,這是否要先在把這功能寫在arduino都程式碼那,還是我們能寫在c++內,然後呼叫這功能?

      Delete
    3. arduino的程式碼就是C++程式碼。
      但arduino的CPU是AVR架構,你用virtual c++編譯出來的東西(如果可以編譯的話),arduino無法執行。

      > 這是否要先在把這功能寫在arduino都程式碼那,還是我們能寫在c++內
      都可以,由你決定。

      Delete
    4. 你的馬達連接到Arduino,也只有Arduino能控制它。

      你的C++程式在Windows電腦上,一定要透過某種連線,傳送指令給Arduino,叫Arduino控制馬達。

      我想你需要的是更高階的程式庫,譬如Firmata。

      Delete
    5. 恩恩,我照著葉大的建議去搜尋firmata但是載下來後,這幾天,爬了不少文,還是不知道怎麼用
      可否請葉大告訴我流程,如何用C++透過firmata控制Arduino的功能,東西要放在哪裡,或者要更改那些地方

      Delete
    6. 我只用過Python版本的Firmata,可參閱
      http://yehnan.blogspot.tw/2016/01/arduinowindowspythonfirmataarduino.html

      流程如下:
      Arduino端要燒錄能接收、解析Firmata訊息的草稿碼,例如內建範例草稿碼StandardFirmata。

      電腦端要下載安裝Firmata(假定你需要的是C++版),然後撰寫C++程式,使用Firmata的API,傳送訊息給Arduino、操控腳位。

      Delete
    7. 葉大python使用firmata一定要安裝pip嗎?

      Delete
    8. This comment has been removed by the author.

      Delete
    9. > python使用firmata一定要安裝pip嗎?
      使用pip最方便啊。

      pyFirmata已經包裝成Python模組,使用pip的話,就能輕鬆安裝,這也是正統的安裝方式。

      否則,請看https://github.com/tino/pyFirmata,
      你可以自己下載手動安裝。

      Delete
  8. 葉大,不好意思,我真的看不懂PIP安裝教學阿~~~~@@?
    到底在寫什麼,一點下去全部都是程式碼,東西要放哪要按哪真的不知道.........
    可否教一下到底怎麼安裝,網路上的不知道在寫什麼..........

    ReplyDelete
    Replies
    1. 現在的Python實作,不是都已經預設包含pip了嗎?

      若要自己安裝,請看https://pip.pypa.io/en/stable/installing/

      我就算寫,也不會超越官方文件。

      Delete
    2. > 您推薦的方法我已經嘗試且成功了
      你之前不是已經使用C++與序列埠的方式嗎,而且成功了。
      為什麼不使用C++版的Firmata?

      現在你要換成python嗎?

      Delete
    3. 是嘛? 我是安裝2.7.5版本,裡頭也已經有了? 如果有了 我接著只要照大大給我的網只安裝firmata即可?
      是阿~ 因為看不懂firmata如何安裝在C++,網路上找了好多文,完全都不知道他們在寫什麼
      要安裝也不知道放哪裡.....,然後有些又只有講一半=="結果就出來了,不詳細,照作她們給的流程安裝了也是錯誤......
      想說這樣還不如改成大大的python,大大懂,我也比較好問~

      Delete
    4. 2.7.5版沒有。自2.7.9或3.4版起才預設內建pip。

      > firmata如何安裝在C++
      嗯,我找了一下,的確不容易,可能要安裝openFrameworks吧。

      > 改成python
      是嗎?應該要選你會的語言吧。要不然怎麼開發?

      Delete
    5. 葉大,我重新安裝python,安裝2.7.11版本,裡頭已經安裝好PIP了
      也照著大大的說明安裝好pyfirmata了
      但後面的我就看不懂了
      然後進入Python shell,匯入模組: (這個是要開啟IDLE輸入的嗎?)後面這些程式碼我要輸入在哪邊?
      $ python
      >>> from pyfirmata import Arduino, util

      傳入埠號,開啟序列埠裝置。從Arduino IDE的選單裡,可看到我的UNO板連接到電腦的COM3,若是在Windows的命令提示字元底下,應傳入'COM3';而若是在Cygwin裡,會被命名為裝置/dev/ttyS2:
      >>> board = Arduino('COM3')

      然後運用API,傳出Firmata訊息,控制腳位13(LED):
      >>> board.digital[13].write(1)
      >>> board.digital[13].write(0)
      便可看到LED被點亮與熄滅。

      如果沒有安裝API的東西,大大有沒有推薦比較好用或淺顯易懂容易讓新手上手的?

      Delete
    6. 葉大,我重新安裝python,安裝2.7.11版本,裡頭已經安裝好PIP了
      也照著大大的說明安裝好pyfirmata了
      但後面的我就看不懂了
      然後進入Python shell,匯入模組: (這個是要開啟IDLE輸入的嗎?)後面這些程式碼我要輸入在哪邊?
      $ python
      >>> from pyfirmata import Arduino, util

      傳入埠號,開啟序列埠裝置。從Arduino IDE的選單裡,可看到我的UNO板連接到電腦的COM3,若是在Windows的命令提示字元底下,應傳入'COM3';而若是在Cygwin裡,會被命名為裝置/dev/ttyS2:
      >>> board = Arduino('COM3')

      然後運用API,傳出Firmata訊息,控制腳位13(LED):
      >>> board.digital[13].write(1)
      >>> board.digital[13].write(0)
      便可看到LED被點亮與熄滅。

      如果沒有安裝API的東西,大大有沒有推薦比較好用或淺顯易懂容易讓新手上手的?

      Delete
  9. 大大,我重新安裝python,版本2.7.11,裡面已經有PIP了
    也照著大大的流程安裝好pyfirmata,只是後面這邊看不太懂

    然後進入Python shell,匯入模組:(是要開啟python的IDLE,輸入進去嗎? 我輸入後顯示錯誤)
    $ python
    >>> from pyfirmata import Arduino, util

    傳入埠號,開啟序列埠裝置。從Arduino IDE的選單裡,可看到我的UNO板連接到電腦的COM3,若是在Windows的命令提示字元底下,應傳入'COM3';而若是在Cygwin裡,會被命名為裝置/dev/ttyS2:
    >>> board = Arduino('COM3')

    然後運用API,傳出Firmata訊息,控制腳位13(LED):
    >>> board.digital[13].write(1)
    >>> board.digital[13].write(0)

    便可看到LED被點亮與熄滅。
    以上那些程式碼要打在哪裡? 我沒有安裝任何API的東西還能啟動控制Arduino的機制嗎?
    大大有沒有比較推薦或是容易上手的API給我這新手學習?

    ReplyDelete
    Replies
    1. > 是要開啟python的IDLE,輸入進去嗎?
      呃,執行python指令進入Python的shell,然後便可輸入一行一行的程式碼。
      > 我輸入後顯示錯誤
      什麼錯誤?

      > 以上那些程式碼要打在哪裡?
      Python shell。

      > 我沒有安裝任何API的東西還能啟動控制Arduino的機制嗎?
      不透過軟體程式,你怎麼控制Arduino?

      > 大大有沒有比較推薦或是容易上手的API給我這新手學習?
      沒有。


      > 感謝葉大,您推薦的方法我已經嘗試且成功了,
      還沒使用Firmata之前,你不是已經成功了嗎?就使用那種方式不就好了。

      Firmata只是制定傳輸訊息的格式,如果你沒那麼多功能,簡簡單單地透過序列埠、使用一兩個byte當做指令傳過去,不就好了?

      Delete
    2. 葉大,經昨天實驗,我已經能像大大所說讓LED燈亮暗了,亦能用Python shell下達指令讓馬達正反轉
      想請教怎麼把這些功能寫進欲執行的程式中? 比如:我想開啟鏡頭後馬達也可以被控制著轉動,是否一樣要先用python程式透過serial port溝通然後再結合firmata下指令進而做到這效果,還是只需要用到serial port跟Arduino溝通就可以控制了?

      Delete
    3. > 能用Python shell下達指令讓馬達正反轉
      > 想請教怎麼把這些功能寫進欲執行的程式中?
      在Python shell裡下達的指令,都是Python程式碼。

      Delete
    4. > 就可以控制了?
      不懂你想問什麼。

      Delete
    5. 所以說 我只要把那些指另寫進成事當中就可讓控制馬達的?
      就是說,現在已經用firmata了,可以直接用python控制馬達,
      那在撰寫程式中我是否還是必須先透過serial port開啟跟Arduino溝通,然後才可以用firmata下達指令
      或者直接撰寫程式碼,不需要再透過serial port的溝通,直接就可以控制了

      Delete
    6. > 現在已經用firmata了,
      對。

      > 可以直接用python控制馬達,
      你不是已經
      > 亦能用Python shell下達指令讓馬達正反轉
      了嗎?

      Firmata自己會開啟serial port。

      Delete
  10. 請問
    .cpp及.h檔要用什麼程式寫在存檔,我用arduinoIDE不行
    謝謝

    ReplyDelete
  11. 請問
    .cpp及.h檔要用什麼程式寫在存檔,我用arduinoIDE不行
    謝謝

    ReplyDelete
    Replies
    1. > 我用arduinoIDE不行
      可以。

      點按IDE右邊的「向下箭頭」,選擇「新增標籤」,就可以新增檔案,副檔名由你自取。

      Delete
  12. 用arduino IDE直接存和新增的檔案只能用arduino IDE開啟才找的到檔案 從C:無法找到檔案這樣正常嗎
    謝謝

    ReplyDelete
    Replies
    1. 草稿碼都放在草稿碼簿裡,
      檔案-偏好設定-草稿碼簿的位置。

      Delete
  13. 葉大 不好意思 您有在教人怎麼撰寫Arduino的GPS程式嗎,因為看的不是很懂TinyGPS的函式庫,只需要入個門就好,因為我還是新手,
    網路上也比較少在教,我使用的是PAM-7Q GPS Module不知道跟其他GPS Module的程式差很多嗎
    我的e-mail : y1y1y1gv23@gmail.com 打擾了!

    ReplyDelete
    Replies
    1. > 教人
      沒有。

      TinyGPS函式庫有範例程式,找找關鍵字「PAM-7Q arduino」,也有一些示範用的程式,如parallax網站。雖然不多。


      Delete