下一篇文章的续篇:适用于初学者的STM32。介面

一篇:“另一篇文章-STM32面向初学者



以及如何使用它?



在上一篇文章中,我们创建了一个用于处理I / O端口的类,已选中。那么,下一步是什么?为什么要把这些全部塞进课堂?



让我们以一个简单的按钮轮询为例:





对于这种方案,在最简单的情况下,调查将如下所示:



int GetKey()
{
  volatile uint32_t* addr = reinterpret_cast<uint32_t*>(GPIOA_IDR);
  uint32_t ret_val = *addr;
  return ret_val & 0x0F;
}


但是,如果更改连接到电路中按钮的端口,则必须更改轮询功能。在每个项目中都是如此。这并不总是很方便。我想编写,测试和使用一次。



让我们在先前创建的类下重写此函数:



int GetKey(Pin* p0, Pin* p1, Pin* p2, Pin* p3)
{
  int ret_val = p0->Get() + (p1->Get() << 1) + (p2->Get() << 2) + (p3->Get() << 3);
  return ret_val;
}


它保留在主程序中以初始化端口并将它们传递给函数:



...
using namespace STM32F1xx;
Pin key0('a', 0);
Pin key1('a', 1);
Pin key2('a', 2);
Pin key3('a', 3);
...
int main()
{
  key0.ModeInput();
  key1.ModeInput();
  key2.ModeInput();
  key3.ModeInput();
  int key_code = GetKey(&key0, &key1, &key2, &key3);
...
  return 0;
}


接口在哪里?



现在,让我们想象一下f10x系列控制器已经用完了,但是有一堆f030。就性能和引脚数而言,就足够了,您只需要更改GetKey函数的标题或使用... #ifdef。制作一个全局头文件,其中使用的控制器类型(类似于#define STM32F030)并堆积一堆定义。不,这不是为什么创建高级语言来使宏感到困惑的原因!



让我们走另一条路。让我们创建一个类,在其中列出使用端口所需的虚拟方法:



iPin.h
#pragma once

class iPin
{
public:
  virtual void ModeInput()              = 0;
  virtual void ModeAnalogInput()        = 0;
  virtual void ModeInputPulled()        = 0;
  virtual void ModeOutput()             = 0;
  virtual void ModeOutputOpenDrain()    = 0;

  virtual void Set(bool st) = 0;
  virtual bool Get() = 0;

  virtual void Reverse() { Set(!Get());}

  void On()              { Set(true);  }
  void Off()             { Set(false); }
};




(那些等于0的方法必须在派生类中定义!)

,我们将在Pin类中将其用作基类:



...
#include "iPin.h"
...
class Pin : public iPin
...


然后GetKey函数将略有变化:



int GetKey(iPin* p0, iPin* p1, iPin* p2, iPin* p3)
{
  int ret_val = p0->Get() + (p1->Get() << 1) + (p2->Get() << 2) + (p3->Get() << 3);
  return ret_val;
}


现在我们不在乎任何控制器!即使它是通过SPI或I2C工作的总线扩展器。在下一篇文章中,我们将考虑串行接口。



那么,下一步是什么?



接下来,您需要设计一个用于使用系统计时器的类。但这已经在下一个出版物中了。



All Articles