Continuation of the next article: STM32 for beginners. Interfaces

Previous post: " Another article - STM32 for beginners "



And how do you use it?



In the previous article, we created a class for working with I / O ports, checked. So, what is next? Why stuff this all into class?



Let's take a simple button poll as an example:





For this scheme, in the simplest case, the survey will look like this:



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


But, if you change the ports connected to the buttons in the circuit, you will have to change the polling function. And so in every project. This is not always convenient. I would like to write, test and use once.



Let's rewrite this function under the previously created class:



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


It remains in the main program to initialize the ports and pass them to the function:



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


Where are the interfaces?



And now let's imagine that the f10x series controllers have run out, but there are a bunch of f030s. In terms of performance and the number of pins, it is enough, only you need to change the header for the GetKey function or use ... #ifdef. Make a global header file, in which the type of controller used (something like #define STM32F030) and heap up a bunch of defines. No, this is not why high-level languages ​​were created to get confused in macros!



Let's go the other way. Let's create a class in which we list the virtual methods that we need in life to work with ports:



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




(those methods that are equal to 0 must be defined in the derived class!)

and we will use it as the base one in the Pin class:



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


then the GetKey function will change slightly:



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


Now we don't care about any controller! Even if it is a bus expander working over SPI or I2C. We will consider serial interfaces in the next articles.



So, what is next?



Next, you need to design a class to work with the system timer. But this is already in the next publication.



All Articles