You are on page 1of 48

Comunicação Serial com

Microcontroladores

Daniel Quadros
dqsoft.blogspot.com
dqsoft.blogspot@gmail.com
Comunicando com a Periferia...
Um bit de cada vez
Agenda
• O Que é Comunicação Serial?
• Porque Comunicação Serial?
• Comunicação Serial Assíncrona
– RS232, RS422 e RS485
• Comunicação a 1 fio: 1-Wire
• Comunicação a 2 fios: I2C
• Comunicação a 3 fios
• Comunicação a 4 fios: SPI e Microwire
Comunicação Serial
• Um bit enviado de cada vez
• Half x Full duplex
• Necessidades:
– Localizar os bits: síncrono ou assíncrono
– Localizar os bytes
– Endereçamento se multiponto
• Base da implementação é o shift register
Porque Comunicação Serial?
• Reduz interconexões
– Menos pinos
– Layout mais simples
– Menos interferência
– Meio pode dificultar múltiplas conexões
• Desvantagem é o desempenho
Exemplos
• Escolhidos por
– Disponibilidade
– Variedade
• Não necessariamente os melhores
• Relógio + Ram
• PIC – PCF8583
• MSP430 – DS1002
• HCS08 • EEProm
– 24W256
– 93C66
• Sensor Temp
– DS18B20
Comunic. Serial Assíncrona

• Start pode vir a qualquer instante


• Demais bits determinados pela taxa
• Stop e paridade podem ser usados para
consistência
Comunic. Serial Assíncrona
• Implementação por Software
– Requer precisão no tempo dos bits
– Determinar start na recepção pode ser problemático

• Implementação por Hardware


– Shift registers
– Interrompe qdo recebe ou pronto p/ tx
– Cuidado com overrun
– Opções com buffer maior
Comunic. Serial Assíncrona
• RS-232
– Ponto a ponto
– Sinais de controle (para modem)
– Conectores DB25 e DE9
Comunic. Serial Assíncrona
• RS-232
– Tensões “altas” para aumentar imunidade a ruídos
– Transmissor deve operar com ±12V
– Receptor deve aceitar ± 3 a 15V
– Dados: 1 = -12V, 0 = +12V
– Sinais de controle: ativo = +12V, inativo = -12V
– Cabo limitado a 15 metros pela capacitância
Comunic. Serial Assíncrona
Comunic. Serial Assíncrona
• RS-422
– Maiores distâncias, maiores velocidades e melhor
imunidade a interferências
– Ponto a ponto ou multi-drop (1 transmissor ligado a
vários receptores)
– Usa sinal diferencial
– Par trançado com blindagem
Comunic. Serial Assincrona
• RS-485 (EIA-485)
– Maiores distâncias, maiores velocidades e melhor
imunidade a interferências
– Ponto a ponto ou multi-ponto
– Usa sinal diferencial
– Resistores de terminação
– Operação half-duplex ou full-duplex
Comunic. Serial Assincrona
void RTCC_isr()
{
PIC Tx SET_TIMER0 (76);
if (bitTx == 10)
“bit banging” bitTx = -1;
if (bitTx != -1) {
if (bitTx == 0)
output_low (SERIAL_TX);
byte bufTx; else if (bitTx == 9)
volatile int8 bitTx = -1; output_high (SERIAL_TX);
else {
void TxByte (byte b) if (bufTx & 1)
{ output_high (SERIAL_TX);
while (bitTx != -1) else
; output_low (SERIAL_TX);
bufTx = b; bufTx = bufTx >> 1;
bitTx = 0; }
} bitTx++;
}
}
Comunic. Serial Assincrona

PIC Rx volatile int8 bitRx;

#INT_RA
void RA_isr()
{
if ((input(SERIAL_RX)==0) &&
(bitRx==0))
{
bitRx = 1;
disable_interrupts(INT_RA4);
SET_TIMER1 (0xFFFF - 60);
disable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
}
}
Comunic. Serial Assincrona
case 1: // confirma start
PIC Rx bitRx = 2;
break;
(cont)
case 10: // confirma stop
byte filaRx [16]; if (dado == 1) {
volatile int8 poeRx, tiraRx; aux = (poeRx+1) & 0xF;
byte bufRx; if (aux != tiraRx) {
filaRx[poeRx] = bufRx;
#INT_TIMER1 poeRx = aux;
void TrataRx () }
{ }
int1 dado; enable_interrupts(INT_RA4);
int8 aux; disable_interrupts(INT_TIMER1);
enable_interrupts(INT_RTCC);
SET_TIMER1 (0xFFFF-156); break;
dado = input (SERIAL_RX);
switch (bitRx) default: // 2 a 9 = dados
{ bufRx = bufRx >> 1;
// ..................... if (dado == 1)
} bufRx |= 0x80;
} bitRx++;
break;
Comunic. Serial Assincrona

HCS08
#define BusClock 8000000
#define Baud 19200

SCIC1 void InitSCI ()


{
ICSC1 = 0x04;
ICSC2 = 0x00;
ICSSC = NVFTRIM;
SCIC2 ICSTRM = NVICSTRM;
while (ICSC1_CLKS != ICSSC_CLKST)
;
SCIBD = BusClock/16/Baud;
SCIC1 = 0; // 8N1
SCIS1 SCIC2 = 0x2C; // Int Rx, Rx e Tx
}
Comunic. Serial Assincrona
static byte filaRx[8]; int LeRx ()
static volatile int poeFilaRx = 0; {
Static volatile int tiraFilaRx = 0; int ret = -1;

interrupt VectorNumber_Vscirx DisableInterrupts;


void SCIRx_ISR(void) if (poeFilaRx != tiraFilaRx)
{ {
if (SCIS1_RDRF) ret = filaRx[tiraFilaRx];
{ tiraFilaRx = (tiraFilaRx+1)&7;
byte c = SCID; }
int prox = (poeFilaRx + 1) & 7; EnableInterrupts;
if (prox != tiraFilaRx) return ret;
{ }
filaRx[poeFilaRx] = c;
poeFilaRx = prox; void TxByte (byte c)
} {
} while(!SCIS1_TDRE)
} ;
SCID = c;
}
Comunicação a 1 Fio

• Proprietário da Dallas (hoje Maxim)


• Bi-direcional e multiponto (end 64bits)
• Alimentação pela linha de dados
• Mestre força 0, força 1, deixa livre
• Baixa velocidade
• Procedimento especial para descobrir disps
Comunicação a 1 Fio

Fonte: wikipedia
Comunicação 2 Fios - I2C

• SCL: Clock gerado pelo mestre


• SDA: Dado/Endereço (bidirecional)
• Endereços de 7 bits
• Pinos de endereçamento para ligar “em varal”
dispositivos do mesmo tipo
Comunicação 2 Fios - I2C

Normalmente SDA muda somente quando SCL = 0


Comunicação 2 Fios - I2C

Escrita EEProm

Leitura EEProm
Comunicação 2 Fios - I2C
Comunicação 2 Fios - I2C

• PCF8583 (Relógio + Ram)


– Relógio: 12/24 horas
– Calendário: 4 anos
– Alarme: data + horário
– 240 bytes de Ram
– Baixo consumo
– Uso com cristal de 32KHz
– Endereço I2C: 1 0 1 0 0 0 A0
– I2C 100KHz
Comunicação 2 Fios - I2C
#define sda_alto output_float(PCF8583_SDA)
#define sda_baixo output_low(PCF8583_SDA)
PIC #define
#define
scl_alto
scl_baixo
output_float(PCF8583_SCL)
output_low(PCF8583_SCL)

byte PCF8583_TxByte (byte b)


