terça-feira, 22 de abril de 2014

Usando sensor de temperatura TC72 da microchip.

Olá vou demonstrar como usar o sensor de temperatura TC72 da microchip com o microcontrolador PIC 18F13K22 , a comunicação com este sensor é via SPI , vamos ao código fonte :
/*
 *                                 Usando sensor de temperatura TC72
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor: aguivone
 * Versão: 1
 * Data :  22 de abril 2014
 * Descrição : como usar o sensor de temperatura TC72 e enviar via porta serial 
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "GenericTypeDefs.h"
#define _XTAL_FREQ 16000000    // cristal de 16 Mhz
#include <xc.h>

/////////////////////////////////////////////////////configuraçôes do pic //////////////////////////////////////////////////
//**************************************************************************************************
// CONFIGURAÇÃO DOS FUSÍVEIS
//**************************************************************************************************
// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
//#pragma config PLLEN = ON       // Se igual a 1(on) o clock será multiplicado por 4
#pragma config PLLEN = OFF      // desabilitado
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = ON     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF       // MCLR Pin Enable bit (MCLR pin enabled, RA3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = ON        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = ON        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = ON       // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = ON        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = ON       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = ON       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = ON       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = ON       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = ON       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)


/////////////////////////////Defines utilizados////////////////////////////////////////////////////////////////////////
#define SPI_SS    LATCbits.LATC6 //configura pino de Slave selected
#define LED       LATCbits.LATC0

// Wiznet W5200 endereço dos registradores
#define LER_LSB         0x01   // lê o byte menos significativo
#define LER_MSB         0x02   // lê o byte mais significativo
#define LER_ID          0x03   // lê o ID do chip

#define ESCREVE         0x80   // escreve dados
////variaveis usadas /////////////
unsigned int temp_msb;
unsigned char temp_lsb,sensor_id;
unsigned int temperatura;
char caracter;
bit flag_interrupcao = 0;
////////////////////////////////////rotina de tempo////////////////////////////////////////////////////////////
void delay_ms(long mili) {
    while (mili > 0) {
        _delay(15600); //aprox. 1ms com clock de 64mhz
        mili--;
    }
}
void delay_us(long micro) {
    while (micro > 0) {
        _delay(15); //aprox. 1us com clock de 64mhz
        micro--;
    }
}

unsigned char ler_SPI( unsigned char dado )
{
  unsigned char TempVar;
  SPI_SS    = 1;
   delay_us(5);
  TempVar = SSPBUF;        // limpa BF
  SSPBUF = dado;           // escreve no buffer
  while ( !SSPSTATbits.BF );//espera terminar o envio
  SSPBUF = 0X00;           // envia um dado qual qualquer
  while ( !SSPSTATbits.BF );
   SPI_SS    = 0;
  return (SSPBUF);       // byte lido
}
void escreve_SPI( unsigned char dado )
{
   unsigned char TempVar;
   SPI_SS    = 1;
   delay_us(5);
   TempVar = SSPBUF;        // limpa BF
   SSPBUF = 0x80;           // escreve no buffer
   while ( !SSPSTATbits.BF ); //espera terminar o envio
   SSPBUF = dado;           // escreve no buffer
   while ( !SSPSTATbits.BF );
   SPI_SS    = 0;
}
void inicializa_spi_mestre(void)//inicialica modo mestre
{    
    SSPCON1 = 0X20; //habilita pinos de spi // FOSC/4 //clock em nivel 0
    SSPSTAT = 0X80; //pega amostras no fim do byte e a trasmissão será na borda de subida
    SPI_SS = 0;
}

void inicializa_TC72(void)
 {
     escreve_SPI(0x40);//solicita escrita - configura o TC72
    //configura registrado de controle, configura para captura continua e shutdown desabilitado
 }

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    //verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    int valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
   // PIE1 = 0X20;
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TXIF ==0);//espera enviar caracter
}

void imprime(const char frase[])
{
     char indice = 0;
     unsigned char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve(frase[indice]);
           indice++;
       }
}

void int_to_char(int quant)
{
    char convert_char3='0';
    char  convert_char2='0';
    char convert_char1='0';
        int temp = quant;
      
       while(quant>=100)
        {
         quant=quant-100;
         convert_char3++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char2++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char1++;
         }
           if(temp>=100)
           {
             escreve(convert_char3);
           }
          if(temp>=10)
           {
            escreve(convert_char2);
           }
        escreve(convert_char1);
            escreve('\n');//pula linha
            escreve('\r');//vai ao inicio da linha
}

//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{

    TRISA = 0XFF;
    TRISB = 0X30; //configura portB como saida exceto o pino b4(SDI)e b5(RX da serial)
    TRISC = 0X00; //configura portc como saida
    ANSEL = 0xFF; //desabilita porta analogicas(para não atrapalhar recepção no pino)
    ANSELH = 0xFF; //em alguns casos não funciona nem a interrupção de recepção.
    CM1CON0 = 0X00;
    CM2CON0 = 0X00;
    CM2CON1 = 0X00;
    inicializa_RS232(9600,1);//modo de alta velocidade
    inicializa_spi_mestre();
    INTCON = 0xC0;//interrrupção global e de periferico habilitadas
    inicializa_TC72();
    imprime("Usando sensor de temperatura TC72! \n\r");
    for (;;)
    {
        LED = ~LED;
        temp_msb = ler_SPI(LER_MSB);//solicita escrita
      //  temp_lsb = ler_SPI(LER_LSB);//vamos usar somente a parte inteira da temperatura
        sensor_id = ler_SPI(LER_ID);//solicita escrita
        imprime(" \n\r Temperatura : ");
        if((temp_msb&0b10000000)< 127)//o maximo que o sensor vai é até 125°C
        {
          int_to_char(temp_msb&0b01111111);
        }
        else
         {
           escreve('-');
           int_to_char(128 -(temp_msb&0b01111111));//o valor é negativo
        }
        imprime(" \n\r Numero do chip: ");
        int_to_char(sensor_id);
        delay_ms(500);
    }//chave do laço infinito (for)
}//chave de main

Esquemático e simulação:

sexta-feira, 4 de abril de 2014

Servidor web usando dois sockets

           Quando se tem uma aplicação(rodando em um PC) que fica o tempo todo conectado a nosso hardware e então surge a necessidade de acessar remotamente esta placa, mas como? existe 2 possibilidades a primeira seria  o hardware conecta e desconecta o tempo todo ou então a segunda opção seria criar  um outro socket(uma nova porta de comunicação), se usar a primeira opção você pode ter problemas pois no momento que alguém está conectado você não consegue acessar aquele socket,caso  escolha a opção 2 é possível manter duas conexões simultâneas.Vale lembra que este exemplo roda também em dispositivos moveis pois utiliza uma página http(com isso não precisa de software adicional). 
             O projeto é o mesmo deste aqui http://microcontroladores-c.blogspot.com.br/2014/01/servidor-web-com-wiz820-usando-o.html que já foi explicado aqui no blog o que muda é somente o código fonte utilizado,usei  a porta 5000 e a porta padrão de ethernet (porta 80), para acessar o hardware basta digitar no browser 192.168.50.141 e para acessar o socket0 192.168.50.141:5000, segue abaixo o exemplo:

O código fonte : 

//***********************************************************************************************************
//                               Usando o modulo wiz820io
//
// no gravador configurar os fuses assim:
//  EXTENDED 0XFF 
//  HIGH     0XD8 - neste modo funciona com qualquer valor de cristal usei um de 16Mhz  
//  LOW      0XC7
//  LOKBITS  0XFF  - sem proteção
//
//
//  versão                        : 1
//  descrição                   : Servidor web que aceita 2 conexões com o modulo modulo wiz820
                               // para isso vamos ter o mesmo IP mas portas diferentes
                               // aqui no exemplo será a porta 5000 e a porta 5001 
//  Autor                      : Aguivone
//  microcontrolador           : ATmega328P
//  compilador                   : AVR-GCC / Atmel AVR Studio 4.17
//  Data do projeto            : 03 / 04 / 2014 
//  aviso! - no modulo wiz 820 deve ser colocado um capacitor de 100nF no pino de reset para evitar problemas de ruido
//*************************************************************************************************************
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>// AVRJazz Mega328 SPI I/O

////////////////////////funçoes auxiliares/////////////////////////////
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))

/////////////////////////////////////////////////////////////////////////////////////////////
//configuração dos pinos SPI
#define SPI_PORT PORTB //porta que será usado para SPI
#define SPI_DDR  DDRB  
#define SPI_SS   PORTB2//seleção de chip(habilita comunicação SPI)



// Wiznet W5200 endereço dos registradores
#define MR         0x0000   // Registrador de modo
#define GAR           0x0001   // endereço(inicial) de Gateway : 0x0001 a 0x0004
#define SUBR       0x0005   // mascara de subrede           : 0x0005 a 0x0008
#define SHAR       0x0009   // Source Address Register , endereço de hardware (MAC)   : 0x0009 a 0x000E
#define SIPR       0x000F   // IP do hardware(escolhido pelo programador): 0x000F to 0x0012 //Socket 0

#define RTR       0x0017      // timeout
#define RCR       0x0019      // timeout

/////////////////configurei apenas o sockt0 pois vou usar apenas este.///////////////
/*
para colocar mais socket 2 por exemplo (0X4n00)
S0_PORT  0X4204
lembre que agora os buffer de rx e tx mudaram uma vez que o wiz820 tem capacidade para até 7 sockets
*/

