Et comment l'utilisez vous?
Dans l'article précédent, nous avons créé une classe pour travailler avec les ports d'E / S, cochée. Alors, quelle est la prochaine? Pourquoi mettre tout ça en classe?
Prenons un simple sondage de bouton comme exemple:
Pour ce schéma, dans le cas le plus simple, l'enquête ressemblera à ceci:
int GetKey()
{
volatile uint32_t* addr = reinterpret_cast<uint32_t*>(GPIOA_IDR);
uint32_t ret_val = *addr;
return ret_val & 0x0F;
}
Mais, si vous changez les ports connectés aux boutons du circuit, vous devrez changer la fonction d'interrogation. Et ainsi dans chaque projet. Ce n'est pas toujours pratique. Je voudrais écrire, tester et utiliser une fois.
Réécrivons cette fonction sous la classe créée précédemment:
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;
}
Il reste dans le programme principal pour initialiser les ports et les passer à la fonction:
...
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;
}
Où sont les interfaces?
Et maintenant, imaginons que les contrôleurs de la série f10x sont épuisés, mais il y a un tas de f030. En termes de performances et de nombre de broches, cela suffit, il vous suffit de changer l'en-tête de la fonction GetKey ou d'utiliser ... #ifdef. Créez un fichier d'en-tête global, dans lequel le type de contrôleur utilisé (quelque chose comme #define STM32F030) et accumulez un tas de définitions. Non, ce n'est pas la raison pour laquelle des langages de haut niveau ont été créés pour se confondre dans les macros!
Allons dans l'autre sens. Créons une classe dans laquelle nous listons les méthodes virtuelles dont nous avons besoin dans la vie pour travailler avec les 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); }
};
(les méthodes égales à 0 doivent être définies dans la classe dérivée!)
et nous l'utiliserons comme méthode de base dans la classe Pin:
...
#include "iPin.h"
...
class Pin : public iPin
...
alors la fonction GetKey changera légèrement:
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;
}
Maintenant, nous ne nous soucions d'aucun contrôleur! Même s'il s'agit d'un extenseur de bus fonctionnant sur SPI ou I2C. Nous examinerons les interfaces série dans les prochains articles.
Alors, quelle est la prochaine?
Ensuite, vous devez concevoir une classe pour travailler avec une minuterie système. Mais c'est déjà dans la prochaine publication.