{
int i; byte ack;

for (i = 0; i < 8; i++)


{
if (b & 0x80) sda_alto; else sda_baixo;
delay_us (5); scl_alto;
delay_us (5); scl_baixo;
b = b << 1;
}
delay_us (5); scl_alto;
ack = input(PCF8583_SDA) == 0;
delay_us (5); scl_baixo;
return ack;
}
Comunicação 2 Fios - I2C
void PCF8583_Write (byte ender, byte dado)
{
// Start
delay_us (10); sda_baixo;
delay_us (5); scl_baixo;
delay_us (5);

// Efetua a escrita
if (PCF8583_TxByte (PCF8583_ADDR) &&
PCF8583_TxByte (ender) &&
PCF8583_TxByte (dado))
;

// Stop
delay_us (5); sda_baixo;
delay_us (5); scl_alto;
delay_us (5); sda_alto;
}
Comunicação 2 Fios - I2C
byte PCF8583_Read (byte ender) byte PCF8583_RxByte ()
{ {
byte result = 0; int i; byte dado;
delay_us (10); sda_baixo;
delay_us (5); scl_baixo; for (i = 0; i < 8; i++)
delay_us (5); {
if (PCF8583_TxByte (PCF8583_ADDR) && delay_us (5); scl_alto;
PCF8583_TxByte (ender)) { dado = dado << 1;
delay_us (10); scl_alto; if (input(PCF8583_SDA))
delay_us (10); sda_baixo; dado |= 1;
delay_us (5); scl_baixo; delay_us (5); scl_baixo;
delay_us (5); }
if (PCF8583_TxByte(PCF8583_ADDR|1)) sda_alto; delay_us (5);
result = PCF8583_RxByte (); scl_alto; delay_us (5);
} scl_baixo;
delay_us (5); sda_baixo; return dado;
delay_us (5); scl_alto; }
delay_us (5); sda_alto;
return result;
}
Comunicação 2 Fios - I2C
• 24WC256 – EEProm 256Kbits (32Kx8)
– Não volátil (100 anos)
– 100.000 ciclos de apagamento
– I2C 1MHz
– Tempo de escrita: 5ms (Vcc 3 a 5,5V)
– Page Write (Page = 64 bytes)
– Endereço I2C : 1 0 1 0 0 A1 A0 R
Comunicação 2 Fios - I2C
// Iniciação USI
USICKCTL = USIDIV2 | USIDIV0 | USISSEL1 |
MSP430 USICKPL | USISWRST;
USICTL0 = USIPE7 | USIPE6 | USIMST;
USICTL1 = USII2C;
USICNT = 0;
USICKCTL &= ~USISWRST;

// Transmite um byte
byte I2C_TxByte (byte b)
{
USISRL = b;
USICTL0 |= USIOE;
USICNT = 8;
while ((USICTL1 & USIIFG) == 0)
;
USI USICTL0 &= ~USIOE;
• I2C e SPI USICNT = 1;
while ((USICTL1 & USIIFG) == 0)
• Shift & Clock ;
• Interrupções return (USISRL & 1) == 0;
}
Comunicação 2 Fios - I2C
void I2C_TxStart ()
// Recebe um byte {
byte I2C_RxByte () USICTL0 |= USIOE;
{ USISRL = 0xFF;
byte dado; USICNT = 1;
while ((USICTL1 & USIIFG) == 0)
USICTL0 &= ~USIOE; ;
USICNT = 8; USISRL = 0;
while ((USICTL1 & USIIFG) == 0) USICTL0 |= USIGE;
; USICTL0 &= ~USIGE;
dado = USISRL; }

USISRL = 0xFF; void I2C_TxStop ()


USICTL0 |= USIOE; {
USICNT = 1; USICTL0 |= USIOE;
while ((USICTL1 & USIIFG) == 0) USISRL = 0;
; USICNT = 1;
while ((USICTL1 & USIIFG) == 0)
return dado; ;
} USISRL = 0xFF;
USICTL0 |= USIGE;
USICTL0 &= ~(USIGE | USIOE);
}
Comunicação 2 Fios - I2C
void EEProm_Write (word ender, byte EEProm_Read (word ender)
byte dado) {
{ byte dado;
I2C_TxStart();
I2C_TxByte (ADDR); I2C_TxStart();
I2C_TxByte ((byte) (ender >> 8)); I2C_TxByte (ADDR);
I2C_TxByte ((byte) (ender & 0xFF)); I2C_TxByte ((byte) (ender >> 8));
I2C_TxByte (dado); I2C_TxByte ((byte) (ender & 0xFF));
I2C_TxStop(); I2C_TxStart();
} I2C_TxByte (ADDR | 1);
dado = I2C_RxByte ();
I2C_TxStop();
return dado;
}
Comunicação 3 Fios
Comunicação 3 Fios
• DS1302 (Clock/Calendar + Ram)
– Relógio: 12/24 horas, precisão 0.01 seg
– Calendário: 100 anos
– Alarme: data + horário
– 31 bytes de Ram (0x10 a 0cFF)
– Baixo consumo p/ uso de bateria
– Uso com cristal de 32KHz
– Clock comunicação até 2MHz (5V)
– Suporte a bateria recarregável
Comunicação 3 Fios
Comunicação 3 Fios

• A4 a A0 é o endereço da RAM ou do registrador


