sexta-feira, 24 de janeiro de 2014

Servidor web com o modulo WIZ820 usando o ATmega328:

    Olá hoje vou demonstrar como fazer um servidor web com o modulo WIZ820 para este projeto montei uma fonte que transforma 12V em 3,3V(pois o wiznet  funciona com essa tensão)e assim o circuito funciona em 3,3V.Para montar a fonte recorri ao circuito integrado MC33063.
    Na figura abaixo é mostrado o aparência do modulo wiz820: 





O esquemático:


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 com o modulo modulo wiz820
//  Autor                      : Aguivone
//  microcontrolador           : ATmega328P
//  compilador                   : AVR-GCC / Atmel AVR Studio 4.17
//  Data do projeto            : 24 / 01 / 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

///aqui houve alteração em relação ao wiz810
#define RMSR       0x401E   // RX - localização do buffer de recepção
#define TMSR       0x401F   // TX - localização do buffer de envio

/////////////////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
*/


#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 S0_RTR       0x0017      // timeout
#define S0_RCR       0x0019      // timeout

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

#define TXBUFADDR  0x8000      // W5200 posição inicial do buffer de escrita
#define RXBUFADDR  0xC000      // W5200 posição inicial do buffer de recepção

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

//S0_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)
// S0_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
// S0_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 para o socket0(4096 - 1 = 4095 = 0X0FFF)
#define RX_BUF_MASK      0x0FFF   // Mascara do buffer de recepção 4K para o socket0(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          20      // tamanho maximo do buffer de recepção reduzi de 100 pra 20
/////////
//////// 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 porta[] = {0x00,0X50};// ex PORTA 80 = 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,0,5};//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,0,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(S0_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
  _delay_ms(1);
   temp[0] = 0X07;
  temp[1] = 0XD0;//timeouto para 200ms(por padrão é 100us)
   spi_escreve(S0_RTR,temp,2);            // desabilita todas as interrupções do W5200
  _delay_ms(1);
  //configura porta de comunicação para acesso remoto
  spi_escreve(S0_PORT , porta,2);
   _delay_ms(1);
  spi_escreve(S0_DPORT , porta,2);
  temp[0] = MR_TCP;//conf. para TCP
  spi_escreve(S0_MR,temp,1);    // configura o registrador de modo (MR)
  _delay_ms(1);
  // configura o MAC de acesso remoto
  spi_escreve(S0_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 será sempre 1 na ultima casa
  spi_escreve(S0_DIPR,ip_dipr,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(RMSR,temp,1);//configura para cada socket 2K de memoria de leitura(no W5200 tem 8 socket mas vamos usar somente o socket 0)
  _delay_ms(1);
  spi_escreve(TMSR,temp,1);//configura para cada socket 2K de memoria de transmissao(no W5200 tem 8 socket mas vamos usar somente o socket 0)
  _delay_ms(1);
}
//////////////////////////////////fecha socket 0  ///////////////////////
void fechar_socket(uint8_t socket)
{
   if (socket != 0)return;
   // manda fechar
   temp[0] = CR_CLOSE;
   spi_escreve(S0_CR,temp,1);   // espera que S0_CR seja zerado(finalizado)
   while(spi_ler(S0_CR));
}

//////////////////////////////////fecha conexão//////////////////////////
void desconectar(uint8_t sock)
{
   if (sock != 0) return;   // envia comando para desconectar
   temp[0] = CR_DISCON;
   spi_escreve(S0_CR,temp,1);   // espera desconexão.
   while(spi_ler(S0_CR));
}
////////////////////////////////conecta pelo modo servidor////////////////////
uint8_t conex_servidor(uint8_t socket)
{
    uint8_t retval=0;   
     if (socket != 0)//teste socket0
      return retval;
     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);
    return retval;
}

/////////////////////////////"escuta" a rede/////////////////////////////////
uint8_t escutar_rede(uint8_t socket)
{
     uint8_t retval = 0;
     if (socket != 0)
     return retval;
     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);
     }
    return retval;
}

