Protocolo robusto para serial RS232

Para "abobrinhas" use o " Boteco"

Moderadores: andre_luis, 51, guest2003, Renie

Protocolo robusto para serial RS232

Mensagempor gibim » 16 Nov 2006 16:14

Pessoal, preciso de uma ajuda. Estou desenvolvendo um projeto e uma determinada placa irá conversar com um software pela serial RS232, tudo está funcionando bem, mas....

Tenho problemas que se o windows resolve "comer" um bit, ou se perde no caminho, tudo trava, pois está sincrono. E estou com dificuldades de saber qual seria o melhor método de implementar um protocolo com controle de erro. Preciso de um protocolo que não se perca, caso falhe algum byte ou a mensagem não seja compreendida, seja enviado um NACK e a outra ponta retransmita.

Nesta aplicação, não se tem mestre nem escravo, eles apenas trocam mensagens, pois é uma aplicação ponto-a-ponto.

Por motivos óbvios, não vou implementar um stack de TCP/IP, pois não tenho conhecimento e nem recursos hábeis pra isso. Porém estou estudando outras possibilidades, como os protocolo:

SLIP, PPP, ou desenvolver um próprio.

Mesmo esses dois, não consigo achar nada muito aprofundado a respeito de como seria sua implementação em microcontroladores.

Agradeço a ajuda de todos.
Avatar do usuário
gibim
Byte
 
Mensagens: 117
Registrado em: 08 Nov 2006 21:40
Localização: Londrina - PR

Mensagempor chipselect » 16 Nov 2006 16:40

poderia ser um protocolozinho de pergunta e resposta, com checksum.
chipselect
Word
 
Mensagens: 744
Registrado em: 16 Out 2006 18:50

Mensagempor gibim » 16 Nov 2006 17:00

Eu fiz isso, na verdade o protocolo atual ele é assim:

Cabeçalho, Classe, Método, Tamanho da Mensagem, Mensagem, CRC16

E tudo sincrono, ou seja, se ele perder um bit do cabeçalho, não conseguirá decodificar a mensagem e por consequência, quem enviou vai estar aguardando uma determinada resposta, mas não irá receber nada, ou receberá lixo de volta.

Por isso teria que enviar um ACK se desse certo, ou um NACK se não. Mas são tantas variáveis... Que ainda estou perdido.

Outro problema que ainda não comentei é sobre a sincronização inicial... Quem conecta em quem?(Olha a piadinhas sem graça..rs) e depois se algum pacote é perdido por várias vezes, na hora de fazer a re-sincronização?
Avatar do usuário
gibim
Byte
 
Mensagens: 117
Registrado em: 08 Nov 2006 21:40
Localização: Londrina - PR

Mensagempor proex » 16 Nov 2006 19:09

Gibim, acho que vc esta substimando o RS232.

Vc não deve complicar o "negocio" assim.

Rs232 é uma comunicação simples para até uns 3 metros de distancia. Se qualquer coisa que vc for fazer com Rs232 ficar sujeito a perda de 1 bit, vc deve rever seus conceitos pois dessa forma, nada sera possivel.

As principais dicas para se comunicar com PC via RS232 são;

1-Criar um protocolo mais simples e confiavel possivel;

2-Dar tempo ao PC para capturar os dados que vc estiver enviando;
( para cada byte recebido pela serial, o PC gera um interrupçao, se vc nao der tempo ao software do PC tratar essa interrupçao, ai sim as coisas complicam)

3- Sempre que possivel, (preferencialmente sempre) o PC deve ser o Mestre da comunicaçao e seu dispositivo, o Escravo.


Em vez de :Cabeçalho, Classe, Método, Tamanho da Mensagem, Mensagem, CRC16 .

Por que nao algo mais simples como:

1-Mande 1 Byte especifico indicando o inicio da transaçao;

2-O PC deve responder esse mesmo valor (se vc mandou 0xFE, o PC devolve 0xFE). Se ele responder diferente, fica claro que o PC nao deve ter recebido seu dado corretamente, certo?

Se após 3 tentativas, o PC responder errado, aborte a comunicaçao pois algo de muito errado esta acontecendo e nenhum protocolo do mundo irá arrumar isso.

