Como um Arduino pode emitir uma frequência portadora específica (ou seja, 56 kHz)?


9

Estou trabalhando em um projeto de óptica de espaço livre para enviar dados sem fio entre dois pontos. Para fazer isso, estou usando um LED IR conectado a um Arduino Uno que pulsa com uma frequência portadora de 56 kHz para o transmissor e um segundo Arduino com um módulo detector de 56 kHz IR para o receptor.

Tentei usar delayMicroseconds () entre os comandos pin high e pin low para criar a frequência da portadora. Isso funciona, mas a frequência nem sempre é a mesma e atrasos adicionais para pulsar o sinal (ou seja, o tempo necessário para chamar a função e diminuir) podem alterá-lo.

Lendo a folha de dados do ATmega328, parece que há uma maneira de definir um pulso mais preciso usando os temporizadores do chip. Isso é possível? Em caso afirmativo, como você cria um pulso de 56 kHz usando os temporizadores?


Qual é a precisão que você precisa para sua frequência de 56KHz? Ou seja, qual faixa de frequência é aceitável no seu projeto? Eu pergunto porque, usando os temporizadores do Arduino, a precisão tem limitações.
Jfpoilpret

55,5khz a 56,5khz seria ideal para manter um alto nível de responsividade no detector.
jlbnjmn

Respostas:


10

É realmente possível gerar um sinal de 56 kHz com um timer Arduino .

Na verdade, um timer pode ser visto como um registro especial, no MCU, que possui um valor (começando em 0) que é incrementado em uma frequência que é a freqüência do clock do MCU (16 MHz no Arduino Uno), possibilidade dividida por um fator chamado prescaler . Quando esse valor atinge um limite, chamado Compare Match , que você especifica, duas coisas acontecem:

  • O valor do registro do timer é redefinido para 0.
  • Uma função de retorno de chamada ISR (rotina de interrupção do serviço) é chamada (você pode defini-la para apontar para seu próprio código).

A idéia é usar esse ISR para alterar a saída de um pino lógico toda vez que for chamado ( HIGH, então LOW, então HIGH...).

Agora, para gerar uma onda quadrada de 56 kHz, você precisará que seu ISR seja chamado 56000 * 2vezes por segundo ( * 2porque você precisa alterar o valor da saída duas vezes por período).

Você pode escolher o valor do pré-calibrador que deseja para um timer entre as seguintes listas:

  • 1 (a frequência do relógio não é dividida, portanto, 16 MHz)
  • 8 (a frequência do relógio é dividida por 8, daí 2 MHz)
  • 64
  • 256
  • 1024

Existem dois tamanhos de temporizadores / contadores no Arduino Uno ( na verdade , são chamados de temporizador / contador ): 8 bits e 16 bits.

No Arduino Uno (ATmega328P), você tem três timers em geral, mas alguns podem ser usados ​​pela biblioteca principal do Arduino ou por outras bibliotecas usadas em seus esboços (você precisará verificar isso sozinho):

  • timer0 (8 bits)
  • timer1 (16 bits)
  • timer2 (8 bits): este possui mais opções de pré-dimensionamento (1, 8, 32, 64, 128, 256 e 1024)

Agora você precisa gerar uma onda de 56 kHz a partir de 16 MHz, portanto, sem pré-escala, você precisará contar para:

16000000 / (56000 * 2) - 1 = 141.857( - 1porque um cronômetro conta de 0 a esse valor e redefine somente depois de atingido)

A partir deste cálculo, podemos desenhar duas observações:

  1. 141.857 não é um número inteiro e, portanto, você não poderá gerar uma onda de exatamente 56 kHz.
  2. Sem pré-escala, você precisa de um timer de 16 bits, pois 285 não é representável como um número inteiro não assinado de 8 bits.

A partir de agora você tem duas opções:

  1. Use um cronômetro de 16 bits ( timer1 ), use prescaler = 1 e selecione 142como Compare Match; que lhe dará a seguinte frequência:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Use um cronômetro de 8 bits ( timer0 ), use prescaler = 8 e selecione 17como Comparar Comparar; isso fornecerá menos precisão com a seguinte frequência: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hzque ainda está dentro da faixa necessária.

Agora, sobre como escrever seu esboço para isso, recomendo que você verifique este manual que é muito completo e muito interessante de ler.

Obviamente, a folha de dados completa do ATmega328P também é importante se você quiser entender, nos mínimos detalhes, o que está fazendo.

Algumas notas importantes:

  • Um ISR é executado com interrupções desativadas e, portanto, deve ser o mais curto possível. Em particular, existem várias funções da biblioteca do Arduino que não devem ser chamadas de um ISR.
  • O relógio do Arduino Uno não é muito preciso (ele usa um ressonador de cerâmica em vez de um quartzo, o que seria muito mais preciso), portanto, isso significa que a frequência de saída mudará ainda mais.

2
Além disso, quando o limite especificado é atingido, o hardware pode alternar um pino. Portanto, não há necessidade de usar ISRs. Sempre haverá tremulação com um ISR porque uma instrução não pode ser interrompida depois que ela é iniciada. No entanto, o hardware sempre alterna o pino na taxa desejada.
Nick Gammon

É um tanto surpreendente que o Arduino Uno use um ressonador de cerâmica, mas uma fonte para isso é o Arduino UNO FAQ (próximo a "O Uno usa um ressonador ou um cristal para o relógio do processador?" ).
Peter Mortensen

3

Eu achei tone()útil para gerar pulsos de alta frequência em qualquer pino. Deve ser capaz de lidar com 56 KHz. (Edit: Como observado por jfpoilpret, o mais próximo que você pode realmente chegar de um Arduino de 16 MHz é de cerca de 55,944 KHz)

Obviamente, a dificuldade será combiná-lo com o seu sinal de dados. Eu não acho que você poderia fazer isso em software sem recorrer a códigos de baixo nível. No entanto, deve ser bem fácil no hardware, pois é digital.

Tudo o que você precisa fazer é emitir seu sinal de dados em um pino diferente e depois combiná-lo com a operadora usando uma porta AND. O sinal combinado pode ir direto para o seu transmissor IR.

Se você não tem um portão AND à mão, é muito simples criar o seu próprio usando um par de transistores. Basta pesquisar on-line por "transistor e porta".


Os receptores geralmente têm saídas baixas ativas em geral. Se você conectar a parte superior do LED aos 56khz e a parte inferior ao pino de dados, quando o pino de dados ficar baixo, você obtém uma saída de infravermelho, o que deve fazer o receptor ficar baixo. Não e portão necessário, apenas um led e resistor. O único problema está sendo limitado a quaisquer pinos io atuais que possam ser acionados.
EternityForest

2

A resposta aceita pelo jfpoilpret é muito bem escrita, perfeitamente válida e em 99% dos casos farei exatamente o que ele explica. As soluções dele estão dentro dos parâmetros definidos, portanto, devem funcionar muito bem. Mas o que é melhor do que " muito bem "? Perfeição! Afinal, a questão é gerar um valor exato. Como dito perto o suficiente, é bom na maioria dos casos (sem dúvida todos), e mesmo ao lidar com algo como um relógio quando 1 segundo precisa ser 1 segundo, você ainda precisa sofrer imperfeições nas partes herdadas.

O que vou sugerir nem sempre é possível. Em alguns casos, é possível, mas com muito mais trabalho e esforço do que neste caso. Vale a pena depender caso a caso. Meu objetivo é mostrar principalmente uma alternativa para futuras referências que é melhor em casos um tanto marginais. Isso foi escrito tendo em mente os usuários iniciantes do Arduino que não possuem uma vasta experiência em eletrônica.

Para pessoas mais avançadas, isso provavelmente parecerá muito detalhado e embotado. Mas acredito que essas mesmas pessoas provavelmente já sabem disso e não precisam dessa resposta. Isso também é aplicável a todos os microcontroladores, fabricantes e arquiteturas. Porém, para outros microcontroladores, você precisará consultar a folha de dados correta para descobrir os registros adequados e os nomes e valores de pré-escala.

No seu caso, você precisa de uma frequência específica e o mais interessante é que exatamente 56 kHz podem ser alcançados com muita facilidade (sem contar as imperfeições práticas das partes). Portanto, este também é um exemplo perfeito.

A geração de um sinal depende dos temporizadores e da fonte de clock do microcontrolador, conforme explicado pelo jfpoilpret. Sua resposta lida com o problema de apenas um ponto de vista e que está mexendo com temporizadores. Mas você também pode mexer com a fonte do relógio ou, melhor ainda, com sinergia e resultados impressionantes. Alterando os parâmetros do ambiente, neste caso invadindo o sistema e substituindo a fonte do relógio, podemos lidar com um problema específico com muito, muito mais facilidade e simplicidade.

Primeiro, para lembrar, devido à alternância do estado do pino, você precisa executar o ISR duas vezes mais que a frequência do sinal. Isso é 112.000 vezes por segundo. 56.000 e 16.000.000 não somam muito bem, como já apontado. Precisamos mudar a frequência do sinal ou a frequência do tato. Vamos lidar agora com uma frequência de sinal imutável e encontrar uma melhor velocidade de clock.

Seria mais simples escolher um relógio com uma ordem de magnitude maior que 56 kHz (ou 112 kHz, mas é praticamente o mesmo), pois você só adiciona zeros e esse tipo de matemática é mais simples para a maioria das pessoas. Infelizmente, tudo neste mundo é algum tipo de compromisso com alguma coisa. Nem todo valor vai funcionar.

O primeiro exemplo é com uma velocidade de gerador de tato muito baixa.

Se você escolher um relógio de 56.000 Hz, não poderá fazer nada, pois precisará ligar para o ISR a cada ciclo e não poderá fazer mais nada. É totalmente inútil. Se você escolher uma velocidade 10 vezes mais rápida (560 kHz), você terá 9 (10 ciclos para o temporizador atingir seu valor máximo - um ciclo para chamar a função ISR) ciclos de microcontrolador para fazer seu trabalho, e isso é possível e pode não ser suficiente. Você simplesmente precisa de mais poder computacional.

Se você escolher um valor muito alto por outro lado, como 56 MHz, o microcontrolador simplesmente não pode trabalhar com ele. É muito rápido. Portanto, simplesmente escolher o maior valor na loja também não será suficiente.

O Arduino Uno R3 original tem um relógio de estoque em 16 MHz, portanto, qualquer coisa mais lenta do que é garantida que funcione. O próximo valor que é uma ordem de magnitude maior que 56 e menor que 16 MHz é 5,6 MHz. Isso fará com que seja possível ligar para o ISR a cada 50 ciclos e criará a frequência de timer perfeita de 112.000 Hz. E seu sinal será exatamente 56 kHz. Você terá 49 ciclos de MCU para executar seu programa entre chamadas ISR, mas ainda é cerca de 1/3 da velocidade do relógio original. Pode-se usar 112 como base e usar um relógio de 11,2 MHz e isso dará cerca de 2/3 do ressonador de 16 MHz. A função ISR será chamada a cada 100 ciclos e ainda gerará um sinal perfeito de 56 kHz.

No entanto, existem dois grandes problemas com esses valores.

  • O primeiro problema depende muito de suas necessidades: Você sacrifica cerca de 1/3 (com 11,2 MHz) de sua potência computacional máxima para obter a frequência exata do sinal que usa um valor de registro fácil de encontrar (OCR iirc ). Você pode ficar bem com isso ou não.

  • O segundo problema é muito difícil : é muito fácil encontrar valores, mas muitas vezes eles simplesmente não existem como uma fonte de relógio fabricada. Esta é a página ressonadora da Farnell que simplesmente não possui 5,6 MHz e 11,2 MHz.

Para contornar isso, podemos examinar os valores disponíveis do ressonador e descobrir outra coisa que pode ser usada para gerar exatamente os valores desejados. Se dividirmos 56 por 4, obtemos 14 e, felizmente, existe um ressonador de 14 MHz. Isso nos fornece uma velocidade muito mais alta, mais potência e um valor de registro igualmente fácil de encontrar. Para chamar o ISR 112.000 vezes por segundo, precisamos colocar o valor decimal 124 ou hexadecimal 0x7C no registro OCR, portanto, contando 124 ciclos + 1 para chamar o ISR, obtemos o valor perfeito desejado.

NB

  1. ISR - rotina de serviço de interrupção (este é o código que é executado apenas nas interrupções geradas)
  2. O tamanho do seu programa depende do tamanho da memória! Não tem nada a ver com a velocidade do relógio e nada com a frequência com que você liga para o ISR.
  3. Quando o microcontrolador inicia com o comando do programa, um contador é incrementado. Se uma interrupção for gerada, o ISR é chamado e esse valor é armazenado em um registro especial. Quando o código ISR é concluído, o valor do contador de programa é restaurado a partir desse registro especial e o programa continua de onde foi interrompido como se nunca tivesse acontecido.

    Vou dar um exemplo extremamente estúpido. Se você é purista, eu o aviso: pode ocorrer sangramento no nariz e nos olhos.

    Imagine que você tem que andar de algum lugar para outro lugar. As instruções da rota passo a passo são o seu programa principal e seus comandos. A rapidez com que você anda ou corre depende da sua "velocidade do relógio", mas não das instruções da rota (30 passos à frente, 1 volta 90 graus à esquerda, 10 passos à frente, 45 graus à direita, etc.). Eles são sempre os mesmos . Agora imagine uma criança ou um político local ganancioso e corrupto desamarrar seus sapatos de vez em quando. Este é o evento que gera uma interrupção. Então você pára após o último passo, ajoelha-se e amarra o sapato novamente. Este é o seu programa ISR.

    Então você continua do lugar em que parou; você não começa do começo. Quando você anda sem se importar com o mundo e com o tempo todo, não se importa, mesmo que tenha que amarrar o sapato a cada dois passos. No entanto, se você fizer isso com restrições de tempo, como correr 100 metros nas Olimpíadas (ou correr contra um predador faminto de comer carne), parar e amarrar os sapatos pode ter consequências terríveis. O mesmo acontece com os microcontroladores. Mesmo se você executar apenas uma linha de código, seu programa continuará, embora lento. Se você não se importa com velocidade, não será um problema. Se você precisar dedicar algum tempo, como usar outras ações dependentes do timer, a interferência pode ser muito indesejada e problemática.

  4. Menos é mais! Um relógio mais rápido nem sempre é melhor. Dispositivos com clock mais lento usam consideravelmente menos energia. Esse pode ser um ponto crucial em um dispositivo operado por bateria.

  5. Os ciclos necessários são derivados destas fórmulas:
    (velocidade do relógio / (valor do pré-calibrador * frequência de chamada ISR necessária)) - 1


TLDR: Dessolda o oscilador de 16 MHz em cerâmica e substitui-o por outro que permita exatamente 56 kHz por divisão inteira (por exemplo, 14 MHz e divida por 250).
Peter Mortensen

0

Você pode ativar e desativar o suporte simplesmente alternando o modo de pinos do suporte entre saída e entrada. Eu usei isso para controlar uma bomba de calor através da porta de infravermelho de 37KHz (controle remoto).


0

Não há necessidade de usar um ISR para criar a transportadora. Basta configurar um temporizador para produzir uma saída PWM de 50% na frequência da portadora necessária. O ISR fica encarregado de modular a transportadora - normalmente em intervalos de 0,5 ou 1ms - uma taxa muito mais confortável. Na minha experiência, um erro de 5% na frequência da portadora é tolerado pela maioria dos receptores de infravermelho. Usei um Freetronics EtherMega 2560 (que possui muitos temporizadores), mas tenho certeza que outras CPUs farão o mesmo.


Como exatamente a modulação da transportadora é implementada? Alterar o modo do pino de captura da saída do timer entre a entrada (portadora desativada) e a saída (portadora ativada)?
Peter Mortensen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.