I2L 2024 Groupe4

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche

Proposition de système

Ce projet consiste à concevoir un simulateur de Morse basé sur un microcontrôleur ATmega32U4. Il permet la traduction :

  1. Morse → Texte : L'utilisateur entre un code Morse via un bouton poussoir, et la carte le convertit en texte affiché sur le PC via une connexion USB série. On peut imaginer également afficher en temps réel les caractères entrés dans un écran LCD, dans le cas où il n'y a aucune connexion avec un poste fixe.
  2. Texte → Morse : Le PC envoie un message via USB, et la carte le traduit en signaux lumineux (LED) et sonores (buzzer). On peut également imaginer un affichage sur l'écran LCD.

Le circuit comprend :

  • Un bouton poussoir pour saisir le Morse.
  • Une LED et un buzzer pour la restitution des signaux.
  • Un écran LCD pour afficher le message saisi en morse.
  • Une interface USB pour la communication avec un PC.

Contre-proposition

OK pour le système embarqué décrit.

Pas de difficulté de programmation au niveau du système embarqué pour le buzzer et le bouton (gestion classique d'entrée et de sortie).

Pour la gestion de l'écran LCD vous pouvez vous inspirer du code des groupes 3 et 4 I2L en 2023/2024.

Pour la gestion série au niveau du système embarqué vous pouvez vous inspirer du code du groupe 5 I2L en 2023/2024.

Proposition définitive

Système de communication en port série avec deux boutons : un pour changer le mode (transmission ou réception) et un pour écrire des données en mode transmission.

La led s'allumera en mode transmission et reception, soit lorsque l'utilisateur appuie sur le bouton en transmission, soit lors de la traduction en mode réception et le buzzer émettera du son en conséquence. Les caratères traduits seront envoyés dans le port USB série et l'écran LCD et le texte à chiffrer en morse sera entré par le port série et affiché au fur et à mesure de la traduction sur l'écran LCD. Un mode de reset permettera de supprimer le texte affiché sur l'écran LCD lorsque le bouton sera maintenu.

Les caractères ASCII et les caractères spéciaux seront gérés, sauf les accents et caractères qui ne font pas partis du code international du morse.

Répartition du travail

Maxime se concentre sur la partie du haut parleur et les boutons poussoirs.

Jérémy réalise le micro controlleur avec les LEDs.


Conclusion : nous avons travaillé tous les deux sur des sujets différents au départ. Jérémy a réussi à réaliser la transmission et la réception USB en port série et Maxime a géré l'affichage sur l'écran LCD. Pour le reste, nous avons travaillé à part égale, ensemble, sur toutes les fonctionnalités spécifiées.

Carte

Schéma initial

Schéma de notre montage
Schéma de notre montage

Carte routée

Schéma de la carte
vue de la carte

Composants

  • ATmega32u4 : disponible
  • quartz GND24 : disponible
  • buzzer : disponible
  • perle ferrite MH2029-300Y : commandée
  • chargeur MAX1811 : disponible
  • potentiomètre : disponible
  • connecteur femelle 16 contacts : commandé
  • écran LCD 2 lignes : commandé
  • boutons : disponibles

Carte au 23/02/2025

Début de réalisation

Non encore réalisé :

  • ajouter les connecteurs J5, J6, J7 et J9 pour la charge ;
  • ajouter le condensateur de 2,2uF pour la charge ;
  • ajouter R8 et le potentiomètre pour l'écran LCD ;
  • ajouter le buzzer.

Carte au 27/02/2025

Réalisation terminée

Carte finalisée avec l'écran LCD et prête à l'emploi.

Code

Tout d'abord, pour développer notre projet, il nous fallait un moyen de représenter le code morse, et donc des structures :

typedef struct
{
    char character;
    const char *code;
} CharToMorseEntry;

typedef struct
{
    const char *code;
    char character;
} MorseToCharEntry;

Nous avons également définis les valeurs associées du code morse international afin de pouvoir faire la correspondance entre le français et le code morse associé et inversement (puisque chaque lettre a un code qui lui est propre) :

CharToMorseEntry char_to_morse_table[] = {
    {'A', ".-"}, {'B', "-..."}, {'C', "-.-."} /* autres....*/ }};