Depois, para cada byte de dados que vc enviar, o PC responde com o mesmo valor.
Assim fica facil descobrir que esta havendo alguma interferencia na comunicaçao.

Vc só precisa definir dois valores especificos para indicar Inicio da Transação e Fim da Transaçao.

Exemplo:

Vamos definir que 3 bytes de 0xFE seja o sinal de Inicio da Transaçao e
3 bytes de 0xCF seja o sinal de Fim da Transaçao.

Para iniciar uma tranferencia para o PC, seu dispositivo enviaria o seguinte:


0XFE,0XFE,0XFE, DADO, DADO, DADO,DADO,0XCF,0XCF,0XCF.

Para cada byte enviado, o PC responderia com o mesmo valor.

Percebeu?
proex
Dword
 
Mensagens: 2101
Registrado em: 11 Out 2006 14:05
Localização: São Paulo

Mensagempor Wagner de Queiroz » 16 Nov 2006 19:45

Eu particularmente prefiro inverter os bits de eco.

Mandei FFh, o outro lado me responde 00h.
Mandei FEh, o outro lado me responde 01h.
Mandei FDh, o outro lado me responde 02h.

E assim se vai, pois ja peguei em chao de fabrica um problema muito bizarro que matei na hora com esse recurso.

Bem, eu tive que encurtar o cabo rs232 que tinha 32 metros. Quando chegou a 19 metros, o problema sumiu.

Detalhe, eu tinha eco identico mando FFh volta FFh, Mas sempre eu tinha o mesmo eco varias vezes. Como um analizador de protocolo serial quebra um galho Enorme ! (Na bancada funcionava bonito o cabo de 32 Metros)

Na pior das hipoteses mande 2 vezes cada byte. Vai ter um overhead Lascado, mas se a comunicacao é breve e vai pouca coisa, pq nao fazer ?
Seja Livre, Use Linux
Avatar do usuário
Wagner de Queiroz
Word
 
Mensagens: 872
Registrado em: 11 Out 2006 13:38
Localização: Barueri-SP

Mensagempor fenix3 » 16 Nov 2006 21:45

Usar uma velocidade baixa de comunicacao, dar uma pequena pausa para cada byte enviado, usar o eco, e habilitar se possivel o aumento do buffer da serial no PC (16550), e ainda limitar o tempo de comunicacao, se nao conseguir uma resposta dentro de um tempo limite reinicia...conta tentavivas, deixar o computador como mestre...

Acho que com esta lista de opcoes ja sao suficientes....
Luis Fenix
Maaaaraaaaviiilhaaaaaa! (Bem devagar para irritar a todos).
Avatar do usuário
fenix3
Byte
 
Mensagens: 317
Registrado em: 12 Out 2006 03:46
Localização: Minha sala, ora pois!

Mensagempor gibim » 17 Nov 2006 14:23

Agradeço a contribuição de todos.

Proex, imagina que eu pensei em utilizar a serial para transferir dados sobre o protocolo TCP/IP!. Realmente isso seria ABUSAR da boa vontade da pobre serial.rs

Mas não vou me abater pela simplicidade da mesma. E aproveitando todas as contribuições vou colocar minhas evoluções:

Fenix3 -> Protocolo com ACK, aumentar o buffer da serial do PC (fiz isso para garantir), protocolo que reinicia quando estourar o tempo limite ou receber lixo várias vezes.
*OBS: Não posso e não precisaria diminuir a taxa, na verdade quero até aumentar se possível. A distância entre a placa e o PC é de apenas 30cm.

Wagner -> Inicialmente pensei em fazer apenas um eco de tudo que eu enviasse, porém a comunicação já está um tanto "pesada", pois são feitas inúmeras requisições e a quantidade de dados transmitida é enorme, tenho estruturas de dados de até 3kb.! Esse problema do eco por causa do comprimento do fio eu também já percebi. Para ter um eco fantasma você precisa apenas de 5 metros de cabo serial conectada no PC e a outra ponta desligada. Isso vai gerar um eco por indução de linha