////////////////////////////envia pacote////////////////////////////////////
uint16_t envia_pacote(unsigned char *frase,uint16_t buffer_tamanho)
{
      unsigned int ponteiro,ende_temp,ende_real,tx_tamanho,timeout;   

    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 = TXBUFADDR + (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));
    return 1;
}
/////////////////////////////////recebe pacote//////////////////////////////////////////
void recebe_pacote(uint8_t *pacote)
{
        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;  
             
        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=RXBUFADDR + (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.                    
}
///////////////////////////////////////////////////////////////////////
uint16_t tamanho_recepcao(void)
{
  return (((spi_ler(S0_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S0_RX_RSR + 1)); //
}
////////////////////////////////////////////////////////////////////////
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;
}
/*8 void limpa_buffer(void)
{
   int16_t temp=MAX_BUF-1;
   while(temp>0)
   {
    buf[temp]='\0';
   }
}*/

int envia_pagina(void)
{
 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"));
                                    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)) <= 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);                        
                           // 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)//se falhar sai da conexão
                                      break;
                                         // atualiza estado dos botoes   
                                 }//fim do getpos                            
                             desconectar(0);// desconecta socket 0
                    }
              else
                    {
                      _delay_us(10);    //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
   }//chave do laço infinito (for)
}//chave de main

A aplicação rodando ficou assim via navegador do chrome:

Veja como ficou o protótipo:




sexta-feira, 3 de janeiro de 2014

BUG no compilador XC8, fiquem atentos:

Mexendo no compilador XC8 encontrei um bug estranho,veja o código a seguir:
  
/************************************************************************************************************************************
 *                                               Bug no compilador XC8 
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F648A
 * Autor: aguivone
 * Versão: 1
 * Data :  03/01/2014
 *************************************************************************************************************************************/
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // apesar de não usar cristal devo configurar pois esse define é usado para rotinas de tempo e da serial
#include <xc.h>

/**********************************************************************************************************************************/
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
//#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
/************************************************defines***************************************************************************/
#define A1 RB0     
#define B1 RB3     
#define C1 RB4     
#define D1 RB5     

void main(void)
{
    TRISB = 0X02;//configura portB  B1 (pino RX) como entrada
    TRISA = 0X00;//configura portA como saida
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTA = 0;  // limpar as portas que estão configuradas como saidas
    CMCON = 7;//desliga modulo comparador
   
    A1=1;
    B1=1;
    C1=1;
    D1=1; 
    for(;;)
    {
         A1=1;
         B1=1;
         C1=1;
         D1=1;       

    }//loop infinito

}

     Neste simples codigo eu apenas mando ligar 4 pinos do microcontrolador,mas a saída não é bem assim(rode ele no simulador do proteus), verá que os pinos ficam sequenciando, agora retire do código o laço for e veja o resultado! se ocorrer o mesmo que aconteceu em meu pc vc verá apenas o pino B5 acionado,uma explicação seria que toda vez que vc manda setar um pino da forma como foi feito ele zera a porta e seta apenas aquele pino uma das formas de se resolver é usando a instrução : PORTB=0B00111001; ou PORTB = 0X39; pois assim se escreve direto no "PORTB" do microcontrolador.

quarta-feira, 4 de dezembro de 2013

Gerando 13000V com o pic 12F675

       Um dia meu carro deu um problema na bobina(mas sabemos que dificilmente essas bobinas queimam de verdade o que acontece é defeitos no circuito de acionamento) então pensei em demostrar como gerar altas tensões utilizando um microcontrolador PIC de 8 pinos (12F675) , vale lembra que eu aproveitei o circuito já existente(pois o único defeito dessa bobina eram os fios de ligação aos terminais que estavam todos ressecados e dobradiços devido ao calor do motor do carro),na figura abaixo é demostrado a bobina do corsa:
        Para fazer o acionamento desta bobina é preciso saber quais os terminais desta placa será utilizado, então veja a descrição na figura a seguir:


       Os sinais que vem do modulo de gerenciamento central do carro são aplicados nas entrada in1 e in2, out1 e out2 vão para os terminais da bobina e o +12V vai ao outro terminal da bobina e a placa de controle e por fim o GND que também vai a esta placa.Depois de saber onde colocar o sinal que vira do microcontrolador montei um circuito para acionar e refiz algumas interligação da placa aos terminais da bobina ficando assim:

     O esquemático do circuito que fiz é este:
       O circuito é muito simples coloquei um led para indicar cada vez que pressiono um dos botões e caso eu fique com ele pressionado o valor da largura de pulso aumenta ou diminue enquanto manter este pressionado,no pino GP2 sai o sinal que será aplicado ao circuito de controle da bobina(que nada mais é do que um drive que aciona 2 IGBTs que mandam o pulso ao transformador da bobina).vou mostrar o vídeo que está disponível no you tube e logo em seguida o código fonte do circuito:

      O código fonte:

