首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Arduino代码设计的接口

Arduino代码设计的接口
EN

Software Engineering用户
提问于 2018-09-10 06:12:52
回答 1查看 116关注 0票数 1

我经常想要Arduino板控制几个外围设备。使用#define SOME_PIN 4构造在一个文档中为所有这些人编写程序对我来说似乎很不方便。尤其是在这种情况下,您必须修改很久以前编写的旧代码。

我选择使用以下方法来组织项目的编程部分。因此,编写代码可以分为三个部分。

1.接口结构

在这个阶段,程序员应该描述在他的项目中使用的所有设备。当然,只有那些Arduino编程交互的人(例如传感器、芯片而不是中间电阻器)。在这个阶段,每个设备都由一个类描述类表示.描述类具有特殊的成员函数-引脚函数.这些函数是纯虚拟的,每个函数都打算从Arduino引号集合中返回8位无符号整数值。引脚功能在Arduino和外围设备之间起着导线的作用.Description类还应该包含用于此具体设备的Arduino指令函数。

Arduino也有一个description类,但现在它被用作带有常量的命名空间。到目前为止,不需要这个类的对象。

下面是一个使用该接口的示例。

  • 控制器: Arduino Uno R3
  • 外围:超声波传感器HC-SR04 04

1.1 Arduino Uno R3类-description

Arduino Uno R3 description-类仅由静态常量组成,这些常数是引脚号.

1.1.1 Uno.h

代码语言:javascript
运行
复制
#ifndef UNO_H
#define UNO_H

#include <inttypes.h>

class Uno
{
    public :
        //Digital pins
        static const uint8_t D0 = 0;
        static const uint8_t D1 = 1;
        static const uint8_t D2 = 2;
        static const uint8_t D3 = 3;
        static const uint8_t D4 = 4;
        static const uint8_t D5 = 5;
        static const uint8_t D6 = 6;
        static const uint8_t D7 = 7;
        static const uint8_t D8 = 8;
        static const uint8_t D9 = 9;
        static const uint8_t D10 = 10;
        static const uint8_t D11 = 11;
        static const uint8_t D12 = 12;
        static const uint8_t D13 = 13;
        //Analog pins
        static const uint8_t A0 = 0;
        static const uint8_t A1 = 1;
        static const uint8_t A2 = 2;
        static const uint8_t A3 = 3;
        static const uint8_t A4 = 4;
        static const uint8_t A5 = 5;
        //SPI
        static const uint8_t SS = D10;
        static const uint8_t MOSI = D11;
        static const uint8_t MISO = D12;
        static const uint8_t SCK = D13;
        //I2C
        static const uint8_t SDA = A4;
        static const uint8_t SCL = A5;
        //Serial
        static const uint8_t TX = D0;
        static const uint8_t RX = D1;
};
#endif

1.2.超声波传感器类.描述(抽象设备)

在这个例子中,我选择使用超声波传感器HC-SR04。它有四个引脚:VCCGNDTRIGECHO。尽管在现实中(不管是什么),所有四个引脚都连接到了Arduino,但是程序中只使用了TRIGECHO。到目前为止我不知道该怎么处理这些别针。也许他们不应该出现在代码中。

1.2.1 HC_SR04.h

代码语言:javascript
运行
复制
#ifndef HC_SR04_H
#define HC_SR04_H

#include <inttypes.h>

#include <Arduino.h>

class HC_SR04
{
    public :
        //pin-functions
        virtual uint8_t VCC() = 0;//???
        virtual uint8_t TRIG() = 0;
        virtual uint8_t ECHO() = 0;
        virtual uint8_t GND() = 0;//???
        //device specific functions
        void setup();

        long get_distance();
};
#endif

1.2.2 HC_SR04.cpp

代码语言:javascript
运行
复制
#include "HC_SR04.h"

void HC_SR04::setup()
{
    pinMode( TRIG(), OUTPUT );
    pinMode( ECHO(), INPUT );
}


long HC_SR04::get_distance()
{
    digitalWrite( TRIG(), LOW );
    delayMicroseconds( 2 );
    digitalWrite( TRIG(), HIGH );
    delayMicroseconds( 10 );
    digitalWrite( TRIG(), HIGH );

    return 0.017 * pulseIn( ECHO(), HIGH );
}

2.描述

在这个阶段,程序员应该“插入”表上的所有实际设备,方法是在派生自相应的类描述的子类中重载引脚函数。

2.1超声波传感器(实设备)

2.1.1 US.cpp

代码语言:javascript
运行
复制
#include "Uno.h"
#include "HC_SR04.h"

class US : public HC_SR04
{
    public :
        uint8_t VCC() { return 0; }//What to do with this pin
        uint8_t GND() { return 0; }//What to do with this pin
        uint8_t TRIG() { return Uno::D10; }//wire between TRIG-pin on US and 10th digital pin on Uno
        uint8_t ECHO() { return Uno::D11; }//...
};

3.主文件(.ino文件)

代码语言:javascript
运行
复制
#include "US.cpp"//bad line?

US us;//Create ultrasonic device plugged in as descripted in US.cpp file

void setup()
{
    Serial.begin( 9600 );

    us.setup();
}


void loop()
{
    Serial.println( us.get_distance() );
    delay( 1000 );
}

4.项目目录结构

5.讨论

下面是我对上述方法的看法。当然,可能是错的。

缺点:

  • 额外的抽象级别=(可能)对低内存控制器不利
  • 整个程序分为几个部分。各部分负责与具体设备的通信。(可能)对有依赖设备的项目不利

优势:

  • 整个程序分为几个部分。各部分负责与具体设备的通信。适合于具有许多独立外设的项目。
  • 自描述代码
  • 用于类似设备或具有相同设备的其他项目的可重用代码

请告诉我你怎么想的。一如既往,任何想法、更正、批评等都将不胜感激。

要将程序上传到Arduino,我使用Arduino的Makefile

EN

回答 1

Software Engineering用户

发布于 2018-09-10 09:42:36

封装设备行为的基本想法是个好主意。但是,使用继承来提供配置值(比如设备连接到哪个引脚)并不是正确的方法。

首先,仅仅因为连接了第二个传感器就必须创建一个新的类,这不符合OO设计的原则。Singleton类(其中只应该创建一个实例的类)应该是罕见的,并且通常是不允许的。

其次,更重要的是,对于小型嵌入式系统来说,虚拟功能比非虚拟功能耗费了相当多的内存。对于典型的编译器,在调用虚拟函数时,虚函数每个函数要花费1个指针,而包含虚拟函数的类的每个实例要花费1个指针,外加一些额外的开销。

一种更好、更常见的方法是将引号传递给HC_SR04类的构造函数,如下所示:

代码语言:javascript
运行
复制
#ifndef HC_SR04_H
#define HC_SR04_H

#include <inttypes.h>

#include <Arduino.h>

class HC_SR04
{
    private:
       const uint8_t pin_trig;
       const uint8_t pin_echo;

    public :
        HC_SR04(uint8_t trig, uint8_t echo) :
          pin_trig(trig), pin_echo(echo) {}

        //device specific functions
        void setup();

        long get_distance();
};
#endif

我已经取出了VCC和GND引脚,因为它们通常不应该由软件控制,而是分别连接到电源和地面。

创建这样一个传感器的实例如下所示

代码语言:javascript
运行
复制
HL_SR04 us(Uno::D10, Uno::D11);
票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/378215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档