Continuação do próximo artigo: STM32 para iniciantes. Interfaces

Postagem anterior: " Outro artigo - STM32 para iniciantes "



E como você usa isso?



No artigo anterior, criamos uma classe para trabalhar com portas de E / S, marcada. Então, o que vem a seguir? Por que enfiar tudo isso na aula?



Vejamos uma simples votação de botão como exemplo:





Para este esquema, no caso mais simples, a pesquisa terá a seguinte aparência:



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


Mas, se você alterar as portas conectadas aos botões no circuito, terá que alterar a função de polling. E assim em todos os projetos. Isso nem sempre é conveniente. Eu gostaria de escrever, testar e usar uma vez.



Vamos reescrever essa função na classe criada 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;
}


Ele permanece no programa principal para inicializar as portas e passá-las para a função:



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


Onde estão as interfaces?



E agora vamos imaginar que os controladores da série f10x acabaram, mas há um monte de f030s. Em termos de desempenho e número de pinos, basta, basta alterar o cabeçalho da função GetKey ou usar ... #ifdef. Faça um arquivo de cabeçalho global, no qual o tipo de controlador usado (algo como #define STM32F030) e monte um monte de definições. Não, não é por isso que as linguagens de alto nível foram criadas para se confundir em macros!



Vamos por outro caminho. Vamos criar uma classe na qual listamos os métodos virtuais que precisamos na vida para trabalhar com portas:



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




(os métodos que são iguais a 0 devem ser definidos na classe derivada!)

e vamos usá-lo como base na classe Pin:



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


então a função GetKey mudará ligeiramente:



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


Agora não nos importamos com nenhum controlador! Mesmo se for um expansor de barramento trabalhando em SPI ou I2C. Consideraremos as interfaces seriais nos artigos a seguir.



Então, o que vem a seguir?



Em seguida, você precisa criar uma classe para trabalhar com o cronômetro do sistema. Mas isso já está na próxima publicação.



All Articles