/*
 *                       Gerando altas tensões com uma bobina
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 12F675
 * Autor: aguivone
 * Versão: 1
 * data: 04/12/2013
*/ #include <stdio.h> #include <stdlib.h> #include <xc.h> /////////////////////////////////////////////////////////configuraçôes////////////////////////////////////////////////// #pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-Up Timer Enable bit (PWRT enabled) #pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD) #pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled) #pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled) #pragma config CPD = ON // Data Code Protection bit (Data memory code protection is enabled) //////////////////////////////////////////////////////Rotina principal/////////////////////////////////////////////////////////////// delay_ms(long t)//tempo aproximado {//aqui está usado o clock interno long temp=0; int conta=0; while(temp < t) { conta=0; while(conta<40) { conta++; } temp++; } } void main(void) { TRISIO = 0X03;//configura gp1 e gp2 como entrada CMCON = 7;//desabilita comparadores ANSEL = 0;//habilita as portas de I/O int tempo=1; for(;;) { if(GP0 == 0) { delay_ms(100);//debounce do botão(filtro) if(GP0 == 0) { while(GP0 == 0)//enquanto botão pressionado incrementa { tempo++; delay_ms(100);//debounce do botão(filtro) GP4 = !GP4;//alterna led a cada incremento if(tempo>50) { tempo = 1;//limita valor maximo para 50 } } GP4 = 0; } } if(GP1 == 0) { delay_ms(100);//debounce do botão(filtro) if(GP1 == 0) { while(GP1 == 0)//enquanto botão pressionado decrementa { tempo--; delay_ms(100);//debounce do botão(filtro) GP4 = !GP4;//alterna led a cada decremento if(tempo<1) { tempo = 10;//limita valor minimo para 1 } } GP4 =0; } } GP2 = 1; delay_ms(tempo); GP2 = 0; delay_ms(1000); }//loop infinito }

quinta-feira, 3 de outubro de 2013

