< Micro contrôleurs AVR < Travail pratique

Le but de ce TP est de partir d'un châssis existant de robot composé d'une carte de puissance (de type L298N) et d'une carte de commande qui sera composée d'un Arduino Nano placé sur une plaque à essai et qui sera connecté au L298N et au composant radio NRF24L01.

L'objectif de ce TP est donc de faire réaliser une télécommande (sur plaque à essais). Cela nécessite un Joystick qui fait partie des périphériques Arduino que l'on peut trouver pour quelques Euros. La partie robotique sera elle réalisée avec un châssis de votre choix,des moteurs de votre choix, un L298N et pour finir le module NRF24L01. Tous ces modules sont extrêmement bon marchés.

Nous vous présenterons le matériel que nous avons utilisé mais vous devez adapter le matériel à votre budget.

Introduction

NRF24l01 Nordic Semiconductor radio

Nous allons dans ce TP réaliser une télécommande pour un robot à l'aide du circuit NRFL01. C'est un composant qui est fabriqué par une entreprise norvégienne Nordic Semiconductor qui permet de transmettre des données par liaison radio. Le gros intérêt de ce composant est son prix (6 € pour 10 pièces en Chine). Son concurrent le plus connu, XBee, frôle plutôt les 20€, même en Chine.

Ce composant NRF24L01 est un module radio intégrant tout le nécessaire pour émettre et recevoir des données sur la gamme de fréquences de 2.4GHz (comme le WiFi ou le Bluetooth) en utilisant le protocole de communication propriétaire de Nordic nommé "ShockBurst".

L'intérêt de ce TP est une révision assez importante des concepts présentés dans ce cours. D'autre part, comme le composant NRF24L01 est relativement configurable, vous serez amené à lire un peu de sa documentation. Il vous sera ainsi possible de le configurer correctement pour un fonctionnement particulier : un émetteur et un récepteur.

Remarques pour les enseignants

Ce TP consiste donc à réaliser logiciellement et matériellement deux parties qui communiquent. Mettre en œuvre les deux parties simultanément n'est pas spécialement simple. Ainsi les enseignants intéressés par ce TP devront fournir une partie réceptive opérationnelle qui sort ce qu'elle reçoit sur la liaison série. Cela permettra de valider la partie émission lorsqu'elle sera opérationnelle.

La partie châssis sera laissée à l'initiative des enseignants. Nous avons utilisé nous-même un châssis robot assez volumineux, mais vous pouvez utiliser un châssis de dimension plus restreinte.

Vous pouvez concevoir ces deux parties avec des plaques à essais pour laisser les étudiants câbler (complètement ou partiellement).

Vous pouvez aussi remplacer le châssis Robot par quelque chose de plus simple : deux servomoteurs ou tout autre idée.

Il existe des librairies sur Internet pour réaliser ce TP. Nous proposons ici de construire complètement l'ensemble. Le code qui en résultera ne sera pas adaptable à d'autres architectures car trop dépendant du matériel ! Nous avons par exemple réussi à faire fonctionner la librairie MIRF sans changement avec un ARM Texas Instrument dans l'environnement Energia ! Le code de ce TP ne sera pas aussi général.


Nous allons donc commencer par la partie révision qui utilise donc des chapitres précédents de ce livre.

Liaison série

La difficulté de vérifier que ce qui est envoyé est bien ce qui est reçu nécessite l'utilisation d'une liaison série. Elle est évidemment disponible si vous utilisez une programmation de type Arduino (avec un setup() et un loop()). Mai rappelons encore une fois qu'il est possible d'utiliser l'environnement Arduino pour faire du C standard : il suffit d'écrire un main(). Dès qu'un main() est détecté dans un programme l'environnement sait qu'il doit travailler sans les librairies Arduino. Nous n'aurons donc pas accès au "Serial.print()" de l'Arduino. Dans ce chapitre nous allons donc écrire des fonctions RS232 simples. Nous aurons besoin de celles-ci essentiellement pour déboguer.

Voir aussi le chapitre correspondant dans ce cours.

Réalisation d'une transmission série à 9600 bauds

La transmission série n'a pas besoin d'être rapide puisqu'elle servira seulement à vérifier le bon fonctionnement de chacune des parties : émetteur (la télécommande) et récepteur le robot. C'est pour cela qu'on a choisi 9600 bauds. Cette valeur peut naturellement être augmentée.

