Baixe o app para aproveitar ainda mais
Prévia do material em texto
ITAndroids “Ser a melhor equipe de robótica do mundo” Tutorial de SPI Autor: Igor Franzoni Okuyama T-16 Data: 12/12/2012 1. Introdução O Serial Peripheral Interface (SPI) é um protocolo de comunicação síncrono que opera em modo duplex. Ele é síncrono, porque usa um clock externo para mandar informações e é duplex, pois usa duas linhas de transmissão de dados, uma para enviar e outra para receber dados. Nesse protocolo, é importante a distinção entre Master e Slave. O Master, ou mestre é aquele que controla a comunicação. Ele é que decide quando o Slave (escravo) vai mandar ou receber algum dado. No SPI, há apenas um Master, mas pode haver vários Slaves. Esse tutorial será baseado no PIC16F877A, e usaremos o compilador do MikroC. 2. Interface O SPI usa basicamente 4 pinos: · Serial Data Out (SDO) – RC5/SDO: Pino de saída de dados. (OUTPUT); · Serial Data In (SDI) – RC4/SDI/DAS: Pino de entrada de dados (INPUT); · Serial Clock (SCK) – RC3/SCK/SCL: Pino que envia ou recebe o clock. (OUTPUT para Master e INPUT para Slave); · Slave Select (SS) – RA5/AN4/SS/C2OUT: Pino usado para ativar ou desligar um Slave e é usado apenas nos Slaves. 0 (zero) significa que o Slave está ativo, e 1 significa inativo. Os Slaves desligados não receberão dados do Master, ou enviarão dados para ele. Use o Slave Select apenas quando houver mais de um Slave. (INPUT para Slave somente. Master controla o SS com um pino de output qualquer). Veja um esquema da pinagem para 1 Master e 1 Slave: Legenda: · SCLK: serial clock (saída do master, entrada no slave); · MOSI: master output, slave input (saída do master, entrada no slave); · MISO: master input, slave output (saída no slave, entrada no master); · SS: slave select (saída no master, entrada no slave). Agora um esquema para 1 Master e 3 Slaves (independentes): 3. Registradores Os registradores ligados ao SPI são 4: · SSPCON · SSPSTAT · SSPBUF · SSPRS Olhe o datasheet do PIC16F877A para entender o que eles fazem. Comentaremos um pouco sobre alguns no próximo item. 4. Operação Aqui explicaremos como funciona o protocolo SPI no PIC16F877A. A figura a seguir será usada na explicação: Tudo começa com um dado (byte) sendo escrito no buffer (SSPBUF) do Master. Esse byte é copiado para o Shift Register (SSPSR) e a transmissão começará. O clock inicia-se e a cada mudança do clock (ver o bit 6 CKE do SSPSTAT) um bit é enviado para o Slave (do mais significativo para o menos significativo). Cada bit enviado é guardado no Shift Register do Slave até formar o byte completo. Quando o clock se inicia, o Slave também começa a enviar o byte que foi colocado em seu buffer previamente. Assim, ao mesmo tempo em que o Master envia um byte para o Slave, o Slave envia um byte para o Master, caracterizando a transmissão duplex. Quando um byte foi totalmente recebido pelo Master ou pelo Slave o flag SSPSTAT.BF (Buffer Status bit) fica com estado alto e ocorre a interrupção do SPI (flag SSPIF). Não usaremos a interrupção nesse tutorial. É importante notar que a transmissão de um dado só é completada se a recepção de um dado for completada. Por isso, o flag SSPSTAT.BF é importante. Quando o flag SSPSTAT.BF fica alto, deve-se ler o buffer para que ele volte ao estado baixo. Se isso não for feito, o flag ficará sempre alto e não poderemos detectar se o PIC recebeu algum dado. Ler o buffer também é importante para evitar overflow, isto é, evitar que um novo byte seja recebido, enquanto o buffer ainda guarda o byte anterior que não foi lido. OBS*: Comentaremos sobre os flags WCOL e SSPOV do SSPCON1. Se você tentar transmitir um dado (escrever dado no buffer) enquanto estiver transmitindo outro, o flag WCOL ficará alto e o novo byte a ser enviado será ignorado. Por isso, sempre verifique se o WCOL está alto antes de enviar algum dado. O flag SSPOV ficará alto se ocorrer overflow, como explicamos acima: se você tem um byte não lido no buffer e receber outro, acontece overflow. Se SSPOV ficar alto, significa que você não leu o buffer. Sempre leia o buffer, mesmo que ele seja não seja importante. 5. Implementação Mãos à obra! 5.1. 1 Master e 1 Slave: O primeiro circuito que iremos fazer terá apenas um Master e um Slave, trocando informação entre si. O Master enviará potências de 2 para o Slave, e o Slave enviará um contador binário para o Master =D. Veja os códigos: Código do Master: //ITAndroids //1 Master e 1 Slave //Código para o Master //Compilado em MikroC 5.3 //by Igor Franzoni Okuyama T-16 char rec; char x = 0b00000001; char SPI(char buf) { while(SSPCON.WCOL); //Esperar para não haver colisão de dados (Esperar a transmissão anterior se completar) SSPBUF = buf; //Carrega o dado a ser enviado no buffer (A transmissão irá começar) while(!SSPSTAT.BF); //Esperar o recebimento de dados ser completado return SSPBUF; //Retornar o dado recebido do slave } void init() { //Configuração do SPI //SSPSTAT: SSPSTAT.SMP = 0; //Input data sampled at middle of data output time SSPSTAT.CKE = 0; //Transmit occurs on transition from Idle to active clock state //SSPCON: SSPCON.SSPEN = 1; //Enables serial port and configures SCK, SDO, SDI, and SS as serial port pins SSPCON.CKP = 0; //Idle state for clock is a low level SSPCON.SSPM3 = 0; SSPCON.SSPM2 = 0; //SPI Master mode, clock = FOSC/4 SSPCON.SSPM1 = 0; SSPCON.SSPM0 = 0; //Configurando portas TRISC.F3 = 0; //SCK, Pino de clock, Master output TRISC.F4 = 1; //SDI, Pino de entrada de dados, Master input TRISC.F5 = 0; //SDO, Pino de saída de dados, Master output TRISD = 0b00000000; //A porta D será usada para vermos o que o Master está recebendo } void main() { init(); while(1) { delay_ms(10); //Espera Slave carregar buffer. IMPORTANTE! O Slave tem que carregar seu buffer antes de o Master carregar! Teste comentar essa //linha. O Master recebe a mesma coisa que ele enviou, pois não dá tempo de o Slave carregar seu buffer. rec = SPI(x); //Enviar byte x PORTD = rec; delay_ms(1000); //Esperar para transmitir dado novamente x = x << 1; //Operação shift para esquerda. O bit 1 vai andando if(x == 0b00000000) x = 0b00000001; } } Código do Slave: //ITAndroids //1 Master e 1 Slave //Código para o Slave //Compilado em MikroC 5.3 //by Igor Franzoni Okuyama T-16 char rec; int cont = 0; char SPI(char buf) { while(SSPCON.WCOL); //Esperar não haver colisão de dados (Esperar a transmissão anterior se completar) SSPBUF = buf; //Carrega o dado a ser enviado no buffer (A transmissão irá começar) while(!SSPSTAT.BF); //Esperar o recebimento de dados ser completado return SSPBUF; //Retornar o dado recebido do slave } void init() { //Configuração do SPI //SSPSTAT: SSPSTAT.SMP = 0; //Input data sampled at middle of data output time SSPSTAT.CKE = 0; //Transmit occurs on transition from Idle to active clock state //SSPCON: SSPCON.SSPEN = 1; //Enables serial port and configures SCK, SDO, SDI, and SS as serial port pins SSPCON.CKP = 0; //Idle state for clock is a low level SSPCON.SSPM3 = 0; SSPCON.SSPM2 = 1; //SPI Slave mode, clock = SCK pin. SS pin control disabled. SS can be used as I/O pin. SSPCON.SSPM1 = 0; SSPCON.SSPM0 = 1; //Configurando portas TRISC.F3 = 1; //SCK, Pino de clock, Slave input TRISC.F4 = 1; //SDI, Pino de entrada de dados, Slave input TRISC.F5 = 0; //SDO, Pino de saída de dados, Slave output TRISD = 0b00000000; //A porta D será usada para vermos o que o Slave está recebendo } void main() { init(); while(1) { rec = SPI(cont); //Enviar cont PORTD = rec; //Escrever o que foi recebido na porta D delay_ms(100); //Esperar para transmitir dado novamente cont++; //Aumentar cont para fazer um contador binário na porta D do Masterif(cont > 255) cont = 0; } } Veja um vídeo do funcionamento do circuito no Proteus: 5.2 1 Master e 2 Slaves: Agora faremos um circuito com 1 Master controlando 2 Slaves. Sendo assim, precisaremos mudar uma configuração nos Slaves. Precisamos ativar o pino Slave Select (RA5). Para isso, configure os 4 primeiros bits do registrador SSPCON1. Além disso, precisamos configurar o pino SS como input. Para isso, além de fazer TRISA.F5 = 1, devemos desativar os conversores analógicos configurando o registrador ADCON1. No Master, devemos usar dois pinos quaisquer como output para controlar os Slaves. 0 (zero) significa que o Slave está ativo e 1 significa inativo. Nesse exemplo, os Slaves enviam uma informação qualquer para o Master, pois o foco está no envio de informação do Master para os Slaves. Seguem os códigos do Master e dos Slaves: Código do Master: //ITAndroids //1 Master e 2 Slaves //Código para o Master //Compilado em MikroC 5.3 //by Igor Franzoni Okuyama T-16 #define SS1 PORTB.F6 #define SS2 PORTB.F7 char rec; char x = 0b00000001; char y = 0b10000000; char SPI(char buf) { while(SSPCON.WCOL); SSPBUF = buf; while(!SSPSTAT.BF); return SSPBUF; } void init() { //Configuração do SPI //SSPSTAT: SSPSTAT.SMP = 0; SSPSTAT.CKE = 0; //SSPCON: SSPCON.SSPEN = 1; SSPCON.CKP = 0; SSPCON.SSPM3 = 0; SSPCON.SSPM2 = 0; SSPCON.SSPM1 = 0; SSPCON.SSPM0 = 0; //Configurando portas TRISB.F6 = 0; TRISB.F7 = 0; TRISC.F3 = 0; TRISC.F4 = 1; TRISC.F5 = 0; } void main() { init(); while(1) { SS1 = 0; //Slave 1 ativo SS2 = 1; //Slave 2 inativo delay_ms(1); rec = SPI(x); delay_ms(500); x = x << 1; if(x == 0b00000000) x = 0b00000001; SS1 = 1; //Slave 1 inativo SS2 = 0; //Slave 2 ativo delay_ms(1); rec = SPI(y); delay_ms(500); y = y >> 1; if(y == 0b00000000) y = 0b10000000; } } Código para os Slaves: //ITAndroids //1 Master e 2 Slaves //Código para os Slaves //Compilado em MikroC 5.3 //by Igor Franzoni Okuyama T-16 char rec; char SPI(char buf) { while(SSPCON.WCOL); SSPBUF = buf; while(!SSPSTAT.BF); return SSPBUF; } void init() { //Configuração do SPI //SSPSTAT: SSPSTAT.SMP = 0; SSPSTAT.CKE = 0; //SSPCON: SSPCON.SSPEN = 1; SSPCON.CKP = 0; SSPCON.SSPM3 = 0; SSPCON.SSPM2 = 1; //SPI Slave mode, clock = SCK pin. SS pin control enabled. SSPCON.SSPM1 = 0; SSPCON.SSPM0 = 0; //Configurando portas ADCON1.PCFG3 = 0; ADCON1.PCFG3 = 1; //Todo o port A é digital ADCON1.PCFG3 = 1; ADCON1.PCFG3 = 0; TRISA.F5 = 1; //Slave Select TRISC.F3 = 1; TRISC.F4 = 1; TRISC.F5 = 0; TRISD = 0b00000000; } void main() { init(); while(1) { rec = SPI(0); PORTD = rec; delay_ms(1); } } Vídeo do funcionamento: 6. Bibliografia: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus Datasheet pic 16F877A Escreva aqui sua opinião sobre o tutorial. O que podemos melhorar? Alguma parte não está clara? Sugestões? Página 13 1 Master 1 Slave.avi 1 Master e 2 Slaves.avi
Compartilhar