Comunicação Serial com
Microcontroladores
Daniel Quadros
dqsoft.blogspot.com
dqsoft.blogspot@gmail.com
Agenda
• O Que é Comunicação Serial?
• Porque Comunicação Serial?
• Comunicação Serial Assíncrona
– RS232, RS422 e RS485
• Comunicação a 2 fios: I
2
C
• Comunicação a 3 fios
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
Porque Comunicação Serial?
• Reduz interconexões
– Menos pinos
– Layout mais simples
– Menos interferência
– Meio pode dificultar múltiplas conexões
Exemplos
• Escolhidos por
– Disponibilidade
– Variedade
• Não necessariamente os melhores
• Relógio + Ram
– PCF8583
– DS1002
• EEProm
– 24W256
– 93C66
• PIC
• MSP430
• HCS08
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
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
• 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
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
Comunic. Serial Assincrona
byte bufTx;
volatile int8 bitTx = -1;
void TxByte (byte b)
{
while (bitTx != -1)
;
bufTx = b;
bitTx = 0;
}
void RTCC_isr()
{
SET_TIMER0 (
76
);
if (bitTx == 10)
bitTx = -1;
if (bitTx != -1) {
if (bitTx == 0)
output_low (SERIAL_TX);
else if (bitTx == 9)
output_high (SERIAL_TX);
else {
if (bufTx & 1)
output_high (SERIAL_TX);
else
output_low (SERIAL_TX);
bufTx = bufTx >> 1;
}
bitTx++;
}
}
PIC Tx
“bit banging”
Comunic. Serial Assincrona
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);
}
}
PIC Rx
Comunic. Serial Assincrona
byte filaRx [16];
volatile int8 poeRx, tiraRx; byte bufRx; #INT_TIMER1 void TrataRx () { int1 dado; int8 aux; SET_TIMER1 (0xFFFF-156); dado = input (SERIAL_RX); switch (bitRx)
{
// ... }
}
case 1: // confirma start bitRx = 2;
break;
case 10: // confirma stop if (dado == 1) {
aux = (poeRx+1) & 0xF; if (aux != tiraRx) { filaRx[poeRx] = bufRx; poeRx = aux; } } enable_interrupts(INT_RA4); disable_interrupts(INT_TIMER1); enable_interrupts(INT_RTCC); break; default: // 2 a 9 = dados bufRx = bufRx >> 1; if (dado == 1) bufRx |= 0x80; bitRx++; break;
PIC Rx
(cont)
Comunic. Serial Assincrona
HCS08
#define BusClock 8000000 #define Baud 19200 void InitSCI () { ICSC1 = 0x04; ICSC2 = 0x00; ICSSC = NVFTRIM; ICSTRM = NVICSTRM;while (ICSC1_CLKS != ICSSC_CLKST) ; SCIBD = BusClock/16/Baud; SCIC1 = 0; // 8N1 SCIC2 = 0x2C; // Int Rx, Rx e Tx }
SCIS1
SCIC1
SCIC2
Comunic. Serial Assincrona
int LeRx () { int ret = -1; DisableInterrupts; if (poeFilaRx != tiraFilaRx) { ret = filaRx[tiraFilaRx]; tiraFilaRx = (tiraFilaRx+1)&7; } EnableInterrupts; return ret; }void TxByte (byte c) {
while(!SCIS1_TDRE) ;
SCID = c; }
static byte filaRx[8];
static volatile int poeFilaRx = 0; Static volatile int tiraFilaRx = 0; interrupt VectorNumber_Vscirx void SCIRx_ISR(void) { if (SCIS1_RDRF) { byte c = SCID;
int prox = (poeFilaRx + 1) & 7; if (prox != tiraFilaRx) { filaRx[poeFilaRx] = c; poeFilaRx = prox; } } }
Comunicação 2 Fios - I
2
C
• 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 - I
2
C
Comunicação 2 Fios - I
2
C
Leitura EEProm
Escrita EEProm
Comunicação 2 Fios - I
2
C
• 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 I
2C: 1 0 1 0 0 0 A0
Comunicação 2 Fios - I
2
C
#define sda_alto output_float(PCF8583_SDA) #define sda_baixo output_low(PCF8583_SDA) #define scl_alto output_float(PCF8583_SCL) #define scl_baixo 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; }
PIC
Comunicação 2 Fios - I
2
C
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 - I
2
C
byte PCF8583_Read (byte ender) {
byte result = 0;
delay_us (10); sda_baixo; delay_us (5); scl_baixo; delay_us (5);
if (PCF8583_TxByte (PCF8583_ADDR) && PCF8583_TxByte (ender)) { delay_us (10); scl_alto; delay_us (10); sda_baixo; delay_us (5); scl_baixo; delay_us (5); if (PCF8583_TxByte(PCF8583_ADDR|1)) result = PCF8583_RxByte (); } delay_us (5); sda_baixo; delay_us (5); scl_alto; delay_us (5); sda_alto; return result; } byte PCF8583_RxByte () {
int i; byte dado;
for (i = 0; i < 8; i++) { delay_us (5); scl_alto; dado = dado << 1; if (input(PCF8583_SDA)) dado |= 1; delay_us (5); scl_baixo; } sda_alto; delay_us (5); scl_alto; delay_us (5); scl_baixo; return dado; }
Comunicação 2 Fios - I
2
C
• 24WC256 – EEProm 256Kbits (32Kx8)
– Não volátil (100 anos)
– 100.000 ciclos de apagamento
– I
2C 1MHz
– Tempo de escrita: 5ms (Vcc 3 a 5,5V)
– Page Write (Page = 64 bytes)
Comunicação 2 Fios - I
2
C
MSP430
// Iniciação USIUSICKCTL = USIDIV2 | USIDIV0 | USISSEL1 | 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) ;
USICTL0 &= ~USIOE; USICNT = 1;
while ((USICTL1 & USIIFG) == 0) ;
return (USISRL & 1) == 0; }
USI
• I2C e SPI
• Shift & Clock
• Interrupções
Comunicação 2 Fios - I
2
C
// Recebe um byte byte I2C_RxByte () { byte dado;USICTL0 &= ~USIOE; USICNT = 8;
while ((USICTL1 & USIIFG) == 0) ; dado = USISRL; USISRL = 0xFF; USICTL0 |= USIOE; USICNT = 1;
while ((USICTL1 & USIIFG) == 0) ; return dado; } void I2C_TxStart () { USICTL0 |= USIOE; USISRL = 0xFF; USICNT = 1;
while ((USICTL1 & USIIFG) == 0) ;
USISRL = 0;
USICTL0 |= USIGE; USICTL0 &= ~USIGE; } void I2C_TxStop () { USICTL0 |= USIOE; USISRL = 0; USICNT = 1;
while ((USICTL1 & USIIFG) == 0) ;
USISRL = 0xFF; USICTL0 |= USIGE;
USICTL0 &= ~(USIGE | USIOE); }
Comunicação 2 Fios - I
2
C
void EEProm_Write (word ender, byte dado) {
I2C_TxStart(); I2C_TxByte (ADDR);
I2C_TxByte ((byte) (ender >> 8)); I2C_TxByte ((byte) (ender & 0xFF)); I2C_TxByte (dado);
I2C_TxStop(); }
byte EEProm_Read (word ender) {
byte dado;
I2C_TxStart(); I2C_TxByte (ADDR);
I2C_TxByte ((byte) (ender >> 8)); I2C_TxByte ((byte) (ender & 0xFF)); I2C_TxStart(); I2C_TxByte (ADDR | 1); dado = I2C_RxByte (); I2C_TxStop(); return dado; }
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
• A4 a A0 é o endereço da RAM ou do registrador
do relógio
Comunicação 3 Fios
byte DS1302_RxByte ()
{
int i;
byte dado;
for (i = 0; i < 8; i++) {
delay_us (1);
dado = dado >> 1;
if (input (DS1302_IO))
dado |= 0x80;
output_high (DS1302_SCLK);
delay_us (1);
output_low (DS1302_SCLK);
}
return dado;
}
PIC
void DS1302_TxByte (byte b)
{
int i;
set_tris_a (0xD8);
for (i = 0; i < 8; i++) {
if (b & 1)
output_high (DS1302_IO);
else
output_low (DS1302_IO);
delay_us (1);
output_high (DS1302_SCLK);
delay_us (1);
output_low (DS1302_SCLK);
b = b >> 1;
}
set_tris_a (0xDA);
}
Comunicação 3 Fios
byte DS1302_Read (byte ender)
{
byte result;
output_high (DS1302_CE);
delay_us (2);
DS1302_TxByte (ender|0x81);
result = DS1302_RxByte ();
delay_us (2);
output_low (DS1302_CE);
return result;
}
void DS1302_Write (byte ender,
byte dado)
{
output_high (DS1302_CE);
delay_us (2);
DS1302_TxByte (ender | 0x80);
DS1302_TxByte (dado);
delay_us (2);
output_low (DS1302_CE);
}
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
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
Comunicação 4 Fios - SPI
Comunicação 4 Fios - SPI
HCS08
SPI V3
• Gera clock
• Gerencia shift
• Gera/Trata –CS
• Interrupções
Comunicação 4 Fios - SPI
// Iniciação
SOPT2_SPIPS = 1; // pinos
SPIC1 = 0x52; // hab SPI, Mode 0 SPIC2 = 0x00; // MISO/MOSI SPIBR = 0x05; // busclk/64 // Write Enable PTBD_PTBD7 = 1; for (i = 0; i < 100; i++) ; WriteSPI (0x04); WriteSPI (0xFF); for (i = 0; i < 100; i++) ; PTBD_PTBD7 = 0; // Envia um byte
void WriteSPI (byte b) {
while (!SPIS_SPTEF) ;
SPID = b; }
void Grava (byte addr, word dado) { int i; PTBD_PTBD7 = 1; for (i = 0; i < 100; i++) ;
WriteSPI (0x05); WriteSPI (addr); WriteSPI (dado >> 8);
WriteSPI (dado & 0xFF); for (i = 0; i < 100; i++) ; PTBD_PTBD7 = 0; for (i = 0; i < 100; i++) ; PTBD_PTBD7 = 1; while (PTAD_PTAD0 == 0) ; PTBD_PTBD7 = 0; for (i = 0; i < 100; i++) ; }
Comunicação 4 Fios - SPI
byte ReadSPI () { byte d; int i, j; for (i = 0; i < 8; i++) { PTBD_PTBD6 = 1; for (j = 0; j < 100; j++) ; d = (d << 1) | PTAD_PTAD0; PTBD_PTBD6 = 0; for (j = 0; j < 100; j++) ; } return d; }word Le (byte addr) { byte d1, d2; int i; PTBD_PTBD7 = 1; for (i = 0; i < 100; i++) ;
WriteSPI (0x06); WriteSPI (addr); for (i = 0; i < 100; i++)
;
SPIC1 = 0x12; // desab SPI d1 = ReadSPI(); d2 = ReadSPI(); SPIC1 = 0x52; // hab SPI for (i = 0; i < 100; i++) ; PTBD_PTBD7 = 0; return (d1 << 8) | d2; }