MorseToCharEntry morse_to_char_table[] = {
    {".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'} /* autres....*/};

Ensuite nous avons définis différentes fonctions utilitaires afin de transformer les caractères en morse et inversement, de les lire, de mettre à jour des tableaux, comme en témoigne ces signatures de méthodes (leur documentation détaillée est disponible dans le code et nous n'allons pas nous attarder sur ceci).

const char *get_morse_from_char(char c);
char get_char_from_morse(const char *morse);
void get_morse_from_text(const char *input, char *output, size_t max_size);
bool is_character_is_valid_morse(char c);
void update_morse_array(char *morse_array, int *char_index, char character);
void update_message_array(char *message_array, int *char_index, char character);
void reinitilize_array(char *array, int max_index);

Nous avons ajouté des fonctions pour contrôler la partie hardware du programme, tel que le buzzer, l'initialisation du timer, etc.

void initiliaze_timer(int diviseur, long periode);
void initialize_morse_game(void);
void use_buzzer(void);

La partie la plus complexe réside finalement dans ces fonctions qui sont les principales du projet :

int main(void);
char translate_morse_to_char(bool reset_message);
bool translate_text_to_morse(const char *message, const char *morse_message, bool reset_message);

La fonction translate_morse_to_char permet de réaliser la traduction de morse en texte. C'est la fonction qui est chargée de détecter lorsque le bouton est appuyé et la durée pendant laquelle il est appuyé. Cela permet ainsi de savoir quel caractère à été écrit, puisque chaque lettre correspond à un code morse bien déterminé. Par exemple, le signe SOS s'écrirait ... --- ... en morse, puisque le S est composé de 3 points et le O de trois traits, comme inscrit dans le code international du morse.

Pour comprendre la suite, il va nous falloir détailler comment fonctionne le morse, car la mesure du temps est primordiale pour comprendre comment fonctionnent la traduction et le fonctionnement.

Un point représente une unité de temps et un trait représente trois unités de temps. Chaque point ou trait est séparé d'une unité de temps. Chaque lettre est séparé de trois unités de temps soit l'équivalent d'un trait, et un mot est séparé d'un autre par sept unités de temps.

Cela signifie donc qu'un mot comme SOS prendrait 27 unités de temps + 7 autres unités de temps si un autre mot est émis ensuite. Pour arriver à ce résultat, il suffit d'aditionner chaque caractères :

  • 6 points = 6 unités de temps
  • 3 traits = 3 x 3 = 9 unités de temps
  • 6 unités de temps entre chaque caractère (sauf entre chaque lettre)
  • et 2 x 3 unités de temps séparant les trois lettres

Il nous fallait définir des constantes précises pour l'unité de temps, puis ensuite les calcul se baserai sur le temps défini, sachant que nous ne sommes pas des experts en morse, l'idéal est de mettre des temps élevés pour qu'on arrive à formuler des messages mais à l'époque il fallait aller vite puisque le but était d'écrire vite... Le véritable porblème réside donc dans cette mesure du temps. Nous avons dû utiliser le TIMER3 de notre carte afin d'avoir un compteur de temps qui s'incrémente régulièrement afin de pouvoir facilement détecter les caractères que souhaite faire l'utilisateur.

/**
 * @brief Initializes the hardware timer for periodic interrupts.
 *
 * @param diviseur Clock divider value.
 * @param periode Timer period in milliseconds.
 */
void initiliaze_timer(int diviseur, long periode)
{
    CLKSEL0 = 0b00010101; // sélection de l'horloge externe
    CLKSEL1 = 0b00001111; // minimum de 8Mhz
    CLKPR = 0b10000000;   // modification du diviseur d'horloge (CLKPCE=1)
    CLKPR = 0;            // 0 pour pas de diviseur (diviseur de 1)

    TCCR3A = 0;
    TCCR3B |= (1 << WGM32); // Le mode choisi n'utilise pas ce registre
    switch (diviseur)
    {
    case 8:
        TCCR3B |= (1 << CS31);
        break;
    case 64:
        TCCR3B |= (1 << CS31 | 11 << CS30);
        break;
    case 256:
        TCCR3B |= (1 << CS32);
        break;
    case 1024:
        TCCR3B |= (1 << CS32 | 1 << CS30);
        break;
    }
    // Un cycle prend 1/F_CPU secondes.
    // Un pas de compteur prend diviseur/F_CPU secondes.
    // Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas
    // soit (periode*F_CPU)/(1000*diviseur)
    OCR3A = F_CPU / PERIOD * periode / diviseur; // Calcul du pas
    TCNT3 = 0;                                   // Compteur initialisé
    TIMSK3 = (1 << OCIE3A);                      // Comparaison du compteur avec OCR1A
}

/**
 * @brief Timer interrupt service routine.
 *
 * Increments the global time counter.
 */
ISR(TIMER3_COMPA_vect)
{
    time_counter++;
}


Lancement

Pour lancer le projet, il faut insérer la carte dans l'ordinateur et se placer dans le dossier I2L/VirtualSerial à la racine du projet. Depuis cet endroit, il faudra lancer la commande de compilation qui va appeler les makefiles et transférer le code dans la carte : sudo make dfu Une fois cette commande effectuée vous serez en mesurer de texter en morse comme l'illustre les vidéos ci-dessous!

Démonstrations

Voici deux vidéo, la première montre comment il est possible d'écrire du texte en morse (même si c'est très dur on ne dira pas qu'on a enregistré la vidéo plusieurs fois) et la deuxième, ce que représente en morse un texte écris dans un port série USB.

Rendus

Projet KiCAD : Fichier:I2L-2024-Carte-G4-rex.zip

Programmes : Fichier:I2L-2024-Programmes-G4.zip