我经常想要Arduino板控制几个外围设备。使用#define SOME_PIN 4
构造在一个文档中为所有这些人编写程序对我来说似乎很不方便。尤其是在这种情况下,您必须修改很久以前编写的旧代码。
我选择使用以下方法来组织项目的编程部分。因此,编写代码可以分为三个部分。
在这个阶段,程序员应该描述在他的项目中使用的所有设备。当然,只有那些Arduino编程交互的人(例如传感器、芯片而不是中间电阻器)。在这个阶段,每个设备都由一个类描述类表示.描述类具有特殊的成员函数-引脚函数.这些函数是纯虚拟的,每个函数都打算从Arduino引号集合中返回8位无符号整数值。引脚功能在Arduino和外围设备之间起着导线的作用.Description类还应该包含用于此具体设备的Arduino指令函数。
Arduino也有一个description类,但现在它被用作带有常量的命名空间。到目前为止,不需要这个类的对象。
下面是一个使用该接口的示例。
Arduino Uno R3 description-类仅由静态常量组成,这些常数是引脚号.
#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
在这个例子中,我选择使用超声波传感器HC-SR04。它有四个引脚:VCC
、GND
、TRIG
和ECHO
。尽管在现实中(不管是什么),所有四个引脚都连接到了Arduino,但是程序中只使用了TRIG
和ECHO
。到目前为止我不知道该怎么处理这些别针。也许他们不应该出现在代码中。
#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
#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 );
}
在这个阶段,程序员应该“插入”表上的所有实际设备,方法是在派生自相应的类描述的子类中重载引脚函数。
#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; }//...
};
#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 );
}
下面是我对上述方法的看法。当然,可能是错的。
缺点:
优势:
请告诉我你怎么想的。一如既往,任何想法、更正、批评等都将不胜感激。
要将程序上传到Arduino,我使用Arduino的Makefile。
发布于 2018-09-10 09:42:36
封装设备行为的基本想法是个好主意。但是,使用继承来提供配置值(比如设备连接到哪个引脚)并不是正确的方法。
首先,仅仅因为连接了第二个传感器就必须创建一个新的类,这不符合OO设计的原则。Singleton类(其中只应该创建一个实例的类)应该是罕见的,并且通常是不允许的。
其次,更重要的是,对于小型嵌入式系统来说,虚拟功能比非虚拟功能耗费了相当多的内存。对于典型的编译器,在调用虚拟函数时,虚函数每个函数要花费1个指针,而包含虚拟函数的类的每个实例要花费1个指针,外加一些额外的开销。
一种更好、更常见的方法是将引号传递给HC_SR04类的构造函数,如下所示:
#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引脚,因为它们通常不应该由软件控制,而是分别连接到电源和地面。
创建这样一个传感器的实例如下所示
HL_SR04 us(Uno::D10, Uno::D11);
https://softwareengineering.stackexchange.com/questions/378215
复制相似问题