use*_*501 6 c++ electronics class gpio raspberry-pi
我正在使用Raspberry PI GPIO做一些工作.到目前为止,我正在编写代码,就像在C中一样,使用函数将代码段组合在一起.
我的工作已经到了我很高兴一切正常,但现在事情开始变得混乱,所以我想转向面向对象的方法.
这是我面临的问题.
目前我有一个代表我的"设备"的课程.(我构建的硬件连接到GPIO端口.)硬件有2个不同的部分.一部分是"输入"部分,另一部分是"输出"部分.
为了帮助您更好地理解这一点,"输入"部分是一个ADC.(模数转换器.)这是一种将模拟信号转换为10位二进制表示的设备.(如果你不熟悉电子产品.)
"输出"部分只是一个开关一组LED的晶体管.
我想要一个代表ADC板的类,以及一个代表LED板的类,因为它们是两个概念上不同的器件,因为它们没有以任何方式"链接".
这会导致问题,因为在设置模式之前必须将GPIO引脚设置为特定值.值我的意思是"高"或"低",1或0.模式我的意思是"输入"或"输出".这听起来很奇怪,但基本上,如果控制线在上电之前没有设置为正确的LOGIC HIGH和LOGIC LOW值,ADC将变为去同步.(这是一个非常奇怪的设备,即使它被连接到电源也不会通电.(VCC或VDD 5.0V)其中一条控制线发送信号给设备上电.
为了实现上述目的,请考虑GPIO引脚最初处于INPUT模式.为了"使ADC正常工作",我们首先设置引脚上的数据值(HIGH/LOW),然后再将它们更改为OUTPUT模式.这样,当模式从INPUT变为OUTPUT时,数据存在正确的值,我们不会扰乱ADC.
我最初的想法是为ADC提供一个构造函数,它首先设置输出数据的值,然后将需要的引脚从INPUT模式更改为OUTPUT模式.但这迫使我们在LED板级之前构建ADC板级.
这可以通过执行相同代码来设置输出模式的两个构造函数来解决,但这似乎是一个坏主意,因为我们两次调用2位代码 - 这不是一个非常优雅的解决方案.
另一种解决方案是使用GPIOPort类将输入和输出设备组合在一起,但这也不是很优雅,如果我们要添加第二个相同的LED板,则很难修改.(例如.)
我想我想要的是另一个代表GPIOPort本身的类.(我猜是一种抽象的想法?)然后我想我想要"一个班级中的一个班级"来代表ADC板和"一个班级中的一个班级"来代表LED板.我不记得调用这种技术是什么,但通常"外部类"就像一个shell,指向一个类型为"内部类"的对象,以及一个create方法和一个destroy方法.外部类pointer = new type;在create方法和delete pointerdestroy方法中执行类似操作.这允许在需要时调用构造函数,并在需要时调用类析构函数.
关键是GPIOPort类构造函数处理这些对象的创建顺序,它隐藏了main()中的所有对象.在main中,程序员只是做了类似的事情GPIOPort myGPIOPort;,并且处理了你需要的所有东西,所以你不必在main()中包含20行代码来设置输出引脚的数据,这是唯一的其他解决方案.(我上面没有提到.)
所以我的第一个问题是这种技术被称为什么?我认为它被称为包装类,但我的理解是包装类是用于使用基本类型double和int作为对象.(并添加类似clear()或reset()类似的方法.)这是我真正想要做的,还是有更好的方法?(我想这归结为"如何解决我的问题".)
我的第二个问题是,据我所知,我必须制作一些方法(析构函数?)虚拟方法,但我不记得为什么.(或许我不这样做,我只是感到困惑.)
我的第三个问题是,我可以用它来帮助自己理解它,或者我可以在哪里提高我的理解.(参考资料).
谢谢,显然这是一个很长的问题.我试图尽可能多地提供信息来帮助解释这种情况.如果你想要澄清,那么我会尝试改进我说的话.
在将模式从输入更改为输出之前,必须将数据发送到GPIO引脚.
GPIO引脚看起来像全零,因为引脚上有下拉电阻,它们仍然设置为输入.发送的数据在模式更改之前不会出现.
然后将引脚设置为输出模式.(或者其中一些是无论如何.)现在发送的数据出现在引脚上.
如果在发送数据之前将引脚设置为输出模式,则无法阻止ADC上电,因为控制ADC上电的数据引脚可能设置为高电平.它可能被设置为LOW,但没有办法说明,它的状态是未定义的,直到我们在设置模式输出之前告诉GPIO我们想要什么值.幸运的是,我们可以保证所有引脚都处于输入模式.
编辑:我对这篇文章进行了重大编辑,因为我认为这目前不是最好的解决方案。这个编辑与 @MarkusMayer 的答案非常相似,但我以一种非常不同的思维方式(我认为)来实现它,所以也许它会对你有所帮助。
首先,让我们定义一个 GPIO 引脚,它可以是您想要的任何内容(一个类就很好,然后您可以执行pin.setOutput()orpin.set()等操作。我让您按照您想要的方式定义它,让我们假设我们有一个GPIOPin类。
首先,我将抽象板定义为一组引脚,这对我来说看起来非常正确:
template <int N>
class Board {
protected:
Board (std::array <GPIOPin, N> const& pins) : _pins(pins) { }
std::array <GPIOPin, N> _pins ;
};
Run Code Online (Sandbox Code Playgroud)
然后我定义接口 和ADC,LEDs它也是抽象的:
class ADC {
public:
ADC () { }
float read () { }
} ;
class LEDs {
public:
LEDs () { }
void set (int) { }
} ;
Run Code Online (Sandbox Code Playgroud)
ADC现在我可以使用和创建代表真实板的内容LED:
class MyBoard : public Board <5> { // Let's assume it's connect to 5 bits
public:
MyBoard (std::array <GPIOPin, N> const& pins) : Board<5>(pins) {
// Here you can initialize what you want
}
} ;
Run Code Online (Sandbox Code Playgroud)
然后你创建自己的ADC并且LED:
class AD7813 : public ADC {
Board <5> _board ;
public:
AD7813 (Board <5> *board) : ADC(), _board(board) { }
} ;
// Same for the LED
Run Code Online (Sandbox Code Playgroud)
最后,您可以简单地使用它,如下所示:
Board <5> *board = new MyBoard(/* The corresponding GPIO pins. */) ;
ADC *adc = new AD7813(board) ;
LEDs *led = new MyLEDs(board) ;
Run Code Online (Sandbox Code Playgroud)
我没有为MyBoardor定义析构函数Board,但你当然可以。您也可以shared_ptr像@MarkusMayer 一样使用。
编辑结束。
我认为解决这个问题有不同的方法,我将在这里介绍我会做的事情。在嵌入式系统上使用面向对象设计通常很困难,第一件事是你应该几乎到处都有单例类,因为你只有一个ADC(你不能实例化多个 ADC),所以你的 ADC 类(和 LEDBoard 类)应该如下所示:
class ADC {
public:
static ADC *getInstance () {
if (_instance == nullptr) {
_instance = new ADC () ;
}
return _instance ;
}
private:
ADC () ;
};
Run Code Online (Sandbox Code Playgroud)
为了回答您的问题,我将创建一个基类来执行初始化,并且仅执行一次(使用静态成员来了解端口是否已初始化)。
class GPIOs {
protected:
GPIOs () {
if (!GPIOs::_init) {
/* Do what you want. */
GPIOs::_init = true ;
}
}
private:
static bool _init ;
} ;
bool GPIOs::_init = false ;
Run Code Online (Sandbox Code Playgroud)
然后你的ADC类LEDBoard继承自GPIOs:
class ADC : public GPIOs {
public:
ADC *getInstance () { /* ... */ }
private:
ADC () : GPIOs () { } // Call constructor
} ;
Run Code Online (Sandbox Code Playgroud)
然后在您的代码中,您只需执行以下操作:
ADC *adc = ADC::getInstance () ;
Run Code Online (Sandbox Code Playgroud)
您还可以为该类使用单例GPIOs,但由于它是一个抽象类,仅被使用ADC并且LEDBoard已经是单例,因此它不是最有用的。
我确信还有很多其他方法可以解决您的问题,但我想展示的主要思想是使用init可以多次调用的方法/类,而无需因为_init布尔值而进行多次初始化。
| 归档时间: |
|
| 查看次数: |
954 次 |
| 最近记录: |