Função de número aleatório do Arduino. Geração de números aleatórios em microcontroladores

10.09.2021

randomSeed(semente)

Define o valor, ou semente, como ponto de partida para a função random().

randomSeed(valor); // define 'valor' como o valor aleatório inicial

Como o Arduino não pode gerar números verdadeiramente aleatórios, randomSeed permite colocar uma variável, constante ou outra função na função aleatória, o que ajuda a gerar mais números aleatórios.

números "aleatórios". Existem muitas sementes ou funções diferentes que podem ser usadas nesta função, incluindo millis(), ou mesmo analogRead() para ler ruído elétrico através de um pino analógico.

aleatório (máx.)

aleatório (mínimo, máximo)

A função aleatória permite retornar um número pseudoaleatório dentro do intervalo especificado pelos valores mínimo e máximo.

valor = aleatório(100, 200); // define 'valor' como aleatório

//um número entre 100 e 200

Observação: Use isto depois de usar a função randomSeed(). O exemplo a seguir cria um número aleatório entre 0 e 255 e gera o PWM

sinal para a saída PWM igual a um valor aleatório:

intNúmero aleatório; //variável para armazenar um valor aleatório

LED interno = 10; //LED com resistor no pino 10

void setup()() // configuração não é necessária

randomSeed(milis()); // define milis() com o número inicial

NúmeroRand = aleatório(255); // número aleatório de 0 a 255 analogWrite (led, randNumber); // saída do sinal PWM

atraso(500); //pausa por meio segundo

Fonte: Gololobov V. – Onde começam os robôs. Sobre o projeto Arduino para crianças em idade escolar (e não só) – 2011

Postagens relacionadas

