Automatización de cuencos tibetanos con la ayuda de "Arduino". Motor paso a paso en lugar de un monje. Programación inalámbrica

Y TRANSFERENCIA DE DIVINA VOLUNTAD DE SEÑALES DE TIEMPO EXACTO A TRAVÉS DE ESP8266.
CUARTA PARTE



Entonces todo coincidió. Primero, vi un artículo sobre Gytayms sobre cortinas controladas por un motor paso a paso. Recordé que tenía el mismo motor al ralentí por segundo año. Luego mi mirada cayó sobre el cuenco , que había estado acumulando polvo en el estante durante cinco años. Y entonces varios pensamientos inteligentes comenzaron a venir a mi cabeza ...

No, por supuesto, a veces según mi estado de ánimo, tomé esta copa en mis manos y durante algún tiempo extraje varios tipos de sonidos hechizantes, pero esto no era exactamente lo que quería. Y quería hacer algo en paralelo y dejar que la copa sonara en ese momento. Está claro que hace mil años, esto habría requerido un esclavo separado, hace trescientos años sería un mecanismo de mecanismo ingenioso, y ahora ... Bueno, ahora tenemos un motor paso a paso y una placa Arduino ProMini y otros dispositivos electrónicos no sofisticados. Solo queda codificar un poco el ganado . Y al mismo tiempo, asegúrese de que este cincel tibetano al mismo tiempo lucha contra la hora exacta, en vano, o algo que produjo tantos servidores de hora exactos. Y deje que ESP8266 se comunique con ellos, ella sabe cómo.

Entonces ...

Hay un cuenco con badajo.



Es necesario hacer que el mazo golpee contra el borde del tazón. Automáticamente También con posibilidad de control remoto (¡y reprogramación!). Y solo para vencer el tiempo como un reloj viejo, pero con precisión moderna.

Mirando hacia el futuro, mostraré lo que sucedió al final. Mira mejor con sonido.


Pero empecemos en orden. Primero tenía que entender cómo se vería y funcionaría la mecánica. Para la electrónica y el software, estaba tranquilo: detrás de tres artículos sobre cómo lidiar con Arduinki desde la distancia.

El principal elemento móvil era un simple motor paso a paso 28YBJ-48 y necesitaba entender si podía manejar el mazo.



La conexión misma del dvigun al arduino no es difícil, afortunadamente, se vendió con un controlador ULN2003 listo para usar. Solo era necesario proporcionar una fuente de alimentación separada para 5 voltios y una reserva de 200-300 mA, porque definitivamente no tendrá suficiente convertidor en el arduino. Luego, en cualquiera de los cuatro puertos digitales (tomé PB1, PB2, PB3, PB4) transferimos los siguientes cuadernos de bits en la cantidad de ocho piezas.

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

Para la rotación en la dirección opuesta, transferimos los mismos cuadernos, pero en el orden inverso.

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

Lo único que surge es la velocidad con la que se transmiten los datos. Está claro que cuanto más a menudo, más rápido rotará el eje del motor, pero ¿hasta qué límite? Hay una frecuencia misteriosa de 100 Hz en la descripción, pero ¿qué significa exactamente: el período de un ciclo completo o cada mordisco por separado?

En el curso de los experimentos, resultó que, aparentemente, se quería decir la frecuencia del cambio de tétradas precisamente. Al máximo, logré acelerar esta frecuencia a 147 Hz, en la cual el eje del motor hizo una revolución en aproximadamente un segundo o dos. No lo medí exactamente, pero puedes juzgar por ti mismo que este modelo con esta caja de cambios no difiere en agilidad especial. Pero para mi mazo, parecía, en principio, adecuado.

