Eu estava aqui brincando com uma plaquinha na qual eu fiz um conversor ethernet para serial /serial para ethernet e resolvi postar o código fonte pra vcs. Se alguém quiser um aplicativo que funciona como terminal ethernet é só me enviar um e-mail, para o serial existe no mercado um monte de opção. neste projeto o único porem que vi foi quando envio dados da serial para o pc pois se for maior que 40 caracteres ele acaba perdendo o restante ,para minha aplicação do jeito que está basta ,veja a figura abaixo que demonstra como configurar os pinos do AVR como o modulo wiznet (o qual apresentei em posts anteriores.)
O código fonte :
//***********************************************************************************************************
// conversor ethernet - serial RS232
//
// versão : 1.0
// descrição : conversor ethernet-serial/serial-ethernet
// Autor : Aguivone
// microcontrolador : ATmega328 P
// compilador : AVR-GCC / Atmel AVR Studio 4.17
// Data do projeto : 05 / 06 / 2013.
//*************************************************************************************************************
#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
#include <avr/eeprom.h> ///para usar a eeprom
////////////////////////funçoes auxiliares/////////////////////////////
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)
#define pino_alto(x,y) ((x & _BV(y)) == _BV(y)) //o pino deve estar como entrada ,testa se está em nivel logico 1
/////////////////////////////////////////////////////////////////////////////////////////////
//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 W5100 Op Code usados
#define WIZNET_ESCREVE_OPCODE 0xF0
#define WIZNET_LER_OPCODE 0x0F
// Wiznet W5100 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 SAR 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 RMSR 0x001A // RX tamanho do buffer(memória) de recepção
#define TMSR 0x001B // TX tamanho do buffer(memória) de envio
#define S0_MR 0x0400 // Socket 0: registrador do socket0
#define S0_CR 0x0401 // Socket 0: registrador de comandos do socket0
#define S0_IR 0x0402 // Socket 0: registrador de interrupçoes do socket0
#define S0_SR 0x0403 // Socket 0: registrador de status do socket0
#define S0_PORT 0x0404 // Socket 0: aqui é colocado o valor da porta TCP -> endereço = 0x0404 a 0x0405
#define S0_DPORT 0x0410 // Socket 0: aqui é colocado o valor da porta TCP de destino-> endereço = 0x0410 a 0x0411
#define S0_DHAR 0x0406 // Socket 0: endereçamento de registro de hardware(tipo MAC)-> endereço = 0x0406 a 0x040B
#define S0_DIPR 0x040C // Socket 0: IP de acesso remoto -> endereço = 0x040C a 0x040F
#define SO_TX_FSR 0x0420 // Socket 0: tamanho do registrador de transmissão: 0x0420 to 0x0421
#define S0_TX_RD 0x0422 // Socket 0: ponteiro de leitura do buffer de transmissão : 0x0422 a 0x0423
#define S0_TX_WR 0x0424 // Socket 0: ponteiro de escrita do buffer de transmissão: 0x0424 a 0x0425
#define S0_RX_RSR 0x0426 // Socket 0: tamanho do registrador de recepção: 0x0426 a 0x0427
#define S0_RX_RD 0x0428 // Socket 0: ponteiro de leitura do tamanho dos dados: 0x0428 a 0x0429
#define TXBUFADDR 0x4000 // W5100 posição inicial do buffer de escrita
#define RXBUFADDR 0x6000 // W5100 posição inicial do buffer de recepção
//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 0x07FF // Mascara do buffer de transmissão 2K :
#define RX_BUF_MASK 0x07FF // Mascara do buffer de recepção 2K :
#define NET_MEMORIA 0x05 // Use 8K de Tx/Rx Buffer(pode se usar até 8K)
#define TCP_PORT 0X1388 // porta TCP/IP usada pelo pc porta 5000
#define MAX_BUF 100 // tamanho maximo do buffer de recepção reduzi de 100 pra 10
/////////
//////// variaveis globais ////////////////////////////////////////
////////
char buf[MAX_BUF];//o maior dado será #C-255-255-255-255-255-255-255-255-255-255-255-1023-1022*
char buffer_serial[MAX_BUF];//buffer da serial
//////////////valores padrao
uint8_t sockstat=0;
char comando;
int ip_placa=5;
int rsize;
int tempo_250ms=0;
//para serial
unsigned char caracter;//
//int tam_buffer;//usado para contar o tamanho do buffer de recepção
volatile char rec_buffer ='S';
int dados_serial_conta=0;
int timeout_serial =0;
///////////////////////função de escrita SPI////////////////////////
void spi_escreve(unsigned int endereco,unsigned char dados)
{
// ativa pino de habilitação do SPI
SPI_PORT &= ~(1<<SPI_SS);
SPDR = WIZNET_ESCREVE_OPCODE;//inicializa escrita pelo W5100
// espera terminar a comunicação
while(!(SPSR & (1<<SPIF)));
// 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)));
SPDR = dados; // inicializa transmissão de dados
while(!(SPSR & (1<<SPIF))); // espera finalizar a transmissão
// finaliza comunicação.
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);
//inicializa leitura pelo W5100
SPDR = WIZNET_LER_OPCODE;
// espera finalizar a transmissão
while(!(SPSR & (1<<SPIF)));
// inicialização do Wiznet W5100 envia os bytes mais significativo
SPDR = (endereco & 0xFF00) >> 8;
// espera finalizar a transmissão
while(!(SPSR & (1<<SPIF)));
//inicialização do Wiznet W5100 envia os bytes menos significativo
SPDR = endereco & 0x00FF;
// 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 W5100
}
////////////////////////inicializa ethernet //////////////////////////////////
void W5100_Inicializa(void)
{
unsigned char porta[] = {0x13,0X88};// ex 5000 = 0X1388 -> 0X13 +0X88 //porta 5000
//unsigned char porta[] = {0x00,0X50};// ex 80 = 0X0050 -> 0X00 +0X50 //porta tcp
unsigned char mac_addr[] = {0x00,0x16,0x36,0xDE,0x58,0xF6};//MAC usado pelo microcontrolador(para teste)
unsigned char ip_addr[] = {192,168,0,ip_placa};//enderreço de ip do servidor(valor para teste,do microcontrolador)
unsigned char sub_mask[] = {255,255,255,0};//mascara de sub_rede
unsigned char gtw_addr[] = {192,168,0,1};//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
spi_escreve(MR,0x80); // MR = 0b10000000; isso inicicializa os registradores internos automaticamente
_delay_ms(1);
//configura porta de comunicação para acesso remoto
spi_escreve(S0_PORT , porta[0]);
spi_escreve(S0_PORT + 1,porta[1]);//porta de envio e de destino são iguais
spi_escreve(S0_DPORT , porta[0]);
spi_escreve(S0_DPORT + 1,porta[1]);
spi_escreve(S0_MR,MR_TCP); // configura o registrador de modo (MR)
_delay_ms(1);
// configura o MAC de acesso remoto
spi_escreve(S0_DHAR , mac_addr[0]);
spi_escreve(S0_DHAR + 1,mac_addr[1]);
spi_escreve(S0_DHAR + 2,mac_addr[2]);
spi_escreve(S0_DHAR + 3,mac_addr[3]);
spi_escreve(S0_DHAR + 4,mac_addr[4]);
spi_escreve(S0_DHAR + 5,mac_addr[5]);
_delay_ms(1);
// endereço de IP de acesso remoto será sempre 1 a mais
spi_escreve(S0_DIPR,ip_addr[0]);
spi_escreve(S0_DIPR + 1,ip_addr[1]);
spi_escreve(S0_DIPR + 2,ip_addr[2]);
spi_escreve(S0_DIPR + 3,ip_placa + 1);
_delay_ms(1);
//configura gateway
spi_escreve(GAR + 0,gtw_addr[0]);///o gateway deve ter mesma faixa de ip senão não funciona,mas nunca usar ip 1 pois é do gateway.
spi_escreve(GAR + 1,gtw_addr[1]);
spi_escreve(GAR + 2,gtw_addr[2]);
spi_escreve(GAR + 3,gtw_addr[3]);
_delay_ms(1);
// configura o MAC (SAR): 0x0009 à 0x000E
spi_escreve(SAR ,mac_addr[0]);
spi_escreve(SAR + 1,mac_addr[1]);
spi_escreve(SAR + 2,mac_addr[2]);
spi_escreve(SAR + 3,mac_addr[3]);
spi_escreve(SAR + 4,mac_addr[4]);
spi_escreve(SAR + 5,mac_addr[5]);
_delay_ms(1);
// mascara de sub rede (SUBR): 0x0005 à 0x0008
spi_escreve(SUBR ,sub_mask[0]);
spi_escreve(SUBR + 1,sub_mask[1]);
spi_escreve(SUBR + 2,sub_mask[2]);
spi_escreve(SUBR + 3,sub_mask[3]);
_delay_ms(1);
// endereço de IP (SIPR): 0x000F à 0x0012
spi_escreve(SIPR,ip_addr[0]);
spi_escreve(SIPR + 1,ip_addr[1]);
spi_escreve(SIPR + 2,ip_addr[2]);
spi_escreve(SIPR + 3,ip_addr[3]);
_delay_ms(1);
// configura o tamanho do buffer de memoria de escrita e leitura
spi_escreve(RMSR,NET_MEMORIA);//configura para cada socket 2K de memoria de leitura(no W5100 tem 4 socket mas vamos usar somente o socket 0)
spi_escreve(TMSR,NET_MEMORIA);//configura para cada socket 2K de memoria de transmissao(no W5100 tem 4 socket mas vamos usar somente o socket 0)
}
//////////////////////////////////fecha socket 0 ///////////////////////
void fechar_socket(uint8_t socket)
{
if (socket != 0)return;
// manda fechar
spi_escreve(S0_CR,CR_CLOSE); // 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
spi_escreve(S0_CR,CR_DISCON); // 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
spi_escreve(S0_CR,CR_OPEN); // 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)
{
spi_escreve(S0_CR,CR_LISTEN);//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;
}
void put_serial(unsigned char *carac)
{
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 = *carac;
/* Wait for empty transmit buffer */
}
void escreve_caracter(unsigned char carac)
{
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 = carac;
}
////////////////////////////envia pacote////////////////////////////////////
uint16_t envia_pacote(unsigned char pacote[],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_ms(1);
tx_tamanho= spi_ler(SO_TX_FSR);
tx_tamanho=(((tx_tamanho & 0x00FF) << 8 ) + spi_ler(SO_TX_FSR + 1)); // Timeout para aproximadamente 10ms
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)
{
buffer_tamanho--;
// calcula o endereço real do buffer de transmissão.
ende_real = TXBUFADDR + (ende_temp & TX_BUF_MASK); // copia pacote para W5100(TX_buffer)
spi_escreve(ende_real,pacote[tx_tamanho]);
ende_temp++;
tx_tamanho++;
}
// incrementa valor de S0_TX_WR , então este será o ponto da proxima transmissão
spi_escreve(S0_TX_WR,( ende_temp & 0xFF00) >> 8 );
spi_escreve(S0_TX_WR + 1,( ende_temp & 0x00FF));
// agora envia o comando de enviar dados para rede.
spi_escreve(S0_CR,CR_SEND);
// espera terminar o envio
while(spi_ler(S0_CR));
return 1;
}
/////////////////////////////////recebe pacote//////////////////////////////////////////
void recebe_pacote(char pacote[],int taman)
{
unsigned int ponteiro,ende_temp,ende_real;
char recebido;
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(taman>0)
{
taman--;
ende_real=RXBUFADDR + (ende_temp & RX_BUF_MASK);//endereço inicial de leitura + endereço dos dados recebidos
recebido = spi_ler(ende_real);
escreve_caracter(recebido);
ende_temp++;
}
// incrementa S0_RX_RD ,este será o ponto da proxima recepção
spi_escreve(S0_RX_RD,(ende_temp & 0xFF00) >> 8 );
spi_escreve(S0_RX_RD + 1,(ende_temp & 0x00FF));///////////////////////////////////////////////////vou ver isso//////////
//envia comando para leitura
spi_escreve(S0_CR,CR_RECV);
_delay_us(5); // espera terminar leitura.
}
///////////////////////////////////////////////////////////////////////
int Buffer_recepcao(void)
{
return (((spi_ler(S0_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S0_RX_RSR + 1)); //
}
////////////////////////funçoes auxiliares///////////////////////////////
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çoes usadas pela usart////////////////////////////////////////////////
void serial_inicializa(int BAUD)
{
int valor = ((F_CPU/16)/BAUD)-1; //verifique se na simulação não está habilitado pra divir por oito o clock do microcontrolador
/* baud rate */
UCSR0A = 0X20;
/* habilita receiver and transmitter buffers */
UBRR0H = (unsigned char)(valor>>8);
UBRR0L = (unsigned char)valor;
/* habilita receiver and transmitter buffers */
UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador
/* modo assicrono,8 bits , 1 stop bit, assincrono , sem paridade */
UCSR0C = 0X06;
//UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//////////////////////////interrupções requerida para usar a serial///////////////////////////////////
ISR(USART_RX_vect)
{
caracter = (char)UDR0;
buffer_serial[dados_serial_conta] = caracter;
dados_serial_conta++ ;
timeout_serial=0;
rec_buffer ='D';
}
//////////////////////////////////////////////função principal/////////////////////////////////////
int main(void)
{
//////////////////inicializa port D e port C /////////////////////////////////////////////////////////////////////
DDRD = 0xFF;//configura port D como saida
PORTD = 0x00;//limpa o port D
DDRC = 0x00;//configura port C como entradas
//i = PINB; //ler pinos
inicializa_spi(); //comunicação spi
ip_placa=5;
W5100_Inicializa(); //ethernet
serial_inicializa(9600);//não importa frequencia e 9600
sei();
//impri_serial("Use < ou > \n ");
//impri_serial("para enviar comando ! \n ");
desliga_pino(PORTB,PB0);///// //reseta o chip de ethernet
_delay_ms(1);
liga_pino(PORTB,PB0);
///////////////////////////////////
sei();
///////////////////////////////////////////////////////
//OBS : devo desabilitar o bit RSTDISBL para qu e o pino C6 possa ser usado como I/O
///////////////////////////////////////////////////////
for(;;)
{
if(tempo_250ms > 30000)//tempo qualquer
{
alterna_pino(PORTB,PB1);
tempo_250ms =0;
}
tempo_250ms++;
timeout_serial++;
////////////////////////rotina ethernet////////////////////////
sockstat=spi_ler(S0_SR);
switch(sockstat)
{
case SOCK_CLOSED: ///socket fechado. fica escutando a rede
if ( conex_servidor(0) > 0)
{// Listen(escuta) Socket 0
if (escutar_rede(0) <= 0)//socket 0
_delay_ms(1);
}
break;
case SOCK_ESTABLISHED://conectado
{
// lê o pacote recebido e verifica se é valido
if(timeout_serial > 3000)//se maior que alguns milisegundos verifica se houve novos dados
{
if(rec_buffer == 'D')
{///tem dados
envia_pacote(buffer_serial,MAX_BUF);//envia dados
while(dados_serial_conta>0)
{
buffer_serial[dados_serial_conta] = 0;
dados_serial_conta--;
}
rec_buffer = 'S';
}
timeout_serial=0;
}
if (Buffer_recepcao() > 0)//checa buffer de recepção
{
// lê o pacote recebido e verifica se é valido
rsize=((spi_ler(S0_RX_RSR) & 0x00FF) << 8 ) + spi_ler(S0_RX_RSR + 1);//pega tamanho dos dados recebido
recebe_pacote(buf,rsize);
}
tempo_250ms++;//se conectado pisca 2X mais
tempo_250ms++;//se conectado pisca 3X mais rapido
}break;//fim socket estabilizado
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
////////////////////////fim da rotina ethernet////////////////////////
}//chave do laço infinito (for)
}//chave de main
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!