1. 程式人生 > >如何編寫自己的arduino類庫

如何編寫自己的arduino類庫

當我們在arduino中有大量的程式碼需要在不同的工程中重複時,我們可以把這段程式碼進行封裝,那麼由此我們就想到了要編寫自己的arduino類庫。這個工作並不複雜,稍有面對物件程式設計經驗的小夥伴即可比較容易完成。下面我們以例項的方式將步驟一一列出。

我們以,我前面編寫的《Arduino中使用超聲波測距實驗》為例來進行說明。程式碼如下:

int TrgPin = A0;
int EcoPin = A1;
float dist;
void setup()
{   
Serial.begin(9600);
//設定TrgPin為輸出狀態
pinMode(TrgPin, OUTPUT);
// 設定EcoPin為輸入狀態
pinMode(EcoPin, INPUT);
}
void loop()
{
digitalWrite(TrgPin, LOW);
delayMicroseconds(8);
digitalWrite(TrgPin, HIGH);
// 維持10毫秒高電平用來產生一個脈衝
delayMicroseconds(10);
digitalWrite(TrgPin, LOW);
// 讀取脈衝的寬度並換算成距離
dist = pulseIn(EcoPin, HIGH) / 58.00;
Serial.print("Distance:");
Serial.print(dist);
Serial.println("cm");
delay(300);
}

我在看來,封裝的目的就是讓必要而機械的步驟得到簡化。
從這段程式碼中我們可以看出:
1、對Trig及Echo兩個管腳與Arduino板上的兩個訊號管腳的繫結是必要且機械的工作,所以這個初始化工作我們可以交給我們的初始化函式。
2、讓Trig腳保持高電平已經後續讀取Echo腳的數值,也是機械的,我們可以封裝為一個獲取距離的函式;
3、距離的輸出,是否輸出提示字串是可選的,但距離的數值是必須的,通過串列埠傳送到上位機必須靠它了。

通過上面的分析我們明白了封裝類的設計目的了就好辦了。假定我們定義的類為USensor我們來看看程式碼如何實現:
USensor.h

#ifndef USensor_H
#define USensor_H

#if defined(ARDUINO) && ARDUINO >= 100
	#include "Arduino.h"
#else
	#include "WProgram.h"
#endif
//#include "pins_arduino.h"

#include <inttypes.h>

#define PULSE_TIMEOUT 150000L	// 100ms
#define DEFAULT_DELAY 10
#define DEFAULT_PINGS 5
class USensor {
public:
	
	/**
	* Constructor
	* Ultrasonic sensor SR04, four connections pins
	* VCC, ECHO, TRIGGER, GND
	* <br>
	* \param echoPin digital INPUT-Pin for measuring distance
	* \param triggerPin if 10us high a trigger signal is generated from 
	*					SR04
	*
	* \return void
	*/
	USensor(int echoPin, int triggerPin);

	/**
	* Do a measurment for this sensor. Return distance as long
	* in centimenter
	* \return long distance in centimeter
	*/
	long Distance();
	
	/**
	* Do count measurents and calculate the average. 
	* To avoid defilement from ow/high peaks, min/max values
	* are substracted from the average
	*
	* \param wait delay between measurements, default = DEFAULT_DELAY/ms
	* \param count number of measurements, default DEFAULT_PINGS
	* \return long distance in centimeter
	**/
	long DistanceAvg(int wait=DEFAULT_DELAY, int count=DEFAULT_PINGS);
	
	/**
	* Do only a ping. Get result with methode getDistance()
	* 
	* \param keine
	*/
	void Ping() ;
	
	/**
	* return latest distance. Methode Ping() should be called before
	* \param keine
	* \return Distanz in Zentimeter
	*/
	long getDistance();
	

private:
	/**
	* Do the measurement calculation and return result in centimeter
	* SR04 measure echo time to obstacle and return way. 
	* <br>
	* Sound travels with 340m/sec
	* <br>
	* Example: Obstace 100cm away from SR04. Measure time is 100cm to
	* obstacle and 100cm return = 200cm
	* <br>
	* 1sec = 1000ms = 1.000.000uS
	* 1.000.000 / 340 = Distance in microseconds for 100cm
	* 2941uS fuer 100cm = 5882 uS fuer 200cm
	*
	* duration / 5882 * 100 = distance in cm
	*/	
	long MicrosecondsToCentimeter(long duration);
	
	long _currentDistance;
	int _echoPin, _triggerPin;
	long _duration, _distance;
	bool _autoMode;
};
#endif



USensor.cpp

//Ultrasonic Sensor Class
#include "USensor.h"

USensor::USensor(int echoPin, int triggerPin) {
    _echoPin = echoPin;
    _triggerPin = triggerPin;
    pinMode(_echoPin, INPUT);
    pinMode(_triggerPin, OUTPUT);
    _autoMode = false;
    _distance = 999;
}


long USensor::Distance() {
    long d = 0;
    _duration = 0;
    digitalWrite(_triggerPin, LOW);
    delayMicroseconds(2);
    digitalWrite(_triggerPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(_triggerPin, LOW);
    delayMicroseconds(2);
    _duration = pulseIn(_echoPin, HIGH, PULSE_TIMEOUT);
    d = MicrosecondsToCentimeter(_duration);
    delay(25);
    return d;
}

long USensor::DistanceAvg(int wait, int count) {
    long min, max, avg, d;
    min = 999;
    max = 0;
    avg = d = 0;

    if (wait < 25) {
        wait = 25;
    }

    if (count < 1) {
        count = 1;
    }

    for (int x = 0; x < count + 2; x++) {
        d = Distance();

        if (d < min) {
            min = d;
        }

        if (d > max) {
            max = d;
        }

        avg += d;
    }

    // substract highest and lowest value
    avg -= (max + min);
    // calculate average
    avg /= count;
    return avg;
}

void USensor::Ping() {
    _distance = Distance();
}

long USensor::getDistance() {
    return _distance;
}

long USensor::MicrosecondsToCentimeter(long duration) {
    long d = (duration * 100) / 5882;
    //d = (d == 0)?999:d;
    return d;
}

keyword.txt

#######################################
# Syntax Coloring Map For 你的類名
#######################################
#######################################
# Datatypes (KEYWORD1) 資料型別關鍵字
#######################################
TN901        KEYWORD1
#######################################
# Methods and Functions (KEYWORD2) 方法型別關鍵字
#######################################
Init        KEYWORD2
Read        KEYWORD2
ReadData        KEYWORD2
GetData        KEYWORD2
#######################################
# Constants (LITERAL1)  常量型別關鍵字
#######################################
ET        LITERAL1
OT        LITERAL1

最重要的是以下幾點,如果我們不遵照這幾點,我們可能無法真正能使我們封裝的類在arduino的IDE中看到:
1、類名和檔名必須統一(比如你的類名叫做ABC,那麼你的檔名對應為ABC.cpp)
2、必須要有keyword,否則你的在IDE中將無法以顏色卻分於普通的程式碼,普通的變數。
3、編輯好的類檔案必須防止在IDE所在libraries目錄下;
4、編輯好的檔案和keyword必須放在同一個目錄下
在這裡插入圖片描述
在這裡插入圖片描述