Proex -> Infelizmente o negócio está complicado porque era pra funcionar na USB, mas como ainda não tenho saco e nem conhecimentos necessários pra isso, vai de serial mesmo..rs
Eu verifiquei que o buffer da serial no PC é muito grande, passa de 10kb, (Enviei 10kb de dados, várias vezes, e ele não perdeu nenhum bit).
Sobre a história de Mestre-Escravo, infelizmente a Placa tem que ser o mestre, isso porque ela é que envia os comandos para o PC, vamos dizer que o PC funciona apenas como um monitor de vídeo e tocador de som para meus eventos.
Sobre a estrutura de dados do Header, eu já diminui 60% do bolado inicialmente. Antes, eu usava CRC32, todos os campos com 4 bytes,... Tava um monstro de grande, bom pra uso na USB.

Abaixo, apresento um esquema de protocolo que estou bolando com a ajuda de vocês. Por favor, se não concordarem, por favor me digam, pois quero montar algo seguro e que mais pessoas interessadas possam usar. Ou vocês acham que os grandes protocolos nasceram dentro de uma única empresa?.



[img]http://www.geocities.com/gibim/ProtocoloGibim.jpg[/img]

Alguém pode postar essa imagem pra mim??? estou com dificuldades de postar essa URL para aparecer a imagem. Obrigado
Avatar do usuário
gibim
Byte
 
Mensagens: 117
Registrado em: 08 Nov 2006 21:40
Localização: Londrina - PR

Mensagempor Maia » 17 Nov 2006 15:54

Já tive muitas dores de cabeça tentando inventar protocolos para RS232. No dia que passei a usar MODBUS, meus problemas se acabaran-se. :lol:
Abraços,
Maia
Avatar do usuário
Maia
Byte
 
Mensagens: 348
Registrado em: 15 Out 2006 16:25
Localização: Rio de Janeiro

Mensagempor ftegon » 17 Nov 2006 16:15

Ola!

Eu implementei meu proprio protocolo com CRC16, tanto no micrcontrolador como no windows. Mas se o teu microcontrolador for AVR ou ARM acho que você deve dar uma olhada em:

http://freemodbus.berlios.de/

E no lado do windows http://www.ozm.cz/ivobauer/modlink/

a++

Fabio Tegon
ftegon
Bit
 
Mensagens: 36
Registrado em: 13 Out 2006 09:05

Mensagempor gibim » 17 Nov 2006 19:52

Ftegon, foi boa sua dica. Mas procurando na net eu encontrei mais informações. Mas neste site ( http://www.control.com/1004462967/index_html )eu encontrei algumas observações a serem feitas:

1º No modo ASCII, o tamanho da mensagem é duplicada, se isso realmente ocorrer, fica difícil pra mim pois existem estruturas de dados enormes para ser transmitido.

2º No modo RTU, aquela história de tempo entre os caracters >=3.5 ainda está um pouco confusa pra mim. Ou seja, a cada frame de dados enviados, tenho que esperar esse tempo?

Por favor, quem já trabalhou com MODBUS coloque seus pós e contra, que eu vou tentar achar mais argumentos.

Para quem quiser saber mais como funciona olhem isso:
http://www.modbus.org/docs/Modbus_over_ ... ine_V1.pdf
...
Avatar do usuário
gibim
Byte
 
Mensagens: 117
Registrado em: 08 Nov 2006 21:40
Localização: Londrina - PR

Mensagempor Red Neck Guy » 17 Nov 2006 20:46

Em TODOS os equipamentos que desenvolvo que necessitam de comunicação comunicação com PC eu utilizo MODBUS RTU. No caso da implementação no PC eu costumo fazer dentro da DLL de comunicação que se comunica com os equipamentos uma máquina de estados, onde só solicito ao equipamento o próximo "contexto" de leitura quando eu ler aquilo que queria.

algo do tipo:
//gerencia.
void troca_mensagens(void){
unsigned char response;
case(contexto){
case 0: response = monta_request(temperaturas); break;
case 1: response = monta_request(entradas); break;
case 2: response = monta_request(preset_saidas);break;
}
if(response == contexto);
contexto++;
if(contexto>0)
contexto = 0;
}
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Mensagempor ftegon » 17 Nov 2006 21:29

Ola!

Minha opinião é a seguinte sobre o ModBUS:


1) A grande vantagem do ModBUS é que ele é um padrão de comunicação, largamente utilizado pela industria, e existem muitos softwares de terceiros que usam ele.
Se você tiver necessidade de comunicação com estes softwares você tera de usar ModBUS.

2) Tambem há bibliotecas (ocx, dll , vcl, etc...) para ModBUS prontas para Windows e Linux (é só usar, não há a necessidade de desenvolver).

3) Não é todo microcontrolador que suporta o protocolo, pois ele é um tanto complexo para certos tipos de microcontrolador. principalmente no quesito memoria RAM.

4) Se não houver a necessidade de padronização de software, não há o porque usa-lo, pode-se desenvolver um protocolo própio, mais simples
e que não necessite tanto de memória.

Um exemplo de protocolo mais simples é o SNAP.

http://www.hth.com/snap/

Outro exemplo é a uLAN.

http://cmp.felk.cvut.cz/~pisa/ulan/ul_drv.html


outro bem simples é o protocolo HCS-II (circuit cellar home control system)

descrito na circuit cellar n° 110

ou http://www.cc-concepts.com/products/pic ... manual.pdf

Bom agora a escolha é sua.

a++

Fabio Tegon
ftegon
Bit
 
Mensagens: 36
Registrado em: 13 Out 2006 09:05

Mensagempor msamsoniuk » 18 Nov 2006 14:45

o mais correto seria trabalhar com camadas

http://en.wikipedia.org/wiki/OSI_model

voce jah esta com a camada 1 definida como sendo o RS232, agora precisa escolher o que vai usar na camada 2. no caso de RS232, eh comum o uso de HDLC:

http://en.wikipedia.org/wiki/HDLC

no caso do HDLC, os frames de dados sao delimitados pelo caracter 0x7E. quando voce recebe um 0x7E, voce comeca a armazenar o frame de dados ateh encontrar outro 0x7E. para conseguir transmitir dados que contem o proprio 0x7E, voce usa uma sequencia de escape, que eh o 0x7D. assim, se vc precisar transmitir um 0x7E, vc transmite um 0x7D7E. o proprio 0x7D seria transmitido como 0x7D7D, isso permite recuperar os dados originais e alerta o codigo de recepcao de que nao se trata de um delimitador de frame. se o frame nao exceder o tamanho maximo que vc definir e voce receber o delimitador indicando o fim do frame, basta fazer a verificacao de CRC e aceitar ou descartar o frame.

obviamente eh necessario fazer a retransmissao dos frames que sao descartados, entao vc precisa de uma camada 4, como o TCP:

http://en.wikipedia.org/wiki/Transmission_Control_Protocol

como voce nao vai organizar isso em rede, nao existe necessidade de implementar uma camada 3, como o IP. e tambem nao precisa necessariamente implementar o proprio TCP, mas pode adotar a ideia chave. o TCP um fluxo de dados em segmentos pequenos, que sao encapsulados nas camadas anteriores e enviados pela rede. esses segmentos podem, eventualmente, serem perdidos ou passarem por caminhos diferentes, assim cabe ao TCP colocar eles na ordem correta e perceber quem esta faltando. assim, cada segmento TCP tem um numero de serie que indica onde ele deve ser encaixado.

se vc transmitir 3 segmentos, numerados como 1, 2 e 3, supondo que a camada de enlace descarte o frame 2 em funcao de algum problema de CRC, o receptor enviaria um ACK-1 e ACK-3, indicando que recebeu os frames 1 e 3 corretamente. o transmissor, que jah estaria a essa altura transmitindo os segmentos 4, 5 e adiante, notaria a falta de um ACK para o segmento 3 e retransmitiria por precaucao, continuando entao a transmitir os proximos segmentos que nao foram ainda transmitidos.

no lado do receptor, ele provavelmente receberia o segmento 3, encaixaria o segmento faltante e enviaria o ACK-3, jah tendo provavelmente recebido os segmentos 4, 5 e adiante. com o recebimento do segmento 3, um grande segmento de dados jah estaria pronto para ser repassado para a camada acima.

e se o frame com o ACK-3 fosse perdido ? bom, o transmissor notaria que jah transmitiu mais meia duzia de segmentos, incluindo o segmento 3 duas vezes e nao recebeu resposta sobre ele, entao ele enviaria mais uma vez o segmento. o receptor, por sua vez, sabendo que o segmento jah nao eh mais necessaria, enviaria um ACK-3 apenas para satisfazer as necessidades do transmissor.

note que enviar um NACK para um frame que foi descartado nao eh uma ideia muito inteligente: se o frame foi descartado pq o CRC nao batia, provavelmente voce nao tem uma forma de dizer qual frame foi descartado, pois o conteudo dele era ilegivel. outro problema eh que pode ser um problema momentaneo na parte fisica e o frame com o NACK pode nao chegar.

assim, cada lado trabalha sempre na pior hipotese em relacao ao outro lado. para isso existe uma redundancia, claro, no exemplo acima o transmissor chegou a enviar 3x o mesmo frame. isso eh um pior caso, onde o mesmo frame foi descartado na ida e seu ACK acabou sendo descartado na volta, mas em uma situacao real teriamos a garantia de que os segmentos de dados estariam completos.

por outro lado, a vantagem de trabalhar em camadas eh que voce pode trocar, por exemplo, a camada fisica, e continuar utilizando as outras camadas no futuro, alem de dividir melhor as coisas e facilitar o desenvolvimento: voce divide um problema grande e dificil em varios problemas pequenos e faceis.

considere isso tb um incentivo para usar frames pequenos. como a camada 4 pode reconstruir segmentos longos de dados, voce pode quebrar uma estrutura de 3KB em 12 frames de 256 bytes. entao, se um frame for perdido, voce precisa reenviar apenas 1/12 a mais de informacao, 12x menos do que enviar novamente um frame de 3KB. isso poderia ser feito por uma camada 5, de controle de sessao! assim voce teria em cada segmento o numero da sessao e o numero do segmento, isso permitiria ter varias sessoes em paralelo. uma sessao poderia transmitir um fluxo de dados bidirecional continuo (como um prompt de comando) ou dados discretos, como estruturas de dados de tamanho variado. a camada 5 de sessao iria estabelecer sessoes separadas e em cada sessao a camada 4 iria reconstruir os segmentos novamente na forma de estruturas maiores. e voce nao precisaria se preocupar com a seguranca dos dados, porque a camada 2 esta fazendo isso para voce :)
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor jeanfernandes » 30 Nov 2006 01:07

STX ID ADDR TAM DATA ETX CRC

Isso resolve....

Voce cria um buffer pra recber dados
e um switch case pra tratar as tarefas do protocolo.....
A resposta ou ausencia dela eh tratada por timeout pra quem envia

STX = 0x02
(*)ID - Classe do Equipamento
(*) ADDR - Endereco dentro da classe
(*) TAM - Tamanho dos Ddaos
(*) DATA - Dados
ETX = 0x03
(*) CRC = ai eh do gosto do fregues

(*) MSB = 1 sempre ehehehehheehe

voce pode implementar no primeiro byte de DATA as condicoes de comando

Eu uso esse protocolo tem anos e obixim da no couro.....nunca me deixou na mao.....

Recebendo um STX eu abro um timer.......e na rotina do kernel se o timer estourar eu aborto o pacote e volto pra tarefa de STX pra esperar o proximo.....

ADDR = 0x80 (mensagem de broadcast)

Algumas pessoas fazem um pouco diferente criando mensagens de enlace entre os processos so pra saber se o trem ta vivo.....mas como sao 6 bytes apenas ....no protocolo eu desisti da ideia.....
Jean P. Fernandes - Eng. Eletrônico - (83) 2102-2116 - APEL - www.apel.com.br - Campina Grande - PB
jeanfernandes
Word
 
Mensagens: 539
Registrado em: 11 Out 2006 15:36
Localização: Campina Grande - PB

Mensagempor chipselect » 30 Nov 2006 01:20

use o algoritmo de janela deslizante que resolve seus problemas....

ou você recebe certo, ou não recebe...

eu fiz um e testei bastante. Dá pra você ficar conectando e desconectando o conector da serial RS232 que o "protocolo" se vira pra mandar certo, ou fica tentando até conseguir.
chipselect
Word
 
Mensagens: 744
Registrado em: 16 Out 2006 18:50

Próximo

Voltar para Assuntos Gerais

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 0 visitantes

cron

x