/////////////// socket 0 ///////////////////////////////////////////////////////

#define S0_MR       0x4000      // Socket 0: registrador do socket0 
#define S0_CR       0x4001      // Socket 0: registrador de comandos do socket0
#define S0_IR       0x4002      // Socket 0: registrador de interrupçoes do socket0
#define S0_SR       0x4003      // Socket 0: registrador de status do socket0
#define S0_PORT    0x4004      // Socket 0: aqui é colocado o valor da porta TCP ->  endereço = 0x0404 a 0x0405
#define S0_DPORT   0x4010      // Socket 0: aqui é colocado o valor da porta TCP de destino->  endereço = 0x0410 a 0x0411
#define S0_DHAR    0x4006      // Socket 0: endereçamento de registro de hardware(tipo MAC)->  endereço = 0x0406 a 0x040B
#define S0_DIPR    0x400C      // Socket 0: IP de acesso remoto ->  endereço = 0x040C a 0x040F
#define SO_TX_FSR  0x4020      // Socket 0: tamanho do registrador de transmissão: 0x0420 to 0x0421
#define S0_TX_RD   0x4022      // Socket 0: ponteiro de leitura do buffer de transmissão : 0x0422 a 0x0423
#define S0_TX_WR   0x4024      // Socket 0: ponteiro de escrita do buffer de transmissão: 0x0424 a 0x0425
#define S0_RX_RSR  0x4026      // Socket 0: tamanho do registrador de recepção: 0x0426 a 0x0427
#define S0_RX_RD   0x4028      // Socket 0: ponteiro de leitura do tamanho dos dados: 0x0428 a 0x0429
#define S0_IMR       0x402C      // mascara de interrupção dos sockets
#define RMSR0       0x401E   // RX - localização do buffer de recepção
#define TMSR0       0x401F   // TX - localização do buffer de envio