Réalisation de l'initialisation de la liaison série

Le code donné ailleurs dans dans ce cours sera notre point de départ :

#include <avr/io.h> 

#define F_CPU 16000000	// 16 MHz oscillator.
#define BaudRate 9600
#define MYUBRR (F_CPU / 16 / BaudRate ) - 1 


void serialInit(void) {
  //Serial Initialization
 	/*Set baud rate 9600 */ 
	UBRR0H = (unsigned char)(MYUBRR>>8); 
	UBRR0L = (unsigned char) MYUBRR; 
	/* Enable receiver and transmitter */
	UCSR0B = (1<<RXEN0)|(1<<TXEN0); 
	/* Frame format: 8data, No parity, 1stop bit */ 
	UCSR0C = (3<<UCSZ00);	
}

Exercice 1

Pouvez-vous écrire la configuration du registre UCSR0C de manière plus traditionnelle en désignant tous les bits configurés à 1 ?

Sous-programme d'émission d'un octet

Nous donnons le programme un peu modifié de la section sur la liaison série. On utilise les macros présentées ici qui à priori sont plus faciles à utiliser pour les étudiants.

#include <avr/sfr_defs.h>

void serialWrite(uint8_t DataOut)
{
  loop_until_bit_is_set(UCSR0A,UDRE0);	// wait while NOT ready to transmit 
  UDR0 = DataOut;
}

Transformation d'un octet en décimal

La liaison série est supposée envoyer des caractères affichables. Si vous prenez un octet venant de n'importe quoi et que vous l'envoyez sur la liaison série vous risquez d'avoir une surprise. C'est pour cela que dans le chapitre sur la liaison série a été développé le sous-programme suivant :

void usart_puts_hexa(uint8_t val) {
  uint8_t tab[2];
  tab[0] = val >> 4; //poids fort
  tab[1] = val & 0x0F; //poids faible
  if (tab[0] < 10) tab[0] += '0'; else tab[0] += '7';
  if (tab[1] < 10) tab[1] += '0'; else tab[1] += '7';
  serialWrite(tab[0]); // poids fort en premier
  serialWrite(tab[1]); // puis poids faible
}

qui transforme un octet en sa valeur hexadécimale.

Exercice 2

Les étudiants ayant des difficultés (normales) avec l'hexadécimal, nous allons plutôt utiliser le décimal.

  • Écrire un sous-programme d'affichage d'un octet en décimal en s'inspirant (vaguement) de l'écriture hexadécimale.
  • Écrire un sous-programme d'affichage de deux octets (uint16_t) en décimal. On rappelle pour ceux qui se poseraient la question de savoir pourquoi deux octets, que les valeurs données par le convertisseur analogique numérique (donc le joystick) sont sur deux octets (10 bits pour être exact).

Conversion Analogique Numérique

La télécommande est réalisée avec une manette joystick qui donne une information analogique. Plus exactement, deux informations analogiques, une pour l'axe x et une pour l'axe y.

La conversion analogique numérique a déjà été traitée dans ce livre au chapitre 11.

Vous pouvez aussi trouver sur Internet un tutoriel pour utiliser un joystick 2 axes. Il est programmé en langage Arduino mais nous voulons nous l'utiliser en langage C.

Exercice 3

Cherchez un code d'utilisation du convertisseur analogique/numérique dans le au chapitre 11 et transformez le simplement en deux sous-programmes :

  • void ADC_Init(void)
  • uint16_t ADC_get(uint8_t channel)

On pourra naturellement câbler un joystick pour des tests qui pourront être validés par la liaison série déjà réalisée.

Remarque

On utilisera A0 et A1 pour les deux axes du Joystick. Ces entrées sont compatibles avec le branchement du futur NRF24L01.

Liaison SPI

La liaison SPI ne nous est pas inconnue non plus. Il nous faudra cependant écrire des fonctions plus pratiques que celles qui ont été faites dans le chapitre 7. Nous allons partir d'un code donné et l'adapter au problème qui nous intéresse, à savoir, l'écriture et la lecture des registres du NRF24L01.

Exercice 4

Reprendre le code du chapitre 7 en transformant la boucle d'attente en choisissant entre loop_until_bit_is_set et loop_until_bit_is_clear. On en profitera pour changer SS en CSN (du NRF24L01) qui pour nous sera en broche 8 Arduino (PB0).

Le code donné en correction n'est plus utilisable de manière générale puisque SS (Slave Select) est utilisé sur PB0 de manière systématique. Par contre vous pouvez l'adapter facilement pour un autre positionnement de SS. Nous avons choisi PB0 comme nous aurions pu utiliser n'importe quelle autre broche ! On rappelle que seule l'utilisation du SPI en esclave impose une broche précise pour le SPI.

Exercice 5

Nous allons maintenant continuer à spécialiser le SPI pour réaliser le protocole SPI du NRF24L01. L'architecture vue du SPI est la suivante :

  • des registres caractérisés par une adresse dans lesquels on peut écrire une ou plusieurs valeurs et que l'on peut lire aussi bien sûr.
  • des instructions

Ainsi le logiciel capable d'utiliser aura les possibilités suivantes :

  • Écriture d'instructions. Les instructions ont des valeurs très particulières qui ne peuvent pas être des adresses de registres. La manipulation de ces données peut se faire avec le code de l'exercice 4 : void SPIMasterSend(uint8_t data)
  • Écriture d'une seule donnée (octet) dans la majorité des registres du NRF24L01. Un registre est caractérisé par une adresse (sur un octet et une valeur sur un octet. En clair, il serait intéressant d'avoir un sous-programme de prototype uint8_t SPI_NRF24_Reg(uint8_t reg, uint8_t value) capable d'écrire "value" dans le registre d'adresse "reg".
  • Écriture d'une donnée pouvant atteindre 32 octets comme les adresses de réception et d'émission, mais aussi des données à transmettre. Un prototype du type uint8_t SPI_NRF24_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes) serait parfait.
  • Lecture d'un ensemble de données pouvant atteindre 32 octets ayant comme prototype uint8_t SPI_NRF24_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes)


  1. Compléter ce code avec un sous-programme d'écriture de deux octets (pour écriture dans les registres)
  2. Compléter ce code avec écriture d'un nombre d'octets passé en paramètre. (Écriture dans le registre de gestion des adresses)
  3. Compléter ce code avec la lecture d'un nombre d'octets passé en paramètre. (Lecture des données envoyées).

Nous allons comencer par réaliser la programmation de la carte de commande du Robot avec le NRF24L01 car nous pensons qu'il est plus facile pour l'enseignant de réaliser une télécommande qui servira tour à tour à chacun des binômes pour les essais. Une fois que tout sera fonctionnel avec cette télécommande, les étudiants pourront se lancer dans la réalisation et la programmation de leur propre télécommande.

Réalisation et programmation de la carte de commande du robot

Il suffit donc de spécialiser encore un peu le code du SPI pour pour résoudre l'ensemble des problèmes pour réaliser une réception. Deux sous-programmes particuliers sont donc à réaliser :

  • un sous-programme d'initialisation du NRF24L01 en mode réception
  • un sous-programme de réception des données

Exercice 6

Réalisation et programmation de la télécommande

Tout est prêt maintenant pour réaliser le code de la télécommande. On a du code pour faire

  • une conversion analogique numérique
  • gérer une liaison série
  • gérer du SPI

Il suffit donc de spécialiser encore un peule code du SPI pour pour résoudre l'ensemble des problèmes pour réaliser une transmission.

Exercice 7

On vous demande de réaliser un sous-programme capable d'initialiser complètement le NRF24L01 en émission et un sous-programme d'émission de données.


Documentation NRF24L01

Le composant NRF24L01 est caractérisé par un ensemble de registres de configuration. On accède à ces registres à travers le protocole SPI qui est le seul protocole disponible sur ce composant.

Registre de configuration

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
00CONFIGRegistre de configuration
Réservé70R/W'0' seulement autorisé
MASK_RX_DR60R/Wmasque d'interruption par RX_DR

1 : interruption non reflectée

0 : refléchie RX_DR active basse sur la broche IRQ

MASK_TX_DS50R/Wmasque d'interruption par RX_DS

1 : interruption non reflectée

0 : refléchie RX_DR active basse sur la broche IRQ

MASK_MAX_RT40R/Wmasque d'interruption par RX_DT

1 : interruption non reflectée

0 : refléchie RX_DR active basse sur la broche IRQ

