Você está na página 1de 6

Engenharia de Sistemas Microprocessados

Professor: Márcio Gil Faccin


Aula 16 – Laboratório 8

Objetivos
Comunicação serial SPI e I2C.
Comunicação mestre-escravo com unidades remotas.

Orientações
Os alunos, em grupos de no máximo 3, deverão ter o material necessário para a execução da
prática de laboratório proposta, incluindo o datasheet dos CIs utilizados e o computador com a IDE
de programação. Após a montagem e as medições, os alunos deverão comprovar, através de
discussão em aula, o entendimento dos conceitos apresentados pelo professor ao longo da atividade.

Material de Apoio
SPI é uma interface serial síncrona a 5 pinos dedicada para conexão com periféricos em alta
velocidade. No protocolo SPI, um elemento é denominado Master (mestre), e é responsável pela
geração do sinal de relógio e pela habilitação do Slave (escravo). Os pinos utilizados para
comunicação SPI são: MOSI (Master Output – Slave Input); MISO (Master Input – Slave Output); SCK
̅̅̅(Slave Selection) e GND (referência de terra).
(Serial Clock); 𝑆𝑆
O protocolo SPI define mecanismos de proteção para evitar que dois mestres ou dois escravos
tentem escrever ao mesmo tempo no barramento, tomando por base o sinal de SS. Mas, como os pinos
de TX e RX são separados, esse protocolo prevê comunicação FULL DUPLEX entre o mestre e o
escravo.
Não é necessário configurar o baud rate nos dois dispositivos envolvidos na comunicação, uma
vez que o sinal de clock é transportado explicitamente, mas é necessário que a configuração de modo
seja feita corretamente (incluindo não apenas o modo Master/Slave, mas também o formato – CPHA
–, a polaridade do clock – CPOL – e a sequência de transmissão dos bits – DORD).
Engenharia de Sistemas Microprocessados
Professor: Márcio Gil Faccin
Aula 16 – Laboratório 8

A comunicação pode ser implementada manualmente, gerando as mudanças de nível no pino de


clock e as leituras/escritas nos pinos MOSI e MISO, mas também pode aproveitar, quando existente,
os recursos disponíveis no hardware do microcontrolador. Para o Arduino Uno existe um canal SPI
configurado através dos registradores SPCR (controle), SPSR (status) e SPDR (dados) e disponível
nos pinos 10, 11, 12 e 13, conforme figura abaixo.

Imagem adaptada de http://br-arduino.org/2016/01/arduino-standalone-protoboard.html


