Qu’est-ce que l’affichage dynamique ? Indicateur à sept segments. Pour ceux qui n'en ont jamais assez

Mis à jour le 03/04/15. Salut tout le monde. Dans le dernier article, nous avons examiné l'algorithme permettant de communiquer avec l'écran LCD, ainsi que de lui transmettre des informations, et de l'avoir testé dans un simulateur. Dans cet article, je parlerai brièvement d'une méthode « peu coûteuse » d'affichage d'informations - c'est indicateur à sept segments

, qui est le plus simple des indicateurs, permettant d'afficher des chiffres arabes, ainsi que certains symboles pouvant y être affichés. Nous considérerons également un programme C pour AVR et une connexion au matériel et au simulateur. Pour afficher les lettres, des indicateurs multi-segments et matriciels plus complexes sont utilisés. Mais ici, nous parlerons de sept segments... Nous examinerons également ce qu'est affichage dynamique
, afin d'afficher instantanément la valeur mesurée. Pour ce faire, nous considérerons l'utilisation d'interruptions dans le programme.

Il faut donc savoir que les indicateurs sont livrés avec une anode et une cathode communes, comme dans la figure ci-dessous. J'avais sous la main un indicateur à cathode commune (partie inférieure de la figure) dont la sortie de commande est connectée au moins. C'est avec cela que nous allons travailler. S'il y a plusieurs indicateurs, alors les cathodes sont contrôlées par plusieurs pattes MK. !!! Mais utilisez toujours des transistors, parce que... Les ports d'E/S peuvent griller en raison du courant relativement élevé. J'ai utilisé des transistors 315 ordinaires. Dans la figure ci-dessous, j'ai montré une connexion approximative, à travers eux, de la sortie de contrôle de l'indicateur et du contrôleur. Pour l'installation, nous avons besoin de 11 pattes de microcontrôleur, c'est-à-dire pour afficher des informations sur les segments il y a 8 pattes (7 + point) et une patte pour chaque indicateur pour le contrôler, j'en ai trois, donc il y a aussi trois pattes de contrôle. Ci-dessous, j'ai donné et décrit le programme. Pour contrôler les segments, nous utiliserons les broches d'un port, afin de ne pas nous tromper. A écrit pour un microcontrôleur ATmega8

. Si vous souhaitez vous débarrasser de la "pierre", ce n'est pas un problème, par exemple, dans lequel vous pouvez facilement modifier les paramètres d'une autre "pierre", il s'agit principalement de numéros de broches et de ports. Les règles générales d'universalité et de transfert y sont également décrites.

Dessin de connexion d'un transistor à un MK et à un indicateur. Passons à programme. Dans ce petit programme (sur ) J'ai donné un exemple d'inclusion de trois éléments indicateurs et d'affichage d'un nombre avec une virgule. Utilisation d'une minuterie et d'une interruption pour la sortie vers l'indicateur. Lors de l'écriture du programme, nous devons décider quelle broche de port doit correspondre au segment sur l'indicateur. L'élément indicateur lui-même est illustré dans la figure ci-dessous. Sur le côté se trouve une description de la connexion des broches aux segments de l'élément indicateur (broche du port – numéro de la jambe de l'élément (Fig. ci-dessus) – lettre du segment – ​​​​numéro dans le tableau responsable de l'allumage les segments sur l'élément).

PB0 - 12 - contrôle du premier élément

PB6 - 9 - contrôle du deuxième élément
PB7 - 8 - contrôle du troisième élément
PD7 – 11 – (A) – 128
PD6 – 10 – (F) – 64
PD5 – 7 – (B) – 32
PD4 – 5 – (G) – 16
PD3 – 4 – – 8
PD2 – 3 – (DP) – 4
PD1 – 2 – (D) – 2
PD0 – 1 – (E) – 1

#inclure
#inclure
#inclure
/*Définissons un élément à sept segments pour chaque broche de port (figure ci-dessus)*/
#définir un 128
#définir b 32
#définir à partir de 8
#définir d 2
#définir e 1
#définir f 64
#définir g 16
#définir dp 4
/*Ces macros contiennent des nombres correspondant à deux élevés à la puissance,égal au numéro du « tronçon » du port auquel le segment indicateur avecle même nom que la macro.*/
court int non signé j, k = 0 ; /*les variables sont utilisées dans la macro d'interruption*/
flotter je = 0 ;
/*Variable pour la sortie vers l'indicateur*/ court non signé
entier w = 0 ;
/*Indicateur variable d'allumage de la pointe*/
emplacement de caractère non signé ;
/*Un tableau qui stocke les nombres dont vous avez besoin sortie via le port vers l'indicateur afin qu'il affiche un chiffre égal au nombre
{
élément de tableau. Les nombres dépendent uniquement des macros.*/
vide Slot_init()
/*Fonction d'initialisation de l'indicateur*/
Emplacement = (a+b+c+d+e+f);
Emplacement = (b+c) ;
Emplacement = (a+b+g+e+d);
Emplacement = (a+b+g+c+d); .
Emplacement = (f+g+b+c);
/*Les noms de macro correspondent aux noms de segments indicateurs*/
Emplacement = (a+f+g+c+d);
Emplacement = (a+f+g+c+d+e);
}
Emplacement = (a+b+c) ;
Emplacement = (a+b+c+d+e+f+g);
Emplacement = (a+b+c+d+f+g);
Emplacement = dp ; /*Point*/
{
/*Ces variables stockent les nombres qui doivent être affichés*/
char Elem1, Elem2, Elem3;/* La fonction extrait les chiffres d'un nombre à trois chiffres Nombre */
Affichage vide (numéro flottant)
{
flotteur N1, N2 ;/*Variables pour la fonction modf*/
N1 = modf(Nombre, &N2);
}
/* Diviser le nombre en parties entières et fractionnaires, N1 = fractionnaire
N2 = entier*/
while (Nombre >= 100) /*Centaines*/
{
Nombre -= 100 ;
Numéro1++ ;
}
while (Nombre >= 10) /*Dizaines*/
{
Nombre -= 10 ;
Numéro2++ ;
}
Numéro3 = Nombre ; /*Unités*/
Elem1 = Emplacement ;
if (w == 1) /*Condition d'inclusion d'un point sur le deuxième élément*/
{
Elem2 = (Emplacement|0×04) ;
/*addition logique avec un pin correspondant à un point*/ w = 0 ;
}
/*Éteignez le point*/
autre
Elem2 = Emplacement ;
}
Elem3 = Emplacement ;
{
int main (void) /*début du programme principal*/ DDRB = 0Xff ;
/*configurer toutes les broches du port B comme sorties*/
DDRD = 0xff ;
/*configurer toutes les broches du port D comme sorties*/
PORTD = 0×00 ;
/*Définir 0*/
PORTB |= _BV(PB6);
PORTB |= _BV(PB0);
PORTB |= _BV(PB7);
slot_init();<sei();
/*Activer l'interruption générale*/</*Initialisation du timer T0*/
TIMSK = (1 /*Drapeau d'activation du dépassement de la minuterie du compteur T0*/
{
TCCR0 = (0
/* 1 000 000/8 = 125 000 = 125 000/256 = 488,28 Hz */
tandis que (1)
/*Boucle sans fin, affiche la variable sur l'indicateur*/
_delay_ms(1000);
} je = je + 0,1 ;
} si (je == 99,9)

je = 0,0 ; afficher(je); /*Support de fermeture de boucle sans fin*/, /*Parenthèse fermante du programme principal*/

L'étape suivante consiste à ajouter une fonction d'interruption qui sera déclenchée par un vecteur spécial TIMER0_OVF_vect, responsable des interruptions de débordement T0. Pour cela, nous utilisons le temporisateur/compteur matériel T0. Ci-dessus, dans le programme, nous avons noté les paramètres de la minuterie et calculé la fréquence à laquelle l'affichage dynamique se produira.
{
Ceux. Quand le registre de comptage du compteur déborde
Le programme général s'arrête et la fonction ci-dessous est exécutée, après en être sorti l'exécution du programme principal continue.<=30; j++) { } ISR (TIMER0_OVF_vect)
PORTB &= 0x3e; //Nettoyage PB7, PB6, PB0_pour (j = 0; j
// Délai pour désactiver le transistor
{
(k == 3) ? k = 0 : k++ ;<< PINB7); /*Variable responsable de la séquence d'incendie
indicateur à trois éléments, 0,1 et 2. A un certain nombre, 1 est mis sur une certaine jambe, puis le transistor s'ouvre et les segments indicateurs correspondant à la variable Elemn s'allument */
interrupteur (k)
cas 0 : PORTB |= (1<< PINB6); // Unités
PORTD = Elem3;
interrupteur (k)
casser;<< PINB0); cas 1 : PORTB |= (1
// Des dizaines
}
}

