Automação de tigelas tibetanas com a ajuda do "Arduino". Motor de passo em vez de um monge. Programação sem fio

E TRANSFERÊNCIA DE VONTADE DIVINA DE SINAIS DE TEMPO EXATO ATRAVÉS DE ESP8266.
PARTE QUATRO



Então, tudo coincidiu. Primeiro, vi um artigo sobre Gytayms sobre cortinas controladas por um motor de passo. Lembrei-me de que tinha o mesmo motor ocioso pelo segundo ano. Então meu olhar caiu na tigela de canto, que estava acumulando poeira na prateleira há cinco anos. E então vários pensamentos inteligentes começaram a vir à minha cabeça ...

Não, é claro, às vezes de acordo com o meu humor, peguei este copo em minhas mãos e por algum tempo extraí vários tipos de sons fascinantes, mas não era exatamente o que eu queria. E eu queria fazer algo em paralelo, e deixar o copo soar naquele momento. É claro que há mil anos atrás isso exigiria um escravo separado, trezentos anos atrás, seria um mecanismo sofisticado de relógio, e agora ... Bem, agora temos um motor de passo, uma placa Arduino ProMini e outros eletrônicos não sofisticados. Resta apenas codificar um pouco o gado . E, ao mesmo tempo, certifique-se de que esse cinzel tibetano, ao mesmo tempo, lute contra a hora exata - em vão, ou algo que tenha produzido tantos servidores de hora exata. E deixe o ESP8266 se comunicar com eles, ela sabe como.

Então ...

Há uma tigela de canto com um badalo.



É necessário fazer o martelo bater contra a borda da tigela. Automaticamente. Também com a possibilidade de controle remoto (e reprogramação!). E apenas para vencer o tempo como um relógio antigo, mas com precisão moderna.

No futuro, mostrarei o que aconteceu no final. Assista melhor com o som.


Mas vamos começar em ordem. Primeiro eu tive que entender como a mecânica ficaria e funcionaria. Em eletrônica e software, fiquei calmo - atrás de três artigos sobre como lidar com o arduinki à distância.

O principal elemento móvel era ser um simples motor de passo de 28YBJ-48 e eu precisava entender se ele podia lidar com o martelo.



A própria conexão do dvigun ao arduino não é difícil, felizmente, foi vendido com um driver ULN2003 pronto. Só era necessário fornecer uma fonte de alimentação separada para 5 volts e uma reserva de 200-300 mA, porque você definitivamente não terá um conversor suficiente no próprio arduino. Então, em qualquer uma das quatro portas digitais (peguei PB1, PB2, PB3, PB4), transferimos os seguintes blocos de anotações de bits no total de oito peças.

PORTB=0b00000010;//     PORTB=0b00000110; PORTB=0b00000100; PORTB=0b00001100; PORTB=0b00001000; PORTB=0b00011000; PORTB=0b00010000; PORTB=0b00010010; 

Para rotação na direção oposta, transferimos os mesmos notebooks, mas na ordem inversa.

  PORTB=0b00010010; PORTB=0b00010000; PORTB=0b00011000; PORTB=0b00001000; PORTB=0b00001100; PORTB=0b00000100; PORTB=0b00000110; PORTB=0b00000010; 

A única coisa que surge é a velocidade com que os dados são transmitidos. É claro que, com mais freqüência, mais rápido o eixo do motor irá girar, mas até que limite? Há uma frequência misteriosa de 100 Hz na descrição, mas o que exatamente significa - o período de um ciclo completo ou cada mordidela separadamente?

No decorrer dos experimentos, descobriu-se que, aparentemente, a frequência da mudança de precisos tétrades era significada. Ao máximo, consegui acelerar essa frequência para 147 Hz, na qual o eixo do motor fez uma revolução em cerca de um segundo ou dois. Não medi exatamente, mas você pode julgar por si mesmo que este modelo com esta caixa de velocidades não difere em agilidade especial. Mas, para o meu martelo, parecia, em princípio, adequado.