do relógio
• Modo burst p/ ler ou escrever tudo
Comunicação 3 Fios
void DS1302_TxByte (byte b)
PIC {
int i;
byte DS1302_RxByte ()
{ set_tris_a (0xD8);
int i; for (i = 0; i < 8; i++) {
byte dado; if (b & 1)
output_high (DS1302_IO);
for (i = 0; i < 8; i++) { else
delay_us (1); output_low (DS1302_IO);
dado = dado >> 1; delay_us (1);
if (input (DS1302_IO)) output_high (DS1302_SCLK);
dado |= 0x80; delay_us (1);
output_high (DS1302_SCLK); output_low (DS1302_SCLK);
delay_us (1); b = b >> 1;
output_low (DS1302_SCLK); }
} set_tris_a (0xDA);
return dado; }
}
Comunicação 3 Fios
byte DS1302_Read (byte ender) void DS1302_Write (byte ender,
{ byte dado)
byte result; {
output_high (DS1302_CE);
output_high (DS1302_CE); delay_us (2);
delay_us (2); DS1302_TxByte (ender | 0x80);
DS1302_TxByte (ender|0x81); DS1302_TxByte (dado);
result = DS1302_RxByte (); delay_us (2);
delay_us (2); output_low (DS1302_CE);
output_low (DS1302_CE); }
return result;
}
Comunicação 4 Fios - SPI
Comunicação 4 Fios - SPI
• CPOL – Polaridade do Clock
• CPHA – Fase do Clock
Modo CPOL CPHA Clock repouso Borda p/ gravar
0 0 0 0 Subida
1 0 1 0 Descida
2 1 0 1 Descida
3 1 1 1 Subida

• Microwire
– Subset restrito do SPI
– Somente modo 0
– Half duplex
Comunicação 4 Fios - SPI
• 93C66 – EEProm 4096bits (256x16 ou 512x8)
– Não volátil (40 anos)
– 1.000.000 ciclos de apagamento
– Microwire 250KHz a 3 MHz
– Tempo de escrita: 15ms a 5ms
Comunicação 4 Fios - SPI

Atenção!
Comunicação 4 Fios - SPI

HCS08 SPI V3
• Gera clock
• Gerencia shift
• Gera/Trata –CS
• Interrupções
• Duas opções de pinos
Comunicação 4 Fios - SPI
// Iniciação void Grava (byte addr, word dado)
SOPT2_SPIPS = 1; // pinos {
SPIC1 = 0x52; // hab SPI, Mode 0 int i;
SPIC2 = 0x00; // MISO/MOSI
SPIBR = 0x05; // busclk/64 PTBD_PTBD7 = 1;
for (i = 0; i < 100; i++)
// Write Enable ;
PTBD_PTBD7 = 1; WriteSPI (0x05); WriteSPI (addr);
for (i = 0; i < 100; i++) WriteSPI (dado >> 8);
; WriteSPI (dado & 0xFF);
WriteSPI (0x04); WriteSPI (0xFF); for (i = 0; i < 100; i++)
for (i = 0; i < 100; i++) ;
; PTBD_PTBD7 = 0;
PTBD_PTBD7 = 0; for (i = 0; i < 100; i++)
;
// Envia um byte PTBD_PTBD7 = 1;
void WriteSPI (byte b) while (PTAD_PTAD0 == 0)
{ ;
while (!SPIS_SPTEF) PTBD_PTBD7 = 0;
; for (i = 0; i < 100; i++)
SPID = b; ;
} }
Comunicação 4 Fios - SPI
byte ReadSPI () word Le (byte addr)
{ {
byte d; byte d1, d2;
int i, j; int i;

for (i = 0; i < 8; i++) PTBD_PTBD7 = 1;


{ for (i = 0; i < 100; i++)
PTBD_PTBD6 = 1; ;
for (j = 0; j < 100; j++) WriteSPI (0x06); WriteSPI (addr);
; for (i = 0; i < 100; i++)
d = (d << 1) | PTAD_PTAD0; ;
PTBD_PTBD6 = 0; SPIC1 = 0x12; // desab SPI
for (j = 0; j < 100; j++) d1 = ReadSPI(); d2 = ReadSPI();
; SPIC1 = 0x52; // hab SPI
} for (i = 0; i < 100; i++)
return d; ;
} PTBD_PTBD7 = 0;

return (d1 << 8) | d2;


}
Referências
• Sites dos Fabricantes
– http://www.microchip.com
– http://www.freescale.com
– http://ti.com/msp430
• Data Sheets dos Periféricos
• Wikipedia
• Livros
– PIC Programação em C, Fábio Pereira
– HCS08 Unleashed, Fábio Pereira
Obrigado!

Perguntas?
Visite o
Garoa Hacker Clube

You might also like