Etape 2: Notre premier AVR-C projet : Bonjour monde, conduit !
Le « Hello World » de la programmation de microcontrôleur est le témoin clignotant. Si c’est juste ce que nous allons essayer d’atteindre avec notre premier programme !
S’il vous plaît note : Vous pouvez obtenir le code complet de ces programmes dans mon dépôt github. Il est aussi beaucoup mieux afficher le code source là parce que github a la bonne coloration syntaxique.
Nous ne voulons pas faire toutes les étapes de la compilation, enchaînement, etc. à la main, donc la première chose que nous avons besoin est un Makefile. Si vous utilisez Crosspack AVR sous OS x, vous pouvez utiliser la commande avr-projet dans le Terminal qui crée automatiquement un fichier Makefile pour nous (et un projet XCode que nous ne devons donc vous pouvez le supprimer). Sinon, vous pouvez utiliser le modèle suivant pour votre Makefile. Veuillez noter que vous devez modifier les premières lignes de ce modèle pour votre propre configuration (c'est-à-dire définir les variables d’appareil et programmeur).
--
#
# Modèle Makefile pour ATtiny45
# Dérivé modèle AVR Crosspack
#
DEVICE = attiny45 # voir avr-aide pour tous les périphériques possibles
HORLOGE = 1000000 # 1Mhz
PROGRAMMATEUR = - c usbtiny -P usb # pour utiliser Adafruit USBtiny
OBJETS = main.o # ajouter des objets supplémentaires pour chaque fichier .c ici
FUSIBLES = - U lfuse:w:0x62:m - U hfuse:w:0xdf:m - U efuse:w:0xff:m # paramètres provenant de http://www.engbedded.com/fusecalc/
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
COMPILER = avr-gcc-Wall -Os-DF_CPU=$(CLOCK)-mmcu=$(DEVICE)
cibles symboliques # :
tous : main.hex
. Cabrera :
$(COMPILE) - c $< -o $@
. Sagna :
$(COMPILE) x - assembleur-avec-cpp - c $< -o $@
. Cabrita :
$(COMPILE) $-S < -o $@
Flash : tous les
$(AVRDUDE) flash:w:main.hex:i - U
Fusible :
$(AVRDUDE) $(FUSES)
installer : flash fusible
# Si vous utilisez un chargeur de démarrage, changer la commande ci-dessous de manière appropriée :
charger : tous
bootloadHID main.hex
nettoyer :
RM -f main.hex main.elf $(OBJECTS)
cibles de fichier # :
main.Elf : $(OBJECTS)
$(COMPILE) -o main.elf $(OBJECTS)
main.hex : main.elf
RM -f main.hex
avr-objcopy - j .text -j .data - O ihex main.elf main.hex
avr-taille--format = avr--mcu=$(DEVICE) main.elf
# Si vous avez une section de l’EEPROM, vous devez également créer un fichier hex pour le
# EEPROM et ajoutez-le à la cible de « flash ».
# Cibles pour l’analyse et de débogage de code :
DISASM : main.elf
avr-objdump - d main.elf
RPC :
$(COMPILE) -E main.c
--
Vous pouvez vous demander, quelle est cette chose « Fusibles » ? Pendant que vous programmez votre microcontrôleur avec un programmeur, il définira quelques morceaux dans la puce qui sont une sorte de configuration initiale. Utilisez cette calculatrice pour définir les bits de droite. Avec cette configuration, vous pouvez par exemple indiquer le microcontrôleur pour servir la broche RESET normal broche I/O (ce qui est utile lorsque vous avez seulement 8 broches!).
Ensuite, vous avez besoin d’un fichier main.c minime qui ressemble à ceci :
--
#include < avr/io.h >
int main (void) {}
for(;;) {
boucle principale
}
return 0 ; n’a jamais atteint
}
--
Ce programme ne fait en fait rien, mais nous allons essayer de le compiler néanmoins. Tapez le faire dans le terminal et il compilera et lien vers le programme. Il vous indique même la taille de votre programme et combien il occupera sur le périphérique.
s’appellera la cible tous de votre Makefile. Il y a autres cibles importantes dans votre Makefile :
- clean supprimera les fichiers binaires générés tout et vous permettent de compiler tout nouveau
- installer transmettra votre programme au microcontrôleur à l’aide d’un programmeur. plus d’infos sur cela plus tard
Maintenant passons étape par étape créer un programme complet pour laisser les deux LEDs clignotent à leur tour :
Dans un premier temps, nous devons inclure certains en-têtes pour les fonctions courantes de AVR-C. Nous avons inclus déjà avr/io.h pour la gestion des I/O, qui signifie la lecture et l’écriture depuis/vers nos goupilles. Nous devrons également une fonction de « retard » parce que nous voulons les LED clignote pendant une durée spécifiée. Cette fonction est incluse dans util/delay.h. Ensuite, nous définissons nos goupilles que nous utilisons et le temps de retard. Si les premières lignes de notre programme de ressemblent à ceci :
--
#include < avr/io.h >
#include < util/delay.h >
Définir des axes
#define PIN_LED1 PB0
#define PIN_LED2 PB1
Définir le délai en ms
#define DELAY_MS 500
--
Nous avons besoin de certaines macros d’assistance et les fonctions que nous utilisons souvent (dans l’avenir). AVR-c, vous définissez « haute » sur une broche spécifique, en écrivant un bit « 1 » à un port spécifique de Registre à l’aide d’opérations de bits. Dans notre ATtiny, nous avons seulement « PORTB » comme j’ai/O-port. Lorsque nous voulons mettre une épingle « PB0 » à « haut » nous pouvons créer : PORTB | = (1 << PB0) ;
Affectation de la valeur « faible » fonctionne également avec une opération de bits en définissant le bit à cette position "0" (logique, non pas 1): PORTB & = ~ (1 << PB0) ;
Nous utilisons cette information pour écrire deux macros permettant de définir une épingle sur un certain port « faible » ou « élevé ». En outre, nous définissons une fonction qui permet de créer des délais longs. Le problème avec des temps de retard est, que l’horloge interne (ou horloge-compteur) Registre volonté débordement très rapide parce que c’est habituellement seulement un compteur 8 bits. Par conséquent, nous définissons une fonction qui divisent notre retard en morceaux de 10 ms et nous X temps 10ms pour obtenir le long délai d’attente.
--
écriture numérique « haute » à broche < pn > < prt > IDE oucédéromsurlesecondport
#define DIGIWRITE_H (prt, pn) prt | = (1 << pn)
écriture numérique « faible » à broche < pn > < prt > IDE oucédéromsurlesecondport
#define DIGIWRITE_L (prt, pn) prt & = ~ (1 << pn)
Définir la fonction de retard
void long_delay_ms (ms uint16_t) {}
pour (ms / = 10; ms > 0; ms--) _delay_ms(10) ;
}
--
Maintenant nous allons passer à notre fonction main() . Dans un premier temps, nous aurons besoin de modifier le « registre de direction de données » pour le port B, qui est défini dans la variable DDRB. Ce registre indique à la puce, les épingles peuvent obtenir des données d’entrée et les pins doivent produire une tension de sortie. Par défaut, toutes les broches sont sur « entrée ». Quand nous voulons définir certaines épingles « sortie », que nous devons définir leur registre sur « 1 »
Le reste est assez simple : nous avons maintenant seulement appeler DIGIWRITE_L() et DIGIWRITE_H() pour les pivots respectifs et remplaçant le statut en utilisant une variable bascule. Ensuite, nous ajoutons un temps de retard.
Notez l’utilisation de uint8_t pour la variable de la bascule . Lorsque vous écrivez du code pour les puces avec très peu de mémoire flash, il est essentiel de toujours utiliser le type de la plus petite possible des données. Vous pouvez le modifier pour, par exemple, int32_t et vous verrez que la consommation de mémoire augmente légèrement.
Il s’agit d’obtenir le code complet pour notre boucle principale :
--
point d’entrée de programme
int main (void) {}
DDRB est le « registre de direction de données » pour le port B
la ATtinyX5 a seulement port B avec des épingles utilisables
Nous avons mis les deux broches de la LED pour « output »
DDRB | = (1 << PIN_LED1) | (1 << PIN_LED2) ;
initialement fixé les broches à « faible »
DIGIWRITE_L (PORTB, PIN_LED1) ;
DIGIWRITE_L (PORTB, PIN_LED2) ;
boucle principale
toggle uint8_t = 0 ;
for(;;) {
alterner entre les LEDs pour les laisser clignoter
DIGIWRITE_L (PORTB, (activer/désactiver == 0 ? PIN_LED1 : PIN_LED2)) ;
DIGIWRITE_H (PORTB, (activer/désactiver == 0 ? PIN_LED2 : PIN_LED1)) ;
alternave la variable toggle
activer/désactiver =! basculer ;
faire un long délai
long_delay_ms(DELAY_MS) ;
}
return 0 ; / * jamais atteinte * /
}
--
Tapez faire pour compiler le code. Il va générer un .hex-fichier. Dans l’étape suivante, je vais vous expliquer comment nous téléchargeons cela à notre ATtiny.