EN_CRC31R/Wautorise le CRC. Forcé à 1 si un bit de EN_AA est à 1
CRCO20R/WSchéma d'encodage de CRC

0 : 1 octet

1 : 2 octets

PWR_UP10R/W1 : en action

0 : éteint

PRIM_RX00R/Wcontrôle RX/TX

1 : PRX

0 : PTX

Gestion de l'accusé de réception

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
01EN_AA Enhanced ShockBurstTMdesactiver cette fonction pour être compatible nrf2401
Réservé7:600R/W'00' seulement autorisé
ENAA_P551R/Waccusé de réception autorisé pour canal 5
ENAA_P441R/Waccusé de réception autorisé pour canal 4
ENAA_P331R/Waccusé de réception autorisé pour canal 3
ENAA_P221R/Waccusé de réception autorisé pour canal 2
ENAA_P111R/Waccusé de réception autorisé pour canal 1
ENAA_P001R/Waccusé de réception autorisé pour canal 0

Gestion de l'autorisation des adresses de réception

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
02EN_RXADDRAutoriser l'adresse de réception
Réservé7:600R/W'00' seulement autorisé
ERX_P551R/Wautorisation pour canal 5
ERX_P441R/Wautorisation pour canal 4
ERX_P331R/Wautorisation pour canal 3
ERX_P221R/Wautorisation pour canal 2
ERX_P111R/Wautorisation pour canal 1
ERX_P001R/Wautorisation pour canal 0

Gestion de la largeur commune des adresses de réception et d'émission

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
03SETUP_AWdéfinition de la taille de l'adresse pour tous les canaux
Réservé7:2000000R/W'000000' seulement autorisé
AW1:011R/WLargeur d'adresse d'émission/réception

00 : illégal

01 : 3 octets

10 : 4 octets

11 : 5 octets

Gestion de la retransmission automatique

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
04SETUP_RETRréglage de retransmission automatique
ARD7:40000R/Wdélai retransmission

0000 : attente de 250 us

0001 : attente de 500 us

....

1111 : attente de 4000 us

ARC3:00011R/Wnombre de retransmissions

0000 : pas de retransmission

0001 : jusqu'à une retransmission en cas d'échec

....

1111 : jusqu'à 15 retransmissions en cas d'échec

Gestion du canal radio fréquence

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
05RF_CHcanal RF
Reserved70R/Walloué à 0 seulement
RF_CH6:00000010R/Wréglage des fréquences des canaux

Registre de configuration RF

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
06RF_SETUPRegistre de configuration RF
CONT_WAVE70R/Wautorise l'émission continue de la porteuse
Réservée60R/WSeulement '0' autorisé
RF_DR_LOW50R/Wpositionne le débit à 250 kbps
PLL_LOCK40R/WForce le verrouillage de la PLL (seulement pour les tests)
RF_DR_HIGH31R/WCombiné à RF_DR_LOW permet éventuellement de changer le débit de transmission
RF_PWR2:111R/WGère la puissance d'émission en sortie

00 : -18 dBm

01 : -12 dBm

10 : -6 dBm

11 : 0 dBm

Obsolète00R/WNe pas utiliser
  • Élément de la liste à puces

Registre de statut

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
07STATUSUne écriture SPI dans ce registre permet de retrouver son contenu en série sur la broche MISO
Réservé70R/WSeul un 0 est possible
RX_DR60R/WMis à '1' quand une donnée arrive dans le FIFO de réception
TX_DS50R/WMis à '1' quand une donnée est émise
MAX_RT40R/WSi ce bit est à 1 il faut le remettre à 0 pour continuer toute utilisation. La mise à 0 se fait en écrivant un 1.
RX_P_NO3:1111RNuméro du canal correspondant à la réception dans RX_FIFO

000 - 101 : unméro du canal

110 : non utilisé

111 : RX_FIFO vide

TX_FULL00RDrapeau pour remplissage du FIFO de réception

1 : FIFO rempli

0 : Possibilité d'utiliser le FIFO

Registre d'observation de la transmission

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
08OBSERVE_TXRegistre d'observation de la transmission
PLOS_CNT7:40RCompte les paquets perdus. Ce compteur est limité à 15 et rest à 15 jusqu'à une initialisation par écriture dans RF_CH
ARC_CNT3:00RCompteur de paquets retransmis. Ce compteur est automatiquement réinitialisé à 0 lors d'une transmission d'un nouveau paquet

Registre de détection de la porteuse

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
09RPDRegistre de détection de la porteuse
Réservé7:10000000RNe pas utiliser
RPD00R

Registres de gestion des adresses de réception pour les canaux

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
0ARX_ADDR_P039:00xE7E7E7E7E7R/WAdresse de réception du canal 0
0BRX_ADDR_P139:00xC2C2C2C2C2R/WAdresse de réception du canal 1
0CRX_ADDR_P27:00xC3R/WAdresse de réception du canal 2 (bits 39:8 égaux à canal 1)
0DRX_ADDR_P37:00xC4R/WAdresse de réception du canal 3 (bits 39:8 égaux à canal 1)
0ERX_ADDR_P47:00xC5R/WAdresse de réception du canal 4 (bits 39:8 égaux à canal 1)
0FRX_ADDR_P57:00xC6R/WAdresse de réception du canal 5 (bits 39:8 égaux à canal 1)

Registres de gestion de l'adresse de transmission pour les canaux

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
10TX_ADDR39:00xE7E7E7E7E7R/WAdresse de transmission. Positionner l'adresse RX_ADDR_P0 à cette valeur pour automatiser le Enhanced ShockBurstTM

Configuration du nombre d'octets utiles dans une trame

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
11RX_PW_P0
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P05:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
12RX_PW_P1
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P15:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
13RX_PW_P2
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P25:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
14RX_PW_P3
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P35:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
15RX_PW_P4
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P45:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
16RX_PW_P5
Réservé7:600R/WSeuls 00 sont autorisés
RX_PW_P55:00R/Wnombre d'octets utilisables pour un envoi/réception (1 à 32 octets)

0 : canal non utilisé

1 : 1 octet

...

32 : 32 octets

Registre de statut du FIFO

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
17FIFO_STATUSRegistre de statut du FIFO
Réservé70R/WSeul un 0 est possible
TX_REUSE60R
TX_FULL50RMis à '1' quand le FIFO de transmission est plein
TX_EMPTY40RSi ce bit est à 1 le FIFO de transmission est vide
Réservé3:200R/WSeulement 00 est autorisé
RX_FULL10RMis à '1' quand le FIFO de réception est plein
RX_EMPTY00RSi ce bit est à 1 le FIFO de réception est vide

Gestion dynamique des longueurs de paquets

NRF24L01+
Adresse (hexa)MnémoniqueBitValeur de resetTypeDescription
1CDYNPDAutorise la gestion dynamique des longueurs de paquets
Réservé7:600R/W'00' seulement autorisé
DPL_P550R/Wautorise une longueur dynamique pour canal 5
DPL_P440R/Wautorise une longueur dynamique pour canal 4
DPL_P330R/Wautorise une longueur dynamique pour canal 3
DPL_P220R/Wautorise une longueur dynamique pour canal 2
DPL_P110R/Wautorise une longueur dynamique pour canal 1
DPL_P000R/Wautorise une longueur dynamique pour canal 0

Les instructions SPI pour NRF24L01

NRF24L01+
Nom de l'instructionInstruction binaireNombre d'octetsOpération
R_REGISTER000A AAAA1 à 5 octets Poids fort en premierLit le registre d'adresse A AAAA
W_REGISTER001A AAAA1 à 5 octets Poids fort en premierÉcrit dans le registre d'adresse A AAAA
R_RX_PAYLOAD0110 00011 à 32 octets Poids fort en premierLit le registre de réception jusqu'à 32 octets
W_TX_PAYLOAD1010 00001 à 32 octets Poids fort en premierÉcrit dans le registre de réception jusqu'à 32 octets
FLUSH_TX1110 00010Vide le FIFO de transmission (utilisé en TX mode seulement)
FLUSH_RX1110 00100Vide le FIFO de réception (utilisé en RX mode seulement)
REUSE_TX_PL1110 00110Utilisé pour les circuits PTX
NOP1111 11110Pas d'opération

Voir aussi

Cet article est issu de Wikiversity. Le texte est sous licence Creative Commons - Attribution - Partage dans les Mêmes. Des conditions supplémentaires peuvent s'appliquer aux fichiers multimédias.