PORTD = Elem2; cas 2 : PORTB |= (1 // Des centaines PORTD = Elem1 ; Le programme ci-dessus a été testé en matériel et dans le simulateur. Ci-dessous les photos en conséquence.délai de désactivation du transistor - entrez 50 cycles d'horloge dans le simulateur. Tout devrait fonctionner.

Au fur et à mesure que nous publiions des articles, notre programme pour l'indicateur a légèrement changé, à savoir, nous avons ajouté un quatrième élément, affichant un signe moins, les symboles « H » et « C », le format de sortie de l'heure et la combinaison de tous les modes. Alors lisez, analysez et expérimentez.

Vous trouverez ci-dessous les sources et le projet basé sur le matériel ci-dessus.

(Téléchargements : 795 personnes)

C'est tout. Dans le prochain article, je décrirai la connexion des capteurs de température et afficherai les informations sur l'indicateur. À bientôt!

Les indicateurs sont généralement situés dans des endroits pratiques pour visualiser les informations qui y sont affichées. Le reste des circuits numériques peut être situé sur d'autres cartes de circuits imprimés. À mesure que le nombre d'indicateurs augmente, le nombre de conducteurs entre le tableau indicateur et le tableau numérique augmente. Cela entraîne certains inconvénients dans le développement de la conception et du fonctionnement de l'équipement. La même raison entraîne une augmentation de son coût.

Le nombre de conducteurs de connexion peut être réduit en faisant fonctionner les indicateurs en mode impulsionnel. L'œil humain a une inertie, et si vous forcez les indicateurs à afficher les informations un par un à une vitesse suffisamment élevée, alors il semblera à la personne que tous les indicateurs affichent leurs informations en continu. De ce fait, il est possible de transmettre alternativement les informations affichées via les mêmes conducteurs. Généralement un taux de rafraîchissement de 50 Hz est suffisant, mais il vaut mieux augmenter cette fréquence à 100 Hz.

Examinons le schéma fonctionnel des indicateurs LED à sept segments illustré à la figure 1. Ce circuit peut fournir une indication dynamique des informations numériques émises.


Figure 1. Schéma fonctionnel de l'indication dynamique

Dans le diagramme illustré à la figure 1, quatre chiffres numériques sont affichés. Chaque bit est brièvement connecté à sa propre entrée du commutateur. Le générateur permet de régler la vitesse de mise à jour des informations sur les indicateurs. Le compteur binaire génère séquentiellement quatre états du circuit et, grâce aux touches, fournit une alimentation alternative aux indicateurs à sept segments.

De ce fait, lorsque le commutateur fournit un code décimal binaire depuis l'entrée A vers les entrées du décodeur à sept segments, ce code est affiché sur l'indicateur HL1. Lorsque le commutateur fournit le code binaire-décimal de l'entrée B aux entrées du décodeur à sept segments, ce code est affiché sur l'indicateur HL2, et ainsi de suite, dans un cycle.

Le taux de mise à jour des informations dans le schéma considéré sera quatre fois inférieur à la fréquence du générateur. Autrement dit, pour obtenir une fréquence de scintillement d'indicateur de 100 Hz, une fréquence de générateur de 400 Hz est requise.

Combien de fois avons-nous ainsi réduit le nombre de conducteurs de connexion ? Cela dépend de l'endroit où nous dessinons la section transversale du circuit. Si nous ne laissons que des indicateurs sur le tableau d'indication, leur fonctionnement nécessitera 7 signaux d'information pour les segments et quatre signaux de commutation. Il y a 11 conducteurs au total. Dans un circuit d'affichage statique, nous aurions besoin de 7 × 4 = 28 conducteurs. Comme vous pouvez le constater, les gains sont évidents. Lors de la mise en œuvre d'une unité d'affichage 8 bits, le gain sera encore plus important.

Il y aura un gain encore plus important si la section transversale du circuit est tracée le long des entrées des indicateurs. Dans ce cas, l'unité d'affichage à quatre chiffres ne nécessitera que six conducteurs de signal et deux conducteurs d'alimentation de circuit. Cependant, un tel point de section du circuit d'affichage dynamique est très rarement utilisé.

Calculons maintenant le courant circulant dans chaque segment de LED lorsqu'il s'allume. Pour ce faire, nous utiliserons un circuit équivalent de courant traversant l'un des segments indicateurs. Ce diagramme est présenté à la figure 2.


Comme mentionné précédemment, une LED nécessite un courant de 3 à 10 mA pour un fonctionnement normal. Fixons le courant minimum de la LED à 3 mA. Cependant, en mode de fonctionnement pulsé, la luminosité de l'indicateur diminue N fois, le coefficient N étant égal au rapport cyclique des impulsions de courant fournies à cet indicateur.

Si nous voulons maintenir la même luminosité de la lueur, nous devons alors augmenter de N fois l'amplitude du courant d'impulsion circulant à travers le segment. Pour un indicateur à huit chiffres, le coefficient N est égal à huit. Choisissons dans un premier temps un courant statique traversant la LED égal à 3 mA. Ensuite, pour maintenir la même luminosité de la LED dans l'indicateur à huit chiffres, un courant pulsé sera nécessaire :

Je segmente din = je segmente stat× N= 3mA×8 = 24mA.

Seules certaines séries de microcircuits numériques peuvent difficilement fournir un tel courant. Pour la plupart des séries de microcircuits, des amplificateurs réalisés sur des commutateurs à transistors seront nécessaires.

Déterminons maintenant le courant qui circulera à travers le commutateur qui commute l'alimentation vers les bits individuels de l'unité d'affichage à huit bits. Comme le montre le schéma illustré à la figure 2, le courant provenant de n'importe quel segment de l'indicateur peut circuler à travers la clé. Lorsque le chiffre 8 est affiché, les sept segments de l'indicateur devront être allumés, ce qui signifie que le courant d'impulsion circulant à travers la touche à ce moment peut être déterminé comme suit :

Je cl = je segmentedingue× N segment= 24 mA × 7 = 168 mA.

Comment aimez-vous ce courant ?! Dans les circuits radioamateurs, je rencontre souvent des solutions où le courant de commutation est prélevé directement sur la sortie du décodeur, qui ne peut pas produire un courant supérieur à 20 mA, et je me pose la question : où chercher un tel indicateur ? Dans le noir complet ? Le résultat est un « appareil de vision nocturne », c’est-à-dire un appareil dont les lectures ne sont visibles que dans l’obscurité totale.

Regardons maintenant le diagramme schématique de l'unité d'affichage résultante. Il est illustré à la figure 3.



Figure 3. Diagramme schématique de l'unité d'affichage dynamique

Maintenant que nous avons reçu le circuit d’affichage dynamique, nous pouvons discuter de ses avantages et inconvénients. L'avantage incontestable de l'affichage dynamique est le petit nombre de fils de connexion, ce qui le rend indispensable dans certains cas, comme par exemple pour travailler avec des indicateurs matriciels.

L'inconvénient est la présence de courants d'impulsions importants, et comme tout conducteur est une antenne, l'indication dynamique constitue une puissante source d'interférences. Une autre source d'interférence est l'alimentation électrique.

Veuillez noter que les fronts montants des impulsions de commutation sont très courts, de sorte que leurs composantes harmoniques couvrent la gamme de fréquences radio jusqu'aux ondes ultracourtes.

Ainsi, l'utilisation de l'indication dynamique permet de minimiser le nombre de fils de connexion entre l'appareil numérique et l'indicateur, mais en même temps c'est une puissante source d'interférences, son utilisation dans les appareils de réception radio n'est donc pas souhaitable.

Si, pour une raison quelconque, par exemple la nécessité d'utiliser des indicateurs matriciels, il est nécessaire d'utiliser une indication dynamique, alors toutes les mesures doivent être prises pour supprimer les interférences.

Les mesures visant à supprimer les interférences de l'indication dynamique comprennent le blindage de l'unité, du câble de connexion et des cartes. Utiliser une longueur minimale de fils de connexion, utiliser des filtres d'alimentation. Lors du blindage d'un bloc, il peut être nécessaire de protéger les indicateurs eux-mêmes. Dans ce cas, un treillis métallique est généralement utilisé. Cette grille peut simultanément augmenter le contraste des caractères affichés.

Littérature:

Avec l'article « Affichage dynamique », lire :

Les indicateurs sont conçus pour afficher différents types d'informations à une personne. Le type d'information le plus simple est...
http://site/digital/Indic.php

Les indicateurs de décharge de gaz sont utilisés à la fois pour indiquer des informations binaires et pour afficher des informations décimales. Lors de la construction d'indicateurs décimaux, la cathode...
http://site/digital/GazIndic/

De nos jours, les LED sont utilisées presque partout pour afficher des informations binaires. Cela est dû à...
http://site/digital/LED.php

Principes de fonctionnement des indicateurs à cristaux liquides... Modes de fonctionnement des indicateurs à cristaux liquides... Formation d'une image couleur...
http://site/digital/LCD.php

L'affichage dynamique est l'un des problèmes rencontrés par les programmeurs de microcontrôleurs débutants. On en a beaucoup parlé, mais j'ai décidé de sauvegarder ce qui est connu avec des images et des exemples de code source en C pour faciliter la maîtrise de cette méthode d'affichage.

1 Bases, ou introduction

Tout d’abord, définissons la terminologie que nous utiliserons tout au long de l’article.

Si vous devez contrôler un écran composé d'une seule familiarité à sept segments, cela ne pose aucun problème - il peut être considéré comme 8 LED indépendantes. Si vous devez afficher plus d'informations qu'un seul caractère, les problèmes commencent : 2 emplacements familiers constituent 16 LED, trois - 24, etc., c'est-à-dire que même pour un affichage à trois chiffres, il se peut tout simplement qu'il n'y ait pas assez de broches du microcontrôleur, pas sans oublier les afficheurs à 6 chiffres ou plus et, surtout, les indicateurs matriciels.

Par souci de simplicité, convenons que tous nos indicateurs ont une cathode commune. La solution au problème est assez simple : connectez les bornes des segments de tous les indicateurs entre elles. Maintenant, si vous souhaitez transmettre des informations au premier emplacement familier, vous devez appliquer les niveaux requis aux lignes de segment et connecter la sortie commune du premier indicateur au fil commun du circuit. Bien entendu, des niveaux élevés doivent être présents aux cathodes communes de tous les autres indicateurs. Évidemment, les segments nécessaires du premier indicateur s'allumeront. Pour la sortie vers le deuxième, le troisième, etc. les indicateurs devraient faire de même, c'est-à-dire En appliquant un zéro logique à l'une des cathodes communes, nous sélectionnons le chiffre actuellement affiché et l'état des lignes de segment détermine le symbole visible.

Pour que l'ensemble de l'écran soit perçu comme brillant en permanence, les chiffres doivent être commutés rapidement - plus de 25 fois par seconde. Comme vous pouvez le constater, les niveaux de tous les résultats (qui, soit dit en passant, sont devenus nettement inférieurs à ceux de l'approche habituelle) changent continuellement, c'est-à-dire n'ont pas de niveaux statiques, mais dynamiques, d'où le nom de la méthode d'indication - dynamique.

Image d'affichage dynamique

2 types de mise en œuvre matérielle

2.1 Matrices plates

Si nous faisons abstraction des indicateurs à sept segments, notre affichage peut être représenté comme une matrice de LED individuelles, dont les anodes sont combinées en lignes de la matrice et les cathodes en colonnes. En fait, c'est exactement comme ça.

Évidemment, en fournissant les niveaux requis aux lignes et colonnes de notre matrice, nous pouvons éclairer n'importe quel segment LED élémentaire (alias pixel - c'est un terme plus traditionnel en relation avec les écrans matriciels). Selon la manière exacte dont nous modifions les niveaux sur les lignes et les colonnes, nous pouvons obtenir plusieurs types d'affichage dynamique :

  • par lignes;
  • par colonnes ;
  • segment par segment (par pixel) ;
  • de manière mixte.

Nous avons examiné l'option de colonne dans le chapitre précédent. L'option row n'en diffère que par le fait que les lignes et les colonnes de notre matrice sont permutées. La méthode segment par segment signifie qu'à un instant donné, une seule ligne et une seule colonne contiennent le niveau nécessaire pour allumer la LED. Autrement dit, à un moment donné, une seule LED de toute la matrice peut s'allumer (contrairement aux options précédentes, lorsque toute la ligne ou la colonne entière peut s'allumer en même temps). Cette méthode rappelle le balayage d'un téléviseur, lorsque le faisceau parcourt tout l'écran, éclairant le phosphore aux bons endroits. L'option mixte, comme son nom l'indique, est que des niveaux « actifs » peuvent être présents simultanément sur plusieurs lignes et colonnes à la fois.

Les deux premières options sont très simples à mettre en œuvre et sont donc largement utilisées. La troisième option est utilisée moins fréquemment, car nécessite des taux de mise à jour des informations plus élevés sur les lignes et les colonnes, et le courant moyen traversant le segment (c'est-à-dire la luminosité du segment) dans ce cas est nettement inférieur à celui des autres. La dernière méthode mixte est la moins courante, même si elle présente un certain nombre de qualités positives. Tout d'abord, cette méthode nécessite d'utiliser des sources de courant stables dans les circuits lignes et colonnes, sinon la luminosité des segments lumineux dépendra inévitablement de leur nombre total. Et calculer des combinaisons de signaux sur des lignes et des colonnes n’est pas très simple.

2.2 Matrices multidimensionnelles

Les exemples que nous avons considérés supposent la mise en œuvre d'un affichage monochrome, c'est-à-dire composé de LED monochromes. Que faire si vous souhaitez obtenir un affichage multicolore, par exemple à partir de LED RVB ? Il existe deux solutions possibles.

La première consiste simplement à augmenter le nombre de lignes (ou de colonnes) de notre matrice, en traitant chaque LED RVB comme 3 LED individuelles indépendantes. Le gros inconvénient de cette approche est le triplement du nombre de lignes (ou de colonnes). Un exemple simple montre facilement ce que cela signifie dans la pratique : en utilisant deux microcontrôleurs à microcontrôleur huit bits, nous pouvons avoir une matrice monochrome de segments 8x8 ou une matrice couleur 4x4. Convenez que dans le second cas, il est pratiquement impossible d'afficher quoi que ce soit d'intelligible...

La deuxième voie consiste à passer d’une matrice de segments « plate » à une matrice « multidimensionnelle ». Si le signal de chaque ligne passe par un multiplexeur 1x3, alors on peut imaginer le système d'affichage de LED RVB comme 3 matrices indépendantes de la dimension d'origine : chaque matrice est constituée de LED de la même couleur, et on sélectionne la matrice souhaitée à l'aide du multiplexeur signaux de commande. L'image explique ce qui a été dit.

Évidemment, dans le cas d'une matrice multidimensionnelle, un nombre supplémentaire de lignes de contrôle est également nécessaire, cependant, ce nombre n'est pas si grand : sur les deux mêmes ports du contrôleur, nous pouvons obtenir un écran couleur 7x7 !!!

2.3 Façons de réduire la dimension des matrices

Si le nombre de broches du microcontrôleur est très limité, nous devrons chercher des moyens de réduire le nombre de lignes et de colonnes de notre matrice. Bien entendu, les miracles ne se produisent pas, et dans ce cas, nous devrons payer en utilisant des microcircuits supplémentaires en plus du microcontrôleur. Comme vous l'avez peut-être deviné, vous pouvez utiliser ici la méthode évoquée précédemment des matrices « multidimensionnelles » - après tout, personne ne nous interdira d'utiliser simplement le triple du nombre de LED monochromes au lieu de LED RVB ? L'essentiel est de les disposer de manière appropriée...

On peut donc réduire la dimension de la matrice en utilisant :

  • décodeurs ou multiplexeurs ;
  • registres à décalage.

Nous avons déjà rencontré des multiplexeurs plus tôt, décodeur, comme vous pouvez le deviner, n'est pas fondamentalement différent d'un multiplexeur. Il faut seulement ajouter qu'en utilisant des décodeurs/multiplexeurs à la fois pour les lignes et les colonnes, il est possible de réduire la dimension de la matrice dans les deux dimensions à la fois, mais dans ce cas il peut être nécessaire d'utiliser uniquement une indication dynamique segment par segment, avec tous ses inconvénients.

Les registres à décalage peuvent être bien plus utiles que les décrypteurs. Considérez le diagramme de la figure ci-dessous.

Il est facile de voir que n'importe quel nombre de lignes et de colonnes ne nécessitera qu'une augmentation du nombre de registres, et le nombre de lignes de contrôle du microcontrôleur impliquées restera le même ! Un petit inconvénient de cette approche est qu'à mesure que le nombre de registres dans la chaîne augmente, la vitesse de sortie séquentielle des informations devra être augmentée, ce qui n'est pas toujours facile à réaliser. Par exemple, les microcontrôleurs courants de la famille AVR, il est pratiquement impossible de dépasser la vitesse de sortie série de 10 mégabits/s. En revanche, si vous utilisez d'autres contrôleurs capables de produire des signaux plus rapidement, des problèmes d'un autre ordre peuvent survenir : la propagation d'un signal d'horloge haute fréquence le long d'une longue ligne (et avec un grand nombre de registres ce sera inévitablement un ) se produit complètement différemment d'un circuit basse fréquence, des mesures spéciales seront donc nécessaires lors de la disposition d'un circuit imprimé et d'autres choses que nous ne considérerons pas dans cet article.

3 Méthodes de mise en œuvre du logiciel

Nous ne considérerons pas l'implémentation logicielle de toutes les options d'affichage dynamique mentionnées - cela alourdirait déraisonnablement l'article. Nous nous limiterons à trois exemples parmi les plus courants : une matrice plate avec contrôle direct des lignes et des colonnes, la même avec l'utilisation d'un décodeur, et, enfin, une variante utilisant des registres à décalage. Dans tous les cas, une attention particulière sera portée à toutes les nuances de mise en œuvre du logiciel, c'est-à-dire que le code C sera accompagné d'explications uniquement dans les cas où cela coïncide avec l'intention de l'auteur, et pas du tout avec votre niveau de formation. . Par là, je laisse entendre que vous devriez connaître les bases du C sans moi.

Pour tous les exemples, nous conviendrons que notre affichage est construit sur des indicateurs à sept segments avec une cathode commune.

3.1 La manière la plus simple

De toute évidence, il serait plus pratique dans le programme d'avoir un certain tableau dont le contenu déterminerait sans ambiguïté quels segments dans lesquels les zones familières de l'écran sont éclairées - une sorte d'analogue de la RAM à l'écran.

Introduisons la définition des constantes suivantes :

#define SCR_SZ 6 /* nombre de familiarisations d'affichage */ #define ROWS PORTB /* affichage du port « lignes », soit gestion des segments */ #define COLS PORTD /* port de gestion « colonne », c'est à dire cathodes communes */

Déclarons maintenant le tableau screen :

Caractère non signé SCR ;

Pour commencer, supposons que chaque élément du tableau correspond à la familiarité de l'affichage, et chaque bit de cet élément correspond à un segment spécifique de l'indicateur. Quel bit correspond à quel segment - dans ce cas, cela n'a pas d'importance, tout comme la façon dont ces bits sont définis dans les octets de notre tableau n'a pas d'importance, nous supposerons simplement pour l'instant qu'ils sont déjà là. Pour plus de simplicité, nous supposerons également que les cathodes communes sont connectées aux broches du port COLS séquentiellement : le bit le moins significatif est l'indicateur le plus à droite, puis le deuxième, puis le troisième, etc.

Comment faire en sorte que ce tableau « s'affiche » sur l'écran ? Écrivons le code suivant :

< SCR_SZ; pos++){ ROWS = SCR; COLS = ~(1 << pos); }

Remplira-t-il la fonction requise ? Oui. Mais ce n'est pas bon.

Tout d’abord, veuillez noter que nous n’avons aucun contrôle sur la rapidité avec laquelle le contenu des lignes et des colonnes est mis à jour. Deuxièmement, notez qu'au moment où le nouvel élément du tableau est imprimé sur RANGÉES sur les lignes COLS L'ancien sens est toujours là ! A quoi cela va-t-il conduire ? Oui, d'ailleurs, pendant une fraction de seconde la zone de familiarité affichera des segments de la zone de familiarité voisine, c'est-à-dire certains segments seront faussement éclairés.

Vous pouvez éviter cet effet en procédant ainsi : avant de mettre à jour le contenu RANGÉES, éteignez toujours le lieu familier qui était précédent. Afin de ne pas vous soucier de déterminer la familiarité précédente, vous pouvez tout éteindre en même temps. Notre code prend donc la forme suivante :

Pos de caractère non signé ; tandis que(1) pour(pos = 0; pos< SCR_SZ; pos++){ COLS = 0xFF; ROWS = SCR; COLS = ~(1 << pos); delay(); }

Nous avons ajouté un masquage de tout l'affichage avant de mettre à jour l'état des lignes de segment (en envoyant les cathodes communes au niveau haut, nous éteindrons l'indicateur quel que soit ce qui est présent sur les anodes) et avons introduit un délai en fin de cycle. Désormais, l'affichage fonctionnera beaucoup mieux. Mais avons-nous écrit un bon programme ? Hélas, non.

Le fait est que le cycle d'affichage sans fin alors que cela ne nous permettra tout simplement pas de faire autre chose. Quel genre de programme aurons-nous qui ne pourra afficher que quelque chose sur l'indicateur ?! Bien sûr, tout n'est pas mauvais à 100%, puisque quelque chose d'utile peut être fait en utilisant des interruptions... et au lieu de retarder retard() vous pouvez effectuer certaines actions... Mais tout cela est très, très tordu : il n'est pas conseillé d'effectuer quelque chose de complexe et de fastidieux dans les gestionnaires d'interruptions ; d'un autre côté, si vous faites quelque chose de complexe et de fastidieux au lieu d'un retard, alors il est difficile d'assurer le même temps de calcul, sinon il s'avérera que les lieux familiers brillent pendant différentes périodes de temps, ce qui ressemblera visuellement à leur lueur ou scintillement de luminosité différente.

En général, cette option ne peut être autorisée qu'à titre exceptionnel, uniquement à titre d'exemple pédagogique, ou dans le cas (mais encore une fois, uniquement à titre exceptionnel !), où le problème principal à résoudre est très simple (cela pourrait être, par exemple , le problème de la mesure à l'aide CDA tension et l'afficher sur l'écran).

Que devez-vous faire ? La réponse, comme toujours, est simple : tous les processus qui doivent être exécutés sans que la tâche principale soit résolue (et l'indication, bien sûr, est un tel processus) doivent être effectués à l'aide d'interruptions de minuterie.
Les interruptions arriveront à des intervalles strictement définis, ce qui garantira un éclairage uniforme des panneaux familiers. L'indication en arrière-plan nous permettra simplement d'écrire quelque chose dans le tableau au bon moment dans la boucle principale RCS- et il apparaîtra instantanément sur l'écran ! Et toutes les modifications apportées au code se résumeront au fait qu'au lieu de boucles, nous utilisons une fonction de gestionnaire d'interruption :

ISR(TIMER0_OVF_vect)(char statique non signé pos = 0 ; COLS = 0xFF ; LIGNES = SCR ; COLS = ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

Quelques commentaires.

Variable position, indiquant le numéro de l'enseigne lumineuse actuelle, on en fait une variable statique locale pour qu'elle conserve sa valeur d'interruption en interruption. À la fin de la fonction, nous augmentons indépendamment (après tout, nous n'avons plus de boucle) le numéro du lieu familier jusqu'à atteindre la limite - dans ce cas, nous revenons au début.

Dans le programme principal, nous aurons seulement besoin d'initialiser les ports et le timer (dans ce cas - Minuterie 0), pour qu'il déborde aux intervalles dont nous avons besoin et permettre les interruptions. Après cela, vous n'avez plus besoin de penser à l'indication - elle fonctionnera de manière silencieuse et paisible. Mais comment déterminer l’intervalle de dépassement de minuterie souhaité ? Très simple. L'œil humain perçoit le scintillement d'une fréquence supérieure à 25 Hz comme une lueur continue. Nous avons 6 indicateurs, chacun d'eux doit scintiller à cette fréquence, ce qui signifie que les informations à l'écran doivent être mises à jour avec une fréquence de 25 x 6 = 150 Hz ou plus. Calculons maintenant la valeur du timer prescaler : divisons la fréquence d'horloge du MK par 256 ( Minuterie 0 tout le monde a AVR huit bits, ce qui signifie qu'il déborde après avoir compté jusqu'à 256) - ce sera la valeur souhaitée du pré-échelonneur de minuterie. Bien sûr, il est peu probable que le résultat coïncide avec l'une des valeurs standard du pré-échelle - ce n'est pas un problème, vous pouvez prendre la valeur appropriée la plus petite la plus proche. L’affichage fonctionnera à une fréquence plus élevée, mais cela ne dégradera pas sa qualité ! Un effet secondaire sera une charge importante sur le noyau MK pour l'affichage. Si cela interfère grandement avec le programme principal, vous devrez basculer l'affichage sur une autre minuterie, par exemple une minuterie 16 bits. Minuterie 1, ou entrez un compteur pour les dépassements de minuterie ignorés :

#define SKIP 15 /* nombre d'interruptions de minuterie à ignorer */ ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; char statique non signé skip = SKIP; if (--skip) return; skip = SKIP; COLS = 0xFF; ROWS = SCR ; COLS = ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

Dans ces exemples simplifiés, nous supposons qu'au port COLS, à l'exception des cathodes communes des indicateurs, rien d'autre n'est connecté. Cependant, dans la vraie vie, une telle chance n'arrive pas souvent et quelque chose d'autre est très probablement lié aux lignes restantes de ce port. Par conséquent, lors de l'organisation d'un affichage dynamique, vous devez toujours vous assurer que l'état de toutes les lignes de port non directement impliquées dans l'affichage reste inchangé. Cela se fait simplement : au lieu de simplement écrire une nouvelle valeur sur le port, vous devez utiliser le masquage des bits inutiles :

COLS |= 0x3F; // donc on éteint toute familiarité COLS &= ~(1<

Les deux opérateurs ne modifient pas la valeur des bits de poids fort du port COLS.

3.2 Méthode avec décodeur

Le décodeur peut être utilisé soit pour convertir HEXAMEN ou BCD coder en symboles à sept segments, ou pour sélectionner l’une des colonnes de la matrice. Les deux options différeront de la méthode la plus simple évoquée précédemment uniquement par la manière dont la sortie vers les ports sera organisée. RANGÉES et/ou COLS, auquel seront connectées les entrées du décodeur.
Une option pour utiliser un décodeur pour obtenir un symbole à sept segments :

ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; COLS |= 0x3F; ROWS = (ROWS & 0xF0) | (SCR & 0x0F); COLS &= ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

Comme vous pouvez le constater, les modifications sont minimes - avant d'afficher RANGÉES code de caractère du tableau RCS, les bits les plus significatifs sont masqués, après quoi les bits les moins significatifs sont définis conformément au code de caractère. Autrement dit, nous pensons que le décodeur est connecté aux 4 bits de poids faible du port RANGÉES.

J'espère qu'il ne sert à rien de donner un exemple de décodage des colonnes - tout est déjà clair.

3.3 Méthode d'enregistrement

Bien que l'indication dynamique utilisant des registres à décalage ne soit pas fondamentalement différente des méthodes évoquées précédemment, il existe plusieurs options pour sa mise en œuvre. Nous considérerons le plus simple : la sortie de bits uniquement par logiciel. Et dans la mise en œuvre d'autres (en utilisant USI/USART/IPS/TWI) vous pouvez vous y essayer vous-même.

Pour la variante de l'affichage précédemment sélectionné des emplacements familiers à 6 et sept segments, on utilise 2 registres à décalage du type 74HC595. Ce registre est contrôlé par trois signaux : des impulsions d'horloge d'entrée de données série CLK, les données réelles DONNÉES et une impulsion de sortie parallèle simultanée des informations écrites dans le registre ENSEMBLE. Déclarons les macros correspondantes (pour plus de simplicité, nous enverrons tous les signaux à un seul port) :

#define CLK _BV(PB0) #define DATA _BV(PB1) #define SET _BV(PB2) #define REG_PORT PORTB

Pour écrire dans un registre, il est pratique d’écrire une fonction distincte :

Décalage de vide statique (char non signé d)( char non signé i; pour (i = 0; i< 8; i++){ // устанавливаем нужный уровень DATA if(d & 1) REG_PORT |= DATA; else REG_PORT &= ~DATA; REG_PORT |= CLK; // даем импульс CLK REG_PORT &= ~CLK; d >>= 1; } }

Il est fortement conseillé de rendre cette fonction statique, car il sera utilisé dans le gestionnaire d'interruption. Le compilateur créera très probablement des fonctions statiques sous la forme en ligne-insertions dans le gestionnaire d'interruption, c'est-à-dire il n'y aura pas d'utilisation inutile de la pile, ce qui n'est pas garanti pour les fonctions non statiques.

Maintenant, notre gestionnaire d'interruption ressemblera à ceci :

ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; shift(SCR); shift(~(1<< pos)); REG_PORT |= SET; // выдаем импульс SET REG_PORT &= ~SET; if(++pos == SCR_SZ) pos = 0; }

Étant donné que les données écrites dans les registres apparaissent simultanément à leurs sorties, il n'est pas nécessaire d'éteindre les indicateurs au préalable. Il ne faut pas oublier que la sortie séquentielle logicielle est un processus assez long, en particulier pour les matrices de grandes dimensions, elle doit donc être optimisée autant que possible pour la vitesse. Cela peut être mieux fait en utilisant le matériel de sortie série trouvé dans le MCU.

4 Pour ceux qui n'en ont jamais assez

Vous vous êtes donc familiarisé avec les bases de la mise en œuvre de l’affichage dynamique. Mais comme d’habitude, les questions ne diminuent pas, mais augmentent. En anticipant certaines d'entre elles, j'essaierai d'apporter immédiatement les réponses nécessaires.

4.1 Anodes, cathodes – que choisir ?

Tout ce que nous avons considéré précédemment concernait les indicateurs à cathodes communes. Et si vous souhaitez l'utiliser avec des anodes communes ? En général, tout reste pareil, sauf qu'avant de sortir, il faudra inverser les données - la suppression de la familiarité s'effectue en sortant des zéros dans COLS, allumage - respectivement, unités et segments dans RANGÉES seront inclus avec des zéros au lieu de uns. Le gestionnaire d'interruption ressemblerait donc à ceci :

ISR(TIMER0_OVF_vect)( char statique non signé pos = 0 ; COLS &= 0xC0 ; ROWS = ~SCR ; COLS |= (1<< pos); if(++pos == SCR_SZ) pos = 0; }

C'est simple. À moins, bien sûr, que vous n'essayiez d'écrire un code universel adapté à la fois aux anodes communes et aux cathodes communes. Il existe deux manières de procéder : soit en utilisant des directives de compilation conditionnelle, soit en utilisant une fonction de conversion. Je vais vous démontrer la première option et vous suggérer de réfléchir à la seconde par vous-même.

#define COMMON_ANODE 1 ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; #if COMMON_ANODE != 1 COLS &= 0xC0; ROWS = ~SCR; COLS |= (1<< pos); #else COLS |= 0x3F; ROWS = SCR; COLS &= ~(1 << pos); #endif if(++pos == SCR_SZ) pos = 0; }

Bien que cela soit un peu fastidieux, après l'avoir écrit une fois, vous pouvez l'utiliser dans tous les projets sans pratiquement aucun changement.

4.2 Scintillement

Dans de nombreux cas, l'écran est utilisé non seulement comme moyen d'afficher des informations provenant de l'intérieur de l'appareil, mais également pour afficher les entrées de l'utilisateur. Et dans ce cas, il faut pouvoir en quelque sorte séparer l'immuable du modifiable sur l'écran. Le moyen le plus simple d'y parvenir est de faire scintiller le lieu familier correspondant (ou plusieurs lieux familiers).

C'est très facile à faire. Introduisons une variable globale, dont chaque bit unitaire désignera un symbole clignotant :

caractère non signé clignotant = 0 ;

Modifions maintenant légèrement le gestionnaire d'interruption :

ISR(TIMER0_OVF_vect)( char statique non signé pos = 0 ; entrée de caractère statique non signé = 0 ; COLS |= 0x3F ; if(!(clignotement & (1<

Comme vous pouvez le voir, une seule variable statique a été ajoutée : le compteur d'entrées dans le gestionnaire d'interruptions. entrée, et un opérateur de test de condition. La logique est simple : la sortie de la prochaine familiarité n'est effectuée que si soit dans le bit correspondant clignoter zéro ou le bit le plus significatif du compteur entrée est égal à 1. Si, supposons, clignoter contient uniquement des zéros, alors cette condition est toujours remplie - tous les lieux familiers sont affichés. Si clignoter contient un 1 dans l'un de ses bits, alors le signe correspondant ne sera affiché qu'au moment où le bit de poids fort du compteur est égal à 1. Puisque le compteur est incrémenté à chaque fois que le gestionnaire d'interruption est entré, le signe correspondant sera scintillement avec une fréquence 128 fois inférieure à la fréquence d'interruption.

4.3 Réglage de la luminosité des segments

J'ai écrit sur le réglage de la luminosité dans un article séparé, intitulé ainsi.

4.4 Distribution arbitraire des épingles

Il a été dit plus tôt que le bonheur de consacrer un port MK entier à l'affichage est assez rare. Mais il est encore plus rare d'obtenir une trace pratique d'une carte de circuit imprimé si un port est entièrement utilisé pour les lignes et l'autre port est utilisé pour les colonnes de la matrice d'affichage. Beaucoup plus souvent, un traçage optimal n'est obtenu que lorsque les lignes et les colonnes sont mélangées entre deux ou même plusieurs ports du microcontrôleur. Vous n'aurez pas à sacrifier la beauté du circuit imprimé si vous organisez un réarrangement logiciel des bits pendant l'affichage.

Regardons un exemple abstrait. Que le meilleur traçage soit fourni avec la répartition suivante des signaux le long des lignes des ports MK :

Segment A

Segment B

Segment H

Segment C

Segment D

Segment G

Segment E

Segment F

Comme vous pouvez le constater, les lignes matricielles sont mélangées entre les trois ports, et toutes les lignes inutilisées de ces ports ne doivent naturellement pas changer de niveau pendant le processus d'affichage.

Il est préférable de commencer à développer une fonction d'indication dynamique dans ce cas en répartissant les segments sur les bits de symbole. Auparavant, nous croyions que dans le tableau RCS Nous stockons des masques de bits de caractères, c'est-à-dire Ceux dans l'octet indiquent des segments lumineux. Nous n’avons pas réfléchi à quel bit correspond à quel segment. Il est donc temps d’y réfléchir.

Il convient de peindre la destination des lignes portuaires sous la forme de trois plaques :

1

UN

0

4

H

3

2

B

F

E

5

G

D

C

Nous devons rassembler tous les segments en un seul octet. Cela devra se faire avec des opérations de décalage, il faudra donc essayer de les répartir de manière à effectuer un minimum de décalages. Parlons.

Si les bits du segment FEGDC laisser dans le symbole pour qu'ils tombent dans PORTD sans décalages, alors le segment H peut également rester dans le 6ème bit du symbole, et il n'a pas non plus besoin d'être décalé avant la sortie PORTC, mais pour les segments UN Et DANS les bits 7 et 3 resteront, c'est-à-dire très probablement le segment DANS devra être décalé de 3 positions avant la sortie, et le segment UN- par 6. Je me concentrerai sur cette option, et vous pourrez continuer à rechercher les décalages minimaux (les décalages de plusieurs positions ne sont pas une opération si rapide, il est donc conseillé de réduire leur nombre au minimum).

Ainsi, dans notre cas, la répartition des bits sur l'octet de caractère était la suivante :

UN

H

F

E

B

G

D

C

Marquons les masques de bits pour la sortie vers les ports correspondants :

D

0

0

1

1

0

1

1

1

0x37

B

1

0

0

0

0

0

0

0

0x80

C

0

1

0

0

1

0

0

0

0x48

À l'aide de ces masques, nous utilisons l'opération « ET au niveau des bits » pour sélectionner les bits nécessaires à la sortie vers le port.

Déclarons les constantes du masque :

#définir MASKD 0x37 #définir MASKB 0x80 #définir MASKC 0x48

Auparavant, nous sortions le symbole sur un seul port RANGÉES, cette procédure sera désormais divisée en trois parties :

PORTD = (PORTD & ~MASKD) | (SCR et MASQUE); PORTB = (PORTB & ~MASKB) | ((SCR & MASKB) >> 6); PORTC = (PORTC & ~MASKC) |

((SCR & _BV(6)) | (((SCR & _BV(3)) >> 3); PORTC Veuillez noter que pour le retrait à un bit doit être émis sans décalage, et le second - avec un décalage, donc au lieu de MASQUEC J'ai dû utiliser des macros distinctes.

_BV()

Il reste maintenant à décider comment éteindre et éclairer les lieux familiers correspondants. Déclarons les constantes correspondant aux bits de contrôle de familiarité :

#define COM0 _BV(0) #define COM1 _BV(3) #define COM2 _BV(4) #define COM3 _BV(5) #define COM4 _BV(7) #define COM5 _BV(3) #define COM_D (COM5) #define COM_C (COM2 | COM3 | COM4) #définir COM_B (COM0 | COM1) Pour éteindre toutes les connaissances, vous devez envoyer les constantes correspondantes aux ports:

COM_x

Mais pour activer la familiarité, il faudra être délicat (cela ne sert à rien de sortir sur les trois ports, car un seul bit sera actif dans un port spécifique, en fonction de la valeur position), par exemple en utilisant l'opérateur changer:

Switch(pos)( cas 0 : PORTB &= ~COM0; pause; cas 1 : PORTB &= ~COM1; pause; cas 2 : PORTC &= ~COM2; pause; cas 3 : PORTC &= ~COM3; pause; cas 4 : PORTC &= ~COM4 ; cas 5 : PORTD &= ~COM5 ;

Ce n'est pas la plus jolie façon, mais ça marche.

Ainsi, notre gestionnaire d'interruption prend la forme suivante :

ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; entrée de caractère statique non signé = 0; // supprimer PORTD |= COM_D; PORTC |= COM_C; PORTB |= COM_B; // imprimer PORTD = (PORTD & ~MASKD) | ( SCR & MASKD); PORTB = (PORTB & ~MASKB) | ((SCR & MASKB) >> 6); PORTC = (PORTC & ~MASKC) | / clignote si (! (clignote & (1<< pos)) || (++entry & 0x80)) { switch(pos){ case 0: PORTB &= ~COM0; break; case 1: PORTB &= ~COM1; break; case 2: PORTC &= ~COM2; break; case 3: PORTC &= ~COM3; break; case 4: PORTC &= ~COM4; break; case 5: PORTD &= ~COM5; break; } } if(++pos == SCR_SZ) pos = 0; }

Il reste maintenant à comprendre comment décrire plus facilement les symboles pour la sortie... Je propose de faire ce qui suit : définir des constantes correspondant aux bits des segments, puis « construire » les symboles nécessaires à partir de ces constantes :

// segments élémentaires #define _A _BV(7) #define _B _BV(3) #define _C _BV(0) #define _D _BV(1) #define _E _BV(4) #define _F _BV(5) #define _G _BV (2) #define _H _BV(6) // symboles numériques #define d_0 (_A | _B | _C | _D | _E | _F) #define d_1 (_B | _C) #define d_2 (_A | _B | _G | _D | _E) // et ainsi de suite

Ainsi, si vous devez afficher un zéro à l’extrême droite de l’afficheur, il vous suffit d’écrire au bon endroit :

RCS = d_0 ;

Si dans un autre projet vous devez répartir les bits différemment, vous modifierez uniquement les nombres dans les macros J'ai dû utiliser des macros distinctes pour les segments élémentaires, et tous les symboles seront « refaits » automatiquement. Pour les cas les plus simples décrits au début, vous n'aurez rien d'autre à faire, mais pour l'option « réarrangement des bits », il faudra bien sûr bricoler.

4.5 Prise en charge des boutons

Avec la pénurie traditionnelle de broches MK, le problème d'un grand nombre de boutons, dont aucun appareil peut rarement se passer, est très aigu. Diverses inclusions matricielles, etc. sont utilisées. astuces, cependant, en compliquant légèrement la fonction d'affichage dynamique, il est facile d'avoir à votre disposition autant de boutons qu'il y a de familiarités dans l'affichage, et dans ce cas vous n'aurez en plus besoin d'utiliser qu'un seul port du microcontrôleur. Certes, il faudra quand même installer une diode sur chaque bouton.

Ceci est représenté schématiquement sur la figure.

Et le programme ressemble à ceci :

#define keypin() (!(PIND & _BV(KEY))) ISR(TIMER0_OVF_vect)( char statique non signé pos = 0; entrée de caractère statique non signé = 0; char statique non signé tmp_key = 0; ROWS = 0; if(keypin( )) clé_tmp |= 1<< pos; COLS |= 0x3F; if(!(blink & (1<< pos)) || (++entry &0x80)){ ROWS = (ROWS & 0xF0) | (SCR & 0x0F); COLS &= ~(1 << pos); } if(++pos == SCR_SZ){ pos = 0; key = tmp_key; tmp_key = 0; } }

Ici CLÉ- c'est une macro qui fixe le bit du port sélectionné sur lequel tous les boutons sont "connectés", macro clé () renvoie la valeur logique TRUE si la broche sélectionnée est logique basse. Dans l'exemple, les boutons sont connectés à PORTD.

Chaque fois qu'une interruption de minuterie se produit, tous les segments sont d'abord éteints - cela est nécessaire pour que le courant traversant les LED ne fasse pas que le bouton enfoncé ne soit pas détecté par erreur. Après cela, l'entrée du bouton est interrogée - si le niveau est bas, cela signifie que le bouton connecté à la cathode pos correspondante est enfoncé. En variable clé_tmp les états des boutons sont accumulés et réécrits dans une variable globale clé après la fin du cycle d’affichage. Il ne vous reste plus qu'à analyser le sens de temps en temps clé et traiter les clics détectés :

Char statique non signé get_key())( char non signé tmp = 0; tmp = key; _delay_ms(10); if(key == tmp) return tmp; else return 0; )

Cette fonction simple garantit que les boutons ne rebondissent pas, malgré le fait qu'en raison de la nature « dynamique » de l'interrogation des boutons, la probabilité de rebond est déjà faible.

5 Quoi d'autre ?

Vous maîtrisez donc des techniques assez classiques de mise en œuvre de l'affichage dynamique. Je pense que cela te suffira pour la première fois, et peut-être même pour le reste de ta vie. En fin de compte, l’essentiel est de comprendre les techniques et les algorithmes, et vous pouvez toujours ajouter vous-même des subtilités et des nuances. Mais qu’est-ce qui peut attendre d’autre « proche » de l’affichage dynamique ?

Comme je l'ai dit plus tôt, vous pouvez ajouter , même au point d'une régulation indépendante de chaque segment.

Vous pouvez penser à l'optimalité du gestionnaire d'interruption - à des fins éducatives, j'ai écrit du code plutôt grossier, par exemple, que j'ai utilisé partout RCS, bien qu'il serait plus optimal de lire une fois la valeur dans une variable locale, puis d'opérer avec sa valeur. Bien que l’optimiseur m’aidera certainement dans mon approche, pour des raisons pratiques, cela vaut la peine d’essayer de vous optimiser, en vous surveillant en termes de taille du code résultant et/ou de vitesse du programme.

Vous pouvez penser à l’idée intéressante d’ajuster automatiquement la luminosité de l’écran en fonction du niveau de lumière ambiante. Comme vous le savez, plus il fait sombre, les indicateurs LED sont d'autant moins visibles - ils sont tout simplement flous. Par conséquent, dans l'obscurité, il est raisonnable de réduire la luminosité des indicateurs, en l'augmentant pendant la journée. Le plus simple est d'utiliser une photorésistance ou une LED séparée comme capteur de lumière, mais vous pouvez procéder différemment : on sait qu'une LED peut également fonctionner comme photodiode, donc si vous utilisez le port connecté à l'entrée pour indication CDA, puis, si vous le souhaitez, vous pouvez mesurer la photo-emf du segment non lumineux de l'indicateur, et utiliser cette valeur pour ajuster la luminosité...

Vous pouvez penser à utiliser du matériel de sortie série, auquel j'ai déjà fait allusion.

Une version intéressante d'une approche totalement universelle de l'affichage dynamique, avec laquelle je recommande également de se familiariser, a été proposée par MOLCHEC. En bref, l'essentiel : la répartition des segments par bits de symbole, l'affectation des ports de contrôle de l'indicateur, et même le type d'indicateur - bref, tous, tous, tous les paramètres - sont précisés sous la forme d'un tableau de configuration dans EEPROM. Sur la base de ce tableau, tout est organisé par programmation : de l'inversion selon le type d'indicateur, à la réorganisation des bits sur différents ports. Dans ce cas, le code source du programme d'affichage dynamique reste toujours inchangé et la table de configuration est compilée par l'utilisateur final en fonction de ses préférences. La méthode est véritablement universelle et flexible, mais est associée à une consommation accrue de mémoire programme.


3 Publié par ARV, à 06:48 le 25/08/2010
Micha, si j'étais vous, je ne ferais pas de déclarations aussi catégoriques « vous ne pouvez pas le faire », « personne ne l'a écrit » ou « copyright », car premièrement, ce n'est pas poli, et deuxièmement :
1. J'ai fait une ligne rampante sur une matrice 10x16 il y a longtemps (c'est ce que c'était) - vous pouvez retrouver une vidéo de son fonctionnement dans cette note http://site/content/view/160/38/
2. J'ai écrit un article (vous le trouverez dans l'actualité - le dernier d'aujourd'hui) sur la façon de créer un ticker sur un écran LCD. Si vous fatiguez un peu votre cerveau, refaire l'algorithme de sortie vers une matrice est une bagatelle.
3. sur mon site Web, il n'y a pas un seul article copié de quelque part (le copier-coller n'est pas un droit d'auteur, vous avez fait une faute de frappe), tous les documents sont entièrement originaux. De nombreux sites ont des copies de ces documents avec ma permission (ou la permission des auteurs des documents, qui ont parfaitement le droit de publier leurs documents dans plusieurs endroits à la fois).

Seuls les utilisateurs enregistrés peuvent laisser des commentaires.
Veuillez vous inscrire ou vous connecter à votre compte.

Poursuivant la leçon, regardons l'affichage dynamique. Si vous avez soigneusement étudié l'indication statique, vous savez qu'un indicateur de segment est un ensemble de LED. Pour connecter l'indicateur, vous avez besoin de 7 broches du microcontrôleur. Mais du coup il a fallu utiliser plusieurs indicateurs, par exemple 2, 3, 4...

Il nous faudra alors 14, 21, 28 pattes, et il n'y a pas assez de pattes... Ici l'affichage dynamique nous vient en aide. La tâche principale de l'affichage dynamique est de réduire le nombre de broches du microcontrôleur utilisées. Veuillez noter que dans le diagramme, 9 pattes sont impliquées et non 14. Les jambes de commande sont toutes connectées en parallèle.

D'une manière générale, cette conception fonctionne comme suit : d'abord, la configuration du premier numéro est sortie sur le bus commun et nous activons PB1. Le premier voyant s'allume, avec le numéro souhaité. Ensuite, nous l'éteignons, envoyons la configuration du deuxième numéro sur le bus de données, allumons le deuxième indicateur et l'éteignons.

Plus de détails. Au premier instant, tout est éteint PORTB=0x00; PORTD=0xFF; puisque le circuit est avec une anode « + » commune. Ensuite, la configuration du premier numéro, par exemple « 0 », est envoyée à PORTD. De l'affichage statique, nous retenons :

cas 0 : ( PORTD= 0xC0 ; pause ; )

cas 0 : ( PORTD=0xC0; pause; )

Mais notez que «+» est connecté au PORTB.1, c'est-à-dire pour allumer un segment, vous devez allumer le pied PORTB.1=1 ;

Au deuxième instant, nous éteignons tout à nouveau, envoyons la configuration du deuxième numéro et allumons, cette fois, le deuxième indicateur. Ensuite, nous répétons.

Aux hautes fréquences, l’œil humain n’est pas capable de discerner ces commutations et l’indicateur semble être constamment allumé. Il est recommandé de ne pas utiliser de fréquences multiples de 50 Hz. Dans mon projet de test, j'ai utilisé 120 Hz. La minuterie est réglée sur une fréquence de 1 MHz. Le code est traité dans l'interruption timer1. L'interruption est appelée 240 fois par seconde, car il y a deux indicateurs, nous enfonçons donc 1 000 000/240 = 4166 ou 0x1046 dans le registre de comparaison. Il n’a pas été possible de coupler Proteus avec un indicateur dynamique, mais cela a fonctionné immédiatement sur le matériel.

Faites attention!!! Lors de la connexion d'un indicateur, il est recommandé de fixer une résistance de limitation de courant à chaque segment, plutôt qu'une résistance commune. De plus, je recommande de connecter le fil indicateur commun via un transistor, sinon vous pourriez vous brûler la jambe.

Pour un circuit avec une anode commune

Pour un circuit cathodique commun

J'ai utilisé une minuterie d'un projet précédent comme firmware de test.

Vidéo du fonctionnement du firmware


Schéma de connexion pour un indicateur à un chiffre et sept segments
Schéma de connexion pour un indicateur à sept segments à plusieurs chiffres

Dispositif d'affichage d'informations numériques. Il s’agit de l’implémentation la plus simple d’un indicateur capable d’afficher des chiffres arabes. Des indicateurs multi-segments et matriciels plus complexes sont utilisés pour afficher les lettres.

Comme son nom l'indique, il se compose de sept éléments d'affichage (segments) qui s'allument et s'éteignent séparément. En les incluant dans différentes combinaisons, ils peuvent être utilisés pour créer des images simplifiées de chiffres arabes.
Les segments sont désignés par les lettres A à G ; huitième segment - point décimal (point décimal, DP), conçu pour afficher des nombres fractionnaires.
Parfois, des lettres sont affichées sur l'indicateur à sept segments.

Ils viennent dans une variété de couleurs, généralement blanc, rouge, vert, jaune et bleu. De plus, ils peuvent être de tailles différentes.

De plus, l'indicateur LED peut être à un chiffre (comme dans la figure ci-dessus) ou à plusieurs chiffres. Fondamentalement, des indicateurs LED à un, deux, trois et quatre chiffres sont utilisés dans la pratique :

En plus de dix chiffres, des indicateurs à sept segments sont capables d'afficher des lettres. Mais peu de lettres ont une représentation intuitive à sept segments.
En latin : majuscule A, B, C, E, F, G, H, I, J, L, N, O, P, S, U, Y, Z, minuscule a, b, c, d, e, g , h, je, n, o, q, r, t, u.
En cyrillique : A, B, V, G, g, E, i, N, O, o, P, p, R, S, s, U, Ch, Y (deux chiffres), b, E/Z.
Par conséquent, les indicateurs à sept segments ne sont utilisés que pour afficher des messages simples.

Au total, l'indicateur LED à sept segments peut afficher 128 caractères :

Un indicateur LED typique comporte neuf fils : l'un va aux cathodes de tous les segments et les huit autres vont à l'anode de chaque segment. Ce schéma est appelé "circuit cathodique commun", il existe aussi des schémas avec anode commune(alors c'est l'inverse). Souvent, non pas une, mais deux bornes communes sont réalisées à différentes extrémités de la base - cela simplifie le câblage sans augmenter les dimensions. Il en existe aussi des soi-disant « universels », mais personnellement, je n'en ai pas rencontré. De plus, il existe des indicateurs avec un registre à décalage intégré, ce qui réduit considérablement le nombre de broches de port du microcontrôleur impliquées, mais ils sont beaucoup plus chers et sont rarement utilisés dans la pratique. Et comme l'immensité ne peut être appréhendée, nous ne considérerons pas de tels indicateurs pour l'instant (mais il existe aussi des indicateurs avec un nombre beaucoup plus important de segments, matriciels).

Indicateurs LED à plusieurs chiffres fonctionnent souvent sur un principe dynamique : les sorties des segments du même nom de tous les chiffres sont connectées entre elles. Pour afficher des informations sur un tel indicateur, le microcircuit de contrôle doit fournir cycliquement du courant aux bornes communes de tous les chiffres, tandis que le courant est fourni aux bornes du segment selon qu'un segment donné est allumé dans un chiffre donné.

Connexion d'un indicateur à un chiffre à sept segments à un microcontrôleur

Le diagramme ci-dessous montre comment un indicateur à sept segments à un chiffre est connecté au microcontrôleur.
Il convient de tenir compte du fait que si l'indicateur avec CATHODE COMMUNE, alors sa sortie commune est connectée à "Terre", et les segments sont enflammés par l'alimentation unité logiqueà la sortie du port.
Si l'indicateur est ANODE COMMUNE, puis il est alimenté sur son fil commun "plus" tension, et les segments sont allumés en commutant la sortie du port à l'état zéro logique.

L'indication dans un indicateur LED à un chiffre est réalisée en appliquant un code binaire aux broches du port du microcontrôleur du chiffre correspondant du niveau logique correspondant (pour les indicateurs avec OK - les logiques, pour les indicateurs avec OA - les zéros logiques).

Résistances de limitation de courant peut être présent ou non dans le diagramme. Tout dépend de la tension d'alimentation fournie à l'indicateur et des caractéristiques techniques des indicateurs. Si, par exemple, la tension fournie aux segments est de 5 volts et qu'ils sont conçus pour une tension de fonctionnement de 2 volts, alors des résistances de limitation de courant doivent être installées (pour limiter le courant qui les traverse pour une tension d'alimentation accrue et ne pas brûler non seulement l'indicateur, mais aussi le port du microcontrôleur).
Il est très simple de calculer la valeur des résistances de limitation de courant, en utilisant la formule de grand-père Ohm.
Par exemple, les caractéristiques de l'indicateur sont les suivantes (extraites de la fiche technique) :
— tension de fonctionnement — 2 volts
— courant de fonctionnement — 10 mA (=0,01 A)
— tension d'alimentation 5 volts
Formule de calcul :
R= U/I (toutes les valeurs de cette formule doivent être en Ohms, Volts et Ampères)
R= (tension d'alimentation - tension de fonctionnement)/courant de fonctionnement
R= (5-2)/0,01 = 300 ohms

Schéma de connexion pour un indicateur LED à sept segments à plusieurs chiffres Fondamentalement, la même chose que lors de la connexion d'un indicateur à un chiffre. La seule chose est que des transistors de contrôle sont ajoutés dans les cathodes (anodes) des indicateurs :

Ce n'est pas représenté sur le schéma, mais entre les bases des transistors et les broches du port du microcontrôleur, il faut inclure des résistances dont la résistance dépend du type de transistor (les valeurs des résistances sont calculées, mais vous pouvez également essayer d'utiliser des résistances d'une valeur nominale de 5 à 10 kOhm).

L'indication par décharges s'effectue de manière dynamique :
— le code binaire du chiffre correspondant est mis aux sorties du port PB pour le 1er chiffre, puis le niveau logique est appliqué au transistor de commande du premier chiffre
— le code binaire du chiffre correspondant est mis aux sorties du port PB pour le 2ème chiffre, puis le niveau logique est appliqué au transistor de commande du deuxième chiffre
— le code binaire du chiffre correspondant est mis aux sorties du port PB pour le 3ème chiffre, puis le niveau logique est appliqué au transistor de commande du troisième chiffre
- donc en cercle
Dans ce cas, il faut prendre en compte :
— pour les indicateurs avec D'ACCORD la structure du transistor de commande est utilisée NPN(contrôlé par unité logique)
- pour indicateur avec OA- structure du transistor PNP(contrôlé par zéro logique)



2024 wisemotors.ru. Comment cela marche-t-il. Fer. Exploitation minière. Crypto-monnaie.