Afinal, não é apenas a velocidade que é importante para nós (ou melhor, nem mesmo é muito importante), mas a força com a qual o motor pode atuar no fluido de trabalho. Nas postagens dedicadas a esse mecanismo, argumentou-se que eles não podiam parar com uma mão. Como se viu, o próprio eixo, sim, você não para, mas já uma alavanca pequena (e eu decidi usar um sistema de alavanca) com literalmente 10 cm de comprimento, para e pára com muita facilidade mesmo com um pequeno impacto local.

Portanto, a opção mais simples inicial, quando a alavanca aparafusada ao eixo empurra o batedor na suspensão, que consequentemente bate na tigela, não passou. O som estava muito fraco. Então decidi pedir ajuda à gravidade (a "cadela sem coração" nas palavras de Sheldon Cooper). Nesta modalidade, a alavanca puxou um badalo até um ângulo de cerca de 30 graus em relação à direção do centro da Terra e, em seguida, desengatou-se dele e enviou-o para a tigela. Gostei muito do som, tanto de baixo como dos meus vizinhos. O mecanismo de liberação foi feito em um ímã montado na extremidade da alavanca. Ao subirem, a gravidade derrotou a magnética e a trava foi liberada. Então fiz uma parada mecânica de ajuda - uma barra transversal com a qual o martelo se encontrava perto do ponto extremo da ascensão. O motor continuou a girar, a alavanca puxou e desengatou com força a trava magnética. Aqui, o motor foi ajudado pela gravidade; portanto, o esforço para desengatar era necessário muito pouco.

O design em si foi montado com base nos detalhes do designer infantil da Torre Eiffel. Comprei por um longo tempo e periodicamente usei suas peças para o meu artesanato. A torre, é claro, não acabou sendo a Eiffel, mas na minha opinião não é de forma alguma pior :)

Quase Torre Eiffel


Tudo funcionou perfeitamente, mas com um sinal de menos - o som sempre foi o mesmo poder. Isso é normal para bater o tempo, mas no modo livre eu gostaria de ouvir não apenas pausas diferentes no tempo, mas também sons de diferentes forças. Portanto, era necessário aplicar um eletroímã, que também era muito útil. Ímãs convencionais também foram úteis - uma coluna de cinco pequenos ímãs que eu usei como amortecedor para domar as vibrações do batedor depois de bater na tigela.



No começo, instalei-o na extremidade da alavanca, mas o design era pesado e frágil e pouco confiável. Portanto, o eletroímã mudou-se para um martelo. Ele consumiu cerca de 300 mA e, é claro, era impossível controlá-lo a partir do porto do arduino. Eu tive que colocar uma simples chave de transistor em uma pequena placa de ensaio.



R1 - 560 Ohm, VD1 - 1N4007, VT1 - BD139

Montei a parte eletrônica principal no módulo “Arduino ProMini” e no ESP8266-07, cujo firmware completei completamente passo a passo, de acordo com o meu artigo antigo . Como resultado, eu, como sempre, tive a oportunidade de programar o arduino sem fio e também me comunicar remotamente com ele, trocando dados, que acabei usando com sucesso. O diagrama mostra, no entanto, o Arduino Nano por razões históricas, mas sua conexão não é diferente.



Então, o que eu desejava e, em seguida, incorporava o código do programa.

  1. Quando você liga o sistema, deve entrar independentemente no modo de exibição.
  2. Deve haver um aplicativo no computador (smartphone) para alterar os modos operacionais e transferir os dados necessários.
  3. Os modos devem ser simples - um relógio, murmúrio aleatório e controle manual.

Comecei, ao que parecia, com a coisa mais simples - horas. De fato, qualquer rádio amador iniciante coleta primeiro uma sonda e depois um relógio eletrônico. E então, no entanto, ele se pergunta por que esse relógio fica para trás um minuto por hora - parece que ele teoricamente calculou tudo corretamente.

Eu já tinha o relógio eletrônico montado.



