11
Utilisation du SPI sur le PIC 16F876 Claude Barbaud 14 septembre 2010 Principe du SPI: Le port synchrone SPI (Serial Peripheral Interface) est un port série synchrone. Il permet de communiquer sur 3 fils avec un certain nombre de périphériques. La synchronisation est assurée par le processeur. Les caractéristiques essentielles sont: rapidité (on peut fonctionner à fosc/4. fosc = oscillation d’entrée du PIC, soit 20 MHz pour le PIC232. On a donc une fréquence maximale de 5 MHz. robustesse( peu sensible aux interférences) peu de fils ou de traces à router. Il y a deux modes de fonctionnement SPI: Master mode: l'appareil contrôle l'horloge Slave mode: l'appareil reçoit une horloge externe Les broches utilisées sont: Serial Data Out: SDO/RC5 Serial Data In: SDI/RC4 Serial Clock: SCK/RC3 Une 4 ème broche peut être utilisée comme Chip Select en mode Slave: Slave select \SS/RA5. Le PIC maître peut choisir un PIC esclave par cette broche. Si on n’utilise qu’un seul PIC esclave, on peut la placer à GND ou la désactiver par logiciel en plaçant SPI_SS_DISABLED en paramètre de la fonction setup_spi(). Fonctionnement: En mode Master, le PIC contrôle le SCK. Une écriture [spi_write()] du Pic master provoque 8 impulsions sur SCK et l'envoi de la donnée sur SDO SPI sur le PIC16F876 Page 1

Sp Microcontrôleur PIC16F887 A.OUMNAD 1 LES MICROCONTROLEURS Par la pratique i

Embed Size (px)

DESCRIPTION

Microcontrôleur PIC16F887 A.OUMNAD1 LES MICROCONTROLEURS Par la pratique

Citation preview

Cours 243-468 Simulation et fabrication

Utilisation du SPI sur le PIC 16F876

Claude Barbaud14 septembre 2010Principe du SPI:

Le port synchrone SPI (Serial Peripheral Interface) est un port srie synchrone. Il permet de communiquer sur 3 fils avec un certain nombre de priphriques. La synchronisation est assure par le processeur. Les caractristiques essentielles sont:

rapidit (on peut fonctionner fosc/4. fosc = oscillation dentre du PIC, soit 20 MHz pour le PIC232. On a donc une frquence maximale de 5 MHz. robustesse( peu sensible aux interfrences)

peu de fils ou de traces router.

Il y a deux modes de fonctionnement SPI:

Master mode: l'appareil contrle l'horloge

Slave mode: l'appareil reoit une horloge externe

Les broches utilises sont:

Serial Data Out: SDO/RC5

Serial Data In: SDI/RC4

Serial Clock: SCK/RC3

Une 4me broche peut tre utilise comme Chip Select en mode Slave:

Slave select \SS/RA5.

Le PIC matre peut choisir un PIC esclave par cette broche. Si on nutilise quun seul PIC esclave, on peut la placer GND ou la dsactiver par logiciel en plaant SPI_SS_DISABLED en paramtre de la fonction setup_spi().

Fonctionnement:

En mode Master, le PIC contrle le SCK.

Une criture [spi_write()] du Pic master provoque 8 impulsions sur SCK et l'envoi de la donne sur SDO

La fonction spi_data_is_in() permet de savoir si une donne est reue.

Une lecture [spi_read()] du Pic slave n'est termine que quand les 8 impulsions sur le SCK sont termines.

Initialisation:

Pour initialiser le SPI, on doit placer un certain nombre de bits. Pour l'essentiel, ces bits se trouvent dans le registre SSPCON, l'adresse 0x14. Ils sont manipuls par la fonction setup_spi(). Les autres bits, l'adresse 0x94 [pour le PIC 16F876] sont manipuls individuellement (CKE et SMP)

setup_spi(SPI_MASTER | SPI_CLK_DIV_4 | SPI_L_TO_H);

les paramtres:

SPI_MASTER ou SPI_SLAVE ou SPI_SS_DISABLED

SPI_MASTER: le PIC est le matre du protocole SPI

SPI_SLAVE: le PIC est l'esclave du protocole

SPI_SS_DISABLED: Broche \SS dsactive

SPI_L_TO_H ou SPI_H_TO_L

Dtermine l'tat du bit CKP (Clock polarity)

SPI_L_TO_H : CKP = 0 : dbut sur un front montant (repos = 0)SPI_H_TO_L : CKP = 1 : dbut sur un front descendant (repos = 1)Voir la figure ci-dessous.

SPI_CLK_DIV_4 ou SPI_CLK_DIV_16 ou SPI_CLK_DIV_64

Division de l'oscillation du PIC (20 MHz)

CKE = TRUE; // Clock Edge

// CKE = TRUE: Transmission de la donne sur un front

// montant du clock (SCK).

// Si on place CKE = 0, la transmission se fait sur un

// front descendant

SMP = FALSE; // chantillonage de l'entre au centre d'un crneau

// si on place SMP = TRUE, l'chantillonage se fait

// sur la fin

Communication:

Du ct du PIC

criture sur la broche SDO du PIC (= RC5)

spi_write(valeur) // valeur 8 bits

Lecture sur la broche SDI du PIC (=RC4)

valeur = spi_read()

valeur = spi_read(0) gnre le Clock sur SCK

tat du registre de rception

If (spi_data_is_in()) {}

Exemple: criture sur master, lecture sur slave

Branchement:

PIC masterPIC slaveLCD Optrex 29481

SDO-C5SDI-C4

SCK-C3SCK-SCK-C3

A4RS [pin 4]

A5E [Pin 6] + pull-up 1k

B0 B7D0 [Pin 7] - D7[Pin 14]

Programme denvoi de donnes(PIC master)

// Claude Barbaud 06 octobre 2005 CCS-C

//----------------------------------------------------------------

// W_MASTER.C

//

// Utilisation du mode SPI

// Le programme envoie des donnees au port SPI

//

// Branchement des PICs:

// SPI_MASTER | SPI_SLAVE

// -------------+------------

// SDO | SDI

// SCLK | SCLK

//

//

//----------------------------------------------------------------

#include "16F876.H"

#fuses HS,NOWDT,PUT,NOPROTECT

#use delay(clock=20000000)

#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7)

#bit CKE = 0x94.6 // SPI Clock edge select

// CKE = 1: la donnee est transmise sur un front montant de SCK

// CKE = 0: sur un front descendant de SCK

//-------------------- Programme principal ------------------------

void main(void)

{

int i;

setup_spi(SPI_MASTER | SPI_CLK_DIV_4 | SPI_L_TO_H); // clk au repos a 0

CKE = TRUE; // Transmission de la donnee sur un front montant

for(;;)

for(i = 'A'; i LCD_4 //

// Enable: PIC_A5 --> LCD_6 //

// Donnees: PIC_B0..PIC_B7 --> LCD_7..LCD_14 //

// Reception SPI: SDI-C4 --> PIC_master SDO-C5 //

//

Clock SPI: SCK-C3 --> PIC_master SCK-C3 //

// //

//--------------------------------------------------------------//

#include

#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP

#use delay(clock=20000000)

#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#use standard_io(B)

#define RS PIN_A4 // Register select

#define E PIN_A5 // Enable

#define ALL_OUT 0 // definition des broches en sortie

#byte port_b = 6 // Adresse du port B = 06h

#bit SMP = 0x94.7 // Sample bit

// SMP = 1: echantillonage de SDI a la fin

// SMP = 0: echantillonage de SDI au milieu

//--------------Pototypes des fonctions-----------------//

void impulsion(void);

void initialise(void);

void pos_cur(int pose);

void ecrit(char ascii);

void enchaine(char chaine[20]);

char auteur[20] = {'C','l','a','u','d','e',' ','B','a','r','b','a','u','d',0x04};

char recu[20] = {'R','e','c','u',' ','=',' ',0x04};

void main(void)

{

char i;

setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_SS_DISABLED);

// Broche \SS desactivee (indispensable)

SMP = FALSE; // echantillonage de l'entree au centre d'un creneau

initialise();

pos_cur(0x80); // premiere ligne

enchaine(auteur);

pos_cur(0xC0); // deuxieme ligne

enchaine(recu);

for(;;)

{

if(spi_data_is_in())

{

i = spi_read();

pos_cur(0xC7);

ecrit (i);

}

}

}

//--------------------------------------------------------------//

void impulsion(void)

{

output_low(E);

delay_ms(5);

output_high(E);

delay_ms(5);

}

//--------------------------------------------------------------//

void initialise(void)

{

char init[5] = {0x38, 0x08, 0x01, 0x0C, 0x06};

int count;

set_tris_b(ALL_OUT); // Les 8 broches du port B en sortie

output_low(RS); // mode commande

for (count = 0; count < 5; count++)

{

port_b = init[count]; // code de controle

impulsion(); // + impulsion sur E

}

output_high(RS); // mode data

}

//--------------------------------------------------------------//

void pos_cur(int pose)

// Place le curseur a la position specifiee sur le LCD

{

output_low(RS); // mode commande

port_b = pose ; // la position

impulsion();

// + impulsion sur E

output_high(RS); // mode data

}

//--------------------------------------------------------------//

void ecrit(char ascii)

// Ecrit le caractere ASCII passe en parametre, a la position du curseur

// Le curseur se deplace a la position suivante

{

port_b = ascii;

impulsion();

}

//--------------------------------------------------------------//

void enchaine(char chaine[20])

// Ecrit la chaine de caractere passee en parametre, a la position du curseur

{

int count;

count = 0;

do

{

ecrit(chaine[count]);

count++;

}

while(chaine[count] != 0x04);

}

Exemple: criture sur slave, lecture sur master

Branchement:

PIC masterPIC slaveLCD Optrex 29481

SDO-C5SDI-C4

SCK-C3SCK-SCK-C3

SDI-C4SDO-C5

A4RS [pin 4]

A5E [Pin 6] + pull-up 1k

B0 B7D0 [Pin 7] - D7[Pin 14]

Principe

Le Clock est encore donn par le PIC Master. Il est dclench par une criture du ct Master.

Du ct du slave, on aura beau crire, cette criture ne sera ralis que quand l'horloge sera prsente.(Il y a une attente)C'est donc le master qui contrle la communication. Par une criture sur le port SPI (spi_write(0) ou spi_read(0)) il cr un Clock sur SCK qui est utilis par le slave, en attente d'criture (spi_write(i);

Programme denvoi de donnes(PIC slave)

// Claude Barbaud 06 octobre 2005 CCS-C

//----------------------------------------------------------------

// W_SLAVE.C

//

// Utilisation du mode SPI

// Le programme envoie des donnees au port SPI

//

// Branchement des PICs:

// SPI_MASTER | SPI_SLAVE

// -------------+-------------

// SDO | SDI

// SCLK | SCLK

// SDI

| SDO

//

//----------------------------------------------------------------

#include "16F876.H"

#fuses HS,NOWDT,PUT,NOPROTECT

#use delay(clock=20000000)

#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7)

#bit SMP = 0x94.7

#bit CKE = 0x94.6

//-------------------- Programme principal ------------------------

void main(void)

{

int i;

setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_SS_DISABLED);

// Broche \SS desactivee (indispensable)

SMP = FALSE; // echantillonage de l'entree au centre d'un creneau

CKE = TRUE; // Transmission de la donnee sur un front montant

for(;;)

for(i = 'A'; i LCD_4 //

// Enable: PIC_A5 --> LCD_6 //

// Donnees: PIC_B0..PIC_B7 --> LCD_7..LCD_14 //

// Reception SPI: SDI-C4 --> PIC_slave SDO-C5 //

//

Clock SPI: SCK-C3 --> PIC_slave SCK-C3 //

// Emission SPI SDO-C5 --> PIC_slave SDI-C4

// //

//--------------------------------------------------------------//

#include

#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP

#use delay(clock=20000000)

#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#use standard_io(B)

#define RS PIN_A4 // Register select

#define E PIN_A5 // Enable

#define ALL_OUT 0 // definition des broches en sortie

#byte port_b = 6 // Adresse du port B = 06h

#bit CKE = 0x94.6

#bit SMP = 0x94.7

//--------------Pototypes des fonctions-----------------//

void impulsion(void);

void initialise(void);

void pos_cur(int pose);

void ecrit(char ascii);

void enchaine(char chaine[20]);

char auteur[20] = {'C','l','a','u','d','e',' ','B','a','r','b','a','u','d',0x04};

char recu[20] = {'R','e','c','u',' ','=',' ',0x04};

void main(void)

{

char i;

setup_spi(SPI_MASTER | SPI_CLK_DIV_4 | SPI_L_TO_H );

SMP = FALSE; // echantillonage de l'entree au centre d'un creneau

CKE = TRUE; // Transmission de la donnee sur un front montant

initialise();

pos_cur(0x80); // premiere ligne

enchaine(auteur);

pos_cur(0xC0); // deuxieme ligne

enchaine(recu);

for(;;)

{

i = spi_read(0);

pos_cur(0xC7);

ecrit (i);

delay_ms(500);

}

}

//--------------------------------------------------------------//

void impulsion(void)

{

output_low(E);

delay_ms(5);

output_high(E);

delay_ms(5);

}

//--------------------------------------------------------------//

void initialise(void)

{

char init[5] = {0x38, 0x08, 0x01, 0x0C, 0x06};

int count;

set_tris_b(ALL_OUT); // Les 8 broches du port B en sortie

output_low(RS); // mode commande

for (count = 0; count < 5; count++)

{

port_b = init[count]; // code de controle

impulsion(); // + impulsion sur E

}

output_high(RS); // mode data

}

//--------------------------------------------------------------//

void pos_cur(int pose)

// Place le curseur a la position specifiee sur le LCD

{

output_low(RS); // mode commande

port_b = pose ; // la position

impulsion();

// + impulsion sur E

output_high(RS); // mode data

}

//--------------------------------------------------------------//

void ecrit(char ascii)

// Ecrit le caractere ASCII passe en parametre, a la position du curseur

// Le curseur se deplace a la position suivante

{

port_b = ascii;

impulsion();

}

//--------------------------------------------------------------//

void enchaine(char chaine[20])

// Ecrit la chaine de caractere passee en parametre, a la position du curseur

{

int count;

count = 0;

do

{

ecrit(chaine[count]);

count++;

}

while(chaine[count] != 0x04);

}

SPI sur le PIC16F876Page 7