Quando deve mudar de ASCII para protocolos seriais avançados?

28

Todos os meus dispositivos de microcontrolador que se comunicam com o PC via UART usam seqüências ASCII para enviar comandos e receber dados (conforme implementado no Arduino). Foi isso que aprendi quando comecei a pesquisar na eletrônica e sempre achei que enviar strings nuas era suficiente. No entanto, notei que a maioria dos dispositivos que encontrei usa protocolos binários sofisticados que incluem códigos de função, endereços e verificação de erros de CRC.

Quando a comunicação ASCII básica é aceitável e quando devo considerar algo mais avançado, como o Modbus? Os dispositivos comerciais usam esse ASCII? Industrial?

Não faço ideia do que estou fazendo
fonte
3
Resposta curta: quando seu aplicativo precisar. Sim, dispositivos comerciais usam ASCII. Tome o GPS NMEA como exemplo. (E, novamente, vou encaminhar minha própria pergunta aqui )
Eugene Sh.
1
O Modbus possui um modo ASCII. Veja Modicon Modbus Protocol
Tut
@EugeneSh .: Vale a pena notar que o NMEA tem um campo de soma de verificação, e soltar uma única amostra de explosão devido à falha da soma de verificação (que acontece com mais frequência do que você imagina) geralmente não é uma falha crítica. Isso pode muito bem não ser o caso de outros protocolos ... e há muitos protocolos binários de GPS em uso (por exemplo, Garmin) para aplicativos em que ele pode ser realmente crítico (ou em que uma taxa de amostragem superior a 1 Hz é necessário, para o qual NMEA é muito detalhado). Embora isso realmente apenas solidifique seu argumento.
Lightness Races com Monica

Respostas:

28
  1. ASCII e CRC não são mutuamente exclusivos. ASCII é uma codificação e CRC é para verificação de erros.

  2. Qualquer coisa pode ser enviada como ASCII. Nós, velhos, certamente lembramos de UUEncoding, que transforma qualquer coisa em uma string ASCII.

  3. A) Para mim, geralmente é uma questão de velocidade e eficiência. O envio de um número grande de 32 bits por ASCII pode demorar, mas são necessários apenas 4 bytes para enviá-lo como binário por meio de um protocolo serial.

    B) Enviar NÚMEROS via ASCII significa que você deve converter o número em ASCII, o que é uma etapa extra clara (isso faz parte do que "printf" faz).

  4. Se você, de alguma forma, perde o seu lugar, estraga tudo, perde o formato, pega o endian errado, etc., um protocolo de comunicação binária certamente pode estragar. Se você estiver enviando ASCII, pode ser mais fácil se recuperar de erros simplesmente entrando e OLHANDO no fluxo de dados.

Scott Seidman
fonte
12
+1 para "ASCII é uma codificação". Não é um protocolo; protocolos podem ser construídos sobre ASCII.
Pete Becker
8
A recuperação automática de uma confusão não é intrinsecamente mais fácil para um protocolo baseado em texto do que o binário, mas a inspeção e depuração certamente podem ser.
Nick Johnson
1
@NickJohnson - absolutamente. Quando estiver no ponto de abrir um arquivo em um editor hexadecimal para ver o que você pode recuperar, você já está no Fubar medida em SOP vai
Scott Seidman
1
@nickjohnson isso não é verdade. O ASCII oferece muitas opções de enquadramento / delimitador fora da banda para ajudar na sincronização e recuperação, o que exigiria escape adicional, excesso de bits, intervalo de tempo ou outros truques se o canal for usado para dados binários de largura total.
Chris Stratton
2
Eu sempre sou a favor do ASCII ao escrever protocolos para obter todos os benefícios óbvios (legibilidade, logabilidade, etc.). Existem dois casos em que o binário faz mais sentido: primeiro, se a velocidade é um problema e você precisa do binário para inserir o máximo de dados possível no fluxo e, segundo, marginalmente, se você estiver tentando deliberadamente ocultar ou mesmo criptografar os dados fluxo para impedir ou impedir a engenharia reversa. Com isso, tenho protocolos binários de engenharia reversa e isso me irritou muito mais do que realmente impediu o ato.
J ...
10

Aqui estão alguns pensamentos sobre isso:

  • O ASCII é bom porque você pode usar um monitor serial para ter uma aparência manual do que é enviado.
  • se sua conexão não for confiável, você deverá esperar erros de transmissão e usar um CRC para verificar a integridade de cada mensagem recebida. Isso também pode ser feito em mensagens ASCII.
  • se sua conexão estiver muito lenta, você poderá reduzir o tamanho de suas mensagens mudando para um formato binário
  • Um formato binário especializado pode ser mais fácil de decodificar no lado do receptor do que o ASCII
MrSmith42
fonte
7

No nível mais simples, você poderia dizer que um protocolo de comunicação simples possui três camadas: físico, transporte e aplicativo. (Existem modelos com mais como OSI com 7 ou TCP / IP com 4. O número de camadas não é muito importante no contexto desta pergunta.)

A camada de aplicativo é a camada com a qual você lida diretamente no seu código e o foco da pergunta. No que diz respeito à camada de transporte, o byte que você passou em send_data é apenas um padrão binário, mas você pode interpretá-lo no código do aplicativo como a letra 'A'. O CRC ou o cálculo da soma de verificação será o mesmo, independentemente de você considerar o byte como 'A', 0x41 ou 0b01000001.

A camada de transporte é o nível do pacote, no qual você tem seus cabeçalhos de mensagens e a verificação de erros, seja CRC ou uma soma de verificação básica. No contexto do firmware, você pode ter uma função como send_data, onde passa um byte para enviar. Dentro dessa função, ele é inserido em um pacote que diz: "Ei, essa é uma mensagem normal, requer um reconhecimento e a soma de verificação é 0x47, a hora atual é X". Este pacote é enviado sobre a camada física para o nó receptor.

A camada física é onde os componentes eletrônicos e a interface são definidos: conectores, níveis de tensão, tempo, etc. Essa camada pode variar de alguns traços que executam sinais TTL para um UART básico em uma PCB, a um par diferencial totalmente isolado, como em alguns Implementações CAN .

No nó de recebimento, o pacote entra na camada física, é descompactado na camada de transporte e, em seguida, seu padrão binário está disponível para a camada de aplicativo. Cabe à camada de aplicação do nó receptor saber se esse padrão deve ser interpretado como 'A', 0x41 ou 0b01000001 e o que fazer com ele.

Em conclusão, é quase sempre aceitável enviar caracteres ASCII, se é isso que o aplicativo exige. O importante é entender seu esquema de comunicação e incluir um mecanismo de verificação de erros.

Matt Young
fonte
Os protocolos ASCII também podem incorporar soma de verificação. Encontrei variações Hex-as-ASCII, usando representação ASCII de números.
Eugene Sh.
@EugeneSh. Esclarecido esse ponto
Matt Young
Não é preciso escolher, mas o TCP não tem quatro camadas; é visto como um ajuste na camada quatro do modelo OSI. As comunicações seriais não se encaixam muito bem no modelo OSI.
batsplatsterson
@batsplatsterson Isso é óbvio, e muito irrelevante ao ponto que estou argumentando.
Matt Young
5

Um ponto ainda não mencionado é que, se alguém estiver usando ASCII ou um protocolo binário, o envio de um caractere de exclusão antes de cada pacote garantirá que, mesmo que o ruído da linha ou os erros de enquadramento apareçam antes do início de um pacote, todos os caracteres após a identificação. A saída será enquadrada corretamente na ausência de mais ruído. Caso contrário, se alguém enviar pacotes continuamente e não incluir caracteres que garantam a ressincronização, é possível que uma falha possa corromper tudo o que se segue até a próxima pausa na transmissão. O caractere 0xFF é bom porque garante que qualquer destinatário poderá ressincronizar no caractere a seguir.

(*) 0xFF - chamado apagamento porque alguém que digita um caractere incorreto ao digitar dados em uma fita de papel pode pressionar o botão "step tape backward" e pressionar rub-out para substituir o caractere erroneamente perfurado por 0xFF, o que ser ignorado pela maioria dos destinatários).

supercat
fonte
2

Uma vantagem do envio de strings ASCII é que os códigos de controle podem ser usados ​​para sinalizar o início / fim da mensagem. por exemplo, STX (caractere 2) e ETX (caractere 3) podem sinalizar a transmissão inicial e final. Como alternativa, você pode adicionar um simples avanço de linha para marcar o final da transmissão.

Ao enviar dados binários, isso se torna mais complicado, pois nenhum padrão de bits específico pode ser reservado para um código de controle (sem sobrecarga ou complexidade extra), pois um byte de dados válido pode ter o mesmo padrão.

Transistor
fonte
3
Muitos protocolos binários reservam um ou mais padrões de bits como códigos de controle, mas também incluem um mecanismo de escape para manipular esses códigos quando eles aparecem nos dados.
Dave Tweed
Você pode reservar qualquer padrão para sinalizar o que quiser em binário. Por exemplo, estou em um projeto com um fluxo de dados rápido e um fluxo de dados lento saindo pelo mesmo uart. I reservados a maior int32 negativo como uma bandeira para os meus dados lentas, e apenas saturar meus dados negativos na maior negativo + 1.
Scott Seidman
Acordado. Esclarei isso na resposta editada, espero.
Transistor
2

ASCII é bom, eu uso em quase todos os projetos. Isso torna a depuração muito mais fácil para monitorar a porta e só seria um problema se houvesse muitos dados a serem enviados.

Outro bônus: uso dispositivos de rádio serial para obter mensagens entre os arduinos e posso usar um monitor serial conectado ao meu laptop e injetar mensagens para que certas coisas aconteçam. Ótimo para teste.

Além disso, o envio de coisas como binárias não é impossível de depurar e, dependendo de suas ferramentas, você pode extrair e converter o binário em algo legível por humanos. Ou, se você souber o que está procurando, poderá inspecionar visualmente o fluxo de dados e reconhecer os valores onde eles devem estar e a falha será encontrada dessa maneira, embora não tão facilmente. ou seja, você reconhecerá os padrões de bytes e os valores esperados

Madivad
fonte
2

Em vez de Modbus, considere o HDLC . Você recebe a detecção de erros (o que é importante em linhas seriais barulhentas). A sincronização é robusta, o escape é robusto.

Eu usei o HDLC em redes RS-485 sem problemas e o PPP também o usa.

teambob
fonte
2
Seria bom se você indicasse por que o sugere no Modbus.
Eu não tenho idéia do que estou fazendo
1

O ASCII sobre o UART é o mais popular em parte porque:

  • É legível por humanos durante a depuração (ainda não vi um analisador lógico que não decodifique o ASCII).

  • É muito fácil de implementar, você tem uma tabela ASCII via google rápido e bem padronizada.

  • Ele foi incorporado na sincronização com os bits de início / parada.

  • Praticamente todo o mundo do hobby estabeleceu-se com ASCII sobre serial, então quaisquer novos métodos terão que lidar com isso, e isso não é fácil de forma alguma.

Em seguida, você entra em uma situação em que começa a enviar codificação específica, como enviar a representação na memória de um float em comparação com a conversão de um float para ASCII, envia-o por serial que pode ter mais de 4 bytes e depois converte-o novamente para uma representação na memória no host. Em vez disso, basta enviar a representação de 4 bytes sempre. Claro, você pode começar a manipular a codificação por conta própria, mas precisará configurar tags de início / fim, pedido etc.

Em vez disso, coisas como Protobuf podem ser usadas. Na verdade, isso foi usado em um projeto no qual eu estava trabalhando e foi extremamente benéfico, ele envia mensagens de tamanho variável, manipula endian para você e alguns outros recursos interessantes. Também não é tão grande no tamanho do código, e você pode especificar tudo a ser alocado estaticamente na inicialização. Você teria que inserir a soma de verificação, se necessário.

hak8or
fonte