Pero después de todo, no solo la velocidad es importante para nosotros (o más bien, ni siquiera es muy importante) sino la fuerza con la que el motor puede actuar sobre el fluido de trabajo. En publicaciones dedicadas a este motor, se argumentó que no podían detenerse con una mano. Resultó que el eje en sí, sí, no se detendrá, pero ya una palanca pequeña (y decidí usar un sistema de palanca) literalmente de 10 cm de largo, se detiene y se detiene fácilmente incluso con un pequeño impacto local.

Por lo tanto, la opción más simple inicial, cuando la palanca atornillada al eje empuja el batidor sobre la suspensión, que en consecuencia golpea el tazón, no pasó. El sonido era demasiado débil. Así que decidí pedir ayuda a la gravedad (la muy "perra despiadada" en palabras de Sheldon Cooper). En esta realización, la palanca empujó un badajo hasta un ángulo de aproximadamente 30 grados con respecto a la dirección del centro de la Tierra, y luego se desenganchó de él y lo envió de camino al tazón. Realmente me gustó el sonido, tanto desde abajo como para mis vecinos. El mecanismo de liberación se realizó en un imán montado en el extremo de la palanca. A medida que ascendían, la gravedad derrotó al magnético y se liberó el bloqueo. Luego hice una parada mecánica de ayuda: una barra transversal con la que el mazo se unía cerca del punto extremo de elevación. El motor continuó girando, la palanca tiró y desactivó por la fuerza la cerradura magnética. Aquí, el motor fue ayudado por la gravedad, por lo que el esfuerzo de desconexión se requirió muy poco.

El diseño en sí fue ensamblado sobre la base de los detalles del diseñador infantil de la Torre Eiffel. Lo compré durante mucho tiempo y periódicamente utilicé sus piezas para mis manualidades. La torre, por supuesto, no resultó ser la Eiffel, pero en mi opinión no es peor :)

Casi la torre eiffel


Todo funcionó a la perfección, pero con una desventaja: el sonido era siempre el mismo poder. Esto es normal para ganar tiempo, pero en modo libre me gustaría escuchar no solo pausas diferentes en el tiempo, sino también sonidos de diferentes intensidades. Por lo tanto, fue necesario aplicar un electroimán, que también fue muy útil. Los imanes convencionales también fueron útiles: una columna de cinco imanes pequeños que utilicé como amortiguador para domar las vibraciones del batidor después de golpear el tazón.



Al principio lo instalé en el extremo de la palanca, pero el diseño era engorroso y poco confiable. Por lo tanto, el electroimán se movió a un mazo. Consumió alrededor de 300 mA y, por supuesto, era imposible controlarlo desde el puerto de Arduino. Tuve que colocar una simple llave de transistor en una pequeña placa de pruebas.



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

Ensamblé la parte electrónica principal en el "Arduino ProMini" y el módulo ESP8266-07, cuyo firmware completé completamente paso a paso de acuerdo con mi artículo anterior . Como resultado, yo, como siempre, tuve la oportunidad de programar el arduino de forma inalámbrica y también comunicarme de forma remota con él, intercambiando datos, que finalmente utilicé con éxito. Sin embargo, el diagrama muestra el Arduino Nano por razones históricas, pero su conexión no es diferente.



Entonces, ¿qué deseaba y luego encarnaba en el código del programa?

  1. Cuando enciende el sistema debe entrar independientemente en modo reloj.
  2. Debe haber una aplicación en la computadora (teléfono inteligente) para cambiar los modos de operación y transferir los datos necesarios.
  3. Los modos deben ser simples: un reloj, murmullos aleatorios y control manual.

Comencé, como parecía, con lo más simple: horas. De hecho, cualquier radioaficionado para principiantes recoge primero una sonda y luego un reloj electrónico. Y luego, sin embargo, se pregunta por qué este reloj se atrasa un minuto por hora, parece que teóricamente calculó todo correctamente.

Ya tenía el reloj electrónico ensamblado.



Y su característica principal útil para mí ahora era su capacidad de arrastrar el tiempo exacto desde los servidores NTP usando el mismo microcircuito ESP8266, en la persona de su primera y más simple encarnación.

