Cette page vous affiche les différences entre la révision choisie et la version actuelle de la page.
robotics:electronics:shield_arduino_ls7366r [2012/05/23 17:46] ldo [Shéma fonctionnel] |
robotics:electronics:shield_arduino_ls7366r [2014/10/03 14:38] (Version actuelle) gdo [Typon] |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== Présentation des LS7366R ====== | ====== Présentation des LS7366R ====== | ||
- | Le LS7366R est un compteur 32 bits spécialisé pour les horloges en quadrature (type codeur incrémentaux). Il peut être configuré en compteur 1, 2 3 ou 4 octets. Il dispose également d'une entrée index. Il communique avec un microcontrolleur via une liaison SPI. | + | Le [[http://www.lsicsi.com/pdfs/Data_Sheets/LS7366R.pdf|LS7366R]] est un compteur 32 bits spécialisé pour les horloges en quadrature (type codeur incrémentaux). Il peut être configuré en compteur 1, 2 3 ou 4 octets. Il dispose également d'une entrée index. Il communique avec un microcontrolleur via une liaison SPI. |
===== Entrées / Sorties ===== | ===== Entrées / Sorties ===== | ||
Ligne 50: | Ligne 50: | ||
Nous réalisons un robot avec deux moteurs à courant continu que nous voulons asservir. Les moteurs ont chacun un codeur incrémental en quadrature (sortie A et B) et nous souhaitons également mettre deux roues codeuses indépendantes. Cela fait donc 4 codeurs à traiter. | Nous réalisons un robot avec deux moteurs à courant continu que nous voulons asservir. Les moteurs ont chacun un codeur incrémental en quadrature (sortie A et B) et nous souhaitons également mettre deux roues codeuses indépendantes. Cela fait donc 4 codeurs à traiter. | ||
- | Pour cela, nous utilisons une carte ARDUINO UNO et une shield moteur ARDUINO pour le contrôle des moteurs (2 x 2A basée sur un L298). Sur le principe des shield ARDUINO, nous avons donc fait une carte avec les 4 compteurs LS7366R communiquant via la liaison SPI. | + | Pour cela, nous utilisons une carte [[http://arduino.cc/en/Main/arduinoBoardUno|ARDUINO UNO]] et une [[http://www.dfrobot.com/wiki/index.php?title=Arduino_Motor_Shield_%28L298N%29_%28SKU:DRI0009%29|shield moteur ARDUINO]] pour le contrôle des moteurs (2 x 2A basée sur un [[http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00000240.pdf|L298]]). Sur le principe des shield ARDUINO, nous avons donc fait une carte avec les 4 compteurs LS7366R communiquant via la liaison SPI. |
===== Shéma fonctionnel ===== | ===== Shéma fonctionnel ===== | ||
Nous utilisons 4 compteur LS7366R et un oscillateur à quartz 40 MHz. | Nous utilisons 4 compteur LS7366R et un oscillateur à quartz 40 MHz. | ||
- | Voici le schéma de la la shield LS7366R. | + | Voici le schéma de la shield LS7366R. |
{{:robotics:electronics:schema.jpg?1000|}} | {{:robotics:electronics:schema.jpg?1000|}} | ||
Ligne 60: | Ligne 60: | ||
Pour l'instant, nous avons réaliser la carte avec des composants traditionnels. Il serait interressant de la refaire avec des composants CMS pour réduire sa taille et pouvoir laisser libre les borniers de la shield moteur. | Pour l'instant, nous avons réaliser la carte avec des composants traditionnels. Il serait interressant de la refaire avec des composants CMS pour réduire sa taille et pouvoir laisser libre les borniers de la shield moteur. | ||
- | ====== Test ====== | + | {{:robotics:electronics:typon.jpg|}} |
- | Dans un premier temps, nous avons fait un petit programme de test pour communiquer avec le compteur. Nous avons utiliser une Arduino uno (ou duemilanove 2009). | + | |
- | Nous générons une horloge sur la sortie PD3 (30 Hz) à mettre sur l'entrée A du compteur. | + | |
- | MDR0 = 0x00 non quadrature count mode (horloge sur A et direction sur B) | + | |
- | MDR1 = 0x03 : comptage sur 1 octet | + | |
- | test 1 : test communication avec le LS7366 | + | Vous pouvez télécharger le typon au format Kicad ici : {{:robotics:electronics:counter_shield.kicad_pcb.zip|}} |
- | vérifier que la valeur inscrite dans le registre MDR0 est correcte | + | ====== Implementation ====== |
- | test 2 : test comptage sens positif (B=1) | + | ===== Fonctions de base ===== |
- | Il faut mettre 5V sur l'entrée B du compteur. | + | Nous avons écrite quelques fonctions de base pour le compteur. Ces fonctions permettent de lire et d'écrire dans les registres de configuration et compteur. |
+ | <code c> | ||
+ | |||
+ | /* LS7366R opcode list */ | ||
+ | #define CLR_CNTR 0x20 /* clear CNTR register to zero */ | ||
+ | |||
+ | #define READ_MDR0 0x48 /* read MDR0 */ | ||
+ | #define READ_MDR1 0x50 /* read MDR1 */ | ||
+ | #define READ_CNTR 0x60 /* transfer CNTR to OTR */ | ||
+ | |||
+ | #define WRITE_MDR0 0x88 /* write serial data into MDR0 */ | ||
+ | #define WRITE_MDR1 0x90 /* write serial data into MDR1 */ | ||
+ | |||
+ | /* configuration MDRO */ | ||
+ | #define NON_QUADRATURE 0x00 /* non-quadrature count mode */ | ||
+ | #define X1_QUADRATURE 0x01 /* x1 quadrature count mode */ | ||
+ | |||
+ | /* configuration MDR1 */ | ||
+ | #define _1_BYTE 0x03 /* 1-byte counter mode */ | ||
+ | |||
+ | |||
+ | /* remise a zero du compteur */ | ||
+ | void | ||
+ | clr(char op_code) | ||
+ | { | ||
+ | PORT_SPI |= (1 << DD_SS); | ||
+ | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | ||
+ | SPI_master_transmit(op_code);/* send command */ | ||
+ | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | ||
+ | } | ||
+ | |||
+ | /* ecriture (envoi d'une commande) */ | ||
+ | void | ||
+ | write(char op_code, char data) | ||
+ | { | ||
+ | PORT_SPI |= (1 << DD_SS); | ||
+ | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | ||
+ | SPI_master_transmit(op_code);/* send command */ | ||
+ | SPI_master_transmit(data);/* send command */ | ||
+ | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | ||
+ | } | ||
+ | |||
+ | /* lecture */ | ||
+ | char | ||
+ | read(char op_code) | ||
+ | { | ||
+ | char data; | ||
+ | PORT_SPI |= (1 << DD_SS); | ||
+ | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | ||
+ | data = SPI_master_transmit(op_code);/* send command */ | ||
+ | data = SPI_master_transmit(0x00);/* start dummy transmission to read data from LS7366R */ | ||
+ | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | ||
+ | return data; | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | ===== Tests ===== | ||
+ | ==== Mode compteur ==== | ||
+ | Dans un premier temps, nous avons fait un petit programme de test pour tester le mode compteur. Nous avons utilisé une ARDUINO UNO (ou duemilanove 2009) et un compteur LS7366R. \\ | ||
+ | Nous générons une horloge sur la sortie PD5 (30 Hz) à mettre sur l'entrée A du compteur. \\ | ||
+ | MDR0 = 0x00 non quadrature count mode (horloge sur A et direction sur B) \\ | ||
+ | MDR1 = 0x03 : comptage sur 1 octet | ||
- | test 3 : test comptage sens negatif (B=0) | + | * test 1 : test communication avec le LS7366R. Vérifier que la valeur inscrite dans le registre MDR1 est correcte |
- | Il faut mettre l'entrée B du compteur à la masse. | + | * test 2 : test comptage sens positif (B=1). Il faut mettre 5V sur l'entrée B du compteur. |
+ | * test 3 : test comptage sens négatif (B=0). Il faut mettre l'entrée B du compteur à la masse. | ||
- | <code> | + | <code c> |
/* | /* | ||
* main.c | * main.c | ||
Ligne 81: | Ligne 140: | ||
* Author: ldo | * Author: ldo | ||
* | * | ||
- | * Arduino duemilanove 2009 | + | * Arduino duemilanove 2009 ou ARDUINO UNO |
* Atmega328P 16MHz | * Atmega328P 16MHz | ||
*/ | */ | ||
- | #include<avr/io.h> /* pour les definitions des registres */ | + | #include <avr/io.h> /* pour les definitions des registres */ |
#include <avr/interrupt.h> /* pour les interruptions */ | #include <avr/interrupt.h> /* pour les interruptions */ | ||
+ | #include <avr/delay.h> | ||
+ | |||
+ | #include "spi.h" | ||
/* SPI port */ | /* SPI port */ | ||
- | #define DDR_SPI DDRB /* SPI port B */ | + | #define DDR_SPI DDRB /* SPI on port B */ |
#define PORT_SPI PORTB | #define PORT_SPI PORTB | ||
- | #define DD_SS 2 /* SS/ : PB2 */ | + | #define DD_SS 1 /* SS/ : PB1 */ |
#define DD_MOSI 3 /* MOSI : PB3 */ | #define DD_MOSI 3 /* MOSI : PB3 */ | ||
#define DD_MISO 4 /* MISO : PB4*/ | #define DD_MISO 4 /* MISO : PB4*/ | ||
#define DD_SCK 5 /* SCK : PB5 */ | #define DD_SCK 5 /* SCK : PB5 */ | ||
- | /* LS7366R opcode list */ | ||
- | #define CLR_CNTR 0x20 /* clear CNTR register to zero */ | ||
- | #define READ_MDR0 0x48 /* read MDR0 */ | + | /* generation d'une horloge pour simuler l'entrée A du compteur */ |
- | //#define READ_MDR1 | + | void |
- | #define READ_CNTR 0x60 /* transfer CNTR to OTR */ | + | generation_horloge(void) |
- | //#define READ_OTR 0x68 | + | |
- | + | ||
- | #define WRITE_MDR0 0x88 /* write serial data into MDR0 */ | + | |
- | #define WRITE_MDR1 0x90 /* write serial data into MDR1 */ | + | |
- | + | ||
- | //#define LOAD_OTR 0xE4 /* load CNTR to OTR in "parallel" */ | + | |
- | + | ||
- | #define CONF_MDR0 0x00 /* non-quadrature count mode */ | + | |
- | #define CONF_MDR1 0x03 /* 1-byte counter mode */ | + | |
- | + | ||
- | void initPort(void) | + | |
{ | { | ||
- | /* configuration des ports : '1' pour sortie */ | + | _delay_ms(15); /* attente 15 ms */ |
- | DDRD = 0b11111111; /* PORTD en sortie */ | + | PORTD ^= (1 << 5); /* inverse PD5 */ |
} | } | ||
- | void SPI_MasterInit(void) | + | /* test communication */ |
+ | void | ||
+ | test_communication(char data) | ||
{ | { | ||
- | DDR_SPI = (1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS); /* set MOSI, SCK and SS/ output */ | + | data = read(READ_MDR1); |
- | SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); /* Enable SPI, Master, set clock rate fck/16 */ | + | if (data == _1_BYTE) |
+ | { | ||
+ | PORTD |= (1 << 4); // PD4 = 1 | ||
+ | } | ||
} | } | ||
- | char SPI_MasterTransmit(char data) | + | /* test comptage sens positif (B=1) */ |
+ | void | ||
+ | test_comptage_positif(signed char data) | ||
{ | { | ||
- | SPDR = data; /* load byte to data register */ | + | if (data > 100) |
- | while (!(SPSR & (1 << SPIF))) | + | { |
- | ; /* wait for transmission complete */ | + | PORTD |= (1 << 4); // PD4 = 1 |
- | data = SPDR; /* load received byte */ | + | } |
- | return data; | + | else |
+ | { | ||
+ | PORTD &= ~(1 << 4); // PD4 = 0 | ||
+ | } | ||
} | } | ||
- | void clr(char op_code) | + | /* test comptage sens negatif (B=0) */ |
+ | void | ||
+ | test_comptage_negatif(signed char data) | ||
{ | { | ||
- | PORT_SPI |= (1 << DD_SS); | + | if (data < -100) |
- | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | + | { |
- | SPI_MasterTransmit(op_code);/* send command */ | + | PORTD |= (1 << 4); // PD4 = 1 |
- | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | + | } |
+ | else | ||
+ | { | ||
+ | PORTD &= ~(1 << 4); // PD4 = 0 | ||
+ | } | ||
} | } | ||
- | void write(char op_code, char data) | + | void |
+ | init_port(void) | ||
{ | { | ||
- | PORT_SPI |= (1 << DD_SS); | + | /* configuration des ports : '1' pour sortie */ |
- | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | + | DDRB = 0xFF; /* PORTB en sortie */ |
- | SPI_MasterTransmit(op_code);/* send command */ | + | PORTB = 0x00; |
- | SPI_MasterTransmit(data);/* send command */ | + | DDRD = 0xFF; /* PORTD en sortie */ |
- | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | + | PORTD = 0x00; |
} | } | ||
- | char read(char op_code) | + | void |
+ | init(void) | ||
{ | { | ||
- | char data; | + | init_port(); |
- | PORT_SPI |= (1 << DD_SS); | + | SPI_master_init(); |
- | PORT_SPI &= ~(1 << DD_SS); /* slave select */ | + | _delay_ms(100); |
- | data = SPI_MasterTransmit(op_code);/* send command */ | + | |
- | data = SPI_MasterTransmit(0x00);/* start dummy transmission to read data from LS7366R */ | + | |
- | PORT_SPI |= (1 << DD_SS); /* slave unselect */ | + | |
- | return data; | + | |
} | } | ||
- | void attente(void) | + | int |
+ | main(void) | ||
{ | { | ||
- | unsigned int i = 0; | + | signed char data; |
- | while (i < 48000) | + | init(); |
- | { | + | |
- | asm("nop"); | + | |
- | i++; | + | |
- | } | + | |
- | } | + | |
- | int main(void) | + | // configuration du LS7366R |
- | { | + | write(WRITE_MDR0, NON_QUADRATURE); |
- | char data; | + | write(WRITE_MDR1, _1_BYTE); |
+ | clr(CLR_CNTR); | ||
- | initPort(); | + | while (1) |
- | PORTD = 0x00; | + | { |
+ | /* lecture du compteur */ | ||
+ | data = read(READ_CNTR); | ||
- | SPI_MasterInit(); | + | test_communication(data); |
+ | //test_comptage_positif(data); | ||
+ | //test_comptage_negatif(data); | ||
+ | } | ||
- | /* configuration du LS7366R */ | + | return 1; |
- | write(WRITE_MDR0, CONF_MDR0); | + | } |
- | write(WRITE_MDR1, CONF_MDR1); | + | </code> |
- | clr(CLR_CNTR); | + | |
- | while (1) | + | ==== Mode quadrature ==== |
- | { | + | Nous avons fait un petit programme pour tester le mode quadrature x1. Les sorties A et B du codeur sont reliées aux entrées A et B du compteur. Nous comptons toujours sur 1 octet. |
- | /* generation d'une horloge pour simuler l'entrée A du compteur */ | + | |
- | attente(); /* attente 15 ms */ | + | |
- | PORTD ^= (1 << 3); /* inverse PD3 */ | + | |
- | /* lecture du compteur */ | + | <code c> |
- | data = read(READ_CNTR); | + | void |
+ | test_quadrature_x1(signed char data) | ||
+ | { | ||
+ | if (data > 0) | ||
+ | { | ||
+ | PORTD |= (1 << 4); // PD4 = 1 | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | PORTD &= ~(1 << 4); // PD4 = 0 | ||
+ | } | ||
+ | } | ||
- | /* test communication */ | + | int |
- | /*data = read(READ_MDR0); | + | main(void) |
- | if (data == CONF_MDR0) | + | { |
- | { | + | signed char data; |
- | PORTD = 0xFF; | + | |
- | }*/ | + | |
- | /* test comptage sens positif (B=1) */ | + | init(); |
- | if (data < 50) | + | |
- | { | + | |
- | PORTD |= (1 << 2); /* PD2 = 1 */ | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | PORTD &= ~(1 << 2); /* PD2 = 0 */ | + | |
- | if (data > 100) | + | // configuration du LS7366R |
- | { | + | write(WRITE_MDR0, X1_QUADRATURE); |
- | clr(CLR_CNTR); | + | write(WRITE_MDR1, _1_BYTE); |
- | } | + | clr(CLR_CNTR); |
- | } | + | |
- | /* test comptage sens negatif (B=0) */ | + | while (1) |
- | /* if (data > -50) | + | { |
- | { | + | /* lecture du compteur */ |
- | PORTD=0xFF; | + | data = read(READ_CNTR); |
- | } | + | |
- | else | + | |
- | { | + | |
- | PORTD=0x00; | + | |
- | if (data<-100) | + | |
- | { | + | |
- | clr(CLR_CNTR); | + | |
- | } | + | |
- | }*/ | + | |
- | } | + | |
- | return 1; | + | test_quadrature_x1(data); |
+ | } | ||
+ | |||
+ | return 1; | ||
} | } | ||
+ | |||
</code> | </code> |