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?
microcontroller
serial
communication
uart
protocol
Não faço ideia do que estou fazendo
fonte
fonte
Respostas:
ASCII e CRC não são mutuamente exclusivos. ASCII é uma codificação e CRC é para verificação de erros.
Qualquer coisa pode ser enviada como ASCII. Nós, velhos, certamente lembramos de UUEncoding, que transforma qualquer coisa em uma string ASCII.
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).
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.
fonte
Aqui estão alguns pensamentos sobre isso:
fonte
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.
fonte
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).
fonte
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.
fonte
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
fonte
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.
fonte
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.
fonte