Dans la pratique de la radio amateur, il est parfois nécessaire de faire quelque chose sur le microcontrôleur. Si vous ne faites pas ce genre d'artisanat tout le temps, vous devez rechercher sur Google pendant longtemps la solution de circuit nécessaire et les bibliothèques appropriées pour MK, ce qui vous permet de résoudre rapidement le problème. Récemment, j'ai voulu faire un commutateur d'antenne automatique. Dans le processus, j'ai dû utiliser de nombreuses fonctionnalités d'Atmega MK dans un projet compact. Ceux qui commencent à étudier l'AVR, à passer de l'arduino ou à programmer occasionnellement MK peuvent être des morceaux de code utiles que j'utilise dans le projet.
J'ai pensé au commutateur d'antenne comme un appareil qui connecte automatiquement l'antenne à l'émetteur-récepteur, ce qui convient le mieux à la plage de travail des ondes courtes. J'ai deux antennes: V inversé et plan de masse, elles sont connectées au tuner d'antenne MFJ, dans lequel elles peuvent être commutées à distance. Il y a un interrupteur manuel de marque MFJ, que je voulais remplacer.
Pour la commutation opérationnelle des antennes, un bouton est connecté au MK. Je l'ai adapté pour mémoriser l'antenne préférée pour chaque gamme: lorsque vous appuyez sur le bouton pendant plus de 3 secondes, l'antenne sélectionnée est mémorisée et sélectionnée correctement automatiquement après la prochaine mise sous tension de l'appareil. Des informations sur la portée actuelle, l'antenne sélectionnée et l'état de son réglage s'affichent sur un écran LCD à ligne unique.
Vous pouvez découvrir de quelle manière l'émetteur-récepteur travaille actuellement de différentes manières: vous pouvez mesurer la fréquence du signal, vous pouvez recevoir des données via l'interface CAT, mais le plus simple pour moi est d'utiliser l'interface de l'émetteur-récepteur YAESU pour connecter un amplificateur externe. Il dispose de 4 lignes de signaux, en code binaire, indiquant la plage actuelle. Ils donnent un signal logique de 0 à 5 volts et ils peuvent être connectés aux jambes du MK via une paire de résistances de terminaison.
Ce n'est pas tout. En mode transmission, les signaux PTT et ALC sont transmis via la même interface. Il s'agit d'un signal logique sur la mise sous tension de l'émetteur (tiré au sol) et d'un signal analogique de 0 à -4 V sur le fonctionnement du système de contrôle automatique de la puissance de l'émetteur. J'ai également décidé de le mesurer et de l'afficher sur l'écran LCD en mode transmission.
De plus, le syntoniseur MFJ peut transmettre à la télécommande des signaux indiquant qu'il syntonise et que l'antenne est syntonisée. Pour ce faire, le panneau de contrôle de la société MFJ dispose de deux LED de contrôle. Au lieu de LED, j'ai connecté les optocoupleurs et envoyé un signal d'eux au MK, afin que je puisse voir toutes les informations sur un seul écran. L'appareil fini ressemble à ceci.
En bref sur le fait maison comme tout. Maintenant sur la partie logicielle. Le code est écrit dans Atmel Studio (téléchargement gratuit sur le site Web d'Atmel). Le projet pour débutants démontre les caractéristiques suivantes de l'utilisation du populaire Atmega8 MK:
- Bouton de connexion
- Connectez l'entrée ligne pour le signal numérique de l'émetteur-récepteur et du tuner
- Connexion de la sortie de commande du relais de commutation d'antenne
- Connexion d'un écran LCD sur une seule ligne
- Connexion du buzzer et sortie audio
- Connexion de ligne d'entrée analogique ADC et mesure de tension
- Utilisation d'interruptions
- Utilisation d'une minuterie pour compter le temps où un bouton est enfoncé
- Utilisation de Watchdog
- Utilisation d'une mémoire non volatile pour stocker les antennes sélectionnées
- Utilisation de UART pour l'impression de débogage
- Économie d'énergie dans le MK inactif
Commençons donc. Au cours du texte, il y aura toutes sortes de noms de registres et de constantes caractéristiques du MK appliqué. Ce n'est pas de l'arduino, ici, malheureusement, vous devez lire la fiche technique sur MK. Sinon, vous ne comprenez pas ce que signifient tous ces registres et comment vous pouvez modifier leurs valeurs. Mais la structure du programme dans son ensemble restera la même.
Tout d'abord, connectez le bouton au MK
C'est le plus simple. Nous connectons un contact au pied MK, le deuxième contact du bouton au sol. Pour que le bouton fonctionne, vous devrez activer la résistance de rappel dans MK. Il connectera le bouton via la résistance au bus + 5V. Pour ce faire, c'est assez simple:
PORTB |= (1 << PB2);
De même, toutes les entrées numériques contrôlées par un défaut à la terre (optocoupleurs, lignes de signal de l'émetteur-récepteur, signal PTT) sont tirées vers le bus + 5V. Parfois, il est préférable de souder physiquement une résistance aussi petite (par exemple 10k) entre l'entrée du MK et le bus + 5V, mais la discussion de ce problème dépasse le cadre de l'article. Étant donné que tous les signaux d'entrée du projet changent rarement de valeurs, ils sont shuntés au sol par 10 condensateurs nanofarad pour se protéger contre les interférences.
Maintenant, nous avons 1 logique à l'entrée PB2, et lorsque vous appuyez sur le bouton, il sera logique 0. Lorsque vous appuyez sur \ presser, vous devez suivre le rebond de contact du bouton, en vérifiant que le niveau du signal n'a pas changé au fil du temps, disons 50 millisecondes. Cela se fait dans le programme comme ceci:
if(!(PINB&(1<<PINB2)) && !timer_on) {
Maintenant, connectez le squeaker
Il donnera un signal audio de confirmation que l'antenne est enregistrée dans la mémoire MK. Un tweeter n'est qu'un élément piézoélectrique. Il est relié par une petite résistance au pied MK, et par un deuxième contact à + 5V. Pour que ce buzzer fonctionne, vous devez d'abord configurer le pied MK pour produire des données.
void init_buzzer(void) { PORTB &= ~(1 << PB0);
Maintenant, il peut être utilisé. Pour ce faire, une petite fonction est écrite qui utilise des retards pour commuter les jambes MK de 0 à 1 et vice versa. La commutation avec les retards nécessaires permet de générer un signal audio de 4 kHz d'une durée d'environ un quart de seconde à la sortie MK, qui est le son de l'élément piézoélectrique.
void buzz(void) {
Pour que les fonctions de délai fonctionnent, n'oubliez pas d'inclure le fichier d'en-tête et de définir la vitesse du processeur constante. Elle est égale à la fréquence du résonateur à quartz connecté au MK. Dans mon cas, il y avait du quartz à 16 MHz.
#ifndef F_CPU # define F_CPU 16000000UL #endif #include <util/delay.h>
Nous nous connectons aux antennes de commutation relais MK
Ici, il vous suffit de configurer le pied MK pour fonctionner à la sortie. Un relais reed est connecté à cette jambe via un transistor amplificateur de manière standard.
void init_tuner_relay(void) { PORTB &= ~(1 << PB1);
Connexion d'affichage
J'ai utilisé un écran LCD 1601 à une seule ligne de 16 caractères, extrait de l'ancien matériel. Il utilise le célèbre contrôleur HD44780, pour la gestion duquel de nombreuses bibliothèques sont disponibles sur le réseau. Une personne gentille a écrit une bibliothèque de contrôle d'affichage légère, que j'ai utilisée dans le projet. La configuration de la bibliothèque se réduit à indiquer dans le fichier d'en-tête HD44780_Config.h le nombre de branches MK connectées aux broches d'affichage souhaitées. J'ai appliqué une connexion d'affichage sur 4 lignes de données.
#define Data_Length 0 #define NumberOfLines 1 #define Font 1 #define PORT_Strob_Signal_E PORTC #define PIN_Strob_Signal_E 5 #define PORT_Strob_Signal_RS PORTC #define PIN_Strob_Signal_RS 4 #define PORT_bus_4 PORTC #define PIN_bus_4 0 #define PORT_bus_5 PORTC #define PIN_bus_5 1 #define PORT_bus_6 PORTC #define PIN_bus_6 2 #define PORT_bus_7 PORTC #define PIN_bus_7 3
Une caractéristique de mon instance d'affichage était qu'une ligne sur l'écran était affichée en deux lignes de 8 caractères, donc un tampon d'écran intermédiaire a été créé dans le programme pour un travail plus pratique avec l'écran.
void init_display(void) { PORTC &= ~(1 << PC0);
La fonction update_display () vous permet d'afficher le contenu du tampon à l'écran. Les valeurs d'octets dans le tampon sont les codes ASCII des caractères de sortie.
Déboguer la sortie d'impression vers le port COM
MK a UART et je l'ai utilisé pour déboguer le programme. Lors de la connexion du MK à l'ordinateur, vous devez simplement vous rappeler que les niveaux de signal à la sortie MK sont dans la norme TTL, et non RS232, vous avez donc besoin d'un adaptateur simple. J'ai utilisé un adaptateur USB-série, similaire sur aliexpress. Tout programme de terminal, par exemple d'arduino, convient à la lecture de données. Code de configuration du port UART:
#define BAUD 9600 #include <stdio.h> #include <stdlib.h> #include <avr/io.h> // UART RS232 void uart_init( void ) { /* // UBRRH = 0; UBRRL = 103; //9600 16 */ #include <util/setbaud.h> UBRRH = UBRRH_VALUE; UBRRL = UBRRL_VALUE; #if USE_2X UCSRA |= (1 << U2X); #else UCSRA &= ~(1 << U2X); #endif //8 , 1 , UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ); // // UCSRB = ( 1 << TXEN ) | ( 1 <<RXEN ); UCSRB = ( 1 << TXEN ); } int uart_putc( char c, FILE *file ) { // while( ( UCSRA & ( 1 << UDRE ) ) == 0 ); UDR = c; wdt_reset(); return 0; } FILE uart_stream = FDEV_SETUP_STREAM( uart_putc, NULL, _FDEV_SETUP_WRITE ); stdout = &uart_stream;
Après avoir configuré le flux de sortie, vous pouvez utiliser le printf habituel pour imprimer sur le port:
printf( "Start flag after reset = %u\r\n", mcusr_mirror );
Le programme utilise l'impression de nombres réels. Les bibliothèques normales ne prennent pas en charge ce mode de sortie, j'ai donc dû connecter une bibliothèque complète lors de la liaison d'un projet. Certes, cela augmente sérieusement la quantité de code, mais j'avais une grande quantité de mémoire, donc ce n'était pas critique. Dans les options de l'éditeur de liens, vous devez spécifier la ligne:
-Wl,-u,vfprintf -lprintf_flt
Travailler avec minuterie et interruptions
Pour compter les intervalles de temps dans un programme, il est important d'avoir un compteur de temps. Il est nécessaire de vérifier que le bouton est enfoncé pendant plus de 3 secondes et, par conséquent, vous devez vous souvenir des nouveaux paramètres dans la mémoire non volatile. Pour mesurer le temps dans le style AVR, vous devez configurer le compteur d'impulsions du générateur d'horloge et l'interruption qui sera exécutée lorsque le compteur atteindra la valeur définie. J'ai réglé la minuterie pour qu'elle produise une interruption environ une fois par seconde. Le gestionnaire d'interruption lui-même compte le nombre de secondes écoulées. La variable timer_on contrôle l'activation / désactivation du temporisateur. Il est important de ne pas oublier de déclarer toutes les variables qui sont mises à jour dans le gestionnaire d'interruption comme volatiles, sinon le compilateur peut les «optimiser» et le programme ne fonctionnera pas.
La valeur depass_secs est vérifiée dans la boucle principale du programme. Lorsque le bouton est enfoncé, la minuterie démarre, puis dans le cycle de programme principal, la valeur de la minuterie est vérifiée lorsque le bouton est enfoncé. Si cette valeur dépasse 3 secondes, l'EEPROM est écrite et la minuterie s'arrête.
Enfin et surtout, après toutes les initialisations, vous devez activer les interruptions avec la commande sei ().
Mesure de niveau ALC
Il est fabriqué à l'aide du convertisseur analogique-numérique (ADC) intégré. J'ai mesuré la tension à l'entrée de l'ADC7. Il faut se rappeler que vous pouvez mesurer une valeur de 0 à 2,5V. et ma tension d'entrée était de -4V à 0V. Par conséquent, j'ai connecté le MK via le diviseur de tension le plus simple des résistances, de sorte que le niveau de tension à l'entrée MK était à un niveau donné. De plus, je n'avais pas besoin d'une grande précision, j'ai donc appliqué une conversion 8 bits (il suffit de lire les données uniquement du registre ADCH). Comme source de référence, j'ai utilisé un ion interne à 2,56 V, cela simplifie légèrement les calculs. Pour que l'ADC fonctionne, assurez-vous de connecter un condensateur de 0,1 µF au pied REF au sol.
ADC dans mon cas fonctionne en continu, signalant la fin de la conversion en appelant l'interruption ADC_vect. Il est recommandé de faire la moyenne des valeurs de plusieurs cycles de conversion pour réduire l'erreur. Dans mon cas, je déduis la moyenne de 2500 transformations. Tout le code ADC ressemble à ceci:
Utilisation de l'EEPROM
Il s'agit d'une mémoire non volatile dans MK. Il est pratique de l'utiliser pour stocker toutes sortes de paramètres, valeurs de correction, etc. Dans notre cas, il est utilisé uniquement pour stocker l'antenne sélectionnée pour la portée souhaitée. À cet effet, un tableau de 16 octets est alloué dans l'EEPROM. Mais vous pouvez y accéder via des fonctions spéciales définies dans le fichier d'en-tête avr / eeprom.h. Au démarrage, le MK lit les informations sur les paramètres enregistrés dans la RAM et allume l'antenne souhaitée, en fonction de la portée actuelle. Lorsque vous appuyez longuement sur le bouton, une nouvelle valeur est enregistrée dans la mémoire, accompagnée d'un signal sonore. Lors de l'écriture dans l'EEPROM, les interruptions sont désactivées au cas où. Code d'initialisation de la mémoire:
EEMEM unsigned char ee_bands[16];
Un extrait du code de traitement pour appuyer sur un bouton pendant 3 secondes et écrire dans la mémoire:
if (!(PINB&(1<<PINB2)) && passed_secs >= 3) {
Utilisation de Watchdog
Ce n'est un secret pour personne que dans des conditions de fortes interférences électromagnétiques, le MK peut geler. Lorsque la radio est en fonctionnement, il y a une telle interférence que «les fers commencent à parler», vous devez donc assurer un redémarrage soigneux du MK en cas de blocage. Une minuterie de surveillance sert à cet effet. Son utilisation est très simple. Tout d'abord, incluez le fichier d'en-tête avr / wdt.h dans le projet. Au début du programme, après avoir terminé tous les paramètres, vous devez démarrer le minuteur en appelant la fonction wdt_enable (WDTO_2S), puis n'oubliez pas de le réinitialiser périodiquement en appelant wdt_reset (), sinon il redémarrera le MK. Pour le débogage afin de savoir pourquoi le MK a été redémarré, vous pouvez utiliser la valeur du registre MCUSR spécial, dont la valeur peut être mémorisée puis sortie dans l'impression de débogage.
Économiser de l'énergie pour les amoureux de l'environnement
Alors que MK n'est occupé à rien, il peut s'endormir et attendre la prochaine interruption. Dans ce cas, un peu d'énergie électrique est économisée. Une bagatelle, mais pourquoi ne pas l'utiliser dans un projet. De plus, c'est très simple. Incluez le fichier d'en-tête avr / sleep.h. Le corps du programme se compose d'une boucle infinie dans laquelle vous devez appeler la fonction sleep_cpu (), après quoi le MC s'endort un peu et la boucle principale s'arrête jusqu'à la prochaine interruption. Ils se produisent pendant le fonctionnement de la minuterie et de l'ADC, donc MK ne dormira pas longtemps. Le mode d'hibernation est déterminé lorsque le MK est initialisé en appelant deux fonctions:
set_sleep_mode(SLEEP_MODE_IDLE);
C'est tout pour l'instant. J'ai fait le changement, cela fonctionne avec succès sur ma station de radio amateur sans échecs. J'espère que le matériel fourni sera utile aux débutants.
73 de R2AJP