Étape 6: Le logiciel
Comme avec tous les programmes C, nous avons tout d’abord hors comprend. Vous aurez besoin des io.h et interrupt.h pour ce projet. Ensuite, j’ai défini quelques symboles de sorte qu’il serait plus facile de travailler avec eux dans le programme. Je pense que c’est plus facile de savoir ce que je fais quand j’ai utiliser SPI_PORT au lieu de PORTB. Ensuite, nous avons les prototypes de fonction ; rien de trop spécial ici. Enfin, dans cette section, nous avons nos définitions de variables globales. Il y a quelques sur que je tiens à attirer votre attention.
currentRow int = 0 ;
unsigned int cRow = 0, cCol = 0 ;
int rowRead, colRead, facteur ;
int soft_prescaler = 0 ;
unsigned long dessin [8] = {0} ;
La variable currentRow, comme son nom l’indique, conserve la valeur de la ligne actuelle que nous sommes affichant. Vous verrez exactement à quoi cela sert un peu plus tard. cRow et CCLO contiennent les valeurs de ligne et de colonne du curseur. rowRead et colRead contiennent les valeurs de l’ADC lecture tirées des pots. Ceux-ci serviront à calculer la valeur des variables cRow et CCLO. Le soft_prescaler est utilisé pour diviser encore plus l’horloge avec le logiciel ; Nous parlerons plus tard. Enfin, la variable la plus importante est un tableau d’entiers long non signé, appelé dessin. Vous remarquerez que ce tableau contient huit éléments-un pour chaque ligne. C’est les 32-bits qui contrôlent les LEDs pour chaque colonne.
Maintenant passons à certaines fonctions. Nous allons commencer avec la fonction principale. Après avoir effectué l’ensemble vers le haut de la minuterie, SPI et les entrées et les sorties, nous entrons dans la boucle principale du programme. La première réflexion à l’intérieur de cette boucle est un if instruction.
si (compteur < CYCLES)
{
rowReadings [compteur] = Analog_Read(PC4) ;
colReadings [compteur] = Analog_Read(PC5) ;
compteur ++ ;
}
C’est tout simplement prendre un échantillonnage des lectures de l’ADC sur tant de CYCLES. Ceci permet de calculer la moyenne de l’ADC lire et évite les problèmes avec le dessin. Entrer dans l’autre montrera comment cela se fait.
d’autre
{
Moyenne des lectures de tous rangs et Col ADC
colRead = CycAvg(colReadings) ;
rowRead = CycAvg(rowReadings) ;
compteur = 0 ;
Après que nous avons un échantillon de valeurs de l’ADC pour les lignes et les colonnes, nous pouvons en moyenne à l’aide de la fonction CycAvg. C’est juste une fonction générique moyenne qui résume les valeurs et puis divise par le nombre total de valeurs. Je ne vais pas en parler ici, comme vous pouvez le trouver dans le code. Eh bien, maintenant que nous avons les lectures de ADC, que nous voulons les pots, nous devons convertir cette à un nombre de lignes et de colonnes, donc nous pouvons placer le curseur là. Ceci est géré ensuite.
si (colRead / diviseur ! = cCol & & colRead / diviseur < DIMENSION)
{
cCol = colRead / diviseur ;
}
La valeur de colonne du curseur est simple à calculer. Nous vérifions que la nouvelle valeur n’est pas le même que l’ancienne valeur (parce qu’il ne serait pas nécessaire de recalculer il) et nous nous assurons que le curseur ne va pas au-delà de nos 16 x 16 surface de dessin. Puis nous assigner la valeur de l’ADC lire divisée par la valeur du diviseur. DIVISEUR est juste la valeur maximale de l’ADC divisé par les dimensions de l’écran (1024/16 = 64, donc chaque 64 nous sommes sur une autre ligne ou colonne). La valeur de ligne du curseur est un peu plus compliquée.
si (rowRead / diviseur ! = Corneille & & rowRead / diviseur < DIMENSION)
{
si (rowRead / diviseur > = 8)
{
Corbeau = rowRead / diviseur - 8 ;
facteur = 0 ;
}
d’autre
{
Corbeau = rowRead / diviseur ;
facteur = 16 ;
}
}
Ce qui est donc avec cette option supplémentaire si Déclaration ? Cela nous ramène à comment nous filaire vers le haut de l’affiche comme si c’était en fait un écran de 8 x 32 au lieu d’un 16 x 16. Les 16 premiers bits de notre variable dessin correspondent aux 16 premières colonnes de l’affichage de 8 x 32. Les 16 bits restants correspondent aux deuxième 16 colonnes. Lorsque nous faisons l’affichage 16 x 16 nous déplaçant les 16 dernières colonnes et en les plaçant sous les 16 colonnes sapins créant artificiellement plus de 8 lignes. Si nous voulons calculer la ligne du curseur de la même manière que nous avons fait la curseur colonne que nous pouvons aboutir à une valeur supérieure à 8. N’oubliez pas que nous avons seulement huit lignes puisque notre écran est techniquement 8 x 32, donc cela crée un problème. Donc si le résultat de la division de l’ADC par diviseur est supérieur à 8, qu'il faut soustraire 8 et l’utiliser comme la ligne, sinon nous pouvons simplement prendre le résultat comme c’est. Nous avons également besoin de suivre ou non le dessin qui se passe dans les 16 premières colonnes (lignes 9-16) ou les 16 dernières colonnes (lignes 1-8). C’est là que la variable de facteur entre en jeu. Cela devrait faire plus de sens lorsque nous en fait assigner une valeur à la variable dessin ensuite.
dessin [Corneille] | = (0 x 80000000 >> (cCol + facteur)) ;
Un peu se fait ici. Tout d’abord, nous allons donner le tableau colonne de notre curseur sous forme d’index et, ensuite, nous allons bit-wise ou ce avec la partie suivante. Nous utilisons bit-wise ou ici parce que nous voulons garder tous les bits qui ont déjà défini où ils sont et ne définir celui correspondant à l’emplacement du curseur. Sur le côté droit de l’opérateur, nous sommes passer un seul bit à son bon emplacement. Par exemple, supposons que la valeur de CCLO est 4 et cRow est 5. Dans ce scénario, dessin [5] | = (0 x 80000000 >> (16 + 4)) = 0b0000000000000000|0001000000000000. Afin de mieux préciser quels bits correspondent à ce que, les 16 bits les plus significatifs correspondent aux colonnes des lignes 1-8, les 16 bits les moins significatifs correspondent aux lignes 9-16.
La dernière partie de cette boucle vérifie si tous les deux d’inclinaison interrupteurs sont fermés en même temps. Il est très simple et s’appuie sur le fait qu’il existe une forte probabilité que les deux interrupteurs seront fermera en même temps lorsque l’appareil est secoué.
Effacer l’écran si les détecteurs d’inclinaison sont déclenchés.
si (bit_is_clear(PINC,0) & & bit_is_clear (PINC, 1))
{
clrscr() ;
}
Maintenant que le dessin est fait, nous avons besoin pour l’obtenir à l’écran. Ceci est pris en charge par l’Interrupt Service Routine (ISR) qui est déclenchée sur chaque débordement du timer. Nous allons étudier.
Rapport de recherche internationale (TIMER0_OVF_vect)
{
soft_prescaler ++ ;
si (soft_prescaler == SFT_PRESCAL_MAX)
{
currentRow = (currentRow + 1) % 8 ;
Transmettre des données sur SPI
SPI_Transmit(Drawing[CurrentRow]) ;
PORTD = (1 << currentRow) ;
soft_prescaler = 0 ;
}
}
La première chose que nous faisons dans l’ISR est incrémenter le Prédiviseur doux. Le Prédiviseur doux fondamentalement nous permet de rendre la durée de chaque ligne est affiche autre chose que ce que nous pouvons avec prescaler matérielle de l’ATmega. Si vous regardez la fonction Timer_Init() vous voyez que nous prescale l’horloge de 8 avec le matériel. Ainsi, notre horloge de 16 MHz devient 2MHz. Avec un prescaler doux avec une valeur maximale de 15 que nous pouvons apporter à la fois chaque ligne est affichée à environ 133 kHz. Ce ne serait pas possible avec un prescaler de matériel. En tout cas, nous allons passer.
Lorsque nous n’atteignons pas le max de diviseur doux que nous tout d’abord décider quelle ligne nous souhaitons afficher. Chaque fois que les feux d’interruption il affiche une seule ligne. Cela arrive si vite que nos yeux ne peuvent voir les changements et si l’image semble solide. Cette technique s’appelle le multiplexage et il a utilisé des tas et des tas d’applications. Pour définir la ligne en cours, nous allons ajouter tout d’abord on lui d’augmenter le rang puis le mod par 8 afin que la valeur sera toujours quelque part entre 0-7. Puis nous envoyer le dessin de la ligne actuelle à la fonction SPI_transmitt pour transmettre les données à le 595s. Après cela, nous avons mis un du Port D pins élevé correspondant à la ligne actuelle. Rappel, que ces broches sont reliées à la ULN2803s. Enfin, nous rétablir le Prédiviseur doux à zéro et recommencer tout.
C’est à peu près tout. Toutes les autres fonctions sont juste soutenir ces deux. Sans aucun doute les vérifier dans le code ci-joint.