编写自己的arduino类库

当我们在arduino中有大量的代码需要在不同的工程中重复时,我们可以把这段代码进行封装,那么由此我们就想到了要编写自己的arduino类库。这个工作并不复杂,稍有面对对象编程经验的小伙伴即可比较容易完成。下面我们以实例的方式将步骤一一列出

我们以,超声波测距为例来进行说明。代码如下:

// 设定SR04连接的Arduino引脚
const int TrigPin = 14;
const int EchoPin = 15;
float distance;
//HC-SR04模块测距原理:
//(1)IO口Trig触发测距,给至少10us的高电平信号;
//(2)模块自动发送8个40khz的方波,自动检查是否有信号返回;
//(3)有信号返回通过IO口Echo输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
// 测试距离=(高电平时间*声速(340m/s))/2
void setup() {
  // put your setup code here, to run once:
  // 初始化串口通信及连接SR04的引脚
  Serial.begin(9600);
  pinMode(TrigPin, OUTPUT);
  // 要检测引脚上输入的脉冲宽度,需要先设置为输入状态
  pinMode(EchoPin, INPUT);
  Serial.println("Ultrasonic sensor:");
}

void loop() {
  // put your main code here, to run repeatedly:
  // 产生一个10us的高脉冲去触发TrigPin
  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TrigPin, LOW);
  // 检测脉冲宽度,并计算出距离
  distance = pulseIn(EchoPin, HIGH) / 58.00;
  Serial.print(distance);
  Serial.print("cm");
  Serial.println();
  delay(1000);
}

我在看来,封装的目的就是让必要而机械的步骤得到简化。 从这段代码中我们可以看出:

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必须放在同一个目录下

文档信息

版权声明:可自由转载(请注明转载出处)-非商用-非衍生

发表时间:2022年2月10日 15:03