E sua principal característica útil para mim agora era a capacidade de arrastar o tempo exato dos servidores NTP usando o mesmo microcircuito ESP8266, na pessoa de sua primeira e mais simples encarnação.

Eu até queria escrever um artigo sobre esse assunto há alguns anos, mas depois de ver quantas vezes isso já foi feito, mudei de idéia. Eles vão rir depois de tudo. Mas, no contexto deste post, a análise de seu trabalho é bastante apropriada. Como mencionei anteriormente nos artigos, escrevo programas para o ESP8266 na linguagem LUA. Isso aconteceu.

Portanto, o código carregado no módulo ESP era assim.
 uart.setup(0,9600,8,0,1,0) timezone = 3 --  tmr.alarm(1,5000,0,function() -- try once connect to NTP-server sk=net.createUDPSocket() sk:send(123,"130.149.17.21",string.char( 227, 0, 6, 236, 0,0,0,0,0,0,0,0, 49, 78, 49, 52, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) sk:on("receive", function(sck, payload) ntp = payload:byte(41) * 128 * 256 * 256 + payload:byte(42) * 128 * 256 + payload:byte(43) * 128 + payload:byte(44) /2 + timezone * 1800 hour =ntp % 43200 / 1800 minute = ntp % 1800 / 30 secund = ntp % 60 uart.write(0,hour) uart.write(0,minute) uart.write(0,secund) sk:close() end ) end) 


A linha inferior é simples. Uma vez (ou não), é chamada a função que configura o cliente UDP, que chama o servidor de horário exato e pergunta a hora exata de acordo. Em resposta, o servidor despeja trinta e dois bytes, dos quais é necessário buscar os quatro bytes de dados desejados. Infelizmente, essa busca não leva minutos e horas, mas o número de segundos decorridos até agora desde 1º de janeiro de 1900. Portanto, você precisará calcular o tempo atual dos quatro bytes desses segundos com várias manipulações complexas.

Além disso, tudo é mais simples. Ligue o transmissor UART e solte o tempo calculado nele em três bytes - horas, minutos e segundos.

E novamente inseri esse código, já no meu gerenciador de inicialização LUA (link), exatamente no local em que a conexão à rede WI-FI já foi feita, mas ainda não foram iniciados outros trabalhos.

À vista completa, fica assim.
 function InstrProgrammingEnable () -- instruction for MC "enable programming" p=0 while p<31 do p=p+1 pin=8 gpio.write(pin, gpio.LOW) spi.send(1, 0xAC,0x53) read = spi.recv( 1, 8) spi.send(1,0,0) gpio.write(pin, gpio.HIGH) if (string.byte(read)== 83) then --print("connection established") p=33 if(p==31) then --print("no connection") end end end end function ProgrammingDisable () pin=2--END OF ESET FOR MK GPIO4 gpio.mode(pin, gpio.INPUT) pin=8 gpio.mode(pin, gpio.INPUT) -- CE chip enable not used GPIO15 pin=5--CLK MASTER for SPI GPIO14 used gpio.mode(pin, gpio.INPUT) pin=6--MISO MASTER for SPI GPIO 12 may not used gpio.mode(pin, gpio.INPUT) pin=7--MOSI MASTER for SPI //GPIO13 used gpio.mode(pin, gpio.INPUT) end --PROGRAMMING ENABLE function ProgrammingEnable () pin=2-- RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) pin=2--POZITIV FOR 4MSEC RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(4) gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) tmr.delay(25000) end function InstrFlashErase() --FFFFFFFFFFFFFFFFFF pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0xAC,0x80,0,0) gpio.write(pin, gpio.HIGH) tmr.delay(15000) pin=2--RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(20000) gpio.write(pin, gpio.LOW) --print( "FLASH is erased") InstrProgrammingEnable () end function InstrStorePAGE(H, address, data) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,H,0,address,data) gpio.write(pin, gpio.HIGH) tmr.delay(500) end function InstrWriteFLASH(page_address_low,page_address_high) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0x4C,page_address_high,page_address_low,0) gpio.write(pin, gpio.HIGH) tmr.delay(5000)--        end function Programming (payload) pin=8--CS MASTER for SPI gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) pin=4--LED LIGHTS ON LOW gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) --print(string.len(payload)) page_count = 7 --  1  for k =0 ,page_count ,1 do--quantity of pages for i=0 , 127, 2 do-- -1 address = i/2 data=payload:byte(i+1+128*k) if data == nil then data = 0xff end InstrStorePAGE(0x40,address,data) -- tmr.delay(100)-- otherwise not in time write data =payload:byte(i+1+1+128*k) if data == nil then data = 0xff end InstrStorePAGE(0x48,address,data) -- tmr.delay(100) end page_address_low=bit.band(k ,3)*64 -- 3   11 page_address_high=k/4+frame1024*2 tmr.delay(1000) InstrWriteFLASH(page_address_low,page_address_high) tmr.wdclr() end pin=4--LED gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) end --MAIN BLOCK wifi.setmode(wifi.STATION) --wifi.sta.config("mixa","M1sh8111") -- set SSID and password of your access point station_cfg={} tmr.delay(30000) station_cfg.ssid="mixa" tmr.delay(30000) station_cfg.pwd="M1sh8111" tmr.delay(30000) wifi.sta.config(station_cfg) tmr.delay(30000) wifi.sta.connect() tmr.delay(1000000) --print(wifi.sta.status()) --print(wifi.sta.getip()) while ( wifi.sta.status()~=1 ) do if( wifi.sta.status()==5) then break end end uart.setup(0,9600,8,0,1,0) --     NTP      AVR timezone = 3 --  tmr.alarm(1,5000,0,function() -- try once connect to NTP-server sk=net.createUDPSocket() sk:send(123,"130.149.17.21",string.char( 227, 0, 6, 236, 0,0,0,0,0,0,0,0, 49, 78, 49, 52, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) sk:on("receive", function(sck, payload) ntp = payload:byte(41) * 128 * 256 * 256 + payload:byte(42) * 128 * 256 + payload:byte(43) * 128 + payload:byte(44) /2 + timezone * 1800 hour =ntp % 43200 / 1800 minute = ntp % 1800 / 30 secund = ntp % 60 uart.write(0,100)-- AVR    uart.write(0,hour) uart.write(0,minute) uart.write(0,secund) sk:close() end ) end) prog_address=""; sv=net.createServer(net.TCP,30) tmr.delay(100) --print("SERVER READY") sv:listen(40000,function(c)-- ,   c:on("receive", function(c, payload) --print(payload) if (payload =="program\r\n") then c:send("ready\r\n") --print("ready for program\r\n") tmr.wdclr() spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,80,spi.FULLDUPLEX) --  SPI 320  115 000  ProgrammingEnable ()---------------------------------------------------------------------  80    1  tmr.delay(100) InstrProgrammingEnable () tmr.delay(100) InstrFlashErase() tmr.delay(100) frame1024=0--   st=net.createServer(net.TCP,30)--         AWR,   stop program st:listen(40001,function(c) c:on("receive", function(c, payload) tmr.wdclr() Programming (payload) frame1024=frame1024+1 end) end) end if (payload =="data\r\n") then tmr.wdclr() c:send("ready\r\n") -- print("ready for data\r\n") c:on("receive", function(c, prog_address_payload) prog_address=prog_address_payload-- IP  UDP       -- print(prog_address) c:send(prog_address) srv=net.createUDPSocket()--     ,   data stop srv:listen(50000) -- uart.setup(0,9600,8,0,1,0) srv:on("receive", function(srv, pl) --      UDP pl=pl*1 -- print(pl) uart.write(0,pl) --    UART  AVR end) uart.on("data", 1, function(data) --    UART  AVR srv:send(50000,prog_address,data) --    UDP   end, 0) tmr.wdclr() end) end if (payload =="stop data\r\n") --      then ready = false if(srv~=nil) then srv:close() -- print("stop data") end collectgarbage() end if (payload =="stop program\r\n") then if(st~=nil) then st:close() frame1024=0 ProgrammingDisable () -- print("stop program") end collectgarbage() end end) end) 


Obviamente, isso vai contra o meu conceito, onde o ESP8266 é uma ponte sem fio limpa e o microcontrolador ATMEL faz o resto, mas como eles dizem: "uma vez, não ...".

Portanto, obtivemos o tempo exato inicial (diretamente do servidor NTP ou indiretamente, através do aplicativo no computador, não importa), então gostaríamos de considerar o tempo. Em primeiro lugar, não há nada para carregar a rede e, em segundo lugar, o ATMEL teoricamente permite contar segundos com boa precisão. Teoricamente, sim. Mas, na prática, existem armadilhas.

Uma pequena digressão sobre o relógio em tempo real no AVR.

Em teoria, não há nada complicado na construção de um relógio no microcontrolador AVR. Os designers mais raivosos até enfiam um relógio de quartzo a 32768 Hz no circuito para isso. Mas, de fato, isso não é necessário. De fato, é necessário um relógio de quartzo para formar uma interrupção múltipla de segundo e ativar um microcontrolador adormecido (nota). Se o seu dispositivo funcionar constantemente e o relógio normalmente funcionar, colocar quartzo adicional ao existente e colocar duas pernas de entrada e saída por baixo é imprudente. É possível usar um ressonador de quartzo, que já está lá, oito ou dezesseis megahertz lá. Sua precisão de quantização é suficiente para seus olhos, e contar um segundo como contador de timer também será fácil.

De fato, o microcontrolador AVR já tem tudo para isso. Como você sabe, o sinal do relógio de entrada (por exemplo, 8 MHz) chega dentro do chip (por exemplo, AVRmega328P como o mais comum para o arduino) no chamado pré-divisor, onde pode ser dividido ainda mais pelo desejo do programador (geralmente por 8, 64, 256, 1024). E então ele chega a algum tipo de contador de tempo (digamos T1), que imediatamente começa a aumentar.

Então, vamos pegar 8 MHz e dividir por 256. Recebemos, respectivamente, a frequência do relógio do contador 31250 Hz. Assim, como o contador T1 tem dezesseis dígitos e pode contar de acordo com até 65535, então ele terá tempo para contar até 31250 em um segundo. Do que precisamos. Além disso, nosso timer possui outro registro de comparação muito útil. Se escrevermos o número 31250 lá, em determinadas condições, ele será constantemente comparado com o conteúdo do contador T1 e, finalmente, quando for igual, o contador gerará um sinal de interrupção, digamos, mantenha seu segundo.

Acontece convenientemente, mas, infelizmente, não é totalmente preciso. Para o nosso contador, contamos com um erro de quantização de 256 / 8.000.000, o que gera um erro bastante grande no cálculo de um segundo em até 32 microssegundos. E isso leva a um erro de 2,8 segundos por dia (0,000032 * 3600 * 24).
Mas se dividirmos os 8 MHz originais por uma quantidade menor, por exemplo, por 64, a precisão da quantização aumentará 4 vezes para 8 μs e reduzirá o erro resultante para 0,33 segundos por dia. Infelizmente, neste caso, o contador precisará ser contado até 125.000, e esse número no registro de dezesseis bits não será inserido. Teremos que escrever um número menor no registro de comparação (62500 ainda pode caber)) e adicionar um loop no próprio programa, em que um segundo será contado não por um, mas por duas interrupções.

