« SE3Groupe2024-2 » : différence entre les versions
(17 versions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 140 : | Ligne 140 : | ||
|} | |} | ||
''Datasheet ATmega32u4 :'' | ''Datasheet ATmega32u4 :'' | ||
[[Fichier:Datasheet ATMEGA32U4.pdf|199x199px|vignette|Datasheet du microcontroleur : ATMEGA32U4|centré]] | [[Fichier:Datasheet ATMEGA32U4.pdf|199x199px|vignette|Datasheet du microcontroleur : ATMEGA32U4|gauche]][[Fichier:AVR042.pdf|199x199px|vignette|AVR Hardware Design Considerations|centré]] | ||
<p style="clear: both;" /> | |||
==== Communication ==== | ==== Communication ==== | ||
La station utilisera une puce '''NRF24L01''' pour la communication sans fil entre les différents actionneurs et capteurs. | La station utilisera une puce '''NRF24L01''' pour la communication sans fil entre les différents actionneurs et capteurs. | ||
Ligne 174 : | Ligne 176 : | ||
Pour proteger les composants, nous allons ajouter un régulateur de tension pour garder une tension de 3,3V sur l'ensemble de notre carte. | Pour proteger les composants, nous allons ajouter un régulateur de tension pour garder une tension de 3,3V sur l'ensemble de notre carte. | ||
Ligne 199 : | Ligne 202 : | ||
La carte comportera également une led afin d'indiquer son état d'alimentation ainsi que deux autres leds permettant de faire des tests de programmation. | La carte comportera également une led afin d'indiquer son état d'alimentation ainsi que deux autres leds permettant de faire des tests de programmation. | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
== Hardware de la station domotique == | == Hardware de la station domotique == | ||
Ligne 226 : | Ligne 227 : | ||
== Software de la station domotique == | == Software de la station domotique == | ||
=== Capteurs === | === <big>Capteurs</big> === | ||
==== Capteur de mouvement ==== | ==== <big>Capteur de mouvement - HC-SR501</big> ==== | ||
===== Principe physique ===== | |||
Le capteur de mouvement HC-SR501 est un capteur infrarouge passif (PIR), ce qui signifie qu’il ne produit aucun rayonnement mais détecte celui émis naturellement par les objets chauds, notamment le corps humain. | |||
Ces deux cellules pyroélectriques sont disposées de manière à percevoir deux zones distinctes du champ de vision. En l'absence de mouvement, les deux reçoivent une quantité similaire d'infrarouge, et le signal reste équilibré. | |||
Lorsqu'un corps chaud passe devant le capteur, la quantité d’infrarouge captée change entre les deux cellules, créant un déséquilibre. Ce changement est interprété comme un mouvement. | |||
Un dôme en plastique blanc recouvre le capteur : c’est une lentille de Fresnel. | |||
Elle concentre et divise la lumière infrarouge en plusieurs zones, augmentant ainsi la portée et la sensibilité du capteur en "segmentant" son champ de vision. Ainsi, même un petit mouvement crée une variation significative de rayonnement perçu. | |||
===== Spécifications techniques ===== | ===== Spécifications techniques ===== | ||
On utilise un capteur de mouvement HC-SR501 (voir datasheet ci-dessous) afin de détecter ou non la présence de quelqu'un dans une pièce | On utilise un capteur de mouvement HC-SR501 (voir datasheet ci-dessous) afin de détecter ou non la présence de quelqu'un dans une pièce. L'intérêt est de pouvoir ensuite allumer la lumière si une personne est présente ou a contrario l'éteindre si la pièce est vide. Ici la lumière sera modélisée par une led présente sur l'arduino UNO en guise de démonstration. | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
[[Fichier:Datasheet mvmt.pdf|alt=datasheet_mvmt|vignette|datasheet_mvmt]] | [[Fichier:Datasheet mvmt.pdf|alt=datasheet_mvmt|vignette|datasheet_mvmt]] | ||
[[Fichier:Mvmt.png|alt=mvmt|vignette|capteur_mvmt|centré]] | [[Fichier:Mvmt.png|alt=mvmt|vignette|capteur_mvmt|centré|479x479px]] | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
* Jumper Set | * Jumper Set | ||
Les deux modes repeat ou single trigger permettent de régler le | Les deux modes, repeat ou single trigger, permettent de régler le trigger de schmith permettant la détection d'une présence. En single, on effectue un seul trigger afin de détecter spontanément une présence (ex : Cas alarme intrusion). | ||
Dans l'autre mode on souhaite détecter un mouvement peu importe si celui-ci est déjà détecter. Par exemple, besoin d'un mouvement après un certains nombre de temps pour que la led reste allumée ou bien besoin de réactiver de temps à autre le capteur en bougeant. | |||
* Sensitivty Adjust | * Sensitivty Adjust | ||
On modifie le potentiomètre à l'aide d'un tournevis afin d'ajuster la sensibilité à la présence de notre main, par exemple pour l'amplitude de nos mouvements. | On modifie le potentiomètre à l'aide d'un tournevis afin d'ajuster la sensibilité à la présence de notre main, par exemple pour l'amplitude de nos mouvements. | ||
*Time Delay Adjust | |||
Ici le potentiomètre permet d'ajuster le temps entre deux seuils de détection afin d'éviter la détection après des mouvements parasites, par exemple pour déclencher sans erreur une alarme intrusion. | |||
===== Circuit ===== | ===== Circuit ===== | ||
Ligne 251 : | Ligne 270 : | ||
===== Programmation ===== | ===== Programmation ===== | ||
Voici le code afin d'allumer une led dès qu'une présence est détectée. <syntaxhighlight lang="c" line="1"> | Voici le code afin d'allumer une led dès qu'une présence est détectée. <syntaxhighlight lang="c" line="1"> | ||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <util/delay.h> | #include <util/delay.h> | ||
Ligne 265 : | Ligne 281 : | ||
PORTB &= ~(1 << PB5); //led éteinte | PORTB &= ~(1 << PB5); //led éteinte | ||
} | } | ||
_delay_ms(500); | _delay_ms(500); // Peut être baisser ou augmenter pour regler la sensibilité de détection | ||
} | } | ||
return 0; | return 0; | ||
Ligne 278 : | Ligne 294 : | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
Dans un second temps, on fera communiquer ce capteur avec notre carte station domotique par le biais des modules | Dans un second temps, on fera communiquer ce capteur avec notre carte station domotique par le biais des modules de communication radio (NRF24L01) afin d'afficher l'état de la pièce sur l'écran et également transmettre ces données via le port série. | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
==== Capteur de température ==== | ==== <big>Capteur de température - DS18B20</big> ==== | ||
===== Principe physique ===== | |||
Ce capteur fonctionne grâce à un principe physique appelé '''variation de la résistance électrique avec la température'''. À l’intérieur du capteur, il y a un composant semi-conducteur, souvent une '''diode ou une jonction PN''', qui change son comportement électrique selon la température. | |||
Quand la température augmente, la façon dont les électrons se déplacent dans ce matériau change, ce qui modifie la tension ou le courant électrique mesuré. | |||
Un convertisseur analogique-numérique (CAN) est intégré au circuit afin de transferer par la suite la mesure via un protole 1-Wire. | |||
<p style="clear: both;" /> | |||
===== Spécifications techniques ===== | ===== Spécifications techniques ===== | ||
Ligne 287 : | Ligne 311 : | ||
[[Fichier:Datasheet temp eau.pdf|alt=Datasheet_temp_eau|vignette|Datasheet_temp_eau|centré]] | [[Fichier:Datasheet temp eau.pdf|alt=Datasheet_temp_eau|vignette|Datasheet_temp_eau|centré]] | ||
<p style="clear: both;" /> | |||
===== Circuit ===== | ===== Circuit ===== | ||
Ligne 293 : | Ligne 318 : | ||
* le gnd est relié à la masse | * le gnd est relié à la masse | ||
* le power est relié au 3,3V | * le power est relié au 3,3V | ||
* le fil de données est branché sur le pin | * le fil de données est branché sur le pin PD2 (digital 2). | ||
On branche également une résistance de 4,7kΩ entre le fil de données et le 3,3V.[[Fichier:Capteur eau.jpg|alt=capteur_eau|vignette|capteur_eau|centré]] | |||
[[Fichier:Capteur eau.jpg|alt=capteur_eau|vignette|capteur_eau|centré]] | |||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
===== Programmation ===== | ===== Programmation ===== | ||
====== Arduino ====== | ====== Arduino ====== | ||
Pour commencer on a testé si notre sonde fonctionnait correctement à l'aide d'un code arduino et on a constaté aucun souci (voir | Pour commencer, on a testé si notre sonde fonctionnait correctement à l'aide d'un code arduino et on a constaté aucun souci ([https://gitea.plil.fr/ahouduss/se3_2024_B2/src/branch/main/02%20-%20Station%20Domotique/2.3-programmation/2.3.2-capteurs/temperature_eau/Arduino/temperature_eau.ino voir code]). | ||
<p style="clear: both;" /> | |||
====== C ====== | ====== C ====== | ||
Nous avons trouvé deux ressources sur github que l'on a fusionné afin d'obtenir un code fonctionnel adapté à nos besoins et surtout un code qui nous correspond. On a utilisé les fichiers de ce répertoire : | |||
https://gitea.plil.fr/ahouduss/se3_2024_B2/src/branch/main/02%20-%20Station%20Domotique/02%20-%20Programmation/Capteurs/Temperature%20eau/1er%20code%20%28C%29 | |||
Fichiers utilisés : | |||
1/ <u>onewire.h, onewire.c </u>: pour remplacer la librairie OneWire.h de l'arduino afin de communiquer avec l'unique fil de données de la sonde. | |||
Fonctions implémentées : | |||
* | * onewireInit : reset le bus de données et renvoie une erreur si le capteur de répond pas et OK sinon. | ||
* onewireWriteBit : envoie un bit sur le bus de données en respectant le temps d'envoi du protocole Onewire. | |||
* UART.h, UART.c : pour afficher la température sur la liaison série. | * onewireWrite : transmet un octet en utilisant la fonction précédente. | ||
* main.c : pour le code principal | * onewireReadbit : lit un bit sur le bus de données. | ||
* Makefile : pour faciliter la compilation | * onewireRead : lit un octet sur le bus de données. | ||
<p style="clear: both;" /> | |||
2/ <u>ds18b20.h, ds18b20.c</u> : pour les fonctions principales utiles à notre sonde. | |||
* ds18B20crc8 : crc signifie cyclic redundacy check est l'octet renvoyé par cette fonction qui permet de savoir si la transmission s'est effectuée sans erreurs. | |||
* ds18b20match : utile si il y a plusieurs capteurs (pas le cas ici). | |||
* ds18b20convert : la valeur de la température est stockée sur les deux premiers octets de la mémoire scratchpad. ds18b20convert permet de convertir ces octets en degré celsius. | |||
* ds18b20rsp : lit le scratchpad (mémoire temporaire) pour récupérer la valeur de la température (sur les deux premiers octets). | |||
* ds18b20wsp : écrit dans le scratchpad. | |||
* ds18b20csp : copie les données du scratchpad dans l'eeprom du capteur. | |||
* ds18b20read : lit la température. | |||
* ds18b20rom : lit l'adresse du capteur rom (pas utile ici car un seul capteur). | |||
<p style="clear: both;" /> | |||
3/ <u>UART.h, UART.c</u> : pour afficher la température sur la liaison série. On définit deux fonctions : | |||
* USART_SendChar pour afficher un caractère sur le minicom. | |||
* USART_SendString pour afficher des mots sur le minicom. Rq : utiliser le retour chariot \r pour un affichage correct. | |||
<p style="clear: both;" /> | |||
4/ <u>main.c</u> : pour le code principal | |||
<syntaxhighlight lang="c" line="1"> | |||
#include <avr/io.h> | |||
#include <util/delay.h> | |||
#include <stdio.h> | |||
#include "UART.h" | |||
#include "ds18b20.h" | |||
#define DS18B20_DDR DDRD | |||
#define DS18B20_PORT PORTD | |||
#define DS18B20_PIN PIND | |||
#define DS18B20_MASK (1 << PD2) | |||
int main(void) | |||
{ | |||
int16_t temperature_raw; | |||
char buffer[32]; | |||
uint8_t error; | |||
USART_init(9600); | |||
USART_SendString("Debut lecture DS18B20...\r\n"); | |||
while (1) | |||
{ | |||
// Démarrer conversion | |||
error = ds18b20convert(&DS18B20_PORT, &DS18B20_DDR, &DS18B20_PIN, DS18B20_MASK, NULL); | |||
if (error != DS18B20_ERROR_OK) { | |||
USART_SendString("Erreur conversion\r\n"); | |||
_delay_ms(1000); | |||
continue; | |||
} | |||
_delay_ms(800); // attendre la fin de conversion | |||
// Lire la température | |||
error = ds18b20read(&DS18B20_PORT, &DS18B20_DDR, &DS18B20_PIN, DS18B20_MASK, NULL, &temperature_raw); | |||
if (error == DS18B20_ERROR_OK) { | |||
float temperature_celsius = temperature_raw / 16.0; | |||
snprintf(buffer, sizeof(buffer), "Temp: %.2f C\r\n", temperature_celsius); | |||
USART_SendString(buffer); | |||
} else { | |||
snprintf(buffer, sizeof(buffer), "Erreur lecture: %d\r\n", error); | |||
USART_SendString(buffer); | |||
} | |||
_delay_ms(1000); | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight><p style="clear: both;" />Dans notre fonction main : | |||
* on initialise la liaison série. | |||
* on convertit les octets de la mémoire du capteur en une température en degré celsius. | |||
* on lit la température afin de l'afficher dans le minicom. Pour cela, il faut au préalable convertir ntre température en flottant en des caractères avec une taille adaptée au buffer à l'aide de la fonction snprintf (string numbered print format).<p style="clear: both;" /> | |||
5/ <u>Makefile</u> : pour faciliter la compilation <p style="clear: both;" />Rq: penser à modifier le port de AVRDUDE_PORT si le make upload de fonctionne pas. | |||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
Ligne 320 : | Ligne 430 : | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
=== Actionneur === | === <big>Actionneur</big> === | ||
==== Lumière ==== | ==== <big>Lumière</big> ==== | ||
On peut décider d'allumer une lumière selon certains | On peut décider d'allumer une lumière selon certains critères (par exemple lorsque le capteur de présence détecte quelqu'un). Ici allumer une led par exemple. | ||
=== Communication === | === <big>Communication</big> === | ||
Pour plus de détails, se référer à la rubrique spécifications techniques->communication. Ici nous traiterons du code implémenté afin de communiquer entre les différents capteurs/actionneurs et notre carte principale. | Pour plus de détails, se référer à la rubrique spécifications techniques -> communication. Ici nous traiterons du code implémenté afin de communiquer entre les différents capteurs/actionneurs et notre carte principale. | ||
=== Ecran === | === <big>Ecran</big> === | ||
Afin d'avoir une interface pour l'utilisateur, nous décidons d'afficher sur un écran les données reçues des capteurs et l'état des actionneurs. On doit donc voir s'afficher la température d'une pièce, si il y a une présence etc. | Afin d'avoir une interface pour l'utilisateur, nous décidons d'afficher sur un écran les données reçues des capteurs et l'état des actionneurs. On doit donc voir s'afficher la température d'une pièce, si il y a une présence etc. | ||
Pour cela, on va devoir coder l'écran NHD‐C12832A1Z‐FSW‐FBW‐3V3 (voir datasheet dans la rubrique spécifications techniques->écran). | Pour cela, on va devoir coder l'écran NHD‐C12832A1Z‐FSW‐FBW‐3V3 (voir datasheet dans la rubrique spécifications techniques->écran). | ||
== Programmateur AVR == | == Programmateur AVR (Projet annexe) == | ||
=== Objectif === | === Objectif === | ||
Réaliser un programmateur AVR afin d'envoyer notre code C sur | Réaliser un programmateur AVR afin d'envoyer notre code C sur un microcontrôleur. Ce projet est une introduction au logiciel et à la programmation sur microcontroleur AVR. | ||
https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/systeme063.html | Nous nous sommes aider du cours afin de réaliser notre projet : https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/systeme063.html | ||
=== Schématique === | === Schématique === | ||
Ligne 355 : | Ligne 465 : | ||
=== Fichier kicad === | === Fichier kicad === | ||
[[Fichier:2024-PSE-G2-Prog.zip|centré]] | [[Fichier:2024-PSE-G2-Prog VFinale sans erreur.zip|alt=2024-PSE-G2-Prog VFinale|centré]] | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
Ligne 366 : | Ligne 476 : | ||
==== Test leds et boutons ==== | ==== Test leds et boutons ==== | ||
Afin de vérifier que notre carte fonctionne correctement après brasure, on code un programme permettant d'allumer une | Afin de vérifier que notre carte fonctionne correctement après sa brasure, on code un programme permettant d'allumer une LED lorsqu'un bouton poussoir est pressé. Chaque bouton est associé à une LED. | ||
===== Modification de l'horloge ===== | |||
<syntaxhighlight lang="c" line="1"> | |||
void setupClock(void) | |||
{ | |||
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) | |||
} | |||
</syntaxhighlight> | |||
====== Fonction initialisation des pins ====== | |||
<syntaxhighlight lang="c" line="1"> | |||
void setupPin(volatile uint8_t* PORTx, volatile uint8_t* DDRx, uint8_t pin, pinmode mode) { | |||
switch (mode) | |||
{ | |||
case INPUT: // Forcage pin à 0 | |||
*DDRx &= ~(1 << pin); | |||
break; | |||
case INPUT_PULL_UP: // Forcage pin à 0 | |||
*DDRx &= ~(1 << pin); | |||
*PORTx |= (1 << pin); | |||
break; | |||
case OUTPUT: // Forcage pin à 1 | |||
*DDRx |= (1 << pin); | |||
break; | |||
} | |||
} | |||
</syntaxhighlight> | |||
====== Fonction initialisation de l'ensemble des boutons et LEDs ====== | |||
<syntaxhighlight lang="c" line="1"> | |||
void setupHardware() { | |||
setupClock(); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED1_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED2_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED3_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED4_PIN, OUTPUT); | |||
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Up_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Down_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Left_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Right_PIN, INPUT_PULL_UP); | |||
} | |||
</syntaxhighlight> | |||
====== Fonction de lecture de pin ====== | |||
<syntaxhighlight lang="c" line="1"> | |||
int readPin(volatile uint8_t* PINx, uint8_t pin) { | |||
return (*PINx & (1 << pin)); | |||
} | |||
</syntaxhighlight> | |||
====== Fonction pour initialiser les composantes de la cartes ====== | |||
<syntaxhighlight lang="c"> | |||
// ------------------ Boutons ------------------ // | |||
#define BTNsUp_Left_PORT &PORTC | |||
#define BTNsUp_Left_DDR &DDRC | |||
#define BTNsUp_Left_PIN &PINC | |||
#define BTNsDown_Right_PORT &PORTB | |||
#define BTNsDown_Right_DDR &DDRB | |||
#define BTNsDown_Right_PIN &PINB | |||
#define BTN_Up_PIN PC4 | |||
#define BTN_Down_PIN PB5 | |||
#define BTN_Left_PIN PC6 | |||
#define BTN_Right_PIN PB6 | |||
// ------------------ LEDs ------------------ // | |||
#define LEDs_PORT &PORTD | |||
#define LEDs_DDR &DDRD | |||
#define LEDs_PIN &PIND | |||
#define LED1_PIN PD0 | |||
#define LED2_PIN PD1 | |||
#define LED3_PIN PD2 | |||
#define LED4_PIN PD3 | |||
// ------------------ Enum ------------------ // | |||
typedef enum { | |||
INPUT, | |||
INPUT_PULL_UP, | |||
OUTPUT, | |||
} pinmode; | |||
void setupHardware() { | |||
setupClock(); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED1_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED2_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED3_PIN, OUTPUT); | |||
setupPin(LEDs_PORT, LEDs_DDR, LED4_PIN, OUTPUT); | |||
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Up_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Down_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Left_PIN, INPUT_PULL_UP); | |||
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Right_PIN, INPUT_PULL_UP); | |||
} | |||
</syntaxhighlight> | |||
==== LUFA ==== | |||
Afin de pouvoir faire de notre carte un périphérique USB, nous allons utiliser la LUFA (Lightweight USB Framefork for AVRs). | |||
* Tout d'abord, nous avons codé un programme permettant de voir si la lufa détecte bien les boutons-poussoirs de notre carte comme des points d'accès d'entrées en affichant sur le minicom quel bouton-poussoir était pressé par l'utilisateur. Notre code se trouve dans le répertoire se ci-dessous : https://gitea.plil.fr/ahouduss/se3_2024_B2/src/branch/main/01%20-%20Programmateur%20AVR/programmation/lufa-LUFA-210130-NSI/se/VirtualSerial | |||
Pour écrire notre code, nous avons réutilisé l'exemple VirtualSerial récupéré au repertoire suivant : <code>LUFA/Demos/Device/LowLevel/VirtualSerial</code> | |||
Afin de mettre le programme sur notre carte, on vérifie au préalable que notre carte est bien reconnue en tant que périphérique USB à l'aide de la commande lsusb. | Afin de mettre le programme sur notre carte, on vérifie au préalable que notre carte est bien reconnue en tant que périphérique USB à l'aide de la commande lsusb. | ||
Ligne 374 : | Ligne 598 : | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
Pour plus de détail sur notre périphérique usb branché on doit faire la commande | Pour plus de détail sur notre périphérique usb branché on doit faire la commande suivante :<syntaxhighlight lang="terminfo" line="1"> | ||
cedricagathe@computer:~$ lsusb -s 003:008 -v | cedricagathe@computer:~$ lsusb -s 003:008 -v | ||
Ligne 422 : | Ligne 646 : | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Comme vu en cours, on revoit nos descripteurs ainsi que la description des interfaces de l'usb ainsi que d'autres données.Une fois notre carte détectée, on appuie sur le bouton HWB puis | Comme vu en cours, on revoit nos descripteurs ainsi que la description des interfaces de l'usb ainsi que d'autres données. Une fois notre carte détectée, on appuie en continue sur le bouton HWB puis une seule impulsion sur le bouton RESET afin de mettre notre carte en mode DFU et ensuite on relache HWB. | ||
On pourra alors téléverser notre programme sur la carte à l'aide d'un makefile préalablement codé en tapant la commande <code>make upload</code>. | |||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
Ligne 429 : | Ligne 655 : | ||
<p style="clear: both;" /> | <p style="clear: both;" /> | ||
* On place le programme dans notre carte à l'aide de la commande <code>make upload</code>. Pour ce faire, il faut modifier le makefile original par ceci : | |||
* On place le programme dans notre carte à l'aide de la commande make upload. Pour ce faire, il faut modifier le makefile original par ceci : | |||
<syntaxhighlight lang="makefile" line="1" start="1"> | <syntaxhighlight lang="makefile" line="1" start="1"> | ||
MCU = atmega8u2 | MCU = atmega8u2 | ||
Ligne 469 : | Ligne 687 : | ||
sudo minicom -os | sudo minicom -os | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<p style="clear: both;" /> | <p style="clear: both;" />Ensuite nous entrons dans Serial port setup :[[Fichier:Image terminal apres commande minicom -os.png|gauche|sans_cadre|361x361px]] | ||
Ensuite nous entrons dans Serial port setup : | |||
[[Fichier:Image terminal apres commande minicom -os.png|gauche|sans_cadre|361x361px]] | |||
[[Fichier:Menu serial port ssetup minicom.png|centré|sans_cadre|395x395px]] | [[Fichier:Menu serial port ssetup minicom.png|centré|sans_cadre|395x395px]] | ||
Ligne 497 : | Ligne 712 : | ||
<p style="clear: both;" /><p style="clear: both;" /> | <p style="clear: both;" /><p style="clear: both;" /> | ||
===== Modification du fichier virtual.c | ===== <big>Modification du fichier virtual.c</big> ===== | ||
</ | |||
===== | |||
====== Afficher sur le minicom lorsqu'un bouton est pressé ====== | ====== Afficher sur le minicom lorsqu'un bouton est pressé et test leds ====== | ||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
Ligne 542 : | Ligne 720 : | ||
void CDC_Task(void) | void CDC_Task(void) | ||
{ | { | ||
char* ReportString = NULL; | |||
static bool ActionSent = false; | static bool ActionSent = false; | ||
Version actuelle datée du 10 mai 2025 à 15:17
Lien GIT
Voici le lien git pour accéder aux différents fichiers relatifs à notre projet : https://gitea.plil.fr/ahouduss/se3_2024_B2.git
Description
Objectif
L'objectif de ce projet est de concevoir une station domotique capable de collecter et d'afficher des mesures provenant de capteurs. Elle devra également être capable d'activer des actionneurs, tels que des LEDs, des cadenas ou tout autre dispositif, en fonction des besoins.
Cahier des charges
La station domotique devra permettre l'affichage des informations suivantes concernant une pièce :
- Température ambiante ;
- Taux d'humidité ;
- Présence humaine (via capteur de mouvement) ;
- D'autres paramètres pourront être ajoutés en fonction de l'avancement du projet.
Elle devra aussi permettre de contrôler différents actionneurs dans la pièce, tels que :
- L'éclairage, en fonction de la présence d'une personne (via un capteur de mouvement) ;
- D'autres dispositifs pourront être intégrés en fonction des besoins.
Des capteurs et actionneurs supplémentaires pourront être ajoutés si le projet atteint ses objectifs initiaux.
Spécification techniques
Microcontrôleur
Le projet nécessite un microcontrôleur, qui contiendra le programme, et qui communiquera avec les autres composants via les GPIOs.
Nous avons le choix entre plusieurs modèles de microcontrôleur : ATmega16u4, AT90USB1286, AT90USB1287.
Voici un tableau comparatif afin de sélectionner le plus adapté pour notre usage :
Caractéristiques | ATmega16U4 | AT90USB1286 | AT90USB1287 |
Architecture | AVR 8 bits | AVR 8 bits | AVR 8 bits |
Mémoire Flash | 16 KB | 128 KB | 128 KB |
RAM (SRAM) | 1.25 KB | 4 KB | 4 KB |
EEPROM | 512 Bytes | 4 KB | 4 KB |
Fréquence d'horloge max. | 16 MHz | 16 MHz | 16 MHz |
Nombre de broches GPIO | 26 | 48 | 48 |
Interfaces de communication | UART, SPI, I²C, USB 2.0 | UART, SPI, I²C, USB 2.0 | UART, SPI, I²C, USB 2.0 |
Contrôleur USB intégré | Oui (USB 2.0) | Oui (USB 2.0) | Oui (USB 2.0) |
Taille des registres | 8 bits | 8 bits | 8 bits |
Nombre de broches | 32 | 64 | 64 |
Différences principales | Conçu pour des applications compactes avec
moins de mémoire et d'E/S |
Plus de mémoire, adapté à des projets complexes nécessitant de nombreuses E/S et de la mémoire | Similaire au AT90USB1286 mais avec des fonctionnalités spécifiques
pour certaines configurations USB (e.g., modes host/OTG). |
Lien documentation | https://www.microchip.com/en-us/product/atmega16u4 | https://www.microchip.com/en-us/product/at90usb1286 | https://www.microchip.com/en-us/product/at90usb1287 |
Avec ce tableau, on constate que l'ATmega16U4 ne possède pas suffisamment de broches GPIOs. Cependant l'AT90USB1286 et son homologue l'AT90USB1287 dépassent notre cadre d'usage (utilisation mode USB spécifique HOST/OTG, etc... ).
Le compromis est donc d'opter pour un ATmega32u4 afin d'avoir suffisamment de broches et de mémoire.
Caractéristiques | ATmega32U4 |
---|---|
Architecture | AVR 8 bits |
Mémoire Flash | 32 KB |
RAM (SRAM) | 2.5 KB |
EEPROM | 1 KB |
Fréquence d'horloge max. | 16 MHz |
Nombre de broches GPIO | 26 |
Interfaces de communication | UART, SPI, I²C, USB 2.0 |
Contrôleur USB intégré | Oui (USB 2.0) |
Taille des registres | 8 bits |
Nombre de broches | 32 |
Différences principales | Conçu pour des applications nécessitant un contrôleur USB intégré, avec une mémoire et un nombre de broches intermédiaires |
Datasheet ATmega32u4 :
Communication
La station utilisera une puce NRF24L01 pour la communication sans fil entre les différents actionneurs et capteurs.
La communication entre le pc et la station se fera quant à elle en USB.
Lien tutoriel utilisation de puces à distance : NRF24L01
Datasheet NRF24L01 :
Énergie
La station sera alimentée de manière hybride, selon les scénarios suivants : - Par un port USB, pour la programmation, les tests et la configuration avec affichage sur moniteur PC ;
- Par une batterie Lithium, en mode autonome pour une utilisation prolongée (avec affichage écran LCD dans un second temps).
Les capteurs/actionneurs seront alimentées de manière hybride, selon les scénarios suivants :
- Par un port USB, pour la programmation, les tests et la configuration ;
- Par une batterie Lithium, en mode autonome pour son usage définitif.
Modèles de batterie à notre disposition :
- Batterie 3.7V 100 mAh, connecteur molex mâle ;
- Batterie 3.7V 300 mAh, connecteur molex mâle ;
Nous allons ajouter la possibilité de recharger notre batterie depuis notre carte via le composant MAX1811. La carte se rechargera lorsqu'elle sera branché en USB mais l'USB fournit du 5V, ce qui peut nuire à certains de nos composants...
Pour proteger les composants, nous allons ajouter un régulateur de tension pour garder une tension de 3,3V sur l'ensemble de notre carte.
Datasheets du chargeur et du régulateur :
Affichage
Dans un premier temps, les informations seront remontées via la connexion USB à un programme sur PC (selon les exigences du cahier des charges).
Dans un second temps, un écran LCD sera utilisé pour afficher les données directement sur la station, offrant ainsi une solution autonome, sous réserve du temps disponible pour cette implémentation.
Datasheet de l'écran graphique utilisé :
On décide de prgrammer l'écran en C. On code donc notre écran via l'API "glcd.h". L'écran sera composé d'un menu permettant de naviguer parmi les différents capteurs enregistrés afin de consulter la valeur renvoyée par cle capteur choisi. Les boutons intégrés sur la carte ainsi que l'encodeur rotatif permettront à l'utilisateur de naviguer entre les différents capteurs..
Diverses
La carte comportera également une led afin d'indiquer son état d'alimentation ainsi que deux autres leds permettant de faire des tests de programmation.
Hardware de la station domotique
Schématique
Notre schéma électrique
Comprendre notre schéma
Vue 3D
Brasure
Software de la station domotique
Capteurs
Capteur de mouvement - HC-SR501
Principe physique
Le capteur de mouvement HC-SR501 est un capteur infrarouge passif (PIR), ce qui signifie qu’il ne produit aucun rayonnement mais détecte celui émis naturellement par les objets chauds, notamment le corps humain.
Ces deux cellules pyroélectriques sont disposées de manière à percevoir deux zones distinctes du champ de vision. En l'absence de mouvement, les deux reçoivent une quantité similaire d'infrarouge, et le signal reste équilibré.
Lorsqu'un corps chaud passe devant le capteur, la quantité d’infrarouge captée change entre les deux cellules, créant un déséquilibre. Ce changement est interprété comme un mouvement.
Un dôme en plastique blanc recouvre le capteur : c’est une lentille de Fresnel.
Elle concentre et divise la lumière infrarouge en plusieurs zones, augmentant ainsi la portée et la sensibilité du capteur en "segmentant" son champ de vision. Ainsi, même un petit mouvement crée une variation significative de rayonnement perçu.
Spécifications techniques
On utilise un capteur de mouvement HC-SR501 (voir datasheet ci-dessous) afin de détecter ou non la présence de quelqu'un dans une pièce. L'intérêt est de pouvoir ensuite allumer la lumière si une personne est présente ou a contrario l'éteindre si la pièce est vide. Ici la lumière sera modélisée par une led présente sur l'arduino UNO en guise de démonstration.
- Jumper Set
Les deux modes, repeat ou single trigger, permettent de régler le trigger de schmith permettant la détection d'une présence. En single, on effectue un seul trigger afin de détecter spontanément une présence (ex : Cas alarme intrusion). Dans l'autre mode on souhaite détecter un mouvement peu importe si celui-ci est déjà détecter. Par exemple, besoin d'un mouvement après un certains nombre de temps pour que la led reste allumée ou bien besoin de réactiver de temps à autre le capteur en bougeant.
- Sensitivty Adjust
On modifie le potentiomètre à l'aide d'un tournevis afin d'ajuster la sensibilité à la présence de notre main, par exemple pour l'amplitude de nos mouvements.
- Time Delay Adjust
Ici le potentiomètre permet d'ajuster le temps entre deux seuils de détection afin d'éviter la détection après des mouvements parasites, par exemple pour déclencher sans erreur une alarme intrusion.
Circuit
On connecte le GND à la masse de l'arduino, le power au 5V et la sortie au pin PB0 (digital 8). Voir la vidéo de démonstration pour plus de détails.
Programmation
Voici le code afin d'allumer une led dès qu'une présence est détectée.
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRB |= (1 << PB5); //led D13 en sortie
while (1) {
if (PINB & (1 << PB0)) { //si mvmt
PORTB |= (1 << PB5); //led allumée
} else { //si absence
PORTB &= ~(1 << PB5); //led éteinte
}
_delay_ms(500); // Peut être baisser ou augmenter pour regler la sensibilité de détection
}
return 0;
}
Démonstration
Voici le résultat en vidéo ci-dessous. On constate bien que la led s'allume lorsqu'une présence est détectée.
Dans un second temps, on fera communiquer ce capteur avec notre carte station domotique par le biais des modules de communication radio (NRF24L01) afin d'afficher l'état de la pièce sur l'écran et également transmettre ces données via le port série.
Capteur de température - DS18B20
Principe physique
Ce capteur fonctionne grâce à un principe physique appelé variation de la résistance électrique avec la température. À l’intérieur du capteur, il y a un composant semi-conducteur, souvent une diode ou une jonction PN, qui change son comportement électrique selon la température.
Quand la température augmente, la façon dont les électrons se déplacent dans ce matériau change, ce qui modifie la tension ou le courant électrique mesuré.
Un convertisseur analogique-numérique (CAN) est intégré au circuit afin de transferer par la suite la mesure via un protole 1-Wire.
Spécifications techniques
On utilise aussi le capteur de température DS18B20 (voir datasheet ci-dessous) afin de mesurer la température de l'eau (pour une piscine ou une plante par exemple).
Circuit
On branche les 3 broches de notre sonde de la manière suivante :
- le gnd est relié à la masse
- le power est relié au 3,3V
- le fil de données est branché sur le pin PD2 (digital 2).
On branche également une résistance de 4,7kΩ entre le fil de données et le 3,3V.
Programmation
Arduino
Pour commencer, on a testé si notre sonde fonctionnait correctement à l'aide d'un code arduino et on a constaté aucun souci (voir code).
C
Nous avons trouvé deux ressources sur github que l'on a fusionné afin d'obtenir un code fonctionnel adapté à nos besoins et surtout un code qui nous correspond. On a utilisé les fichiers de ce répertoire :
Fichiers utilisés :
1/ onewire.h, onewire.c : pour remplacer la librairie OneWire.h de l'arduino afin de communiquer avec l'unique fil de données de la sonde.
Fonctions implémentées :
- onewireInit : reset le bus de données et renvoie une erreur si le capteur de répond pas et OK sinon.
- onewireWriteBit : envoie un bit sur le bus de données en respectant le temps d'envoi du protocole Onewire.
- onewireWrite : transmet un octet en utilisant la fonction précédente.
- onewireReadbit : lit un bit sur le bus de données.
- onewireRead : lit un octet sur le bus de données.
2/ ds18b20.h, ds18b20.c : pour les fonctions principales utiles à notre sonde.
- ds18B20crc8 : crc signifie cyclic redundacy check est l'octet renvoyé par cette fonction qui permet de savoir si la transmission s'est effectuée sans erreurs.
- ds18b20match : utile si il y a plusieurs capteurs (pas le cas ici).
- ds18b20convert : la valeur de la température est stockée sur les deux premiers octets de la mémoire scratchpad. ds18b20convert permet de convertir ces octets en degré celsius.
- ds18b20rsp : lit le scratchpad (mémoire temporaire) pour récupérer la valeur de la température (sur les deux premiers octets).
- ds18b20wsp : écrit dans le scratchpad.
- ds18b20csp : copie les données du scratchpad dans l'eeprom du capteur.
- ds18b20read : lit la température.
- ds18b20rom : lit l'adresse du capteur rom (pas utile ici car un seul capteur).
3/ UART.h, UART.c : pour afficher la température sur la liaison série. On définit deux fonctions :
- USART_SendChar pour afficher un caractère sur le minicom.
- USART_SendString pour afficher des mots sur le minicom. Rq : utiliser le retour chariot \r pour un affichage correct.
4/ main.c : pour le code principal
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "UART.h"
#include "ds18b20.h"
#define DS18B20_DDR DDRD
#define DS18B20_PORT PORTD
#define DS18B20_PIN PIND
#define DS18B20_MASK (1 << PD2)
int main(void)
{
int16_t temperature_raw;
char buffer[32];
uint8_t error;
USART_init(9600);
USART_SendString("Debut lecture DS18B20...\r\n");
while (1)
{
// Démarrer conversion
error = ds18b20convert(&DS18B20_PORT, &DS18B20_DDR, &DS18B20_PIN, DS18B20_MASK, NULL);
if (error != DS18B20_ERROR_OK) {
USART_SendString("Erreur conversion\r\n");
_delay_ms(1000);
continue;
}
_delay_ms(800); // attendre la fin de conversion
// Lire la température
error = ds18b20read(&DS18B20_PORT, &DS18B20_DDR, &DS18B20_PIN, DS18B20_MASK, NULL, &temperature_raw);
if (error == DS18B20_ERROR_OK) {
float temperature_celsius = temperature_raw / 16.0;
snprintf(buffer, sizeof(buffer), "Temp: %.2f C\r\n", temperature_celsius);
USART_SendString(buffer);
} else {
snprintf(buffer, sizeof(buffer), "Erreur lecture: %d\r\n", error);
USART_SendString(buffer);
}
_delay_ms(1000);
}
return 0;
}
Dans notre fonction main :
- on initialise la liaison série.
- on convertit les octets de la mémoire du capteur en une température en degré celsius.
- on lit la température afin de l'afficher dans le minicom. Pour cela, il faut au préalable convertir ntre température en flottant en des caractères avec une taille adaptée au buffer à l'aide de la fonction snprintf (string numbered print format).
5/ Makefile : pour faciliter la compilation
Rq: penser à modifier le port de AVRDUDE_PORT si le make upload de fonctionne pas.
Démonstration
Voici le résultat en vidéo ci-dessous. On constate bien que la température affichée sur le minicom augmente lorsque la sonde reste longtemps dans la bouilloire chauffée au préalable.
Dans un second temps, on fera communiquer ce capteur avec notre carte station domotique par le biais des modules nrf24 afin d'afficher la température de la pièce sur l'écran.
Actionneur
Lumière
On peut décider d'allumer une lumière selon certains critères (par exemple lorsque le capteur de présence détecte quelqu'un). Ici allumer une led par exemple.
Communication
Pour plus de détails, se référer à la rubrique spécifications techniques -> communication. Ici nous traiterons du code implémenté afin de communiquer entre les différents capteurs/actionneurs et notre carte principale.
Ecran
Afin d'avoir une interface pour l'utilisateur, nous décidons d'afficher sur un écran les données reçues des capteurs et l'état des actionneurs. On doit donc voir s'afficher la température d'une pièce, si il y a une présence etc.
Pour cela, on va devoir coder l'écran NHD‐C12832A1Z‐FSW‐FBW‐3V3 (voir datasheet dans la rubrique spécifications techniques->écran).
Programmateur AVR (Projet annexe)
Objectif
Réaliser un programmateur AVR afin d'envoyer notre code C sur un microcontrôleur. Ce projet est une introduction au logiciel et à la programmation sur microcontroleur AVR.
Nous nous sommes aider du cours afin de réaliser notre projet : https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/systeme063.html
Schématique
Notre schéma électrique
Conception de notre schéma électrique
Documents relatifs à la conception du kicad de la carte
Vue 3D
Fichier kicad
Fichier:2024-PSE-G2-Prog VFinale sans erreur.zip
Brasure
Programmation
Test leds et boutons
Afin de vérifier que notre carte fonctionne correctement après sa brasure, on code un programme permettant d'allumer une LED lorsqu'un bouton poussoir est pressé. Chaque bouton est associé à une LED.
Modification de l'horloge
void setupClock(void)
{
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)
}
Fonction initialisation des pins
void setupPin(volatile uint8_t* PORTx, volatile uint8_t* DDRx, uint8_t pin, pinmode mode) {
switch (mode)
{
case INPUT: // Forcage pin à 0
*DDRx &= ~(1 << pin);
break;
case INPUT_PULL_UP: // Forcage pin à 0
*DDRx &= ~(1 << pin);
*PORTx |= (1 << pin);
break;
case OUTPUT: // Forcage pin à 1
*DDRx |= (1 << pin);
break;
}
}
Fonction initialisation de l'ensemble des boutons et LEDs
void setupHardware() {
setupClock();
setupPin(LEDs_PORT, LEDs_DDR, LED1_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED2_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED3_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED4_PIN, OUTPUT);
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Up_PIN, INPUT_PULL_UP);
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Down_PIN, INPUT_PULL_UP);
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Left_PIN, INPUT_PULL_UP);
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Right_PIN, INPUT_PULL_UP);
}
Fonction de lecture de pin
int readPin(volatile uint8_t* PINx, uint8_t pin) {
return (*PINx & (1 << pin));
}
Fonction pour initialiser les composantes de la cartes
// ------------------ Boutons ------------------ //
#define BTNsUp_Left_PORT &PORTC
#define BTNsUp_Left_DDR &DDRC
#define BTNsUp_Left_PIN &PINC
#define BTNsDown_Right_PORT &PORTB
#define BTNsDown_Right_DDR &DDRB
#define BTNsDown_Right_PIN &PINB
#define BTN_Up_PIN PC4
#define BTN_Down_PIN PB5
#define BTN_Left_PIN PC6
#define BTN_Right_PIN PB6
// ------------------ LEDs ------------------ //
#define LEDs_PORT &PORTD
#define LEDs_DDR &DDRD
#define LEDs_PIN &PIND
#define LED1_PIN PD0
#define LED2_PIN PD1
#define LED3_PIN PD2
#define LED4_PIN PD3
// ------------------ Enum ------------------ //
typedef enum {
INPUT,
INPUT_PULL_UP,
OUTPUT,
} pinmode;
void setupHardware() {
setupClock();
setupPin(LEDs_PORT, LEDs_DDR, LED1_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED2_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED3_PIN, OUTPUT);
setupPin(LEDs_PORT, LEDs_DDR, LED4_PIN, OUTPUT);
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Up_PIN, INPUT_PULL_UP);
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Down_PIN, INPUT_PULL_UP);
setupPin(BTNsUp_Left_PORT, BTNsUp_Left_DDR, BTN_Left_PIN, INPUT_PULL_UP);
setupPin(BTNsDown_Right_PORT, BTNsDown_Right_DDR, BTN_Right_PIN, INPUT_PULL_UP);
}
LUFA
Afin de pouvoir faire de notre carte un périphérique USB, nous allons utiliser la LUFA (Lightweight USB Framefork for AVRs).
- Tout d'abord, nous avons codé un programme permettant de voir si la lufa détecte bien les boutons-poussoirs de notre carte comme des points d'accès d'entrées en affichant sur le minicom quel bouton-poussoir était pressé par l'utilisateur. Notre code se trouve dans le répertoire se ci-dessous : https://gitea.plil.fr/ahouduss/se3_2024_B2/src/branch/main/01%20-%20Programmateur%20AVR/programmation/lufa-LUFA-210130-NSI/se/VirtualSerial
Pour écrire notre code, nous avons réutilisé l'exemple VirtualSerial récupéré au repertoire suivant : LUFA/Demos/Device/LowLevel/VirtualSerial
Afin de mettre le programme sur notre carte, on vérifie au préalable que notre carte est bien reconnue en tant que périphérique USB à l'aide de la commande lsusb.
Pour plus de détail sur notre périphérique usb branché on doit faire la commande suivante :
cedricagathe@computer:~$ lsusb -s 003:008 -v
Bus 003 Device 011: ID 03eb:2044 Atmel Corp. LUFA CDC Demo Application
[...]
Device Descriptor:
bLength 18
bDescriptorType 1
[...]
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
[...]
idVendor 0x03eb Atmel Corp.
idProduct 0x2044 LUFA CDC Demo Application
[...]
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
[...]
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
[...]
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
[...]
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
[...]
Comme vu en cours, on revoit nos descripteurs ainsi que la description des interfaces de l'usb ainsi que d'autres données. Une fois notre carte détectée, on appuie en continue sur le bouton HWB puis une seule impulsion sur le bouton RESET afin de mettre notre carte en mode DFU et ensuite on relache HWB.
On pourra alors téléverser notre programme sur la carte à l'aide d'un makefile préalablement codé en tapant la commande make upload
.
- On place le programme dans notre carte à l'aide de la commande
make upload
. Pour ce faire, il faut modifier le makefile original par ceci :
MCU = atmega8u2
ARCH = AVR8
BOARD = NONE
F_CPU = 16000000
F_USB = $(F_CPU)
OPTIMIZATION = s
TARGET = VirtualSerial
SRC = $(TARGET).c Descriptors.c spi.c $(LUFA_SRC_USB)
LUFA_PATH = ../../LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
LD_FLAGS =
PROGRAMMER = dfu-programmer
all:
upload: $(TARGET).hex
$(PROGRAMMER) $(MCU) erase
$(PROGRAMMER) $(MCU) flash $(TARGET).hex
$(PROGRAMMER) $(MCU) reset
clean:
rm -f *.bin *.elf *.lss *.map *.sym *.eep
Le MCU a été changé afin de correspondre au nôtre. Une commande clean à été ajouté et la fréquence CPU augmentée à 16 MHz.
- On lance la commande minicom afin de voir si le bouton pressé est bien affiché via la liaison série. On configure le minicom au préalable.
sudo minicom -os
Ensuite nous entrons dans Serial port setup :
Il va falloir procéder à 3 changements :
- Appuyer sur A et changer modem par l'emplacement de notre carte (ici /ttyACM0) puis ENTRER
- Appuyer sur E puis appuyer sur C pour configurer la vitesse de notre minicom puis ENTRER
- Appuyer sur F puis ENTRER
Appuyer de nouveau sur ENTRER pour enregistrer la configuration et ensuite faite Exit. On est maintenant prêt à recevoir les messages USB qu'on envoie lors d'un appui :
- Nous avons ensuite implémenté un programme permettant d'allumer une led différente à chaque bouton-poussoir pressé.
Modification du fichier virtual.c
Afficher sur le minicom lorsqu'un bouton est pressé et test leds
void CDC_Task(void)
{
char* ReportString = NULL;
static bool ActionSent = false;
init_boutons();
init_leds();
/* Device must be connected and configured for the task to run */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
/* Determine if a button action has occurred */
if ((PINC&0x10)<=0){ //PC4
ReportString = "bouton du haut\r\n"; //affiché dans le minicom
PORTD = 0x01; //allume led1
_delay_ms(300);
}
if ((PINB&0x20)<=0){ //PB5
ReportString = "bouton du bas\r\n";
PORTD = 0x02; //allume led2
_delay_ms(300);
}
if ((PINC&0x40)<=0){ //PC6
ReportString = "bouton de gauche\r\n";
PORTD = 0x04; //allume led3
_delay_ms(300);
}
if ((PINB&0x40)<=0){ //PB6
ReportString = "bouton de droite\r\n";
PORTD = 0x08; //allume led4
_delay_ms(300);
}
else
ActionSent = false;
getID(ReportString);
[...]
}