Serial.begin (taxa) Abre a porta serial e define a velocidade para transferência de dados serial. A taxa de transmissão típica para comunicações de computador é 9.600, embora outras velocidades sejam suportadas. void setup() (Serial.begin…….

Todas as variáveis ​​devem ser declaradas antes de serem usadas. Declarar uma variável significa definir o tipo de seu valor: int, long, float, etc., atribuir um nome exclusivo à variável e, adicionalmente….

Ok, instalamos este programa. Depuramos o “mecanismo” de trabalho com o módulo. E vimos vários exemplos. Mas eu gostaria de criar algo útil sozinho. Vamos tentar. Primeiro, vamos fechar o projeto anterior. Por esta…….

Atenção! Ao trabalhar com Módulo Arduino Em outros ambientes de desenvolvimento, deve-se ter cuidado com a configuração do microcontrolador (Fuses). Até que você saiba exatamente a que a mudança pode levar….

Tempo e aleatoriedade. Reação

Desta vez aprenderemos o que são valores “Aleatórios” e também como trabalhar com o tempo.

Precisaremos de:

  • Botão tato
  • Guinchador
  • Fios de conexão “MACHO-MACHO”

Reação

Nossa tarefa de hoje é montar um diagrama que nos permita descobrir a velocidade da nossa reação.

Quando você clica em botão esquerdo, um sinal soa após um tempo “aleatório”. E quando você pressiona o botão direito, nota-se quanto tempo se passou desde o rangido até o pressionamento do botão direito.

Aqueles que são habilidosos tentam eles mesmos, e nós olhamos o diagrama.

#define BUZ 8 #define START 9 #define STOP 7 int time; //Variável para sincronização void setup() ( Serial. Begin(9600); pinMode(START, INPUT_PULLUP); pinMode(STOP, INPUT_PULLUP); pinMode(BUZ, OUTPUT); ) void loop() ( if(digitalRead(START) == 0) // Quando você pressiona o botão START.. ( int start_time = millis(); // Lembra o horário em que foi pressionado time = start_time; // Escreva em uma variável global. int Rand = random(0, 4000 ); // Vamos gerar um tempo de atraso "aleatório" = time + Rand; //Adicionar o tempo de atraso delay(Rand); digitalRead( START) == 1) // Quando você pressiona o botão STOP... ( int stop_time = millis(); // Lembra o tempo de parada. time = stop_time - time; // Calcula a diferença horária. Serial.println ("Time: "); // Envie o tempo para Serial.println(time); delay(1000) ) // Antes da segunda tentativa, pressione o botão START novamente.

Explicações

interno tempo; As variáveis ​​(não todas), ao denotá-las, não precisam receber nenhum valor. Usamos esta variável para vincular duas instruções if.

Em C++, variáveis ​​declaradas dentro de um loop não estarão disponíveis em outros loops, pois só têm efeito dentro desse loop. Isso é feito para evitar erros de programação. Quando o código do programa crescer, você entenderá do que estou falando.

Para disponibilizar uma variável para múltiplas instruções, você precisa torná-la global. Aqueles. declarar uma variável fora das funções.

milis(); Retorna o número de milissegundos que se passaram desde que o programa foi iniciado.

Precisamos dele para medir a quantidade de tempo que passou desde o sinal dado até o botão ser pressionado.

aleatório(min,máximo); Este é um gerador de números aleatórios. Leva dois valores. Ele gera um número no intervalo de mínimo a máximo.

Números "aleatórios" porque são uma sequência específica de valores. Muito longo, mas o mesmo. Para obter sequências diferentes, você deve usar AleatórioSemente();

Esta função inicializa o gerador. E se definirmos o parâmetro como aleatório, obteremos as sequências de que precisamos. A sequência será a mesma se o parâmetro for fixo.

Conclusão

Agora você pode treinar sua reação usando um dispositivo que você mesmo criou. Ou você pode continuar a estudar mais.

Lista de radioelementos

Designação Tipo Denominação Quantidade ObservaçãoComprarMeu bloco de notas
Placa Arduino

Arduino Uno

1 Para o bloco de notas
Conselho de desenvolvimentoMeia placa de ensaio1 Para o bloco de notas
Emissor piezoelétricoPassiva1 Para o bloco de notas
Botão tatoSem bloqueio2 Para o bloco de notas
Conectando fios"Papai-Papa"1

No Programação Arduino Há momentos em que você precisa obter um número que não será conhecido antecipadamente nem pelo programador que escreve o esboço nem pelo usuário que usará o Arduino com tal programa. Nesse caso, um gerador de números aleatórios (ou melhor, pseudo-aleatórios) vem em socorro.



Para ativar este gerador, basta utilizar as funções random() ou randomSeed(). Este material mostrará como trabalhar com essas funções, bem como se livrar da pseudo-aleatoriedade na geração de números.


Em geral, um gerador de números pseudo-aleatórios simula a aparência caótica ou aleatória dos números, mas, na verdade, se você analisar uma série desses números durante um período suficientemente longo, poderá notar um certo padrão.


Assim, a função aleatória para geração de números pseudoaleatórios pode ter até dois parâmetros e é escrita como random(max) ou random(min, max). Aqui o parâmetro max, que é obrigatório, define o limite superior do intervalo de geração de números pseudoaleatórios. Usando o parâmetro min adicional, você pode definir o limite inferior do intervalo. Como resultado, a função retornará algum número pseudoaleatório no intervalo de mínimo a máximo-1.


É importante entender que ao usar a função random(), exatamente a mesma lista de números pseudo-aleatórios será gerada a cada vez. Por exemplo, se você fizer caça-níqueis, e na primeira vez que você pressiona a alça, uma combinação vencedora aparece, então você pode ter certeza de que se reiniciar o Arduino e pressionar a alça novamente, esta máquina caça-níqueis mostrará a mesma combinação vencedora. Na verdade, não é fácil implementar uma máquina de jogos com geração de números completamente aleatórios no Arduino, como é, por exemplo, implementada em máquinas de jogos www.igrovye-apparati-vulcan.com/, mas você pode resolver parcialmente o problema usando o randomSeed () função.


Esta função recebe um valor (como um número inteiro) e usa o número para modificar a lista aleatória gerada pela função random(). Você pode colocar randomSeed() na função de configuração e usar a função random() em um infinito. laço. Mas mesmo assim, o problema é que, embora a sequência de números aleatórios seja diferente ao usar a função randomSeed(), ela ainda será a mesma sempre que o esboço for executado.


A única solução neste caso pode ser usar periféricos analógicos (ADC) e a função analogRead() correspondente. Se a entrada analógica não estiver conectada a nada, ou seja, deixada “pendurada” no ar, então graças ao ruído nesta linha você poderá obter números verdadeiramente aleatórios. Então em configuração configuração você pode escrever assim: randomSeed(analogRead(A0)). Desde que porta analógica A0 não está conectado em lugar nenhum.

Muito tem sido escrito sobre geradores de números aleatórios, mas quase sempre, quando se trata de implementação, fica implícito (ou explicitamente declarado) que estamos falando de x86/x64 e outras arquiteturas “adultas”. Ao mesmo tempo, fóruns dedicados ao desenvolvimento de dispositivos em microcontroladores estão cheios de perguntas “como posso gerar um número aleatório em %controllername%?” Além disso, a gama de respostas vai desde “olhar no Google/Wikipedia” até “usar a função padrão”. Nem sempre é esse o caso função padrão» existe e é adequado ao desenvolvedor em todos os aspectos, mais frequentemente o oposto: às vezes os números estão longe de ser aleatórios, às vezes a velocidade de operação é muito baixa ou às vezes o código resultante não cabe na memória livre.
Vamos tentar descobrir o que são algoritmos de geração de números aleatórios, como escolher o correto e, o mais importante, quais são os recursos de implementação desses algoritmos em controladores.

Avaliando a "aleatoriedade"

As aplicações do RNG podem ser muito diferentes, desde brinquedos até criptografia séria. Conseqüentemente, os requisitos para o gerador também variam muito. Existem testes especiais para avaliar a qualidade (nível de “aleatoriedade”) do gerador. Aqui estão os mais básicos deles:
  • Teste de frequência. Consiste em contar o número de zeros e uns em uma sequência de bits. Deve haver números aproximadamente iguais de uns e zeros.
  • Teste uma sequência de bits idênticos. Linhas de bits idênticos são pesquisadas, como 000...0 ou 111...1. A distribuição das frequências com que ocorrem as séries, dependendo do seu comprimento, deve corresponder a esta distribuição para um sinal verdadeiramente aleatório.
  • Teste espectral. Aplica-se à sequência original transformada discreta Fourier. O espectro resultante não deve ter picos significativos que indiquem a presença de propriedades periódicas da sequência.
  • Teste de autocorrelação. O valor de correlação entre cópias de sequência deslocadas entre si é calculado. O teste permite encontrar regiões repetidas em uma sequência.
Existem kits especiais que incluem dezenas de testes semelhantes:
NIST – usado na competição AES para avaliar algoritmos de criptografia.
DIEHARD é um dos conjuntos mais rigorosos que existem.

Algoritmos PRNG

Qualquer sequência gerada de acordo com um algoritmo estritamente definido não pode ser considerada verdadeiramente aleatória, portanto, quando se fala em geradores algorítmicos, utiliza-se o termo pseudoaleatório subsequência. Qualquer gerador de números pseudo-aleatórios (PRNG) entrará em loop mais cedo ou mais tarde, a outra coisa é que esse “atraso” pode chegar em alguns milissegundos, ou talvez em alguns anos. A duração do ciclo depende do tamanho do estado interno do gerador N (na verdade, esta é a quantidade de memória necessária ao gerador) e varia de 2 (N/2) a 2 N bits.
Uma grande variedade de algoritmos PRNG foi inventada, mas nem todos são convenientes para implementação em microcontroladores. Estamos severamente limitados em velocidade e memória disponível. Muitos controladores não suportam instruções reais de aritmética ou mesmo de multiplicação. Tendo essas limitações em mente, vejamos alguns algoritmos bem conhecidos.
Método linear congruente
O próximo membro da sequência é calculado usando a fórmula
X i+1 = (aX i + c) mod m
Número eu define o período máximo da sequência, inteiros um E c- coeficientes “mágicos”. Número euÉ razoável escolher igual a uma potência de dois; neste caso, a operação de conversão de módulo se reduz ao descarte dos bits mais significativos; Para obter o prazo máximo, devem ser atendidas as seguintes condições:
- c e m deve ser relativamente primo,
- a-1 deve ser um múltiplo p para todos os fatores primos p números eu,
- Se eué um múltiplo de 4 (e no nosso caso será um múltiplo), então a-1 deve ser um múltiplo de 4.
Há mais uma sutileza: apenas os bits mais significativos da variável de estado X devem ser considerados como resultado, pois para os bits mais baixos os parâmetros estatísticos de aleatoriedade são muito piores. O algoritmo linear congruente é comumente implementado como Rand() padrão em muitas bibliotecas.

Prós:

  • o período máximo possível para um determinado tamanho da variável de estado;
  • rápido o suficiente;
  • muitas vezes já implementado na biblioteca do compilador.
Contras:
  • é necessária uma operação de multiplicação;
  • nem todos os bits são igualmente aleatórios.
Retomar: um algoritmo rápido e simples para aplicações não muito exigentes.
Método Fibonacci com defasagens
Este algoritmo usa a relação
X i = X i-a - X i-b ,
onde está a variável de estado X- inteiro sem sinal. Valores de atraso um E b não apenas qualquer um, mas aqueles estritamente definidos são usados ​​para atingir a qualidade máxima, os pares (17,5), (55,24) ou (97,33) são recomendados. Quanto maior o atraso, maior o período e melhores as propriedades espectrais da sequência. Por outro lado, para que o gerador funcione é necessário armazenar max(a,b) dos números anteriores, o que nem sempre é aceitável. Além disso, para executar o gerador você precisa de números max(a,b), que geralmente são obtidos usando um PRNG mais simples.

Prós:

  • não requer operações de multiplicação;
  • todos os bits de um número aleatório são equivalentes em propriedades estatísticas.
Contras:
  • requer muita memória;
  • requer uma grande variedade de números para ser executado.
Retomar: um algoritmo de alta qualidade, mas que consome muitos recursos.
Registro de deslocamento de realimentação linear


A variável de estado é armazenada em um registro de comprimento N. A geração do próximo estado envolve duas etapas:
  1. O valor do bit é calculado C = X i1 xor X i2 xor… X ik, onde i1, i2…ik- registrar números de bits, chamados curvas.
  2. O registrador é deslocado 1 bit para a direita, o bit mais à esquerda assume o valor COM.
A saída do gerador é o bit mais à direita (ou mais à esquerda, ou qualquer outro) do registro, ou seja, a sequência pseudoaleatória é gerada um bit por iteração. Com números de tap selecionados corretamente, o período do gerador será 2 N - 1. “Menos um”, pois existe um estado zero proibido do registro. Números de filiais para N de 3 a 168 podem ser encontrados neste documento.
Além da configuração descrita acima, que, aliás, é chamada de configuração Fibonacci (não confundir com o método PRNG de mesmo nome!), existe a chamada. Configuração de Galois.


Em vez de usar a soma dos bits na sequência de tap para gerar um novo bit mais à esquerda, ele faz um XOR de cada bit na sequência de tap com o bit mais à direita e, em seguida, gira todo o registro para a direita. Este esquema é mais difícil de entender, mas mais fácil de implementar, uma vez que todas as operações XOR podem ser realizadas simultaneamente. Em termos de duração do período e qualidade dos números pseudoaleatórios, os esquemas de Fibonacci e Galois são equivalentes.

Prós:

  • implementação muito simples, nem requer aritmética, apenas operações e deslocamentos de bits;
  • algoritmo muito rápido (especialmente o esquema de Galois);
  • boas propriedades estatísticas.
Contras:
  • você precisa verificar o valor inicial da desigualdade como zero.
Retomar: algoritmo muito rápido e de bastante alta qualidade.
Algoritmos à prova de criptografia
Para uso em criptografia, os PRNGs possuem mais um requisito essencial: irreversibilidade. Todos os algoritmos listados acima não possuem esta propriedade: conhecendo vários valores de saída do PRNG, você pode, resolvendo um sistema simples de equações, encontrar os parâmetros do algoritmo (as mesmas constantes “mágicas” a, b, c etc). E conhecendo os parâmetros, você pode reproduzir toda a sequência pseudo-aleatória.
Qualquer cifra de bloco suficientemente forte pode ser usada como um algoritmo PRNG criptograficamente forte. Ao escolher uma chave secreta, você pode obter blocos de números pseudoaleatórios aplicando o algoritmo a números naturais sequenciais. Para uma cifra de bloco de N bits, o período não será superior a 2 N. A segurança de tal esquema depende inteiramente do sigilo da chave.
Todos os algoritmos criptográficos modernos são testados para uso como PRNGs, ou seja, usando um algoritmo certificado, não há necessidade de se preocupar especialmente com as propriedades estatísticas e espectrais do fluxo de saída. Você só precisa se preocupar com a “gula” computacional dos algoritmos criptográficos. Se você precisar realizar grande número operações de criptografia, faz sentido escolher um controlador com blocos criptográficos de hardware. Freqüentemente, esses controladores também possuem um PRNG de hardware resistente à criptografia muito bom.

Fontes de entropia

Como já foi dito, utilizando apenas algoritmos determinísticos, é impossível gerar um número verdadeiramente aleatório. Portanto, uma combinação de PRNG + externo é geralmente usada fonte de entropia. A fonte de entropia é utilizada para definir o valor inicial do PRNG, e a tarefa deste último é garantir a pureza espectral e estatística da sequência. O que pode ser usado como fonte de entropia? Sim, quase tudo.
Atividade do usuário
Se o dispositivo interagir com o usuário de alguma forma, é bastante boa decisão usará o próprio usuário como fonte de entropia. Por exemplo, o tempo de pressionamento de um botão, medido com precisão de um microssegundo (ou melhor, seus dígitos menos significativos), é completamente imprevisível. Porém, muitas vezes o dispositivo deve funcionar de forma autônoma, o que significa que estamos privados desse maravilhoso canal de informação.
Conversor analógico para digital
Muitos controladores possuem ADCs integrados. E em muitos controladores eles são de qualidade medíocre, feitos apenas “para ser”. Os bits de ordem inferior de um resultado ADC quase sempre contêm ruído significativo, mesmo quando medidos tensão constante. Isso pode ser usado: conecte a entrada ADC à tensão de alimentação através de um divisor, faça algumas dezenas de medições, faça os bits menos significativos - aqui você tem um grande número aleatório. Se o ADC contiver um pré-amplificador embutido, ligue-o, pois também faz barulho.
Geradores assíncronos
Você pode usar a diferença de períodos de dois geradores de clock não sincronizados. A maioria dos controladores contém, por exemplo, um temporizador de vigilância. Para aumentar a confiabilidade, ele é sincronizado a partir de um gerador separado, que não está de forma alguma conectado ao sinal do relógio principal. Basta contar o número de ciclos do sinal do relógio principal durante um período do temporizador watchdog. Se você escolher períodos para que o contador transborde muitas vezes durante a medição, poderá obter um número bastante aleatório. A desvantagem desse método é que leva muito tempo, até vários segundos.
Relógio em tempo real
Se o diagrama tiver relógio em tempo real, você pode usar suas leituras atuais para inicializar o PRNG. Por exemplo, ao converter a data/hora atual para o formato de hora Unix, obtemos imediatamente 32 bits, o que nunca não acontecerá novamente a menos que você faça leituras mais de uma vez por segundo. Usar o tempo real proporciona exclusividade de valores, mas não fornece nenhuma imprevisibilidade, por isso é melhor combinar este método com outros.
Circuito RC
Se o controlador não possuir nenhum dispositivo periférico além das portas de E/S, você pode proceder da seguinte forma: uma das pernas é conectada através de um capacitor ao terra, e através de um resistor à tensão de alimentação. Se as entradas do controlador possuírem resistores pull-up internos, um resistor externo não será necessário.

Emitimos um sinal “0” para esta porta - o capacitor está descarregado. Mudamos a porta para o modo de entrada - o capacitor começa a carregar. Quando a tensão atinge o limite, a entrada mudará do estado “0” para “1”. O tempo de carregamento depende fortemente de muitos fatores: tensão de alimentação, desvio dos parâmetros do circuito RC, instabilidade do limite, temperatura, vazamentos, interferência. Medindo-o com precisão suficiente e pegando os bits menos significativos, você pode obter uma boa aleatoriedade.
Gerador de ruído de hardware
Para muitas aplicações sérias (principalmente criptografia), é necessária uma fonte de entropia mais confiável do que as listadas acima. Nesses casos, eles utilizam a digitalização do sinal de um gerador de ruído baseado em efeitos térmicos, de disparo ou mesmo quânticos. O elemento de ruído é geralmente um diodo especial ou diodo zener, cujo sinal é amplificado e alimentado a um comparador que gera um fluxo de bits binário.

Para garantir que o limite de resposta do comparador não afete as propriedades estatísticas do sinal recebido, dois geradores de ruído são usados, operando em um comparador:

Conclusão

Por fim, contarei uma história da minha vida. Tudo começou com outra pergunta feita no fórum: “como posso gerar um número aleatório no controlador?” O autor da pergunta explicou que como projeto de curso está fazendo um dispositivo que emula o lançamento de dados. Após várias tentativas frustradas de entender os algoritmos, o topicstarter compartilhou sua solução: ele simplesmente lançou um dado real 1000 vezes e preencheu toda a memória livre do controlador com os números resultantes. O gerador passou brilhantemente em todos os testes de “aleatoriedade”, visto que durante a demonstração utilizou menos de um terço da sua “reserva”.
Portanto, tal solução também tem direito à vida, especialmente se forem impostos requisitos muito rígidos à aleatoriedade dos números, mas eles não são exigidos com muita frequência. Com a queda dos preços das memórias, pode ser sensato equipar um dispositivo com uma “reserva de caos” que durará toda a vida útil do dispositivo.
Obrigado pela sua atenção!

UPD1: Como foi acertadamente observado nos comentários, se for esperado um ataque ao RNG, e o invasor tiver acesso de hardware ao dispositivo, fontes externas de entropia devem ser utilizadas com muito cuidado, pois não é muito difícil substituir o sinal de fonte externa. Devem ser utilizadas fontes internas, além das externas.
Também é uma boa ideia acumular entropia durante todo o seu tempo livre e usá-la quando precisar gerar o próximo número aleatório. Normalmente, nesses casos, o chamado Conjunto de entropia- uma matriz sobre a qual uma das funções do PRNG é executada periodicamente e na qual os dados das fontes de entropia são constantemente misturados.

UPD2: Em muitos casos, é útil salvar o conteúdo do pool Entropy (desculpe, não conheço a tradução normal para o russo) na EEPROM para que depois de desligar e ligar o dispositivo ele não o acumule novamente. Isto se aplica, em primeiro lugar, à obtenção de entropia pelo método dos geradores assíncronos: em condições suficientemente estáveis, a mesma sequência pode ser gerada após cada ligação.
Se for esperado um ataque, tome precauções contra a adulteração da EEPROM. Se o controlador permitir, bloqueie a leitura/apagamento/escrita usando bits de bloqueio e, ao ligá-lo, monitore a integridade da EEPROM, pelo menos usando checksums simples.

Etiquetas:

  • RNG
  • gpsch
  • microcontroladores
  • algoritmos
Adicionar tags