///////////////socket 1 ////////////////////////////////////////////////////////////////////////////////////////

#define S1_MR       0x4100      // Socket 1: registrador do socket1 
#define S1_CR       0x4101      // Socket 1: registrador de comandos do socket1
#define S1_IR       0x4102      // Socket 1: registrador de interrupçoes do socket1
#define S1_SR       0x4103      // Socket 1: registrador de status do socket1
#define S1_PORT    0x4104      // Socket 1: aqui é colocado o valor da porta TCP ->  endereço = 0x0404 a 0x0405
#define S1_DPORT   0x4110      // Socket 1: aqui é colocado o valor da porta TCP de destino->  endereço = 0x0410 a 0x0411
#define S1_DHAR    0x4106      // Socket 1: endereçamento de registro de hardware(tipo MAC)->  endereço = 0x0406 a 0x040B
#define S1_DIPR    0x410C      // Socket 1: IP de acesso remoto ->  endereço = 0x040C a 0x040F
#define S1_TX_FSR  0x4120      // Socket 1: tamanho do registrador de transmissão: 0x0420 to 0x0421
#define S1_TX_RD   0x4122      // Socket 1: ponteiro de leitura do buffer de transmissão : 0x0422 a 0x0423
#define S1_TX_WR   0x4124      // Socket 1: ponteiro de escrita do buffer de transmissão: 0x0424 a 0x0425
#define S1_RX_RSR  0x4126      // Socket 1: tamanho do registrador de recepção: 0x0426 a 0x0427
#define S1_RX_RD   0x4128      // Socket 1: ponteiro de leitura do tamanho dos dados: 0x0428 a 0x0429
#define S1_IMR       0x412C      // mascara de interrupção dos sockets
#define RMSR1       0x411E   // RX - localização do buffer de recepção do socket 1
#define TMSR1       0x411F   // TX - localização do buffer de envio do socket 1


//////////////////endereços de escrita e recepção //////////////////////

#define TXBUFADDR0  0x8000      // W5200 posição inicial do buffer de escrita
#define RXBUFADDR0  0xC000      // W5200 posição inicial do buffer de recepção
/////socket1 pois o tamanho é de 4096(4K)
#define TXBUFADDR1  0x9000      // W5200 posição inicial do buffer de escrita
#define RXBUFADDR1  0xD000      // W5200 posição inicial do buffer de recepção

////////////comando do chip////////////////////////////////////////////

//MR (possiveis configuração)
#define MR_CLOSE      0x00    // socket não usado
#define MR_TCP          0x01    // TCP
#define MR_UDP          0x02    // UDP
#define MR_IPRAW      0x03      // IP LAYER RAW SOCKET
#define MR_MACRAW      0x04      // MAC LAYER RAW SOCKET
#define MR_PPPOE      0x05      // PPPoE
#define MR_ND          0x20      // sem delay de Ack(somente TCP) 
#define MR_MULTI      0x80      // suporte ao multicast(valido somente para UDP)
// CR values
#define CR_OPEN          0x01      // Initializa ou abre socket
#define CR_LISTEN        0x02      // espera resposta de um ponto na rede (no modo tcp(modo servidor))
#define CR_CONNECT       0x04      // envia resposta a um ponto da rede(modo cliente)
#define CR_DISCON        0x08      // finaliza conexão e gera interrupção se falhar(desconexão)
#define CR_CLOSE         0x10      // desconecta socket
#define CR_SEND          0x20      // atualiza memoria de transmissão e envia dados
#define CR_SEND_MAC      0x21      // envia dados com o endereço do MAC, sem o processo ARP(modo UDP)
#define CR_SEND_KEEP     0x22      // ckeca estado da conexão - envia um byte pra testar a conexão (modo tcp)
#define CR_RECV          0x40      // indica uma recepção no socket
//SR values
#define SOCK_CLOSED      0x00     // socket fechado
#define SOCK_INIT        0x13      // inicializa conexão
#define SOCK_LISTEN      0x14      // verifica estado(listen)
#define SOCK_SYNSENT     0x15      // comando de conexão foi iniciado
#define SOCK_SYNRECV     0x16      // houve sincronismo de recepção
#define SOCK_ESTABLISHED 0x17      // sucesso na conexão
#define SOCK_FIN_WAIT    0x18      // esperando finalizar
#define SOCK_CLOSING     0x1A      // finalizando conexão
#define SOCK_TIME_WAIT     0x1B      // espera tempo para finaliza
#define SOCK_CLOSE_WAIT  0x1C      // recebeu comando de fechar pelo host
#define SOCK_LAST_ACK    0x1D      // durante a finalização é o ultimo ack
#define SOCK_UDP         0x22      // UDP     socket
#define SOCK_IPRAW       0x32      // IP raw  socket
#define SOCK_MACRAW      0x42      // MAC raw socket
#define SOCK_PPPOE       0x5F      // PPPOE   socket
#define TX_BUF_MASK      0x0FFF   // Mascara do buffer de transmissão 4K (4096 - 1 = 4095 = 0X0FFF)
#define RX_BUF_MASK      0x0FFF   // Mascara do buffer de recepção 4K  (4096 - 1 = 4095 = 0X0FFF)
#define NET_MEMORIA      0x04     // Use 4K de Tx/Rx Buffer(pode se usar até 16K)
#define TCP_PORT         80       // porta TCP/IP usada pelo modulo
#define MAX_BUF          50       // tamanho maximo do buffer de recepção 
/////////
//////// variaveis globais ////////////////////////////////////////
////////
uint8_t buf[MAX_BUF];
uint8_t sockstat;
uint16_t rsize;
int get_pos;
char radiostat0[10],radiostat1[10];
unsigned char temp[2];//usado para passar os defines - variavel auxiliar