Incluso quería presentar un artículo sobre este tema hace un par de años, pero después de ver cuántas veces esto ya estaba hecho, cambié de opinión. Se reirán después de todo. Pero en el contexto de este post análisis de su trabajo es bastante apropiado. Como mencioné anteriormente en los artículos, escribo programas para ESP8266 en el lenguaje LUA. Sucedió así.

Por lo tanto, el código cargado en ese módulo ESP era así.
 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) 


La conclusión es simple. Una vez (o no), se llama a la función que configura el cliente UDP, que llama al servidor de hora exacto y pregunta la hora exacta en consecuencia. En respuesta, el servidor voltea treinta y dos bytes, de los cuales es necesario obtener los cuatro bytes de datos deseados. Desafortunadamente, esto no se busca minutos y horas, sino la cantidad de segundos que han transcurrido hasta el momento desde el 1 de enero de 1900. Por lo tanto, deberá calcular el tiempo actual a partir de los cuatro bytes de estos segundos con varias manipulaciones complejas.

Además, todo es más simple. Inicie el transmisor UART y reduzca el tiempo calculado en tres bytes: horas, minutos y segundos.

Y nuevamente inserté este código, ya en mi gestor de arranque LUA (enlace), justo en el lugar donde ya se ha realizado la conexión a la red WI-FI, pero aún no se ha comenzado a trabajar.

A la vista, se ve así.
 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) 


Por supuesto, esto va en contra de mi concepto, donde el ESP8266 es un puente inalámbrico limpio, y el microcontrolador ATMEL hace el resto, pero como dicen: "una vez, no ...".

Entonces, obtuvimos el tiempo exacto inicial (directamente del servidor NTP o indirectamente a través de la aplicación en la computadora, no importa), luego nos gustaría considerar el tiempo nosotros mismos. En primer lugar, no hay nada para cargar la red y, en segundo lugar, ATMEL te permite teóricamente contar segundos con buena precisión. Teóricamente sí. Pero en la práctica, hay dificultades.

Una pequeña digresión sobre el reloj en tiempo real en el AVR.

En teoría, no hay nada complicado en construir un reloj en el microcontrolador AVR. Los diseñadores más rabiosos incluso empujan un reloj de cuarzo a 32768 Hz en el circuito para esto. Pero, de hecho, esto no es necesario. De hecho, es necesario un reloj de cuarzo para formar un múltiplo de interrupción de un segundo y despertar un microcontrolador (nota) dormido . Si su dispositivo funciona constantemente, y el reloj generalmente lo hace, entonces poner cuarzo adicional al existente y tomar dos patas de entrada-salida debajo es imprudente. Es posible usar un resonador de cuarzo, que ya está allí, ocho o dieciséis megahercios allí. Su precisión de cuantificación es suficiente para sus ojos, y contar un segundo como contador de tiempo también será fácil.

De hecho, el microcontrolador AVR ya tiene todo para esto. Como saben, la señal de reloj de entrada (por ejemplo, 8 MHz) llega dentro del chip (por ejemplo, AVRmega328P como el más común para arduino) en el llamado pre-divisor, donde puede dividirse aún más por el deseo del programador (generalmente por 8, 64, 256, 1024). Y luego llega a algún tipo de contador de tiempo (digamos T1), que inmediatamente comienza a incrementarse.

Entonces, tomemos 8 MHz y dividamos entre 256. Obtenemos respectivamente la frecuencia de reloj del contador 31250 Hz. En consecuencia, dado que el contador T1 tiene dieciséis dígitos y puede contar en consecuencia hasta 65535, entonces solo tendrá tiempo para contar hasta 31250 en un segundo. Lo que necesitamos Además, nuestro temporizador tiene otro registro de comparación muy útil. Si escribimos el número 31250 allí, entonces, bajo ciertas condiciones, se comparará constantemente con el contenido del contador T1 y, finalmente, cuando sea igual, el contador generará una señal de interrupción, por ejemplo, mantenga su segundo.

Resulta conveniente, pero, desafortunadamente, no es del todo exacto. Para nuestro contador se contará con un error de cuantificación de 256 / 8,000,000, que da un error bastante grande al calcular un segundo en hasta 32 microsegundos. Y esto lleva a un error de 2.8 segundos por día (0.000032 * 3600 * 24).
Pero si dividimos los 8 MHz originales por una cantidad menor, por ejemplo, entre 64, entonces la precisión de cuantificación aumentará 4 veces a 8 μs y reducirá el error resultante a 0.33 segundos por día. Pero, desafortunadamente, en este caso, el contador deberá contarse hasta 125,000, y dicho número en el registro de dieciséis bits no entrará. Tendremos que escribir un número más pequeño en el registro de comparación (62500 todavía puede caber) y agregar un ciclo en el programa en sí mismo, donde un segundo se contará no por una, sino por dos interrupciones.

Pero tomamos un estuche ideal, y un resonador de cuarzo real, especialmente instalado en un tablero "hecho en China", puede traerte muchas sorpresas. No, en general, si observa el cuarzo estándar en las hojas de datos , teóricamente, no todo es tan malo.

Como podemos ver, el cuarzo de rango medio se comporta bastante bien. Tiene una inestabilidad de su propia sintonía a 25 ppm (o, en otras palabras, 25 ppm), es decir, resonará a una frecuencia no de 8 MHz, pero, por ejemplo, a una frecuencia de 8, 0002 MHz, lo que nos dará hasta 2.1 segundos de error por día Pero este es un error constante y se puede tener en cuenta. Tal cuarzo también puede flotar a una temperatura de 5-10 ppm por grado, pero en condiciones de funcionamiento del dispositivo en la habitación, el error también será pequeño. Todavía existe un factor como el envejecimiento, pero es muy escaso y cambia las características del cuarzo a un estado de al menos cierta perceptibilidad, bueno, tal vez cinco años. O diez.

Y aquí nos alegra tomar un clon chino de arduino, por ejemplo ARDUINO UNO.



Ejecutamos en él un programa de prueba para contar el tiempo y comenzarlo. ¿Retrasos por hora por un minuto? Fácil! Segunda junta Arduino UNO? No hay nada mejor.

Toma el Arduino ProMini.



Y aquí está mejor, sí. El error disminuyó a veinte segundos por hora. Bueno, ya comparable a un reloj mecánico de cuco.

El último tablero que tuve a mano fue el Arduino Nano.



Y ella fue la única que mostró resultados más o menos sanos.

Pero incluso con tal tablero, usando solo construcciones teóricas, usted mismo comprende que no hará un reloj exacto. La placa necesita ser configurada y yo, con un suspiro, trepé detrás del osciloscopio.

Resultó que las placas Arduino tienen una característica desagradable: la salida a la que está conectado el resonador de cuarzo no tiene salida al peine de clavijas, aunque corresponde al puerto PB7. Como, ya que el puerto está ocupado por cuarzo, entonces no te aferras a él. Y justo al pie del microcontrolador, es muy difícil levantar la sonda del osciloscopio, para el montaje en superficie y un paso de 0,5 mm entre los terminales. Pero incluso unirme a la pierna derecha no me dio nada. Ya sea porque pinché incorrectamente o pinché en el lugar equivocado, porque la salida del resonador de cuarzo, tal vez no la salida del generador de reloj, y en general, está dentro del microcontrolador. Por lo tanto, tuve que sortear soluciones alternativas: poner el preescalador en el coeficiente de división mínimo: uno, escribir cero en el registro de comparación para que la interrupción se sacudiera inmediatamente e ingresar al microcontrolador en un modo especial en el que el tramo de puerto PB1 cambia su estado lógico con cada una de tales interrupciones.
Lógicamente, cuando enciende la placa Arduino Nano de 16 MHz, debe aparecer un meandro de 8 MHz en la salida de este puerto.

Que es lo que pasó. El osciloscopio mostró una frecuencia de 8. 002 31 MHz. Además, la última descarga vivió su propia vida y todavía no entendía si faltaba la precisión del osciloscopio o si la frecuencia del oscilador de cristal flotaba de esta manera. Más como un segundo.

La buena estabilidad térmica allí tampoco olía. Si respira en el tablero (¿tal vez, por cierto, los recipientes aún provienen de la humedad?) O trae un soldador (desde lejos), entonces el cuarzo podría moverse inmediatamente a cincuenta hertzios. Y estas mediciones aún se duplican aproximadamente, ya que la frecuencia inicial es de 16 MHz.

Por lo tanto, en placas Arduino (al menos las de origen chino) es imposible lograr una precisión de más de 200 Hz a una frecuencia de reloj de 16 MHz. Lo que nos da la máxima precisión de los relojes ensamblados en tales tableros no más de un segundo por día. Y eso está bien.

Porque hay clones chinos de Arduino UNO, ya mencionados por mí anteriormente, con los que, en general, todo está mal. Y son muy comunes, porque son baratos y convenientes.

Por lo tanto, su frecuencia puede diferir de la declarada en más de cien kilohercios. Lo cual es inusual incluso para el peor cuarzo chino.

¡El acertijo comienza con el hecho de que 12 MHz está escrito en el propio cuarzo! Y en las descripciones de los vendedores, también.



Pero no hay 12 MHz, eso es seguro. Si habilita el puerto serie UART en la placa, lo verá por usted mismo. Como el UART sintonizado a esta frecuencia no funcionará. Y sintonizado a una frecuencia de 16 MHz - será. Además, personalmente vi las formas de onda en mis dos tableros Arduino Uno. La primera placa tenía una frecuencia de generador de 15.8784 MHz, y la segunda de 15.8661 MHz.

Pero, de repente, resultó que el cuarzo de 12 MHz no está directamente relacionado con el microcontrolador AVR, sino que está diseñado para operar el puerto serie con una computadora a través de USB (para descargar bocetos). Por lo tanto, la suposición de que no había cuarzo adentro, sino una cadena RC mal ajustada, no se materializó. Y el cuarzo que necesitamos es mucho más pequeño y está ubicado al lado del chip del microcontrolador. Pero es muy pequeño y no tiene inscripción.

Como resultado, todavía no podía entender cómo y dónde encontrar resonadores de cuarzo de tan terrible calidad. Pero aparentemente, todo es posible en China. Y de alguna manera pensé en los temerarios que usaban Arduinki para asuntos serios. Bueno, el software puede y debe escribirse usted mismo, pero ¿qué hacer con la calidad de los módulos mismos? Aparentemente, desde los componentes electrónicos, los chinos están empujando a todos los más baratos y rechazados.

El programa Singing Bowl para AVR.

Al final, habiendo derrotado todas las dificultades con el tiempo preciso, escribí el siguiente código para mi Arduino ProMini

Programa C para el microcontrolador 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 , - , .

La interrupción del interruptor de láminas establece el mismo punto cero, si con el tiempo la palanca que tira del badajo comienza a moverse con relación al eje del motor.

La aplicación para la computadora.

Se basa de todos modos en los mismos programas antiguos , solo la representación visual cambia aquí.



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

.



En general, los monjes tibetanos no solo golpean con badajos en cuencos cantores. Si manejas con cuidado el mazo justo a lo largo del borde del cuenco, entonces, sin ningún golpe, nacerá un sonido maravilloso, teniendo debajo la naturaleza divina de la resonancia. Pero este es un desafío realmente serio para Arduino.

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


All Articles