I2L 2025 Groupe5
Proposition de système (étudiants)
Un début d'ordinateur connecté à un clavier USB. Il permet de récupérer les inputs du clavier afin de les afficher sur l'écran LCD du microcontrôleur.
Contre-proposition (intervenant)
Il ne vous est pas demandé de faire en sorte que votre carte soit utilisable comme un périphérique USB. En effet vous devrez déjà utiliser la bibliothèque LUFA pour récupérer les informations du clavier USB.
Il est par contre demandé que :
- votre carte puisse fonctionner en autonomie à l'aide de la batterie, en mode recharge vous afficherez la progression de la dite recharge ;
- vous utiliserez un écran LCD avec 4 lignes de 20 caractères.
Proposition définitive (étudiants)
Répartition du travail (étudiants)
Carte
Schéma initial (étudiants)
- schéma (projet KiCAD) : Fichier:I2L-2025-Carte-G5.zip
Carte routée (intervenant)
Vous utiliserez la carte AVR7 spécifique à votre projet.
Composants (intervenant)
A la date du 9 octobre 2025, il manque l'inductance de 10 microhenry pour que le releveur de tension puisse fonctionner.
A la date du 10 octobre 2025, une inductance a été soudée mais l'empreinte n'est vraiment pas adaptée, il faudra peut-être revoir ce point. En tout cas vérifier la présence de 5V en sortie du releveur de tension.
Carte réalisée (intervenant)
La carte est entiérement soudée à l'exception de l'inductance de 10mH (effectué le 10 octobre 2025).
Travaux (étudiants)
Partie Premiers pas:
Lors de nos premiers tests, nous avons essayé de faire clignoter une LED en réglant l'horloge. Puis nous avons essayé de faire en sorte que lorsqu'on appuie sur un bouton la LED en PB5, en mode interruption. Mais le problème avec le mode interruption sur un bouton: lorsque le bouton est pressé, le bouton envoie un signal qui n'est pas fixe, il fluctue, ce qui ne permet pas à la LED de s'allumer.
Les boutons sur la carte ne permet donc pas de travailler en interruption.
Mais avec ce code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define LED PB5
#define BOUTON PF0
ISR(INT2_vect){
PORTB |= (1 << LED);
}
ISR(INT3_vect){
PORTB &= ~(1 << LED);
}
int main(void){
CLKPR = 0b10000000; // modification du diviseur d'horloge (CLKPCE=1)
CLKPR = 0; // 0 pour pas de diviseur
// Conf LED
DDRB |= (1 << LED);
// Conf Bouton
DDRF &= ~(1 << BOUTON);
PORTF |= (1 << BOUTON);
DDRD &= ~((1 << PD2)|(1 << PD3));
PORTD |= (1 << PD2)|(1 << PD3);
EICRB |= (1 << ISC21)|(1 << ISC31);
EICRB &= ~((1 << ISC20)|(1 << ISC30));
EIFR |= (1 << INTF2)|(1 << INTF3);
EIMSK |= (1 << INT2)|(1 << INT3);
sei();
while(1);
return 0;
}
Le fait de créer un pont entre la masse et TX, cela éteint la LED en PB5 et créer un pont entre la masse et RX, cela allume la LED en PB5.
(vidéo exemple):
Partie écran LCD:
En lisant la documentation de l'écran LCD (https://cdn.sparkfun.com/assets/9/5/f/7/b/HD44780.pdf), nous avons appris comment bien initialiser l'écran, gérer le curseur, gérer l'affichage de l'écran (page 24). Nous sommes arrivé à écrire des messages avec des fonctions dans laquelle on n'a d'abord cherché à seulement afficher un message pré-écrit dans notre code. Au final, nous nous sommes rendu compte que après les 20 caractères d'une ligne, l'écran LCD fait passer de la ligne n°1 à ligne n°3, puis de la ligne n°3 à la ligne n°2, puis de la ligne n°2 à la ligne n°4. Mais nous avons réussi à écrire sur les 4 lignes avec des petits messages de moins de 20 caractères.
Voici le code:
lcd_print("Ligne 1", 0);
lcd_print("Ligne 2", 1);
lcd_print("Ligne 3", 2);
lcd_print("Ligne 4", 3);
En continuant à lire la documentation, nous sommes arrivés à une conclusion. L'écran LCD possède 2 types de lignes. Un écran LCD HD44780U possède deux types de lignes : les lignes physiques, visibles sur l’écran, et les lignes logiques, stockées dans la mémoire DDRAM du contrôleur. Les lignes physiques affichent les caractères, tandis que les lignes logiques définissent leur position en mémoire. Ces lignes ne sont pas toujours contiguës : par exemple, la ligne 2 commence à l’adresse 0x40. Le contrôleur gère ainsi l’affichage en multiplexant les lignes.
Numéro de la ligne | Adresse DDRAM
| Numéro de la ligne | Adresse DDRAM |
| Ligne 1 | 0x00 à 0x13
|
Ligne 1 est la première partie de la première ligne physique
| Ligne 2 | 0x40 à 0x53
|
Ligne 2 est la première partie de la deuxième ligne physique
| Ligne 3 | 0x14 à 0x27
|
Ligne 3 est la deuxième partie de la première ligne physique
| Ligne 4 | 0x54 à 0x67
|
Ligne 4 est la deuxième partie de la deuxième ligne physique
Nous avons ensuite coder une fonction nous permettant de positionner correctement le curseur, peu importe la taille du message que nous voulons afficher. C'est-à-dire que lorsqu'un caractère est envoyé sur l'écran LCD, on décale le curseur d'une colonne. Si le nombre de colonnes est supérieur au nombre de colonnes de notre écran LCD, il passe à la ligne suivante.
void lcd_print_row(const char *str, uint8_t row) {
// On indique la ligne d'écriture pour pouvoir ajuster si besoin
uint8_t col = 0;
// On vérifie si la ligne est correcte
if(row<0 || row >= LCD_ROWS){
row = 0;
}
// On affiche le texte
while (*str){
lcd_set_cursor(row, col);
lcd_data(*str++);
col++;
if(col >= LCD_COLUMNS){
// On passe une nouvelle ligne si besoin
col = 0;
row++;
if(row >= LCD_ROWS){
// On boucle si besoin
row = 0;
}
}
}
}
void lcd_set_cursor(uint8_t row, uint8_t col) {
// Définition des lignes logicielles par rapport aux adresses matérielles
uint8_t row_offsets[] = {LCD_ROW_1, LCD_ROW_2, LCD_ROW_3, LCD_ROW_4};
// On indique où on va écrire ou lire le caractère
lcd_command(SET_DDRAM | (col + row_offsets[row]));
}
static void lcd_data(uint8_t data) {
lcd_send_byte(1, data);
}
Dans ce code, lcd_print_row est la fonction principale où 'str' est le message que nous voulons afficher et 'row' est la ligne sur laquelle nous voulons commencer à écrire. Si la ligne est correcte on commence à écrire. En mettant le curseur au bon endroit: sur la bonne colonne et sur la bonne ligne grâce à la fonction lcd_set_cursor. Ensuite nous envoyons la donnée vers l'écran LCD grâce à la fonction lcd_data qui envoie caractère par caractère.
Ensuite, nous avons mis une fonction pour effacer tout ce qu'il y a sur l'écran.
void lcd_clear(void){
lcd_print_row(" ", 0);
lcd_print_row(" ", 1);
lcd_print_row(" ", 2);
lcd_print_row(" ", 3);
}
Partie gestion du clavier:
Lors de nos premiers tests pour gérer le clavier, nous avons tout d'abord tester la puissance électrique délivrée au connecteur USB femelle. Nous nous sommes rendu compte que la puissance délivrée n'était que d'environ 3V au lieu de 5V. Ce qui pouvait poser des problèmes lors de l'alimentation de notre clavier USB.
Après échange avec le professeur, le problème venait du convertisseur de la batterie qui était un convertisseur 3V. On nous a donc fourni une nouvelle carte, sans batterie, mais avec un fil qui relie directement l'alimentation au connecteur USB.
Quand nous avons voulu connecter notre clavier USB à notre carte, nous avons eu un problème:
Lorsque le clavier est connecté à notre carte, la liste des connexions USB du PC n'affiche plus notre carte mais uniquement le clavier. Aussi, nous pouvons taper sur notre clavier qui input sur notre PC mais, la carte n'est plus détecté donc on ne peux plus modifier le code de la carte lorsque le clavier USB est branché.
Ensuite, nous avons essayé de mettre la librairie LUFA. Le but de cette manœuvre est de pouvoir récupérer ce qui est tapé par le clavier USB.
Tentative: Tout d'abord, on a passé tout le code de lcd dans un fichier à part. Ce fichier a été mis dans le dossier LUFA/Demos/Host/LowLevel/KeyboardHost. Et inclus dans le fichier KeyboardHost.c. Ca compile après pas mal d'essais. Mais on s'est rendu compte que l'éxécution du code s'arrêtait après la fonction USB_Init() de la bibliothèque LUFA.
Ce que nous avont mal fait: nous avons pris le repo git de LUFA, le plus récent. Ce qui amenait certains problèmes.
Extraits significatifs de code (étudiants)
Rendus (étudiants)
Projet KiCAD : Fichier:I2L-2025-Carte-G5-final.zip
Programmes :
- microcontrôleur : Fichier:I2L-2025-Programmes-uC-G5.zip
- ordinateur Fichier:I2L-2025-Programmes-PC-G5.zip