usando a interface USB HID do PIC18F4550 no MplabXC8

              Para quem leu o post sobre a criação de uma porta com virtual ( http://microcontroladores-c.blogspot.com.br/2013/10/exemplo-de-rs-232-via-usb-com-pic.html ) este exemplo segue o mesmo raciocínio embora seja mais simples que o da porta COM virtual(usa pouca biblioteca ) .Me basei em outro exemplo da microchip onde o microcontrolador vai indicar através de leds o estado da porta usb e também controlar esses leds, além de monitorar o estado de uma chave conectada ao pino RB5.
              Aqui está os arquivos para baixar: https://drive.google.com/folderview?id=0Bx9JeN0dmzXxV0h6LWMzVWVvLVE&usp=sharing  .dentro desta paste tem um aplicativo exemplo da microchip e que será utilizado para testar sua aplicação("HID.exe" veja figura abaixo) , a diferença deste programa em relação ao da porta COM virtual é que aqui é usado o modo de transferência em massa (em que é possível enviar grandes pacotes) .

             o hardware necessário para este exemplo e bem simples veja na figura a seguir:

Ao descompactar a pasta "exemplo usb_HID" e rodar a IDE Mplab XC8 procure na pasta firmware o arquivo do programa , pronto é rodar e gravar no microcontrolador a partir dai faça as alterações que você julgar necessário, finalizo aqui os exemplos usb com pic.  

quarta-feira, 2 de outubro de 2013

exemplo de RS-232 via USB com pic 18F4550 no Mplab XC8

    Olá a todos que seguem este blog pelo face e aos visitantes,hoje vou ensinar como fazer uma aplicação usando a USB no modo CDC(emula uma porta virtual RS232).Este exemplo foi baseado nos exemplos da microchip,todos os includes necessário para funcionar com o PIC18F4550 foram agrupados em uma pasta, procurei manter a estrutura da pasta da microchip pois a pilha usb  só funciona com a mesma estrutura da pasta de exemplo da microchip,assim para criar uma nova aplicação basta copiar esta pasta e alterar o nome da copia, e fazer algumas modificações que será explicado logo mais.
    Para fazer uma aplicação USB você vai precisar de instalar em seu PC os seguintes softwares que podem ser baixados no site da michochip:

    -> compilador C18 vá a este link e faça o dowload(pode ser versão acadêmica)
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010014   
    -> framework USB da microchip (drive da usb).
 http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en547784  
     Supondo que vc já tenha instalados os programas acima, verifique no XC8 se aparece o compilador C18(use como se fosse abrir um novo projeto),quando aparecer esta tela estará ok!



      Agora baixe a pasta "exemplo usb_cdc.rar" neste link : https://drive.google.com/folderview?id=0Bx9JeN0dmzXxV0h6LWMzVWVvLVE&usp=sharing,descompacte a pasta e renomeie(se quiser) e em seguida abrir com o XC8(abra pelo programa XC8),depois de aberto clique no arquivo "main.c" conforme a foto abaixo:

        

      veja que aparecerá algum "Warning" no compilador mas não se preocupe com isso pois isso é pelo fato de ter retirado algumas biblioteca que não são necessário para esta aplicação.
pronto! agora é só compilar e gravar o micro controlador.
      para criar seu programa basta alterar e verificar as seguinte bibliotecas:

"HardwareProfile.h", aqui está configurado o clock e os pinos do microcontrolador
"usb_descriptors"  , aqui é configurado o nome do dispositivo e a classe.
 
      Depois disto é só adicionar seu programa no local que está a rotina principal, para testar a microchip já deixou uma aplicativo de teste com o nome "Dynamic CDC Demo.exe" clique nele e digite algo para testar o programa(que apenas pega o que vem da serial virtual e retorna ao pc). o programa main deste exemplo tem a seguinte aparência:

 
O código fonte da rotina main():

//////////////////////includes necessários  /////////////////////////////////////////
// o resto das configurações então em hardware profile
#include "./USB/usb.h"//chama todas as lib necessarias
#include "/MPLAB.X/HardwareProfile.h" //aqui está configurado o clock e os pinos do microcontrolador
#include "GenericTypeDefs.h"//lib que define os tipos utilizados
#include "./USB/usb_function_cdc.h"//funçoes da serial
#include "Compiler.h"//aqui se define o compilador que está sendo utilizado
#include "usb_config.h"//configura a usb
#include "USB/usb_device.h"


//////////////config. dos fuses do microcontrolador///////////////////////////////
#pragma config PLLDIV   = 5         // (usei um cristal de 20 MHz )
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2         // o clock do pll será 96MHz PLL/2 = 48Mhz
#pragma config FOSC     = HSPLL_HS
#pragma config FCMEN    = OFF
#pragma config IESO     = OFF
#pragma config PWRT     = OFF
#pragma config BOR      = ON
#pragma config BORV     = 3
#pragma config VREGEN   = ON      //ativa o regulador de voltagem da USB
#pragma config WDT      = OFF
#pragma config WDTPS    = 32768
#pragma config MCLRE    = ON
#pragma config LPT1OSC  = OFF
#pragma config PBADEN   = OFF
//      #pragma config CCP2MX   = ON
#pragma config STVREN   = ON
#pragma config LVP      = OFF
//      #pragma config ICPRT    = OFF       // Dedicated In-Circuit Debug/Programming
#pragma config XINST    = OFF       // Extended Instruction Set
#pragma config CP0      = OFF
#pragma config CP1      = OFF
//      #pragma config CP2      = OFF
//      #pragma config CP3      = OFF
#pragma config CPB      = OFF
//      #pragma config CPD      = OFF
#pragma config WRT0     = OFF
#pragma config WRT1     = OFF
//      #pragma config WRT2     = OFF
//      #pragma config WRT3     = OFF
#pragma config WRTB     = OFF       // proteção de escrita da inicialização (Boot)
#pragma config WRTC     = OFF
//      #pragma config WRTD     = OFF
#pragma config EBTR0    = OFF
#pragma config EBTR1    = OFF
//      #pragma config EBTR2    = OFF
//      #pragma config EBTR3    = OFF
#pragma config EBTRB    = OFF

/////////////////////variaveis requerida pela USB /////////////////////////////////////////////////////

#pragma udata
char USB_Out_Buffer[CDC_DATA_OUT_EP_SIZE];
char RS232_Out_Data[CDC_DATA_IN_EP_SIZE];

unsigned char NextUSBOut;
unsigned char NextUSBOut;
//char RS232_In_Data;
unsigned char LastRS232Out; // Number of characters in the buffer
unsigned char RS232cp; // current position within the buffer
unsigned char RS232_Out_Data_Rdy = 0;
BOOL espera = 0;
USB_HANDLE lastTransmission;

//BOOL stringPrinted;


/**********prototipo das funções ***************************************/
void USBDeviceTasks(void);
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
void USBCBSendResume(void);
//void BlinkUSBStatus(void);
void UserInit(void);
void InitializeUSART(void);
unsigned char getcUSART();

/********** remapeando vetores ****************************/
#define REMAPPED_RESET_VECTOR_ADDRESS        0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS    0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS    0x1018
#define APP_VERSION_ADDRESS                     0x1016 //Fixed location, so the App FW image version can be read by the bootloader.
#define APP_SIGNATURE_ADDRESS                   0x1006 //Signature location that must be kept at blaknk value (0xFFFF) in this project (has special purpose for bootloader).

#define APP_FIRMWARE_VERSION_MAJOR  1   //valid values 0-255
#define APP_FIRMWARE_VERSION_MINOR  0   //valid values 0-99

/////////////////defines da porta serial /////////////////////////////

#define mDataRdyUSART() PIR1bits.RCIF
#define mTxRdyUSART()   TXSTAbits.TRMT
//--------------------------------------------------------------------------

#pragma romdata AppVersionAndSignatureSection = APP_VERSION_ADDRESS
ROM unsigned char AppVersion[2] = {APP_FIRMWARE_VERSION_MINOR, APP_FIRMWARE_VERSION_MAJOR};
#pragma romdata AppSignatureSection = APP_SIGNATURE_ADDRESS
ROM unsigned short int SignaturePlaceholder = 0xFFFF;

#pragma code HIGH_INTERRUPT_VECTOR = 0x08

void High_ISR(void) {
    _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18

void Low_ISR(void) {
    _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
extern void _startup(void); // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS

void _reset(void) {
    _asm goto _startup _endasm
}
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR(void) {
    _asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR(void) {
    _asm goto YourLowPriorityISRCode _endasm
}
#pragma code
#pragma interrupt YourHighPriorityISRCode

void YourHighPriorityISRCode() {

#if defined(USB_INTERRUPT)
    USBDeviceTasks();
#endif

} //This return will be a "retfie fast", since this is in a #pragma interrupt section
#pragma interruptlow YourLowPriorityISRCode

void YourLowPriorityISRCode() {

} //This return will be a "retfie", since this is in a #pragma interruptlow section

#pragma code
static void inicializa_cpu(void)
{
    ADCON1 |= 0x0F; // coloca todos os pinos como saida
    #if defined(USE_USB_BUS_SENSE_IO)
    tris_usb_bus_sense = INPUT_PIN; // veja HardwareProfile.h
    #endif
    #if defined(USE_SELF_POWER_SENSE_IO)
    tris_self_power = INPUT_PIN; // veja HardwareProfile.h
    #endif

    UserInit();
    USBDeviceInit(); //usb_device.c.  inicializa o modulo USB e os SFRs
    //variaveis para saber o status.
}//fim de inicializa_cpu

void UserInit(void) {
    unsigned char i;
    InitializeUSART();
    //     inicializa vetor
    for (i = 0; i<sizeof (USB_Out_Buffer); i++) {
        USB_Out_Buffer[i] = 0;
    }
    NextUSBOut = 0;
    LastRS232Out = 0;
    lastTransmission = 0;
}//end UserInit

void InitializeUSART(void) {
    unsigned char c;
    UART_TRISRx = 1; // RX
    UART_TRISTx = 0; // TX
    TXSTA = 0x24; // TX enable BRGH=1
    RCSTA = 0x90; // Single Character RX
    SPBRG = 0x71;
    SPBRGH = 0x02; // 0x0271 for 48MHz -> 19200 baud
    BAUDCON = 0x08; // BRG16 = 1
    c = RCREG; // read

}//end InitializeUSART

void putcUSART(char c) {//escreve na serial
    TXREG = c;
}

#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{    
    if (cdc_notice.GetLineCoding.dwDTERate.Val <= 115200)//velocidade maxima
     {
        //atualiza o baudrate no drive CDC
        CDCSetBaudRate(cdc_notice.GetLineCoding.dwDTERate.Val);
        //atualiza o baudrate da porta serial
#if defined(__18CXX) || defined(__XC8) // sem este "if" o programa não funciona(bug do compilador)
        {
            DWORD_VAL dwBaud;
            dwBaud.Val = (DWORD) (GetSystemClock() / 4) / line_coding.dwDTERate.Val - 1;
            SPBRG = dwBaud.v[0];
            SPBRGH = dwBaud.v[1];
        }
    }
}
#endif

unsigned char getcUSART() { //pega caracteres vindo da serial
    char c;
    if (RCSTAbits.OERR) // no caso de ocorrer um overrun
    {
        RCSTAbits.CREN = 0; // reseta porta
        c = RCREG;
        RCSTAbits.CREN = 1; // volta a funciona.
    } else {
        c = RCREG;
    }
    return c;
}



///funçoes prontas para os eventos da usb, caso queira usar alguma é só inserir os codigo-fonte nas chaves
//////////////////////////
void USBCBSuspend(void) {}
void USBCBWakeFromSuspend(void) {}
void USBCB_SOF_Handler(void) {}
void USBCBErrorHandler(void) {}
void USBCBCheckOtherReq(void)
{ 
    USBCheckCDCRequest();
}
void USBCBStdSetDscHandler(void) {}
void USBCBInitEP(void)
{    //habilita os enpoits do modo CDC
    CDCInitEP();
}

void USBCBSendResume(void) {
    static WORD delay_count;

    if (USBGetRemoteWakeupStatus() == TRUE) {
        //Verify that the USB bus is in fact suspended, before we send
        //remote wakeup signalling.
        if (USBIsBusSuspended() == TRUE) {
            USBMaskInterrupts();

            //Clock switch to settings consistent with normal USB operation.
            USBCBWakeFromSuspend();
            USBSuspendControl = 0;
            USBBusIsSuspended = FALSE;
            delay_count = 3600U;
            do {
                delay_count--;
            } while (delay_count);

            //Now drive the resume K-state signalling onto the USB bus.
            USBResumeControl = 1; // Start RESUME signaling
            delay_count = 1800U; // Set RESUME line for 1-13 ms
            do {
                delay_count--;
            } while (delay_count);
            USBResumeControl = 0; //Finished driving resume signalling

            USBUnmaskInterrupts();
        }
    }
}
////////////////////////////////////////////////////////////////////
#if defined(ENABLE_EP0_DATA_RECEIVED_CALLBACK)

void USBCBEP0DataReceived(void) {
}
#endif

BOOL USER_USB_CALLBACK_EVENT_HANDLER(int event, void *pdata, WORD size) {
    switch (event) {
        case EVENT_TRANSFER:
            //funçoes de retorno da porta usb
            break;
        case EVENT_SOF:
            USBCB_SOF_Handler();
            break;
        case EVENT_SUSPEND:
            USBCBSuspend();
            break;
        case EVENT_RESUME:
            USBCBWakeFromSuspend();
            break;
        case EVENT_CONFIGURED:
            USBCBInitEP();
            break;
        case EVENT_SET_DESCRIPTOR:
            USBCBStdSetDscHandler();
            break;
        case EVENT_EP0_REQUEST:
            USBCBCheckOtherReq();
            break;
        case EVENT_BUS_ERROR:
            USBCBErrorHandler();
            break;
        case EVENT_TRANSFER_TERMINATED:
            break;
        default:
            break;
    }
    return TRUE;
}

void rotina_principal(void)
{
   if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1))
         {
             //se a usb estiver em modo suspensonão faz nada
             return;
         }else{
            if(mUSBUSARTIsTxTrfReady())//não tem dados pendentes?
            {
                    if(espera == 0)
                    {
                     putrsUSBUSART(" \r\n escreva algo!");
                     espera = 1;//indica pra esperar uma resposta
                    }
                    else
                    {
                       char buffer[20];
                       char escrever[50] = "\r\n foi digitado:   ";
                      if((getsUSBUSART(buffer , sizeof(buffer))) != 0)//tem dados
                        {
                          int tamanho = 0;
                          while(tamanho <= sizeof(buffer))
                          {
                             escrever[tamanho+17] = buffer[tamanho];
                             //adiciona o que foi digitado ao que está escrito na variavel
                             tamanho++;
                          }
                          putUSBUSART(escrever ,sizeof(escrever));
                         // putUSBUSART(&escrever ,sizeof(escrever));
                          espera = 0;
                        }
                    }
            }
         CDCTxService();
         }

}//fim do programa principal

void main(void)
{
    inicializa_cpu();
  //  #if defined(USB_INTERRUPT)//se definido a usb vai usar as interrupções
    USBDeviceAttach();//para verifica o status e os eventos gerados
 //   #endif
    while (1)
    {
       #if defined(USB_POLLING)//se definido para verificar de tempo em tempo
        USBDeviceTasks();//executa as tarefas da usb(verifica o status e os eventos gerados)
        #endif
        //////////////coloque aqui seu programa///////////////////////////
        rotina_principal();
    ////////////////////////fim do programa /////////////////////////////////////////////
    }//fim do laço infinito
}//fim do main

aparência do programa "Dynamic CDC Demo" :




logo abaixo o hardware necessário: