< Micro contrôleurs AVR
fin de la boite de navigation du chapitre

Nous avons l'intention dans ce chapitre d’aborder divers types de communication : série asynchrone, série synchrone, I2C et USB.

Communication série asynchrone ou RS232

La partie du circuit spécialisée gèrant la liaison série (ou RS232) s’appelle une UART.

Trame RS232

On rappelle que ce type de liaison série permet d'envoyer des informations sans horloge de référence. Elle est à un logique au repos. Une trame est composée des 8 bits à transmettre, précédé d'un bit de start ("0" logique), et suivi par au moins un bit de stop ("1" logique). Le bit de stop peut être doublé et éventuellement précédé par un bit de parité. Pour une parité paire, le bit de parité est mis à "0" quand le nombre de "1" est pair tandis qu'une parité impaire met à "0" pour un nombre impair de "1".

La vue de l'image ci-contre semble indiquer le contraire de ce que je suis en train d'expliquer. Mais n'oubliez pas que du point de vue électrique, un niveau logique "0" est représenté par une tension de +V à +25 V et un niveau logique "1" par une tension de −3 V à −25 V (codage NRZ). Ordinairement, des niveaux de +12 V et −12 V sont utilisés.

Comme nous allons utiliser pour nos essais des platines Arduino pour lesquelles la liaison série est réalisée à l'aide de l’USB, les problèmes de tension n'ont pas lieu.

La liaison série est très populaire à cause de son évolution justement avec l'USB et surtout que tous les systèmes d'exploitation proposent un logiciel pour communiquer par la liaison série. Il est appelé hyperterminal sous Windows. Même si nous utilisons essentiellement Linux pour nos essais, nous continuerons à l'appeler hyperTerminal.

Voici quelques brochages utiles qu’il est facile de retrouver sur Internet.

rs232 basse tension RXDTXD
UNO PD0(Arduino:0)PD1 (Arduino:1)
LEONARDO PD2 (Arduino:0)PD3 (Arduino:1)
Pro Micro (Sparkfun) PD2 (Arduino:0)PD3 (Arduino:1)

Les registres associés

Le « n » apparaissant dans ces dessins peut prendre la valeur 0 ou 1 dans l'ATMega328.

USART and ATMega328

Les bits du registre UCSRnA sont :

  • RXCn : réception complète
  • TXCn : transmission complète
  • UDREn : USART Data Register Empty (vide)
  • FEn : Frame Error
  • DORn : Data OverRun
  • UPEn : USART Parity Error
  • U2Xn : est expliqué dans le dessin
  • MPCMn : Multi Processor Communication Mode

Les bits du registre UCSRnB sont :

  • RXCIEn : interruption quand réception complète autorisée
  • TXCIEn : interruption quand transmission complète autorisée
  • UDRIEn : interruption quand UDRn est vide autorisée
  • RXENn : autorisation de la réception
  • TXENn : autorisation de la transmission
  • UCSZn2 : taille de caractère quand combiné avec UCSZn1:0
  • RXB8n : 9° bit de réception au cas où ce mode est choisi
  • TXB8n : 9° bit de transmission au cas où ce mode est choisi

Une librairie d'utilisation

Nous avons trouvé sur Internet la librairie suivante qui a été écrite pour un ATMega168. Nous l'avons fait fonctionner telle quelle sur un ATMega2560 et la platine Arduino correspondante. Nous la publions avec quelques modifications.

 /*
Title:		SerialCom.c 
Date Created: 6/9/2009
Last Modified: 6/9/2009
Target:		Atmel ATmega168, ATmega368
Environment:	AVR-GCC 
  Note: the makefile is expecting a '168 with a 16 MHz crystal.
Adapted from the Arduino sketch "Serial Call and Response," by Tom Igoe.
  //  This program sends an ASCII A (byte of value 65) on startup
  //  and repeats that until it gets some data in.
  //  Then it waits for a byte in the serial port, and 
  //  sends three (faked) sensor values whenever it gets a byte in.
Written by Windell Oskay, http://www.evilmadscientist.com/
Copyright 2009 Windell H. Oskay
Distributed under the terms of the GNU General Public License, please see below.
Additional license terms may be available; please contact us for more information.
More information about this project is at 
http://www.evilmadscientist.com/article.php/peggy
-------------------------------------------------
USAGE: How to compile and install
A makefile is provided to compile and install this program using AVR-GCC and avrdude.

To use it, follow these steps:
1. Update the header of the makefile as needed to reflect the type of AVR programmer that you use.
2. Open a terminal window and move into the directory with this file and the makefile. 
3. At the terminal enter
		make clean <return>
		make all <return>
		make program <return>
4. Make sure that avrdude does not report any errors. If all goes well, the last few lines output by avrdude
should look something like this:

avrdude: verifying ...
avrdude: XXXX bytes of flash verified
avrdude: safemode: lfuse reads as E2
avrdude: safemode: hfuse reads as D9
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK
avrdude done. Thank you.
If you a different programming environment, make sure that you copy over 
the fuse settings from the makefile.
-------------------------------------------------
This code should be relatively straightforward, so not much documentation is provided. If you'd like to ask 
questions, suggest improvements, or report success, please use the evilmadscientist forum:
http://www.evilmadscientist.com/forum/
-------------------------------------------------
 This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <avr/io.h> 

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

unsigned char serialCheckRxComplete(void)
{
	return( UCSR0A & _BV(RXC0)) ;		// nonzero if serial data is available to read.
}

unsigned char serialCheckTxReady(void)
{
	return( UCSR0A & _BV(UDRE0) ) ;		// nonzero if transmit register is ready to receive new data.
}

unsigned char serialRead(void)
{
	while (serialCheckRxComplete() == 0)		// While data is NOT available to read
	{;;} 
	return UDR0;
}

void serialWrite(unsigned char DataOut)
{
	while (serialCheckTxReady() == 0)		// while NOT ready to transmit 
	{;;} 
	UDR0 = DataOut;
}

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);	
}

Cette librairie a été utilisée avec succès avec une platine Arduino UNO et MEGA2560. L'horloge est aussi à 16 MHz comme ce qui est supposé par cette librairie. L'exercice 8 ici fait une lecture d'une valeur supposée être fournie par deux caractères, valeur variant entre 00 et FF, pour régler le rapport cyclique.

Exercices

Un exercice a déjà été proposé dans ce livre : PWM rapide dans le chapitre sur le timer 0.

En voici un autre assez proche.

Travail à réaliser en C

Pour cette partie, on utilise l'IDE Arduino mais le langage C pur (avec donc un main()).

Changer la vitesse de transmission

La librairie présentée fonctionne pour une vitesse de transmission de 9600 bauds. Cette vitesse est choisie avec les registres UBRR0H et UBRR0L comme indiqué dans les commentaires.

Modifier la librairie pour la faire fonctionner à 19200 bauds. Écrire un programme complet qui permet de réaliser un test avec cette nouvelle vitesse dans l'hyperterminal Arduino.

Après cette mise en jambes, venons-en aux problèmes sérieux...

Changer la fréquence sur un buzzer

On désire changer la fréquence sonore d'un buzzer à l'aide du mode CTC du timer 2. La valeur envoyée pour déterminer la fréquence sera systématiquement envoyée par la liaison série sous forme de deux caractères 0,...,9,A,...,F. Dans ce genre de problème, la difficulté est de comprendre la différence entre des caractères et des valeurs.

  • Écrire un sous-programme "void usart_puts_hexa(unsigned char val)" destiné à transformer la valeur val (hexadécimale) en deux caractères affichables (deux parcequ'on est sur 8 bits). Tester avec un programme principal.

Nous allons maintenant réaliser l'opération inverse : lire deux caractères (en représentation hexadécimale) qui arrivent par la liaison série et les transformer en une valeur numérique correspondante sur un octet.

  • Un sous-programme "unsigned char usart_gets_hexa()" sera donc chargé de lire ces deux caractères d’en vérifier la syntaxe et d’en retourner la valeur. Écrire ce sous-programme et le tester avec le sous-programme de la question précédente. On affichera "--" en cas d'erreur de syntaxe. TOUT SE PASSE PAR LA LIAISON SERIE. Pouvez-vous modifier la fonction un peu naïve ci-dessous pour qu'elle gère correctement les erreurs (car elle ne le fait pas !!!!) même si elle fonctionne parfaitement :
// Pour comprendre la faiblesse de cette fonction donnez-lui "GG" à convertir
// elle vous retourne quelque chose alors que "GG" n'est manifestement pas un
// nombre hexadécimal
unsigned char usart_gets_hexa() {
  unsigned char val;
  char tab[3];
  tab[0] = serialRead(); //poids fort
  tab[1] = serialRead(); //poids faible
  while (serialCheckRxComplete()) serialRead(); // on vide buffer
  tab[0] -= '0';
  tab[1] -= '0';
  if (tab[0] > 9) tab[0] -= 7;
  if (tab[1] > 9) tab[1] -= 7;
  val = (tab[0] << 4) + tab[1];  
  return val;
}

Et l’apothéose finale ....

  • Changer votre programme en utilisant les sous-programmes développés pour la question précédente pour qu’il réalise une fréquence audible sur le bit OC0A du PORTB variant en fonction de la valeur reçue (par la liaison série).

Le bit OC0A correspond au bit B6 pour l'ATMega328 de l'Arduino UNO.

Exercice 2 : Commande d'un servomoteur

Schéma du matériel utilisé

Un potentiomètre est branché sur un Arduino sur l'entrée A0. Un servomoteur est branché sur un deuxième Arduino (sortie (9). Les deux Arduinos sont reliés entre eux par une liaison série. Écrire les deux programmes en C pour les deux Arduinos pour que le potentiomètre commande le servomoteur par l'intermédiaire de la liaison série.

Indications :

  • la résolution de ce problème nécessite quelques connaissances sur la conversion analogique numérique. La broche A0 dont il est question ici est l'entrée AN0. Ceci peut sembler être une information redondante mais elle est seulement vraie pour les Arduino UNO (pas LEONARDO par exemple).
  • La commande d'un servomoteur par un potentiomètre est étudiée dans le chapitre sur la conversion analogique numérique.
  • La broche (9) de l'Arduino est PD1. Mais elle est aussi OC1A. Cela signifie clairement que le timer que l'on utilisera pour commander le servomoteur est le timer1
  • La commande d'un servomoteur par le timer1 a déjà été traité comme exercice 3 dans le chapitre sur le TIMER1

Cas particulier de l'Arduino Leonardo

La particularité de l'Arduino Leonardo est la gestion de la liaison série par l'USB.

Nous allons utiliser du code du site pjrc.com : USB serial

Voir aussi WIKI IUT Troyes

Communication série synchrone ou SPI

Un article de wikipédia Serial Peripheral Interface présente les communications SPI qui nous intéressent dans cette section.

Interface SPI décrit des programmes que nous reprendrons.

Description du protocole

Le protocole SPI est synchrone : une horloge synchronise l'échange de données. Dans tout échange on définit un Maître qui réalise l'horloge et un Esclave. L'esclave (il peut y en avoir plusieurs) est choisi avec une entrée spéciale appelée SS (Slave Select). A ce point, nous connaissons deux broches du SPI : l'horloge appelée SCK et SS. Il en manque deux pour être complet :

  • MISO : Master in Slave Out
  • MOSI : Master Out Slave In

Ces deux broches laissent entendre un échange full duplex (complet dans les deux sens). Voici donc comment les choses se passent avec un Maître et un Esclave :

Liaison SPI: un maître et un esclave

Si vous avez plusieurs esclaves une configuration de ce genre est à choisir :

Liaison SPI avec un maître et trois esclaves

Comme nous allons utiliser des cartes Arduino pour nos expérimentations, nous allons commencer par donner leurs brochages.

Quelques brochages pour les cartes Arduino UNO, Leonardo et Mega2560

Voici résumé dans un tableau le brochage des cartes qui nous intéressent :

SPI MISOMOSISCKSS
UNO / NANO PB4 (Arduino:12)PB3 (Arduino:11)PB5 (Arduino:13)PB2 (Arduino:10)
LEONARDO PB3 (ICSP:1)PB2 (ICSP:4)PB1 (ICSP:3)--aucune--
MEGA2560 PB3 (Arduino:50)PB2 (Arduino:51)PB1 (Arduino:52)PB0 (Arduino:53)
Pro Micro (Sparkfun) PB3 (Arduino:14)PB2 (Arduino:16)PB1 (Arduino:15)--aucune--

Quel est l'impact sur le Leonardo du manque de broche dédiée à SS ? C'est une question à laquelle nous n'avons pas d'explication définitive, mais il nous semble que cela empêche de fonctionner en SPI esclave. A vérifier !

Particularité du Leonardo

Comme on peut le voir dans ce tableau, les broches utilisées pour SPI sur la Leonardo ne sont pas reliées aux connecteurs mais directement sur le programmateur ICSP. Pour éviter des recherches sur internet, nous rappelons la connectique associée des six broches avec les deux photos ci-contre.

Connectique SPI

Voici par exemple ci-contre la connectique ICSP présente sur une carte Arduino.

Connectique ISP de l'Arduino

Mise en œuvre matérielle

Chronogramme des différentes configurations d'horloge

Le problème de la polarité d'horloge est important : un maître et un esclave peuvent être incapabes de se comprendre s'ils n'ont pas la même polarité. Le dessin de wikipédia est redonné ici comme référence.

Les registres correspondants à la description matérielle sont maintenant présentés et seront suivi par un schéma de l'architecture correspondante. En ce qui concerne le registre SPCR :

  • SPIE: pour autoriser les interruptions SPI
  • SPE: SPI Enable, doit être positionné à 1 pour toute opération SPI
  • DORD: Data Order, 1 pour une transmissin du poids faible en premier
  • MSTR: Master/Slave Select, 1 pour le positionnement en maître. Ce bit nécessite d’être en accord avec SS (Slave Select)
  • CPOL: Clock Polarity, 1 pour SCK haut quand idle, 0 pour SCK bas quand idle.
  • CPHA: Clock Phase, détermine si les données sont échantillonnées sur le premier front ou le deuxième front de SCK.
SPI registers in AVR

Pour le registre SPSR :

  • SPIF: est le drapeau d'interruption
  • WCOL: Write COLlision Flag

Le reste est donné dans le dessin.

Image logo indiquant un demande d'attention particulièreCette section est vide, pas assez détaillée ou incomplète. Votre aide est la bienvenue !

Travail en C sur le SPI

Remarque

Les programmes C donnés dans cette section n'ont pas encore été testés. Nous enlèverons cette remarque dès que ce ne sera plus le cas.

De toute façon il vous faudra adapter le brochage en fonction de la platine Arduino utilisée.

Il est facile de trouver un programme d'exemple en C sur internet. En voici un exemple serial peripheral interface in avr microcontrollers :

//SPI master
#include <avr/io.h>
#include <util/delay.h>
//SPI initvoid
void SPIMasterInit(void) {
//set MOSI, SCK and SS as output
  DDRB |= (1<<PB3)|(1<<PB5)|(1<<PB2);
//set SS to high
  PORTB |= (1<<PB2);
//enable master SPI at clock rate Fck/16
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
//master send function
void SPIMasterSend(uint8_t data){
//select slave
  PORTB &= ~(1<<PB2);
//send data
  SPDR=data;
//wait for transmition complete
  while (!(SPSR &(1<<SPIF)));
//SS to high
  PORTB |= (1<<PB2);
}

int main(void) {
//initialize master SPI
  SPIMasterInit();
//initial PWM value
  uint8_t pwmval = 0;
  while (1) {
    SPIMasterSend(pwmval++);
    _delay_ms(1000);
  }
}

Trouvez un esclave SPI et essayez ce programme. Si aucun esclave SPI n'est disponible, réalisez-en un avec une autre platine Arduino.

//SPI slave
#include <avr/io.h>
#include <avr/interrupt.h>
//SPI init
void SPISlaveInit(void) {
//set MISO as output
  DDRB |= (1<<PB4);
//enable SPI and enable SPI interrupt
  SPCR = (1<<SPE)|(1<<SPIE);
}
void InitPort(void) {
//set PD6 (OC0A) as output
  DDRD|=(1<<PD6);
}
//Initialize Timer0
void InitTimer0(void) {
//Set Initial Timer value
  TCNT0=0;
//Place compare value to Output compare register
  OCR0A=0;
//Set fast PWM mode
//and make clear OC0A on compare match
  TCCR0A|=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00);
}
void StartTimer0(void) {
//Set prescaller 64 and start timer
  TCCR0B|=(1<<CS01)|(1<<CS00);
}
ISR(SPI_STC_vect) {
  OCR0A=SPDR;
}

int main(void) {
//initialize slave SPI
  SPISlaveInit();
  InitPort();
  InitTimer0();
  StartTimer0();
  sei();
  while (1) {
    //loop
  }
  return 0;
}

On ne vous demande pas de comprendre la partie interruption SPI de ce programme. Seule la partie Timer0 est à comprendre puisqu’il faut correctement brancher une LED dont la luminosité doit changer en fonction de ce qui est envoyé par le SPI.

Exercice

En vous aidant de la documentation du brochage des quelques Arduino plus haut, on vous demande de :

1°) modifier le programme ci-dessus (uniquement void SPISlaveInit(void)) pour qu’il fonctionne correctement avec un MEGA2560 avec une horloge SPI égale à la fréquence système divisée par 8.

2°) trouver le mode de fonctionnement correspondant ?

3°) Étant pointilleux sur les principes, on vous demande de modifier aussi le sous-programme de réception, sachant que SPIF est un drapeau comme son nom l'indique.

Voir aussi

Communication I2C

Le protocole I²C est un protocole d'échange pour les composants électroniques différents d'un même appareil. Son intérêt par rapport aux protocoles examinés auparavant est qu’il y a une notion d'adressage des esclaves. En clair un maître peut adresser plusieurs esclaves. Quand l'esclave se reconnaît par son adresse, il répond au maître.

Voici quelques brochages utiles qu’il est facile de retrouver sur Internet.

I2C SCLSDA
UNO PC5 (Arduino:A5)PC4 (Arduino:A4)
LEONARDO PD0 (Arduino:SCL)PD1 (Arduino:SDA)
Pro Micro (Sparkfun) PD0 (Arduino:3)PD1 (Arduino:2)

Adaptation de tensions

Les cartes Arduino que nous utilisons sont en général en 5V. Il existe cependant un certain nombre de périphériques I2C qui sont en 3,3 V. La manette Nunchuk en est un exemple. Il faut donc réaliser une adaptation bidirectionnelle. Ce genre d'adaptation est décrit par exemple dans ce lien. La manette Nunchuk est quant à elle décrite ICI.

Interface I2C dans l'AVR

Programmation de l'interface I2C décrit en anglais ce que nous allons présenter dans ce chapitre.

Registres de ATMega328 pour i2c master

Le premier registre important est TWBR qui est utilisé pour régler la fréquence d'horloge de la broche SCL. Il faut ajouter au contenu de ce registre les deux bits TWPS1 et TWPS2 du registre TWSR qui sont destiné à réaliser un préscaler avec les valeurs 1, 4, 16 et 64.

Les documentations officielles donnent la formule de calcul de la fréquence :

Comme toujours, il existe un registre de contrôle TWCR qui a un ensemble de bits utilisés pour :

  • autoriser l'interruption TWIE
  • autoriser le module i2C TWEN : le module prend alors le contrôle physique sur les broches dédiées à l'i2c
  • envoi d'un départ (start) TWSTA : doit être remis à 0 par le logiciel quand le start est effectif
  • envoi d'un stop TWSTO
  • Drapeau d'interruption TWINT qui fonctionne comme un drapeau : mis à 0 par écriture d'un 1. Il peut être utilisé pour détecter une fin de transmission. Il faut un "sei()" et TWIE = 1 en supplément pour déclencher une interruption. Cette possibilité de l'utiliser sans interruption fait qu'il n'est pas mis automatiquement à zéro par l'exécution de l'interruption comme certains autres drapeaux.
  • autorise l'envoi d'un ack avec TWEA quand une donnée de l'esclave est reçue

Le registre d'état déjà mentionné TWSR contient les bits de réglage du présscaler. Mais son utilisation principale est de donner l'état du bus I2C avec les bits TWS[7:3]. TWDR est le registre de données qui est utilisé pour mémoriser le prochain octet à transmettre ou l'octet reçu. Les registres TWAR et TWARM sont utilisés quand l'AVR travaille en mode esclave.

Remarque

La documentation du bit TWSTA insiste sur la nécessité d'une mise à 0 logicielle de ce bit. La bibliothèque présentée plus bas ne le fait pas. Nous réglerons tous ces détails plus tard. Pour le moment nous n'avons fait que le rajouter en commentaire puisque nous n'avons pas de périphérique i2c sous la main.

Une bibliothèque simple pour utiliser l'i2c

Programmation de l'interface I2C donne un ensemble de sous-programmes suffisamment intéressants pour être repris ici.

Commençons à une initialisation à 400 kHz :

void TWIInit(void)
{
    //set SCL to 400kHz
    TWSR = 0x00;
    TWBR = 0x0C;
    //enable TWI
    TWCR = (1<<TWEN);
}

Nous n'avons pas besoin de préscaler. Pour ce qui est du départ et de l'arrêt, ces deux sous-programmes sont proposés :

//send start signal
void TWIStart(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    //TWCR &= ~(1<<TWSTA); //RAZ logiciel du bit TWSTA en commentaire avant des tests
}

//send stop signal
void TWIStop(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

Pour "start" nous devons positionner TWSTA et pour "stop" TWSTO ainsi que les bits TWINT et TWEN. Après qu'un "start" est demandé, il nous faut attendre jusqu'à ce que le bit TWINT passe à un.

Un sous-programme d'écriture peut être :

void TWIWrite(uint8_t u8data)
{
    TWDR = u8data;
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

La lecture est plus compliquée car elle nécessite deux formes :

  • une avec acquittement
  • une sans acquittement

Voici les deux sous-programmes correspondants :

//read byte with ACK
uint8_t TWIReadACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

//read byte with NACK
uint8_t TWIReadNACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

Pour compléter tout ceci, une lecture de l'état est nécessaire :

uint8_t TWIGetStatus(void)
{
    uint8_t status;
    //mask status
    status = TWSR & 0xF8;
    return status;
}

Nous allons utiliser ces sous-programmes pour lire la manette Nunchuk.

Application à la manette de jeux Nunchuk en mode Arduino

Panneau d’avertissement

Cette section a été réalisée avec un Arduino 3,3 V. En effet la manette Nunchuk fonctionne avec cette tension basse. La brancher directement sur un Arduino UNO peut endommager la manette !

Un chapitre de ce livre (parmi les chapitres suivants) est consacré à l'Arduino. Si vous n'avez aucune connaissance sur l'Arduino, lisez-le au moins en partie. Si vous avez de bonnes connaissances en C, il vous suffit cependant de savoir qu'un programme Arduino est composé par un setup() et un loop() en lieu et place du célèbre main(). Le setup() est réalisé une seule fois au démarrage et le loop() est réalisé en boucle (loop en anglais se traduit par boucle en français).

La manette Nunchuk est décrite dans un autre projet : Les nouvelles interfaces : de la nunchuk de Nintendo à android où seule la partie concernant la Nunchuk est à lire.

Documentation de la Wii-Nunchuk

Voici quelques brochages utiles qu’il est facile de retrouver sur Internet.

I2C SCLSDA
UNO PC5 (Arduino:A5)PC4 (Arduino:A4)
LEONARDO PD0 (Arduino:SCL)PD1 (Arduino:SDA)
Pro Micro (Sparkfun) PD0 (Arduino:3)PD1 (Arduino:2)

Wii Nunchuk help donne aussi des informations importantes sur la manette Nunchuk. En particulier, il vous faut garder à l'esprit que cette manette est faite pour fonctionner sous 3,3 V alors que le monde Arduino fonctionne en général plutôt à V.

Panneau d’avertissement Deuxième piqûre de rappel : le risque de détruire une manette Nunchuk est donc réel si vous la connectez à une platine Arduino. Faites une adaptation comme décrit plus haut en tout début de la section sur l'i2c.

Nous avons choisi la Platine "Pro Micro - 3,3 V/8MHz" de chez Sparkfun pour faire les tests de cette section. Comme elle est alimentée en 3,3 V, on n'a aucun problème de compatibilité.

Le point essentiel est que la manette Nunchuk retourne 6 octets dont la signification est la suivante :

Bit
Byte 7 6 5 4 3 2 1 0
0 SX<7:0>
1 SY<7:0>
2 AX<9:2>
3 AY<9:2>
4 AZ<9:2>
5 AZ<1:0> AY<1:0> AX<1:0> BC BZ

(tableau tiré de wiibrew)

SX,SY sont les positions du Joystick analogique en X et Y, tandis que AX, AY, et AZ sont les donnée de l'accéléromètre sur 10 bits suivant les trois axes.

Voici un exemple de lecture des accéléromètres en langage Arduino :

#include <Wire.h>;
 // adresse I2C du nunchuck
#define WII_NUNCHUK_I2C_ADDRESS 0x52
 
// définition d'une variable counter
uint8_t counter;
 
// définition d'un tableau de données
uint8_t data[6];

void setup() {
  Serial.begin(9600);
  // initialisation du nunchuck
  Wire.begin();
  Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
  Wire.write(0xF0);
  Wire.write(0x55);
  Wire.endTransmission();
 
  Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
  Wire.write(0xFB);
  Wire.write(0x00);
  Wire.endTransmission();
}
 
 
void loop() { 
  // on demande 6 octets au nunchuck
  Wire.requestFrom(WII_NUNCHUK_I2C_ADDRESS, 6);
  counter = 0;  // tant qu’il y a des données
  while(Wire.available()) {
    // on récupère les données
    data[counter++] = Wire.read();
  }
 
  // on réinitialise le nunchuck pour la prochaine demande
  Wire.beginTransmission(WII_NUNCHUK_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
 
  if(counter >= 5){
     // on extrait les données
     // dans mon exemple j'utilise uniquement les données d'accélération sur l'axe Y
     int16_t accelX = ((data[2] << 2) + ((data[5] >> 2) & 0x03));
     int16_t accelY = ((data[3] << 2) + ((data[5] >> 4) & 0x03));
     int16_t accelZ = ((data[4] << 2) + ((data[5] >> 6) & 0x03));
     Serial.print("ax = ");
     Serial.print(accelX);
     Serial.print(" : ay = ");
     Serial.print(accelY);
     Serial.print(" : az = ");
     Serial.println(accelZ);
   }
   // un petit delai  pour pas saturer la liaison série.
   delay(1000);
}

Travail à faire

Si l'accéléromètre donne une valeur quand ses positions changent c’est tout simplement parce qu’il est sensible à l'accélération de pesanteur.

1°) On vous demande les valeurs envoyées par l’accéléromètre pour chacun des axes en positif et négatif. Profitez de cet exercice pour bien repérer les trois axes x, y et z de l'accélération. Pour cela chercher à rendre maximum l'accélération sur un des axes : la verticale vous donnera la direction de l'axe correspondant.

2°) On vous demande de repérer le point 0 d'accélération (entre les deux extrêmes, puis de convertir les valeurs données par l'accéléromètre en unité standard sachant que l'accélération de pesanteur vaut 9,81 S.I. ()

3°) Choisissez un axe et réalisez la plus grande accélération possible. Combien de ms⁻2 faites-vous (sans vous démonter l'épaule) ?

4°) Faire un programme qui calcule sans arrêt les minima et maxima des accélérations tant que vous n'appuyez pas sur le bouton Z et affiche les résultats si vous appuyez dessus.

Application à la manette Nunchuk en C pur

Un exemple peut être trouvé ICI sur Internet.

Image logo indiquant un demande d'attention particulièreCette section est vide, pas assez détaillée ou incomplète. Votre aide est la bienvenue !

Communication USB

Il y a deux librairies avancées pour l'USB :

  • VUSB
  • LUFA

L'utilisation de la librairie LUFA de manière transparente dans le monde Arduino est développée dans un autre chapitre avec la réalisation d'un clavier USB.

Nous allons commencer par la librairie VUSB.

Un clavier USB qui utilise la librairie VUSB

Voir aussi

Une liaison série qui utilise la librairie VUSB

Voir aussi

Utilisation de la platine Arduino Leonardo

La platine Arduino Leonardo est équipée d'un AVR32U4 qui permet de faire de l'USB de manière matérielle.

Dans le chapitre sur Arduino de ce livre nous parlons de l'USB sur cette platine. Vous pouvez trouver cela dans la section Clavier USB avec la platine Leonardo. Cela nous montre la simplicité que procure l'environnement Arduino pour résoudre des problèmes assez complexes. Pourtant, si l’on veut aller plus loin il va bien falloir comprendre l’utilisation des registres pour gérer l'USB. C'est ce que nous nous proposons d'examiner maintenant.

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.