Continuación del siguiente artículo: STM32 para principiantes. Interfaces

Publicación anterior: " Otro artículo - STM32 para principiantes "



y como lo usas?



En el artículo anterior, creamos una clase para trabajar con puertos de E / S, marcada. Entonces, ¿qué sigue? ¿Por qué meter todo esto en clase?



Tomemos como ejemplo una simple encuesta de botones:





Para este esquema, en el caso más simple, la encuesta se verá así:



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


Pero, si cambia los puertos conectados a los botones en el circuito, tendrá que cambiar la función de sondeo. Y así en cada proyecto. Esto no siempre es conveniente. Me gustaría escribir, probar y usar una vez.



Reescribamos esta función en la clase creada anteriormente:



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;
}


Queda en el programa principal inicializar los puertos y pasarlos a la función:



...
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;
}


¿Dónde están las interfaces?



Ahora imaginemos que los controladores de la serie f10x se han agotado, pero hay un montón de f030. En términos de rendimiento y número de pines, es suficiente, solo necesita cambiar el encabezado de la función GetKey o usar ... #ifdef. Cree un archivo de encabezado global, en el que el tipo de controlador utilizado (algo como #define STM32F030) y acumule un montón de definiciones. No, ¡no es por eso que se crearon lenguajes de alto nivel para confundirse en macros!



Vayamos por el otro lado. Creemos una clase en la que enumeramos los métodos virtuales que necesitamos en la vida para trabajar con puertos:



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); }
};




(¡aquellos métodos que son iguales a 0 deben estar definidos en la clase derivada!)

y lo usaremos como base en la clase Pin:



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


entonces la función GetKey cambiará ligeramente:



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;
}


¡Ahora no nos importa ningún controlador! Incluso si es un expansor de bus que trabaja sobre SPI o I2C. Consideraremos las interfaces seriales en los próximos artículos.



Entonces, ¿qué sigue?



A continuación, debe diseñar una clase para trabajar con un temporizador del sistema. Pero esto ya está en la próxima publicación.



All Articles