O registrador SPCR é o registrador de controle, no qual o recurso é habilitado, definindo se ele
usará ou não interrupção, definindo as características do modo e, no caso do Master, o prescaler
usado na geração do sinal de clock. Por exemplo, a configuração SPCR = B11010001; habilitaria o
modo SPI Master, com geração de evento de interrupção, com sinal de clock usando prescaler de
1/16, com transmissão primeiro do bit MSB, e com amostragem dos dados na primeira borda de
subida do relógio após a seleção do Slave.
A biblioteca de comunicação com os Shields Ethernet e SD utiliza o barramento SPI, efetuando as
configurações necessárias nos registradores e garantindo a comunicação, desde que os pinos
envolvidos sejam corretamente configurados como entradas ou saídas, dependendo de cada caso.
Maiores informações podem ser encontradas no site de referência do Arduino
(https://www.arduino.cc/en/Reference/SD ou https://www.arduino.cc/en/Reference/Ethernet).
O barramento SPI também pode ser utilizado para comunicação entre dois microcontroladores,
apesar de não ser a forma mais convencional de fazer esse tipo de comunicação.
Nestes casos, é mais usual a comunicação utilizando o barramento I2C (também conhecido como
TWI ou two-wire serial interface). No barramento I2C são utilizados apenas 3 fios: SDA (serial data),
SCL (serial clock) e GND. Além disso, muitos dispositivos são compatíveis com o protocolo I2C, como
memórias E2PROM seriais ou dispositivos de lógica programável.
Os pinos conectados aos sinais SDA e SCL devem ser pinos de saída em coletor aberto (ou dreno
aberto), garantindo a operação wired-and entre os diversos dispositivos conectados ao barramento.
Externamente a todos os dispositivos, resistores de pull-up devem ser conectados ao barramento,
garantindo nível alto em ambos os sinais quando nenhum dos dispositivos estiver acessando o
barramento.
Diferentemente do SPI, na comunicação I2C qualquer dispositivo pode assumir o papel de mestre,
desde que o barramento esteja livre. Porém, como os sinais de TX e RX usam o mesmo pino, a
comunicação será HALF DUPLEX. Para que um dispositivo assuma a condição de mestre, ele deve
gerar um sinal de START de transmissão enquanto o barramento estiver livre (o sinal de START é
caracterizado por uma borda de descida no pino SDA quando o pino SCL estiver em nível alto,
conforme a figura abaixo). Após a geração do START o barramento é considerado ocupado (BUSY)
até que o mestre gere um sinal de STOP.

Com exceção dos sinais de START, STOP e REPEATED START, todos os demais sinais de transição
de dados (SDA) devem ocorrer com o SCL em nível baixo, conforme a figura abaixo.
Engenharia de Sistemas Microprocessados
Professor: Márcio Gil Faccin
Aula 16 – Laboratório 8

Após assumir o barramento, o dispositivo mestre inicia a transmissão do sinal de clock e dos bits
da mensagem. Cada byte da mensagem sempre deve iniciar pelo bit mais significativo e após o
término do byte o dispositivo escravo deve confirmar a recepção, sinalizando através de um pulso de
Ack na linha SDA.

O primeiro byte enviado após um sinal de START (ou de REPEATED START) é sempre um byte
que identifica o endereço da estação de destino da mensagem (identificado por SLA) e o tipo de
transmissão (Leitura ou Escrita – SLA+R ou SLA+W). O endereço é livremente distribuído entre os
dispositivos conectados ao barramento, entre os valores 1 e 119 (o endereço é registrado com 7 bits,
mas o endereço 0 é reservado para comunicações em broadcast e os endereços de 120 até 127 são
reservados para uso futuro). Um dispositivo que esteja recebendo uma mensagem deve responder
com ACK somente se seu endereço for o mesmo endereço de destino da mensagem (ou se o endereço
de destino for 0) e se ele estiver apto a receber e processar o restante da mensagem. Os demais bytes
enviados após o SLA+R/W e antes do STOP são bytes de dados que compõem a mensagem e que
devem ser traduzidos pela camada de aplicação (em software) da estação de destino para gerar uma
resposta (seja a escrita do valor recebido em algum campo ou seja a devolução do valor de leitura
solicitado).
O protocolo I2C pode ser implementado totalmente em software, utilizando dois pinos digitais de
uso geral, ou ainda aproveitando recursos de hardware quando disponíveis no microcontrolador. A
família ATMEGA (usada no Arduino) possui um módulo I2C que controla dois pinos (no Arduino UNO
são os pinos A5 e A4; no Arduino MEGA são os pinos 21 e 20).

Imagem adaptada de http://br-arduino.org/2016/01/arduino-standalone-protoboard.html

Imagem adaptada de https://www.embarcados.com.br/arduino-mega-2560/


Engenharia de Sistemas Microprocessados
Professor: Márcio Gil Faccin
Aula 16 – Laboratório 8

A arquitetura interna do ATMEGA garante a geração do SCL, a transmissão do SDA e a detecção


de colisão no barramento.

A operação do barramento I2C pode ser controlada pelos registradores TWBR (Bit Rate Register),
TWDR (Data Register), TWAR (Address Register), TWSR (Status Register) e TWCR (Control Register)
e pelo evento de interrupção tratado pela rotina ISR(TWI_vect); ou ainda pela biblioteca Wire do
Arduino (maiores informações estão disponíveis em https://www.arduino.cc/en/Reference/Wire).

Também é possível criar barramentos seriais proprietários usando uma mescla

⚠ das técnicas industriais comentadas acima, utilizando apenas os recursos de


software e as interrupções de timer (para geração da base de tempo) e externa
(para entrada do dado).

Exemplo
1. Implementar uma comunicação mestre-escravo entre duas placas Arduino usando o
barramento I2C, que permita que a unidade Mestre envie, periodicamente, os valores
lidos na porta Analógica para exibição na unidade Escrava.

Esse exemplo é baseado no tutorial Master Writer, disponível em


https://www.arduino.cc/en/Tutorial/MasterWriter
Ele pressupõe que os pinos SCL e SDA das duas placas estão interconectados e com resistores
externos de pull-up; e que a serial USB do dispositivo Slave está conectada em um computador PC,
no qual serão visualizados os dados recebidos da unidade Master.

Master Writer Code - Program for Arduino 1

// Wire Master Writer


// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library


// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver" example for use with this
Engenharia de Sistemas Microprocessados
Professor: Márcio Gil Faccin
Aula 16 – Laboratório 8

// Created 29 March 2006

// The original example code is in the public domain.


// Changes in this code made by Marcio Gil Faccin on November, 17 (2016)

#include <Wire.h>

void setup() {
Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop() {
int anl_val = analogRead(0); // read the analog interface(MGF)
Wire.beginTransmission(8); // transmit to device #8
Wire.write((uint8_t *)&anl_val, 2); // sends two byte value (MGF)
Wire.endTransmission(); // stop transmitting
delay(500);
}

Slave Receiver Code - Program for Arduino 2

// Wire Slave Receiver


// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library


// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// The original example code is in the public domain.


// Changes in this code made by Marcio Gil Faccin on November, 17 (2016)

#include <Wire.h>

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}

void loop() {
delay(100);
}
Engenharia de Sistemas Microprocessados
Professor: Márcio Gil Faccin
Aula 16 – Laboratório 8

// function that executes whenever data is received from master


// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
int lsb_x = 0; // will receive the byte LSB of msg (MGF)
while (1 < Wire.available()) { // loop through all but the last
lsb_x = Wire.read(); // receive byte as a int (MGF)
}
int msb_x = Wire.read(); // receive MSB byte as an integer (MGF)
int x = lsb_x + (msb_x<<8); // compose 10-bit value (MGF)
Serial.println(x); // print the integer value
}

Exercícios Propostos
1. Implemente o programa do exemplo e verifique o funcionamento da comunicação entre
os dois dispositivos.
2. Altere os programas do exemplo de modo que o mestre envie os bytes (em ASC II) que
ele receber da porta serial conectada ao PC e que o PC conectado ao dispositivo escravo
receba os mesmos bytes enviados.
3. Altere os programas do exercício 2 de modo que qualquer um dos dois
microcontroladores possa operar como mestre ou como escravo no barramento,
fechando um canal de comunicação bidirecional entre os dois computadores.

Você também pode gostar