Mas nós escolhemos o case ideal, e um ressonador de quartzo real, especialmente instalado em uma placa “fabricada na China”, pode lhe trazer muitas surpresas. Não, em geral, se você observar o quartzo padrão nas folhas de dados , teoricamente nem tudo é tão ruim.

Como podemos ver, o quartzo intermediário se comporta muito bem. Ele tem uma instabilidade de seu próprio ajuste a 25 ppm (ou seja, 25 ppm), ou seja, ele ressoa a uma frequência não de 8 MHz, mas, por exemplo, a uma frequência de 8 0002 MHz, o que nos dá 2,1 segundos de erro por dia. Mas este é um erro constante e pode ser levado em consideração. Esse quartzo também pode flutuar a uma temperatura de 5 a 10 ppm por grau, mas nas condições operacionais do dispositivo, o erro também será pequeno. Ainda existe um fator como o envelhecimento, mas é muito escasso e altera as características do quartzo para um estado de pelo menos alguma visibilidade, bem, talvez cinco anos. Ou dez.

E aqui estamos felizes em pegar um clone chinês do arduino, por exemplo, ARDUINO UNO.



Executamos nele um programa de teste para contar o tempo e o iniciamos. Backlog por hora por um minuto? Fácil! Segunda placa UNO Arduino? Não é melhor.

Pegue o Arduino ProMini.



E aqui está melhor, sim. O erro diminuiu para vinte segundos por hora. Bem, já é comparável a um relógio mecânico cuco.

A última placa que eu tinha em mãos era o Arduino Nano.



E ela foi a única que mostrou resultados mais ou menos saudáveis.

Mas mesmo com esse quadro, usando apenas construções teóricas, você mesmo entende que não fará uma observação exata. A placa precisa ser configurada e eu, com um suspiro, subi atrás do osciloscópio.

Como se viu, as placas do Arduino têm um recurso desagradável - a saída à qual o ressonador de quartzo está conectado não tem uma saída para o pente, embora corresponda à porta PB7. Como o porto é ocupado por quartzo, você não se apega a ele. E bem ao pé do microcontrolador, é muito difícil pegar a sonda do osciloscópio, para montagem em superfície e um passo de 0,5 mm entre os terminais. Mas até juntar a perna direita não me deu nada. Ou porque cutuquei incorretamente, ou cutuquei no lugar errado, porque a saída do ressonador de quartzo talvez não seja a saída do gerador de clock e, em geral, está dentro do próprio microcontrolador. Portanto, eu tive que contornar as soluções alternativas - colocar o pré-calibrador no coeficiente de divisão mínimo - um, escrever zero no registro de comparação para que a interrupção sacudisse imediatamente e entrar no microcontrolador em um modo especial no qual a perna da porta PB1 altera seu estado lógico a cada interrupção.
Logicamente, quando você liga a placa Arduino Nano 16 MHz, um meandro de 8 MHz deve aparecer na saída desta porta.

Foi o que aconteceu. O osciloscópio mostrou uma frequência de 8. 002 31 MHz. Além disso, a última descarga teve vida própria e eu ainda não entendi se a precisão do osciloscópio está faltando ou se a frequência do oscilador de cristal está flutuando assim. Mais como um segundo.

A boa estabilidade térmica também não cheirava. Se você respirar no quadro (talvez, a propósito, os recipientes ainda venham de umidade?) Ou traga um ferro de solda (de longe), o quartzo poderá se mover imediatamente em cinquenta hertz. E essas medidas ainda são praticamente duplicadas, uma vez que a frequência inicial é de 16 MHz.

Assim, em placas de arduino (pelo menos de origem chinesa) é impossível obter precisão superior a 200 Hz a uma frequência de clock de 16 MHz. O que nos dá a precisão máxima dos relógios montados nessas placas, não mais que um segundo por dia. E isso é bom.

Porque existem clones chineses do Arduino UNO, já mencionados por mim anteriormente, com os quais, em geral, tudo está ruim. E eles são muito comuns, porque são baratos e convenientes.

Portanto, a frequência delas pode diferir da declarada por mais de cem quilohertz! O que é até incomum até para o pior quartzo chinês.

O enigma começa com o fato de que 12 MHz são escritos no próprio quartzo! E nas descrições dos vendedores também.



Mas não há 12 MHz, isso é certo. Se você ativar a porta serial UART na placa, verá por si mesmo. Como o UART sintonizou essa frequência, você não funcionará. E sintonizado a uma frequência de 16 MHz - será. Além disso, eu assisti pessoalmente às formas de onda em ambas as placas do Arduino Uno. A primeira placa tinha uma frequência de gerador de 15.8784 MHz e a segunda 15.8661 MHz.

Mas, de repente, descobriu-se que o quartzo de 12 MHz não está diretamente relacionado ao microcontrolador AVR, mas foi projetado para operar a porta serial com um computador via USB (para baixar esboços). Portanto, a suposição de que não havia quartzo no interior, mas uma cadeia RC mal ajustada, não se materializou. E o quartzo de que precisamos é muito menor em tamanho e está localizado próximo ao chip do microcontrolador. Mas é muito pequeno e não há inscrição.

, . , , . - . , , ? , .

« ” AVR.

, , Arduino ProMini

AVRmega328P
 /* * Tibetian_Bowl.c * * Created: 07.06.2018 0:29:57 * Author: User */ #define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #include <stdint.h>//    #include <math.h> //  #include <stdio.h> // - #include <avr/eeprom.h> #include <stdbool.h> #include <setjmp.h> #include <stdlib.h> volatile bool change_mode = false; volatile bool boom =false; volatile bool go_ahead=true; volatile bool go_back=false; volatile bool gerkon=false; volatile uint8_t latency=2;//     latency = 1 volatile uint8_t hour=12; volatile uint8_t hour24=12;//       12 volatile uint8_t minute=0; volatile uint8_t secund=0; volatile uint8_t power=0; volatile uint8_t pause_between_boom=0; volatile uint8_t first_byte=0; volatile uint8_t second_byte=0; volatile uint8_t third_byte=0; volatile uint8_t firth_byte=0; volatile uint8_t fifth_byte=0; volatile uint8_t cSREG; ISR(USART_RX_vect) { //     ,  //   –  ,    . if (first_byte==0) { first_byte=UDR0; change_mode=true; goto ret; } if (second_byte==0) { second_byte=UDR0; goto ret; } if (third_byte==0) { third_byte=UDR0; goto ret; } if (firth_byte==0) { firth_byte=UDR0; goto ret; } if (fifth_byte==0) { fifth_byte=UDR0; goto ret; } cSREG=UDR0; ret: return; } ISR(PCINT1_vect )//PC2 int 10 //    { if (go_ahead) { UDR0=44; //      44 } if (go_back) { gerkon=true; } } ISR(TIMER1_COMPA_vect) { //        secund++; if (secund ==60) { secund=0; minute++; if(minute==60) { minute=0; hour++; if(hour==12) { hour=1;//     12  } hour24++; if(hour24==24) { hour24=1; } boom=true; } } } void time_delay(long dell)//       { long i; dell=dell*796;//  8  for(i=0;i<dell;i++){;;}; sei();//    ,  -    .WTF ?????????????????????? } void turn_onkward()//       { uint8_t legnth=170;//    ( 0  170) for(uint16_t i =0;i<=legnth;i++) { go_ahead=true; PORTB=0b00000010;//       time_delay(latency); PORTB=0b00000110; time_delay(latency); PORTB=0b00000100; time_delay(latency); PORTB=0b00001100; time_delay(latency); PORTB=0b00001000; time_delay(latency); PORTB=0b00011000; time_delay(latency); PORTB=0b00010000; time_delay(latency); PORTB=0b00010010; time_delay(latency); if (i>140) { PORTD |=(1<<PORTD2);//     , 1 -   } } time_delay(100); go_ahead=false; } void turn_backward(uint8_t pause, uint8_t force_of_sound)//     // //       { uint8_t legnth=170;//       ( 0  170) for(uint16_t i =0;i<=legnth;i++) { go_back=true; PORTB=0b00010010; time_delay(latency); PORTB=0b00010000; time_delay(latency); PORTB=0b00011000; time_delay(latency); PORTB=0b00001000; time_delay(latency); PORTB=0b00001100; time_delay(latency); PORTB=0b00000100; time_delay(latency); PORTB=0b00000110; time_delay(latency); PORTB=0b00000010;//16 ms   ,  latency = 2 time_delay(latency); if (i==force_of_sound*17) { PORTD &=~(1<<PORTD2);//     , 0 -   } if (gerkon) { gerkon=false; break; } } time_delay(50); time_delay(pause*1000);//       go_back=false; } void sound(uint8_t force,uint8_t pause) //       1  10           { turn_onkward(); turn_backward(pause,force); } int main(void) { sei(); // UART  9600    8  time_delay(2000);//  , esp     -  UCSR0A=0; UCSR0B=0b10011000;// a UART UCSR0C=0b00000110; UBRR0L=51;// 8  9600  UART UBRR0H=0; //   INT0   2   10 //        PCICR|=(1<<PCIE1);//   14-8 PCMSK1|=(1<<PCINT10);//    INT10 DDRC&=~(1<<PORTC2); DDRB=0b00111110;//PB1-PB4    , PB5      DDRD=0b00000100; // PD2      //SET INTERRUPT FROM TIMER1 AND SET TIMER1 GTCCR=0;//RESET PRESCALER TCCR1A=0;//I/O NORMAL WORK TCCR1C=0; TCCR1B=0B00001100;//1/256 PRESCALING AND CTC MODE TCNT1H=0;//RESET TIMER1 TCNT1L=0; TIMSK1=0B00000010;//SET COMPARE A INTERRUPT ENABLED OCR1AH=0x79;//SET TIME CONSTANT IN COMPARE REGISTER OCR1AL=0xa7;// 31143    7 972 608  TCCR0B=0b00000010;// 8        0  255 while (1) { begining: time_delay(1000); if (first_byte!=0) { UDR0=first_byte;//      .     (100,101,102)    } if (first_byte==100)//   (     NTP  { hour=second_byte;//  if (hour>12)//      12  (24  ) { hour=hour-12; } if (hour==0) { hour=12; } minute=third_byte;//  secund=firth_byte;//  power=fifth_byte;//   first_byte=0;//   second_byte=0; third_byte=0; firth_byte=0; fifth_byte=0; change_mode=false; goto clock_mode; } if (first_byte==101)//   { power=second_byte; pause_between_boom=third_byte; first_byte=0; second_byte=0; third_byte=0; firth_byte=0; fifth_byte=0; change_mode=false; goto random_mode; } if (first_byte==102)//  { power=second_byte; first_byte=0; second_byte=0; third_byte=0; firth_byte=0; fifth_byte=0; change_mode=false; goto hand_mode; } //     ,      first_byte=0; second_byte=0; third_byte=0; firth_byte=0; fifth_byte=0; goto begining; clock_mode: while(change_mode==false) { if (boom)//   { for(uint8_t i =0;i<hour;i++) { if ((hour24>21)|(hour24<10))//  { sound(3,0);//   10 (),  0  boom=false; } else { sound(power,0);//   10 (),  0  boom=false; } } } } goto begining; random_mode: while(change_mode==false) { uint8_t random_power = TCNT0;//      1 uint8_t random_pause = TCNT1L;//      1 random_pause=TCNT0;//      1 random_power=random_power/25; if (random_power<5) { random_power=random_power+2;//      } random_pause=(random_pause/25)+pause_between_boom; UDR0=random_pause; time_delay(100); sound(random_power,random_pause); } goto begining; hand_mode: sound(power,0); goto begining; } } 


. , , UART. :

100
101
102 .

AVR , , ESP8266. , ESP , NTP . , . - 1 , - , .

, , .

.

, , .



AVR HTTP UDP . UDP . , , , -, LUA , -, , UART. , () AVR . , , , , , .

.



. , , . Arduino .

Source: https://habr.com/ru/post/pt415629/


All Articles