/////////variaveis da serial///////////////////////
 unsigned char caracter;//
 unsigned int  tam_buffer;//usado para contar o tamanho do buffer de recepção
 unsigned char buffer_serial[14];//buffer da serial
 volatile char rec_buffer ='S';//usado para ler o buffer de recepção (volatile para funcionar pois sempre ira retornar mesmo valor)


void inicializa_spi(void)
{
// Seta MOSI (PORTB3),SCK (PORTB5) and PORTB2 (SS) , e os outros pinos como saida 
  SPI_DDR = (1<<PORTB3)|(1<<PORTB5)|(1<<PORTB2)|(1<<PORTB1);//coloca b1 como saida
  // SS não ativado
  SPI_PORT |= (1<<SPI_SS); 
  // habilita SPI, modo mestre 0, seta clock para fck/2
  SPCR = (1<<SPE)|(1<<MSTR);
  SPSR |= (1<<SPI2X);  
}
///////////////////////função de escrita SPI////////////////////////

void spi_escreve(unsigned int endereco,unsigned char *dados,unsigned int tamanho)
{
  // ativa pino de habilitação do SPI
  SPI_PORT &= ~(1<<SPI_SS); 
  //******************** endereço ************************
  // escreve bytes mais significativo no buffer spi
  SPDR = (endereco & 0xFF00) >> 8;
   // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
   //escreve os bytes menos significativo no buffer spi
  SPDR = endereco & 0x00FF;  
  // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF)));   
  //******************** Opcode + tamanho dos dados************************
   SPDR = ((0X80)|((tamanho & 0xFF00) >> 8));//indica que vai escrever(opcode)
   // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
   //escreve os bytes menos significativo no buffer spi
  SPDR = tamanho & 0x00FF;
  // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF)));
  unsigned int contagem=0;
  while(contagem<tamanho)
  { 
      SPDR = dados[contagem];  // inicializa transmissão de dados
      while(!(SPSR & (1<<SPIF))); // espera finalizar a transmissão
      // finaliza comunicação.
      contagem++;
  }
  SPI_PORT |= (1<<SPI_SS);
}
/////////////////////////de leitura////////////////////////////////


unsigned char spi_ler(unsigned int endereco)
{
// ativa pino de habilitação do SPI
  SPI_PORT &= ~(1<<SPI_SS); 
  //******************** endereço ************************
  // escreve bytes mais significativo no buffer spi
  SPDR = (endereco & 0xFF00) >> 8;
   // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
   //escreve os bytes menos significativo no buffer spi
  SPDR = endereco & 0x00FF;  
  // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF)));   
  //******************** Opcode + tamanho dos dados************************
  //aqui vou sempre receber 1 byte de dados, embora é possivel enviar mais
  // escreve bytes mais significativo no buffer spi
  SPDR = 0X00;
   // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
   //escreve os bytes menos significativo no buffer spi
  SPDR = 0X01;//seta para receber apenas 1 byte  
  // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
  // envia um valor qualquer para ler os dados(pois isto liga o sinal de clock do registrado SPI)
  SPDR = 0x00;
  // espera finalizar a transmissão
  while(!(SPSR & (1<<SPIF))); 
  // finaliza comunicação.
  SPI_PORT |= (1<<SPI_SS);
  return(SPDR);//retorna o valor lido do W5200
}


////////////////////////inicializa ethernet //////////////////////////////////
void W5200_Inicializa(void)
{
  unsigned char porta0[] = {0x13,0X88};// ex 5000 = 0X1388 -> 0X13 +0X88 //porta 5000
  unsigned char porta1[] = {0x00,0X50};// ex 0X0050 -> 0X00 +0X50 //porta 80
  // esse mac é do AA0000 dezembro obsoleto
   unsigned char mac_addr[] = {0xAA,0x00,0x00,0xFF,0xFF,0x88};//MAC usado pelo microcontrolador(para teste)
  //dois dispositivos na mesma rede não pode ter o mesmo mac, coloquei o mais alto como padrão
  //aqui usei o ip para alterar o mac assim como em cada conexão não pode haver o mesmo ip ,tambem não haverá o mesmo mac
  unsigned char ip_addr[] = {192,168,50,141};//endereço de ip do servidor(valor para teste,do microcontrolador)
  unsigned char sub_mask[] = {255,255,255,0};//sem mascara mascara de sub_rede
  unsigned char gtw_addr[] = {192,168,50,254};//enderreço de ip do gateway cliente (valor para teste,do pc)
  //este ip não é necessariamente o do pc mas deve estar nesta faixa
  //unsigned char ip_dipr[] = {192,168,0,5};
  temp[0] = 0X80;
  spi_escreve(MR, temp,1);            // MR = 0b10000000; isso inicicializa os registradores internos automaticamente
  _delay_ms(1);
  temp[0] = 0X03;//numero de retransmissão
  spi_escreve(RCR,temp,1);            // desabilita todas as interrupções do W5200
  _delay_ms(1);
  temp[0] = 0X00;
  spi_escreve(S0_IMR,temp,1);            // desabilita todas as interrupções do W5200 para o socket0
  _delay_ms(1);
  spi_escreve(S1_IMR,temp,1);            // desabilita todas as interrupções do W5200 para o socket1
  _delay_ms(1);
   temp[0] = 0X07;
   temp[1] = 0XD0;//timeouto para 200ms(por padrão é 100us)
   spi_escreve(RTR,temp,2);            // desabilita todas as interrupções do W5200
  _delay_ms(1);
  //configura porta de comunicação para acesso remoto no socket0
  spi_escreve(S0_PORT , porta0,2);
   _delay_ms(1);
  spi_escreve(S0_DPORT , porta0,2);
  //configura porta de comunicação para acesso remoto no socket1
  spi_escreve(S1_PORT , porta1,2);
   _delay_ms(1);
  spi_escreve(S1_DPORT , porta1,2);
  temp[0] = MR_TCP;//conf. para TCP
  spi_escreve(S0_MR,temp,1);    // configura o registrador de modo(MR) do socket0
  _delay_ms(1);
  spi_escreve(S1_MR,temp,1);    // configura o registrador de modo(MR) do socket1
  _delay_ms(1);
  // configura o MAC de destino vou deixar o mesmo 
  spi_escreve(S0_DHAR , mac_addr,6);
  _delay_ms(1);
  spi_escreve(S1_DHAR , mac_addr,6);
  _delay_ms(1);
    // configura o MAC (SHAR): 0x0009 à 0x000E
  spi_escreve(SHAR ,mac_addr,6);
  _delay_ms(1);
  // endereço de IP de acesso remoto do socket0 será sempre 1 na ultima casa
 // spi_escreve(S0_DIPR,ip_dipr,4);
  spi_escreve(S0_DIPR,ip_addr,4);
  _delay_ms(1);
  // endereço de IP de acesso remoto do socket0 será sempre 1 na ultima casa
  //spi_escreve(S1_DIPR,ip_dipr,4);
  spi_escreve(S1_DIPR,ip_addr,4);
  _delay_ms(1);
  //configura gateway do cliente
  spi_escreve(GAR ,gtw_addr,4);
  _delay_ms(1);
  // mascara de sub rede (SUBR): 0x0005 à 0x0008
  spi_escreve(SUBR ,sub_mask,4);
  _delay_ms(1);
  // endereço de IP (SIPR): 0x000F à 0x0012
  spi_escreve(SIPR,ip_addr,4);
  _delay_ms(1);
  // configura o tamanho do buffer  de memoria de escrita e leitura 
  temp[0] = NET_MEMORIA;
  spi_escreve(RMSR0,temp,1);//configura para socket0 4K de memoria de leitura(no W5200 tem 8 socket mas vamos usar somente o socket0 e o socket1)
  _delay_ms(1);
  spi_escreve(TMSR0,temp,1);//configura para socket0 4K de memoria de transmissao(no W5200 tem 8 socket mas vamos usar somente o socket0 e o socket1)
  _delay_ms(1);
   spi_escreve(RMSR1,temp,1);//configura para socket1 4K de memoria de leitura
  _delay_ms(1);
  spi_escreve(TMSR1,temp,1);//configura para socket1 4K de memoria de transmissao
  _delay_ms(1);
}
//////////////////////////////////fecha socket   ///////////////////////
void fechar_socket(uint8_t socket)
{
   if (socket == 0)
   {
       temp[0] = CR_CLOSE;
       spi_escreve(S0_CR,temp,1);   // espera que S0_CR seja zerado(finalizado)
       while(spi_ler(S0_CR));
   }
   if (socket == 1)
   {
          temp[0] = CR_CLOSE;
       spi_escreve(S1_CR,temp,1);   // espera que S0_CR seja zerado(finalizado)
       while(spi_ler(S1_CR));
   }
  
}

//////////////////////////////////fecha conexão//////////////////////////
void desconectar(uint8_t socket)
{
if (socket == 0)
   {
      temp[0] = CR_DISCON;
      spi_escreve(S0_CR,temp,1);   // espera desconexão.
      while(spi_ler(S0_CR));
   }
   if (socket == 1)
   {
      temp[0] = CR_DISCON;
      spi_escreve(S1_CR,temp,1);   // espera desconexão.
      while(spi_ler(S1_CR));
   }

}
////////////////////////////////conecta pelo modo servidor////////////////////
uint8_t conex_servidor(uint8_t socket)
{
    uint8_t retval=0; 
     if (socket == 0)
       {
            if (spi_ler(S0_SR) == SOCK_CLOSED) // verificando se o socket 0 está fechado.
              {
              fechar_socket(socket);
              }     
            // abrindo o  Socket 0
            temp[0]=CR_OPEN;
            spi_escreve(S0_CR,temp,1);                   // abre socket 
            while(spi_ler(S0_CR)); //espera abrir  
            if (spi_ler(S0_SR) == SOCK_INIT)//checa estado inicial
              retval=1;
            else
              fechar_socket(socket);

       }
       if (socket == 1)
       {
            if (spi_ler(S1_SR) == SOCK_CLOSED) // verificando se o socket 1 está fechado.
              {
              fechar_socket(socket);
              }     
            // abrindo o  Socket 1
            temp[0]=CR_OPEN;
            spi_escreve(S1_CR,temp,1);                   // abre socket 
            while(spi_ler(S1_CR)); //espera abrir  
            if (spi_ler(S1_SR) == SOCK_INIT)//checa estado inicial
              retval=1;
            else
              fechar_socket(socket);
       }
      return retval;
}

/////////////////////////////"escuta" a rede/////////////////////////////////
uint8_t escutar_rede(uint8_t socket)
{
     uint8_t retval = 0;
       if (socket == 0)
       {
             if (spi_ler(S0_SR) == SOCK_INIT) 
             { 
                 temp[0]=CR_LISTEN;
                 spi_escreve(S0_CR,temp,1);//envia comando para escutar a rede
                 while(spi_ler(S0_CR));     // espera terninar processo de escuta
                 if (spi_ler(S0_SR) == SOCK_LISTEN) //verifica status de escuta
                   retval=1;
                 else
                   fechar_socket(socket);
             }
       }
       if (socket == 1)
       {
             if (spi_ler(S1_SR) == SOCK_INIT) 
             { 
                 temp[0]=CR_LISTEN;
                 spi_escreve(S1_CR,temp,1);//envia comando para escutar a rede
                 while(spi_ler(S1_CR));     // espera terninar processo de escuta
                 if (spi_ler(S1_SR) == SOCK_LISTEN) //verifica status de escuta
                   retval=1;
                 else
                   fechar_socket(socket);
             }
       }

    return retval;
}

////////////////////////////envia pacote////////////////////////////////////(falta adaptar)
uint16_t envia_pacote(unsigned char *frase,uint16_t buffer_tamanho,uint8_t socket)
{
    unsigned int ponteiro,ende_temp,ende_real,tx_tamanho,timeout;   
    if(socket == 0)
    {
            if (buffer_tamanho <= 0 )return 0;//verifica se tem espaço livre para transmitir
        tx_tamanho=spi_ler(SO_TX_FSR);
        tx_tamanho=(((tx_tamanho & 0x00FF) << 8 ) + spi_ler(SO_TX_FSR + 1));//calcula tamanho do buffer de transmissão.
        timeout=0;
        while (tx_tamanho < buffer_tamanho) 
        {
              _delay_us(500);//0.5ms
             tx_tamanho= spi_ler(SO_TX_FSR);
             tx_tamanho=(((tx_tamanho & 0x00FF) << 8 ) + spi_ler(SO_TX_FSR + 1));     // Timeout para aproximadamente 5ms
             if (timeout++ > 10) 
               {
                // desconecta socket 0 pois não há espaço livre após 10ms
               desconectar(0);
               return 0;
               }
        }
        tx_tamanho=0;    
       ponteiro = spi_ler(S0_TX_WR);//lê o ponteiro de escrita.
       ende_temp = (((ponteiro & 0x00FF) << 8 ) + spi_ler(S0_TX_WR + 1));
        while(buffer_tamanho>0) 
        {
          buffer_tamanho--;
          // calcula o endereço real do buffer de transmissão. 
          ende_real = TXBUFADDR0 + (ende_temp & TX_BUF_MASK);      // copia pacote para W5200(TX_buffer)
          temp[0] = frase[tx_tamanho]; 
          spi_escreve(ende_real,temp,1);
          ende_temp++;
          tx_tamanho++;
        }
        // incrementa valor de  S0_TX_WR , então este será o ponto da proxima transmissão
        temp[0]=( ende_temp & 0xFF00) >> 8;
        temp[1]= ende_temp & 0x00FF;
        spi_escreve(S0_TX_WR,temp,2);
        // agora envia o comando de enviar dados para rede.
        temp[0] = CR_SEND;
        spi_escreve(S0_CR,temp,1);
        // espera terminar o envio
        while(spi_ler(S0_CR));
    }
    if(socket == 1)
    {
        if (buffer_tamanho <= 0 )return 0;//verifica se tem espaço livre para transmitir
        tx_tamanho=spi_ler(S1_TX_FSR);
        tx_tamanho=(((tx_tamanho & 0x00FF) << 8 ) + spi_ler(S1_TX_FSR + 1));//calcula tamanho do buffer de transmissão.
        timeout=0;
        while (tx_tamanho < buffer_tamanho) 
        {
              _delay_us(500);//0.5ms
             tx_tamanho= spi_ler(S1_TX_FSR);
             tx_tamanho=(((tx_tamanho & 0x00FF) << 8 ) + spi_ler(S1_TX_FSR + 1));     // Timeout para aproximadamente 5ms
             if (timeout++ > 10) 
               {
                // desconecta socket 0 pois não há espaço livre após 10ms
               desconectar(1);
               return 0;
               }
        }
        tx_tamanho=0;    
       ponteiro = spi_ler(S1_TX_WR);//lê o ponteiro de escrita.
       ende_temp = (((ponteiro & 0x00FF) << 8 ) + spi_ler(S1_TX_WR + 1));
        while(buffer_tamanho>0) 
        {
          buffer_tamanho--;
          // calcula o endereço real do buffer de transmissão. 
          ende_real = TXBUFADDR1 + (ende_temp & TX_BUF_MASK);      // copia pacote para W5200(TX_buffer)
          temp[0] = frase[tx_tamanho]; 
          spi_escreve(ende_real,temp,1);
          ende_temp++;
          tx_tamanho++;
        }
        // incrementa valor de  S1_TX_WR , então este será o ponto da proxima transmissão
        temp[0]=( ende_temp & 0xFF00) >> 8;
        temp[1]= ende_temp & 0x00FF;
        spi_escreve(S1_TX_WR,temp,2);
        // agora envia o comando de enviar dados para rede.
        temp[0] = CR_SEND;
        spi_escreve(S1_CR,temp,1);
        // espera terminar o envio
        while(spi_ler(S1_CR));

    }
    return 1;
}
/////////////////////////////////recebe pacote//////////////////////////////////////////
void recebe_pacote(uint8_t *pacote, uint8_t socket)
{
        unsigned int conta=0,buffer_tamanho = MAX_BUF-2;
        char FIM[9]={'H','T','T','P','/','1','.','1'};
        unsigned int ponteiro,ende_temp,ende_real;  
        if(socket == 0)
        {
            ponteiro = spi_ler(S0_RX_RD);//pega localização do dado recebido(tamanho)
            ende_temp = (((ponteiro & 0x00FF) << 8 ) + spi_ler(S0_RX_RD + 1));////pega localização do dado recebido por ser 16 bits "ponteiro" deve ser descolado 
                while((buffer_tamanho) && (conta<8)) 
                {
                  buffer_tamanho--;
                  ende_real=RXBUFADDR0 + (ende_temp & RX_BUF_MASK);//endereço inicial de leitura + endereço dos dados recebidos 
                  *pacote = spi_ler(ende_real);
                  //put_serial(*pacote);
                   if(FIM[conta] == spi_ler(ende_real))
                   {
                    conta++;
                   }else
                   {
                    conta=0;
                   }
                  ende_temp++;
                  pacote++;
                     
                }
            *pacote='\0';        // String de fim de pacote
            // incrementa S0_RX_RD ,este será o ponto da proxima recepção
            temp[0]=(ende_temp & 0xFF00) >> 8;
            temp[1]= ende_temp & 0x00FF;
            spi_escreve(S0_RX_RD,temp,2);
            //envia comando para leitura 
            temp[0]=CR_RECV;
            spi_escreve(S0_CR,temp,1);
            _delay_us(5);    // espera terminar leitura.    
        }
        if(socket == 1)
        {
            ponteiro = spi_ler(S1_RX_RD);//pega localização do dado recebido(tamanho)
            ende_temp = (((ponteiro & 0x00FF) << 8 ) + spi_ler(S1_RX_RD + 1));////pega localização do dado recebido por ser 16 bits "ponteiro" deve ser descolado 
                while((buffer_tamanho) && (conta<8)) 
                {
                  buffer_tamanho--;
                  ende_real=RXBUFADDR1 + (ende_temp & RX_BUF_MASK);//endereço inicial de leitura + endereço dos dados recebidos 
                  *pacote = spi_ler(ende_real);
                  //put_serial(*pacote);
                   if(FIM[conta] == spi_ler(ende_real))
                   {
                    conta++;
                   }else
                   {
                    conta=0;
                   }
                  ende_temp++;
                  pacote++;
                     
                }
            *pacote='\0';        // String de fim de pacote
            // incrementa S0_RX_RD ,este será o ponto da proxima recepção
            temp[0]=(ende_temp & 0xFF00) >> 8;
            temp[1]= ende_temp & 0x00FF;
            spi_escreve(S1_RX_RD,temp,2);
            //envia comando para leitura 
            temp[0]=CR_RECV;
            spi_escreve(S1_CR,temp,1);
            _delay_us(5);    // espera terminar leitura.
        }     
                        
}
///////////////////////////////////////////////////////////////////////
uint16_t tamanho_recepcao(uint8_t socket)
{
   uint16_t retorno;
      if(socket == 0)
    {
       retorno = (((spi_ler(S0_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S0_RX_RSR + 1)); //
    }
    if(socket == 1)
    {
      retorno = (((spi_ler(S1_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S1_RX_RSR + 1)); //
    }
    return(retorno);

}
////////////////////////////////////////////////////////////////////////
int string_index(char *str_de_teste,char *str_compara)//procura posição de uma string
{
  uint16_t i,str_tamanho;

  str_tamanho=strlen(str_compara);// pega tamanho da string
  for(i=0;*(str_de_teste+i); i++)//percorre o ponteiro 
  {
    if (strncmp(str_de_teste+i,str_compara,str_tamanho) == 0)//compara com str_compara  
      return i;
  }
  return -1;
}


int envia_pagina(uint8_t socket)
{
 int flag=0;
                                    // criando pagina HTTP de resposta 
                                    strcpy_P((char *)buf,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
                                    strcat_P((char *)buf,PSTR("<html><body><span style=\"color:#0000A0\">\r\n"));
                                    strcat_P((char *)buf,PSTR("<h1>PROGRAMA DE TESTE</h1>\r\n"));
                                          if(socket == 0)
                                        {
                                         strcat_P((char *)buf,PSTR("<h1>No socket 0 </h1>\r\n"));
                                        }
                                        if(socket == 1)
                                        {
                                         strcat_P((char *)buf,PSTR("<h1>No socket 1 </h1>\r\n"));
                                        }
                                    strcat_P((char *)buf,PSTR("<h2>MICROCONTROLADORES-C</h2>\r\n"));
                                    strcat_P((char *)buf,PSTR("<p><form method=\"GET\">\r\n"));//POST

                                    // cria resposta do botao HTTP
                                    strcat_P((char *)buf,PSTR("<p><input type=\"radio\" name=\"Bot\" value=\"0\" "));
                                    strcat((char *)buf,radiostat0);
                                    strcat_P((char *)buf,PSTR(">Desligar led. \r\n"));
                                    strcat_P((char *)buf,PSTR("<br><input type=\"radio\" name=\"Bot\" value=\"1\" "));
                                    strcat((char *)buf,radiostat1);
                                    strcat_P((char *)buf,PSTR(">Ligar led. \r\n"));

                                    strcat_P((char *)buf,PSTR("</strong><p>\r\n"));
                                    strcat_P((char *)buf,PSTR(" \r\n <input type=\"submit\"  value=\"Enviar\"> \r\n"));
                                    strcat_P((char *)buf,PSTR("</form></span></body></html>\r\n"));//finaliza pagina 
                                    // // enviando pagina HTTP de resposta do botao
                                    if (envia_pacote(buf,strlen((char *)buf),socket) <= 0)//socket 0 ,envia o vetor buf,coloca o tamanho do vetor
                                    flag=1;
                                    return(flag);
}
////////////////////função principal/////////////////////////////////////
int main(void)
 {
  
  //////////////////inicializa port D /////////////////////////////////////////////////////////////////////
    DDRD = 0xFE;       // Seta PORTD como saida exceto a entrada serial
    PORTD = 0x00;
    DIDR0 = 0X00;////desabilita entrada analogico(reduz consumo).evita problemas quando esse pino é usado como saida 
    DDRB = 0x2F;//configura port B
    inicializa_spi();    //comunicação spi         
    rsize = 0;
    liga_pino(PORTB,PB1);//led
    desliga_pino(PORTB,PB0);///// //reseta o chip de ethernet - para garantir uma conexão segura
    _delay_ms(10);//tempo de reset
    liga_pino(PORTB,PB0);
    _delay_ms(150);//nessecessario para o modulo se preparar
    W5200_Inicializa();  //ethernet
    ///////////////////////////////////
    sei();
    desliga_pino(PORTB,PB1);//led
///////////////////////////////////////////////////////
  for(;;)
    {       sockstat=spi_ler(S0_SR);
            switch(sockstat) 
            {
             case SOCK_CLOSED: ///socket fechado.
                if ( conex_servidor(0) > 0) 
                     {// escuta  Socket 0
                        if (escutar_rede(0) <= 0)//socket 0
                             _delay_ms(1);
                     }break;   
             case SOCK_ESTABLISHED://conectado
                 {
                  // pega o tamanho do pacote recebido do cliente
                  rsize=((spi_ler(S0_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S0_RX_RSR + 1);//pega tamanho dos dados recebido
                  if (rsize > 0)//isso indica que o pacote é maior que zero
                     {
                      // lê o pacote recebido
                          recebe_pacote(buf,0);                        
                           // Check the Request Header
                           get_pos=string_index((char *)buf,"GET /");//procura pela posição da string "GET /"
                              if (get_pos >= 0 )
                                 {
                                  // ckeca botão do codigo html
                                         
                                            if (string_index((char *)buf,"Bot=0") > 0)//procura pela posição da string "radio=0"
                                                         { 
                                                         desliga_pino(PORTB,PB1);//led
                                                         strcpy_P(radiostat0,PSTR("checked"));
                                                         strcpy(radiostat1,"");
                                                         }
                                             if (string_index((char *)buf,"Bot=1") > 0)//procura pela posição da string "radio=1"
                                                         {
                                                          liga_pino(PORTB,PB1);//led
                                                          strcpy(radiostat0,"");
                                                          strcpy_P(radiostat1,PSTR("checked"));
                                                  
                                                         }                                            
                                      if(envia_pagina(0)==1)//se falhar sai da conexão
                                      break;
                                         // atualiza estado dos botoes   
                                 }//fim do getpos                            
                             desconectar(0);// desconecta socket 0
                    }
              else
                    {
                      _delay_us(5);    //perde tempo para espera resposta
                    }
              }break;      
              case SOCK_FIN_WAIT:
              case SOCK_CLOSING:
              case SOCK_TIME_WAIT:
              case SOCK_CLOSE_WAIT:
              case SOCK_LAST_ACK:
              fechar_socket(0);// força o fechamento do socket 0
              break;
      }//chave do switch
      ///////////checa socket 1 ///////////////////////////////////////////////////////////////////////////////////
      sockstat=spi_ler(S1_SR);
            switch(sockstat) 
            {
             case SOCK_CLOSED: ///socket fechado.
                if ( conex_servidor(1) > 0) 
                     {// escuta  Socket 0
                        if (escutar_rede(1) <= 0)//socket 0
                             _delay_ms(1);
                     }break;   
             case SOCK_ESTABLISHED://conectado
                 {
                  // pega o tamanho do pacote recebido do cliente
                  rsize=((spi_ler(S1_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S1_RX_RSR + 1);//pega tamanho dos dados recebido
                  if (rsize > 0)//isso indica que o pacote é maior que zero
                     {
                      // lê o pacote recebido
                          recebe_pacote(buf,1);                        
                           // Check the Request Header
                           get_pos=string_index((char *)buf,"GET /");//procura pela posição da string "GET /"
                              if (get_pos >= 0 )
                                 {
                                  // ckeca botão do codigo html
                                         
                                            if (string_index((char *)buf,"Bot=0") > 0)//procura pela posição da string "radio=0"
                                                         { 
                                                         desliga_pino(PORTB,PB1);//led
                                                         strcpy_P(radiostat0,PSTR("checked"));
                                                         strcpy(radiostat1,"");
                                                         }
                                             if (string_index((char *)buf,"Bot=1") > 0)//procura pela posição da string "radio=1"
                                                         {
                                                          liga_pino(PORTB,PB1);//led
                                                          strcpy(radiostat0,"");
                                                          strcpy_P(radiostat1,PSTR("checked"));
                                                  
                                                         }                                            
                                      if(envia_pagina(1)==1)//se falhar sai da conexão
                                      break;
                                         // atualiza estado dos botoes   
                                 }//fim do getpos                            
                             desconectar(1);// desconecta socket 1
                    }
              else
                    {
                      _delay_us(5);    //perde tempo para espera resposta
                    }
              }break;      
              case SOCK_FIN_WAIT:
              case SOCK_CLOSING:
              case SOCK_TIME_WAIT:
              case SOCK_CLOSE_WAIT:
              case SOCK_LAST_ACK:
              fechar_socket(1);// força o fechamento do socket 1
              break;
      }//chave do switch
   }//chave do laço infinito (for)
}//chave de main

Aqui é possível visualizar como fica na tela do PC, abri os dois sockets: