Índice:

Enviar dados numéricos de um Arduino para outro: 16 etapas
Enviar dados numéricos de um Arduino para outro: 16 etapas

Vídeo: Enviar dados numéricos de um Arduino para outro: 16 etapas

Vídeo: Enviar dados numéricos de um Arduino para outro: 16 etapas
Vídeo: Como fazer um dado eletrônico #ManualMaker Aula 5, Vídeo 2 2024, Novembro
Anonim
Envie dados numéricos de um Arduino para outro
Envie dados numéricos de um Arduino para outro

Introdução

por David Palmer, CDIO Tech. na Aston University.

Você já precisou enviar alguns números de um Arduino para outro? Este Instructable mostra como.

Você pode facilmente testar se funciona simplesmente digitando uma string de números para enviar no terminal Serial Monitor e ver os números voltando em um segundo monitor Serial conectado ao segundo Arduino. Você pode até usar um link Bluetooth.

O que faz

Dois programas Arduino (sketches na linguagem Arduino) precisam ser desenvolvidos, um programa Master para conectar ao computador host que executa o Arduino Serial Monitor, outro para atuar como Slave para receber a mensagem serial do Master, decodificá-la e enviá-la de volta. O escravo é opcionalmente capaz de exibir os números com os quais está lidando em um segundo monitor serial do IDE - apenas no caso de você querer usá-lo. Pode ajudar a fazer as coisas funcionarem em primeiro lugar e ajudá-lo se você decidir fazer quaisquer alterações nos programas para atender às suas próprias necessidades.

Equipamento

  • 2 Arduino's
  • 2 cabos USB
  • patch Wire (conforme necessário)
  • 1 PC / laptop carregado com Arduino IDE (disponível como download gratuito no site Arduino.cc)

Etapa 1: Configuração - Configure o seu hardware primeiro

Configurando - Configure Seu Hardware Primeiro
Configurando - Configure Seu Hardware Primeiro
Configurando - Configure Seu Hardware Primeiro
Configurando - Configure Seu Hardware Primeiro

Conecte os 2 Arduinos em 2 portas USB em seu computador.

Dica, é uma boa ideia rotulá-los como M e S (mestre e escravo) para não se complicar mais tarde (como mostrado nas 2 fotos aqui).

Etapa 2: Configurando - Defina sua tela

Configurando - Defina sua tela
Configurando - Defina sua tela

A melhor coisa é configurar sua tela para que você tenha

  • o IDE carregado com o programa Master à esquerda e
  • isso com o Slave à direita.

Mantenha os monitores seriais para Maser e Slave à esquerda e à direita também, conforme mostrado na captura de tela aqui.

Etapa 3: configurar a extremidade principal e, em seguida, conectar-se - Parte 1

Configure a extremidade principal e, em seguida, conecte-a - Parte 1
Configure a extremidade principal e, em seguida, conecte-a - Parte 1

Ao configurar o Master End Serial Monitor para enviar dois números, você deve sempre usar os caracteres delimitadores de início e fim e o caractere separador de vírgula, conforme mostrado aqui.

Agora você precisa conectar os 2 Arduinos em série. Isso é feito com dois fios de remendo.

Usei verde e amarelo

  • Pegue o amarelo primeiro, ele deve se conectar ao D6 em um Arduino e ao D7 no segundo
  • Depois, o oposto para o fio verde, D7 no primeiro e D6 no segundo Arduino.

Como alternativa, se você tiver algo disponível como um par de módulos Bluetooth - como o HC-05 - eles também funcionarão para fornecer exatamente o mesmo efeito que os fios acima.

Etapa 4: configurar a extremidade principal e, em seguida, conectar-se - parte 2

Configure a extremidade principal e, em seguida, conecte-a - Parte 2
Configure a extremidade principal e, em seguida, conecte-a - Parte 2
Configure a extremidade principal e, em seguida, conecte-a - Parte 2
Configure a extremidade principal e, em seguida, conecte-a - Parte 2

Estamos fazendo uso da biblioteca serial do software. Mais informações estão disponíveis neste link

Você pode vê-lo chamado na linha 7 de qualquer um dos programas. Ele configura os pinos digitais 7 e 6 como TX e RX (transmitir e receber). É assim que os dados viajarão do Arduino mestre através do fio verde para o escravo e, quando o programa Slave no segundo Arduino terminar seu trabalho, de volta pelo fio amarelo. Na parte inferior da mesma ilustração (na janela Serial Monitor), você pode ver que os dados que transmitimos agora percorrem com sucesso o loop descrito aqui e voltam para o PC como o par de inteiros bem separados.

Etapa 5: Visão geral dos esboços / programas - Estrutura do programa

Visão geral dos esboços / programas - Estrutura do programa
Visão geral dos esboços / programas - Estrutura do programa
Visão geral dos esboços / programas - Estrutura do programa
Visão geral dos esboços / programas - Estrutura do programa

Layout Como em todos os esboços do Arduino, existem 3 partes básicas:

  • As declarações
  • A configuração
  • O loop principal

Como sempre ocorre, usamos aqui uma 4ª seção que é a adição de 'Funções'. Se não estiver familiarizado com o uso de funções, você pode pesquisar "funções do Arduino" no Google e encontrará sites de explicação como o exemplo neste link: www.tutorialspoint.com/arduino/arduino_functions…..

Também usamos guias para separar o programa em blocos mais gerenciáveis.

Os três blocos que usamos podem ser vistos na parte superior de cada ilustração das janelas IDE acima:

  • simpleRxTx0330Master
  • comum
  • notas

Na verdade, são arquivos separados dentro da pasta do programa, como você pode ver nesta visualização do Windows Explorer dos arquivos do programa Slave.

Há uma razão muito boa para termos feito isso.

  • Conforme estávamos construindo o programa, percebemos que a maior parte do programa para o Mestre era igual ao do Escravo.
  • Acabamos colocando todas as partes comuns em uma guia, que chamamos de "comum" e, em seguida, cada vez que depurávamos uma parte (testávamos e ficávamos satisfeitos se funcionava bem), apenas copiamos e colamos toda a guia de Master para Slave, ou vice-versa.
  • As guias de notas também são idênticas, pois o design é genérico.

Nenhuma das funções é chamada a partir da configuração, todas são chamadas a partir do loop, portanto, as criamos após a configuração, mas antes do loop.

Etapa 6: Design de cima para baixo

É uma boa ideia projetar seu esboço começando com uma definição do que você deseja fazer.

Assim que tiver isso, você pode começar a fazer o esboço fazer essas coisas. Geralmente, se houver um detalhe que você ainda não sabe fazer, basta torná-lo uma função e deixar a criação da função para mais tarde.

Isso segue a filosofia de bom design, ensinada em muitas universidades, chamada CDIO (se você ainda não conhece este, pode pesquisar no Google e encontrar sites para explicá-lo como: https://www.cdio.org/s.) Basicamente, isso diz: Não inicie o Design antes de entender o conceito. Não comece a implementação até que você tenha o design claro. Não espere que ele opere antes de ter a implementação clara. C primeiro, depois D, I e O. Em cada estágio subsequente, você itera (volte em volta do (s) loop (s), então, quando estiver satisfeito com seu loop inicial de Design, verifique se ele ainda atende ao Conceito e atualize o C se você precisar. E assim por diante, então mesmo quando você tiver operado, volte ao topo e novamente veja como o C está agora, então o D e I, e faça e verifique todos Com os esboços de programação, isso funciona da mesma forma se você projetar de cima para baixo.

Etapa 7: Conceito e Design - Parte 1

Conceito e Design - Parte 1
Conceito e Design - Parte 1
Conceito e Design - Parte 1
Conceito e Design - Parte 1

O conceito aqui se parece com os requisitos básicos declarados na guia 'notas'. '

O Design pode se parecer com uma versão inicial do loop, que corresponde à guia de notas e pode ser parecido com o que você vê nesta figura

Veja como eu gosto de começar copiando primeiro CTRL-C os comentários para o cabeçalho do loop, e então começar a preencher os espaços em branco com comandos que farão essas coisas.

Isso realmente compila bem, como você pode ver na parte inferior da tela na figura. Isso vai do estágio D ao I do CDIO e, à medida que desenvolvemos o código, é uma boa ideia continuar percorrendo esse loop D-I.

Agora é hora de descer para o próximo estágio, há um comentário lá que diz que vamos: // receber algo do hardware USB, então vamos transmitir isso para o canal serial do software. Escrevemos este código para que isso aconteça - linhas 133 a 138 mostradas aqui em marcador amarelo

Etapa 8: Conceito e Design - Parte 2

Conceito e Design - Parte 2
Conceito e Design - Parte 2
Conceito e Design - Parte 2
Conceito e Design - Parte 2

As duas primeiras funções que apresentamos aqui são (recv () e tran () para fazer a recepção da porta de hardware e a transmissão para a porta de software - portanto, chamando-as com os parâmetros 'hw' ou 'sw' mostrados.

Além deles, adicionamos um teste em uma variável global chamada newData. Este é um sinalizador que definiremos dentro da função "void recv ();". Quando uma mensagem é recebida, essa variável é sinalizada de falsa para verdadeira. Fazemos isso para que apenas transmitamos uma mensagem se ela tiver sido recebida (sinalizador == verdadeiro) na linha 134. E, uma vez que transmitimos nossa mensagem, está "trabalho feito", então limpamos o sinalizador de volta para falso novamente na linha 137.

Novamente, podemos verificar a compilação (D para I) e, desta vez, temos uma mensagem de erro 'não declarada' (mostrada). Isso está nos dizendo que não declaramos o recv (); função. Planejamos fazer isso mais tarde, então apenas por agora, para nos permitir obter uma compilação limpa, precisamos criar uma função fictícia ou de espaço reservado, como mostrado a seguir.

Novamente podemos verificar a compilação (D para I), e desta vez temos outra mensagem de erro 'não declarada' para o tran (); função. Isso precisa de uma criação de stub semelhante. Mais uma vez, podemos verificar a compilação (D para I) e, desta vez, descobriremos que funciona perfeitamente; até agora tudo bem.

Etapa 9: Concluir o loop principal: A) Recebendo do USB, B) Recebendo do Slave Arduino

Conclua o loop principal: A) Recebendo do USB, B) Recebendo do Arduino Slave
Conclua o loop principal: A) Recebendo do USB, B) Recebendo do Arduino Slave
Conclua o loop principal: A) Recebendo do USB, B) Recebendo do Arduino Slave
Conclua o loop principal: A) Recebendo do USB, B) Recebendo do Arduino Slave

Há uma peça final que adicionamos para finalizar esta parte, que é adicionar algum código de depuração.

Há outro Instructable sobre depuração de esboços que pode ser consultado para entender o que fizemos aqui e por quê. Consulte o instrutivo "Como construir e testar esboços do Arduino até que funcionem"

Portanto, essas linhas de depuração [136-139 mostrado] são adicionadas a seguir no loop principal e, vejam só, você pode testá-las na extremidade Master tornando a variável de depuração verdadeira e Compilando (I), então se você conecta um Arduino, você pode fazer o upload, abrir o Serial Monitor e ver se o que volta para o Serial Monitor é como mostrado aqui (você vê a mensagem "DEBUG MODE" adicionada?)

Etapa 10: Recebendo e manipulando os dados no Slave Arduino

Recebendo e manipulando os dados no Slave Arduino
Recebendo e manipulando os dados no Slave Arduino
Recebendo e manipulando os dados no Slave Arduino
Recebendo e manipulando os dados no Slave Arduino

Recebendo do Slave Arduino

Adicione o código necessário para o segundo canal ao loop principal, o receptor serial do software, conforme mostrado - linhas 149 a 155.

Você pode ver que a estrutura é vagamente baseada no que escrevemos acima para o caso Master?

Além disso, você verá que obtemos um erro do compilador, outra função não declarada - desta vez parseData (); - então precisamos fazer um esboço para isso também, antes de podermos executar uma compilação de teste sem erros.

Manipulando os dados no Slave Arduino

Adicione o código de loop principal necessário para o Arduino se ele estiver configurado como um dispositivo Slave, conforme mostrado - linhas 163 a 174. Você pode ver que a estrutura dele é muito semelhante à do primeiro canal?

E você deve descobrir que desta vez ele compila perfeitamente.

Etapa 11: escrever a função de recepção

Escreva a função de recepção
Escreva a função de recepção

A função Receber - void recv (char de) {} - tem duas tarefas principais.

1 para receber uma sequência de caracteres do canal USB e

2 para receber um do canal Arduino para o Arduino.

Para o primeiro, precisaremos usar porque ele usa o UART de hardware integrado do Arduino e, para o segundo, usando a biblioteca padrão do Arduino: software UART.

Quando começamos a adicionar código a uma função - para criar uma função que faz algo, em vez de apenas um esboço - precisamos nos lembrar de remover ou comentar o esboço que está substituindo. Caso contrário, obteremos um erro de compilação: refefintion of 'void lrec (char)'.

Tente obter o erro e, em seguida, tente uma das maneiras sugeridas acima para se livrar dele.

Comece com uma função que se pareça com aquela que mostramos aqui nas linhas 75 a 88 em amarelo.

Agora você sabe que, tendo o código, você precisará tentar a operação Compile. Obtém um erro, como os anteriores, do tipo: nome da função não declarado neste escopo. Vamos precisar inicialmente de outro stub para nos permitir compilar após este erro, então adicione um como antes e certifique-se de que agora você pode obter uma compilação sem erros.

Agora vamos dar uma olhada no código que escrevemos para a função recv ().

É bastante limpo, você pode ver o uso da condição 'se' para produzir as duas partes da função mencionada acima.

O código dentro da parte 'sw' e da parte 'hw' é da mesma forma, e vou descrevê-lo aqui.

O primeiro do par de linhas em cada caso é o início de um loop while. Se você não estiver familiarizado com os while's, pode procurá-los no site Arduino.cc/Reference para obter explicações e exemplos. Aqui, esperamos 'enquanto' a função embutida 'Serial' não recebeu nenhum caractere (s) e porque a variável newData foi desligada (ou seja, a condição newData == false é verdadeira). Assim que um caractere - ou mais de um caractere - for recebido, o tempo 'passará' para a segunda linha neste par. Isso irá então chamar o recAstringChar (char); função para lidar com o caractere atual. Este par de linhas se alternará enquanto (ou enquanto) houver caracteres que ainda precisam ser recebidos. Assim que todos estiverem concluídos, o estado while termina, permitindo que o próximo nível if ou else chegue ao fim e, por sua vez, permitindo o rec (char); função até o fim. Assim, uma mensagem completa foi recebida.

Etapa 12: Escreva a subfunção de recepção - Parte 1

Escreva a subfunção de recepção - Parte 1
Escreva a subfunção de recepção - Parte 1
Escreva a subfunção de recepção - Parte 1
Escreva a subfunção de recepção - Parte 1

Agora precisamos escrever a função chamada recAstringChar (char);. Você vê no comentário da linha 50 aqui no topo, que seu trabalho é atualizar dois buffers com cópias da mensagem serial recebida. [Acontece que enquanto eu tentava fazer tudo funcionar, uma coisa que aprendi foi que precisava de dois buffers diferentes - ou pelo menos essa era a maneira mais fácil de contornar alguns problemas, portanto, meio que evoluiu para a necessidade de 2 buffers, então Acabei de criá-los.] Chamei um buffer: receivedData e o outro: receivedChars.

Os buffers são variáveis globais, portanto, são declarados no nível do módulo, consulte as linhas 9 e 10 da guia comum. Existem outras variáveis declaradas dentro desta função que, portanto, têm escopo local - mostrado nas linhas 51-54 aqui. Este não é o lugar para explicar as diferenças entre globais e locais, mas há mais informações sobre isso em https://www.arduino.cc/glossary/en/ em Local e Global.

Você também pode descobrir tudo sobre os tipos de dados e modificadores de tipo: estático, booleano, byte, const, char em https://www.arduino.cc/reference/en/#variables, mostrado aqui.

O fluxo do programa principal nesta função é controlado pelo if na linha 56 aqui, e seu else correspondente na linha 74. Isso lida com dois cenários

a) [da linha 74 em diante] quando a mensagem recebida está começando. Isso acontece quando o startMarker é localizado - isso foi definido como o caractere '<', e é por isso que sempre que testamos o esboço, sempre iniciamos nossa string com esse caractere. Se não o fizermos, nada será processado como recebido, tudo será ignorado, como se estivéssemos digitando algo sem sentido no prompt do teclado 'Monitor serial'.

b) [linhas 56 a 73] que recebe todos os outros caracteres, sejam eles quais forem, mas eles só lidam com caracteres após um início válido ter acontecido (um '>' foi recebido como em a) acima.)

Nessas linhas (de 74 a 78) colocamos o recebido <em um dos buffers (receivedData [0]), mas não no outro. Ajustamos o ponteiro do buffer (variável: char ndx) para apontar para a próxima posição do buffer sobressalente (receivedData [1]) usando o comando pós-incremento (++) na linha ndx ++;, e definimos o sinalizador em andamento como verdadeiro.

O fluxo do programa nesta parte da função é controlado pelo if na linha 57 aqui, e seu else correspondente na linha 65. Isso lida com dois cenários

a) [da linha 65 em] quando a mensagem recebida é encerrada. Isso acontece quando o endMarker é localizado - definido como>, e é por isso que sempre que testamos nosso esboço, sempre terminamos nossa string com esse caractere. Uma das coisas que acontece quando o caractere final é recebido é que o sinalizador global (tecnicamente variável) newData é definido como verdadeiro assim que a função termina, de modo que a função que chamou nossa subfunção (a função de chamada: recv (char);) pode 'saber' que novos dados válidos foram recebidos completos.

b) [linhas 57 a 64] que recebe todos os outros personagens, sejam eles quais forem. Ele apenas os estaciona ordenadamente em fileiras em ambos os amortecedores.

Etapa 13: Escreva a subfunção de recepção - Parte 2

Escreva a subfunção de recepção - Parte 2
Escreva a subfunção de recepção - Parte 2
Escreva a subfunção de recepção - Parte 2
Escreva a subfunção de recepção - Parte 2

Pode ser útil dar um exemplo de como os 2 buffers se parecem quando são preenchidos. Se tivéssemos que digitar enter, os buffers teriam os caracteres mostrados neles:

Portanto, agora você pode ver que temos um buffer que tem exatamente os mesmos caracteres que digitamos primeiro, e um buffer que tem apenas os dois valores e uma vírgula de separação. Agora que temos algum código que pode receber os caracteres que digitamos no teclado do Serial Monitor, podemos passar da fase I do CDIO para O, digitando algumas strings e vendo o que acontece. Faça upload do código para o Arduino Master, abra o Serial Monitor e tente digitar algo válido, como enter. Você recebe um eco na tela Serial Monitor como a mostrada aqui?

Etapa 14: escrever as funções de transmissão e análise

Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise

Primeiro para a transmissão

Agora que recebemos uma string, podemos escrever a função de transmissão: tran (char); para substituir seu esboço. Isso nos permitirá enviar uma string do Master para o Slave Arduino, portanto, certifique-se de que ambos os dispositivos estejam plugados e conectados juntos para testar esta nova funcionalidade.

Insira esta função conforme mostrado aqui nas linhas 117 a 133. Como você reconhecerá, ela tem duas partes, uma para transmitir para o canal USB (hardware UART) e outra para transmitir para o outro Arduino (software UART). -gratuito, e você pode carregar imediatamente o esboço e ver o que acontece. Desta vez vou enviar. Você consegue o resultado mostrado?

A captura de tela é interessante porque a string Recebida … deve parecer correta como antes, e a string Transmitida … agora deve estar correta. No entanto, observe que a conversão de inteiro não funcionou. Ainda há um pouco mais de código a ser adicionado para que isso funcione.

Etapa 15: escrever as funções de transmissão e análise

Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise
Escreva as funções de transmissão e análise

Então, para o Parse

Este é um trecho de código que analisa a string recebida para buscar as strings parciais numéricas e as converte em valores inteiros. É o void parseData (); função do loop principal

Substitua o stub de análise pelo código mostrado nas linhas 98 - 113. Faça o upload e vamos ver se o problema que estávamos tendo com os 2 valores inteiros foi corrigido. Vamos tentar.

Sim, funciona, conforme mostrado, os inteiros encontrados são 49 e 98.

Etapa 16: Final

Final!
Final!

Esses dados percorrem o circuito do PC, passando pelo Master, passando pelo escravo, e voltando pelo Master novamente para o PC. Com a versão final do common carregado nas extremidades Master e slave, e com o modo de depuração desativado agora, podemos ver os dados recebidos corretamente em ambas as extremidades, conforme mostrado aqui.

Recomendado: